1
0
Fork 0

Fix type errors and tests

pull/10320/head
Jordi Boggiano 2022-05-13 09:52:02 +02:00
parent 55dc80862e
commit b52053893c
No known key found for this signature in database
GPG Key ID: 7BBD42C429EC80BC
9 changed files with 45 additions and 50 deletions

View File

@ -66,7 +66,7 @@ trait CompletionTrait
if ($locker->isLocked()) { if ($locker->isLocked()) {
$platformRepo = new PlatformRepository(array(), $locker->getPlatformOverrides()); $platformRepo = new PlatformRepository(array(), $locker->getPlatformOverrides());
} else { } else {
$platformRepo = new PlatformRepository(array(), $composer->getConfig()->get('platform') ?: array()); $platformRepo = new PlatformRepository(array(), $composer->getConfig()->get('platform'));
} }
if ($input->getCompletionValue() === '') { if ($input->getCompletionValue() === '') {
// to reduce noise, when no text is yet entered we list only two entries for ext- and lib- prefixes // to reduce noise, when no text is yet entered we list only two entries for ext- and lib- prefixes
@ -115,36 +115,43 @@ trait CompletionTrait
$repos = new CompositeRepository($composer->getRepositoryManager()->getRepositories()); $repos = new CompositeRepository($composer->getRepositoryManager()->getRepositories());
$results = []; $results = [];
$showVendors = false;
if (!str_contains($input->getCompletionValue(), '/')) { if (!str_contains($input->getCompletionValue(), '/')) {
$results = $repos->search('^' . preg_quote($input->getCompletionValue()), RepositoryInterface::SEARCH_VENDOR); $results = $repos->search('^' . preg_quote($input->getCompletionValue()), RepositoryInterface::SEARCH_VENDOR);
$vendors = true; $showVendors = true;
} }
// if we get a single vendor, we expand it into its contents already // if we get a single vendor, we expand it into its contents already
if (\count($results) <= 1) { if (\count($results) <= 1) {
$results = $repos->search('^'.preg_quote($input->getCompletionValue()), RepositoryInterface::SEARCH_NAME); $results = $repos->search('^'.preg_quote($input->getCompletionValue()), RepositoryInterface::SEARCH_NAME);
$vendors = false; $showVendors = false;
} }
$results = array_column($results, 'name'); $results = array_column($results, 'name');
if ($vendors) { if ($showVendors) {
$results = array_map(function (string $name): string { $results = array_map(function (string $name): string {
return $name.'/'; return $name.'/';
}, $results); }, $results);
// sort shorter results first to avoid auto-expanding the completion to a longer string than needed // sort shorter results first to avoid auto-expanding the completion to a longer string than needed
usort($results, function (string $a, string $b) { usort($results, function (string $a, string $b) {
return \strlen($a) - \strlen($b); $lenA = \strlen($a);
$lenB = \strlen($b);
if ($lenA === $lenB) {
return $a <=> $b;
}
return $lenA - $lenB;
}); });
$pinned = []; $pinned = [];
// ensure if the input is an exact match that it is always in the result set // ensure if the input is an exact match that it is always in the result set
$completionInput = $input->getCompletionValue().'/'; $completionInput = $input->getCompletionValue().'/';
if (in_array($completionInput, $results, true)) { if (false !== ($exactIndex = array_search($completionInput, $results, true))) {
$pinned[] = $completionInput; $pinned[] = $completionInput;
array_splice($results, array_search($completionInput, $results, true), 1); array_splice($results, $exactIndex, 1);
} }
return array_merge($pinned, array_slice($results, 0, $max - \count($pinned))); return array_merge($pinned, array_slice($results, 0, $max - \count($pinned)));
@ -177,7 +184,7 @@ trait CompletionTrait
private function suggestPlatformPackage(): \Closure private function suggestPlatformPackage(): \Closure
{ {
return function (CompletionInput $input): array { return function (CompletionInput $input): array {
$repos = new PlatformRepository([], $this->requireComposer()->getConfig()->get('platform') ?? []); $repos = new PlatformRepository([], $this->requireComposer()->getConfig()->get('platform'));
$pattern = BasePackage::packageNameToRegexp($input->getCompletionValue().'*'); $pattern = BasePackage::packageNameToRegexp($input->getCompletionValue().'*');
return array_filter(array_map(function (PackageInterface $package) { return array_filter(array_map(function (PackageInterface $package) {

View File

@ -159,7 +159,7 @@ EOT
$preferSource, $preferSource,
$preferDist, $preferDist,
!$input->getOption('no-dev'), !$input->getOption('no-dev'),
$input->getOption('repository') ?: $input->getOption('repository-url'), \count($input->getOption('repository')) > 0 ? $input->getOption('repository') : $input->getOption('repository-url'),
$input->getOption('no-plugins'), $input->getOption('no-plugins'),
$input->getOption('no-scripts'), $input->getOption('no-scripts'),
$input->getOption('no-progress'), $input->getOption('no-progress'),
@ -197,7 +197,7 @@ EOT
$repositories = (array) $repositories; $repositories = (array) $repositories;
} }
$platformRequirementFilter = $platformRequirementFilter ?: PlatformRequirementFilterFactory::ignoreNothing(); $platformRequirementFilter = $platformRequirementFilter ?? PlatformRequirementFilterFactory::ignoreNothing();
// we need to manually load the configuration to pass the auth credentials to the io interface! // we need to manually load the configuration to pass the auth credentials to the io interface!
$io->loadConfiguration($config); $io->loadConfiguration($config);
@ -424,7 +424,7 @@ EOT
} }
} }
$platformOverrides = $config->get('platform') ?: array(); $platformOverrides = $config->get('platform');
$platformRepo = new PlatformRepository(array(), $platformOverrides); $platformRepo = new PlatformRepository(array(), $platformOverrides);
// find the latest version if there are multiple // find the latest version if there are multiple

View File

@ -119,6 +119,10 @@ EOT
private function prepareSubcommandInput(InputInterface $input, bool $quiet = false): StringInput private function prepareSubcommandInput(InputInterface $input, bool $quiet = false): StringInput
{ {
if (!method_exists($input, '__toString')) {
throw new \LogicException('Expected an Input instance that is stringable, got '.get_class($input));
}
// The COMPOSER env var should not apply to the global execution scope // The COMPOSER env var should not apply to the global execution scope
if (Platform::getEnv('COMPOSER')) { if (Platform::getEnv('COMPOSER')) {
Platform::clearEnv('COMPOSER'); Platform::clearEnv('COMPOSER');

View File

@ -99,7 +99,7 @@ trait PackageDiscoveryTrait
foreach ($requires as $requirement) { foreach ($requires as $requirement) {
if (!isset($requirement['version'])) { if (!isset($requirement['version'])) {
// determine the best version automatically // determine the best version automatically
list($name, $version) = $this->findBestVersionAndNameForPackage($input, $requirement['name'], $platformRepo, $preferredStability, null, null, $fixed); list($name, $version) = $this->findBestVersionAndNameForPackage($input, $requirement['name'], $platformRepo, $preferredStability, $fixed);
$requirement['version'] = $version; $requirement['version'] = $version;
// replace package name from packagist.org // replace package name from packagist.org
@ -268,7 +268,7 @@ trait PackageDiscoveryTrait
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
* @return array{string, string} name version * @return array{string, string} name version
*/ */
private function findBestVersionAndNameForPackage(InputInterface $input, string $name, ?PlatformRepository $platformRepo = null, string $preferredStability = 'stable', ?string $requiredVersion = null, ?string $minimumStability = null, bool $fixed = false): array private function findBestVersionAndNameForPackage(InputInterface $input, string $name, ?PlatformRepository $platformRepo = null, string $preferredStability = 'stable', bool $fixed = false): array
{ {
// handle ignore-platform-reqs flag if present // handle ignore-platform-reqs flag if present
if ($input->hasOption('ignore-platform-reqs') && $input->hasOption('ignore-platform-req')) { if ($input->hasOption('ignore-platform-reqs') && $input->hasOption('ignore-platform-req')) {
@ -278,17 +278,17 @@ trait PackageDiscoveryTrait
} }
// find the latest version allowed in this repo set // find the latest version allowed in this repo set
$repoSet = $this->getRepositorySet($input, $minimumStability); $repoSet = $this->getRepositorySet($input);
$versionSelector = new VersionSelector($repoSet, $platformRepo); $versionSelector = new VersionSelector($repoSet, $platformRepo);
$effectiveMinimumStability = $minimumStability ?? $this->getMinimumStability($input); $effectiveMinimumStability = $this->getMinimumStability($input);
$package = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, $platformRequirementFilter); $package = $versionSelector->findBestCandidate($name, null, $preferredStability, $platformRequirementFilter);
if (false === $package) { if (false === $package) {
// platform packages can not be found in the pool in versions other than the local platform's has // platform packages can not be found in the pool in versions other than the local platform's has
// so if platform reqs are ignored we just take the user's word for it // so if platform reqs are ignored we just take the user's word for it
if ($platformRequirementFilter->isIgnored($name)) { if ($platformRequirementFilter->isIgnored($name)) {
return array($name, $requiredVersion ?: '*'); return array($name, '*');
} }
// Check if it is a virtual package provided by others // Check if it is a virtual package provided by others
@ -308,17 +308,16 @@ trait PackageDiscoveryTrait
} }
// Check whether the package requirements were the problem // Check whether the package requirements were the problem
if (!($platformRequirementFilter instanceof IgnoreAllPlatformRequirementFilter) && false !== ($candidate = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, PlatformRequirementFilterFactory::ignoreAll()))) { if (!($platformRequirementFilter instanceof IgnoreAllPlatformRequirementFilter) && false !== ($candidate = $versionSelector->findBestCandidate($name, null, $preferredStability, PlatformRequirementFilterFactory::ignoreAll()))) {
throw new \InvalidArgumentException(sprintf( throw new \InvalidArgumentException(sprintf(
'Package %s%s has requirements incompatible with your PHP version, PHP extensions and Composer version' . $this->getPlatformExceptionDetails($candidate, $platformRepo), 'Package %s has requirements incompatible with your PHP version, PHP extensions and Composer version' . $this->getPlatformExceptionDetails($candidate, $platformRepo),
$name, $name
is_string($requiredVersion) ? ' at version '.$requiredVersion : ''
)); ));
} }
// Check whether the minimum stability was the problem but the package exists // Check whether the minimum stability was the problem but the package exists
if (false !== ($package = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, $platformRequirementFilter, RepositorySet::ALLOW_UNACCEPTABLE_STABILITIES))) { if (false !== ($package = $versionSelector->findBestCandidate($name, null, $preferredStability, $platformRequirementFilter, RepositorySet::ALLOW_UNACCEPTABLE_STABILITIES))) {
// we must first verify if a valid package would be found in a lower priority repository // we must first verify if a valid package would be found in a lower priority repository
if (false !== ($allReposPackage = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, $platformRequirementFilter, RepositorySet::ALLOW_SHADOWED_REPOSITORIES))) { if (false !== ($allReposPackage = $versionSelector->findBestCandidate($name, null, $preferredStability, $platformRequirementFilter, RepositorySet::ALLOW_SHADOWED_REPOSITORIES))) {
throw new \InvalidArgumentException( throw new \InvalidArgumentException(
'Package '.$name.' exists in '.$allReposPackage->getRepository()->getRepoName().' and '.$package->getRepository()->getRepoName().' which has a higher repository priority. The packages from the higher priority repository do not match your minimum-stability and are therefore not installable. That repository is canonical so the lower priority repo\'s packages are not installable. See https://getcomposer.org/repoprio for details and assistance.' 'Package '.$name.' exists in '.$allReposPackage->getRepository()->getRepoName().' and '.$package->getRepository()->getRepoName().' which has a higher repository priority. The packages from the higher priority repository do not match your minimum-stability and are therefore not installable. That repository is canonical so the lower priority repo\'s packages are not installable. See https://getcomposer.org/repoprio for details and assistance.'
); );
@ -330,21 +329,6 @@ trait PackageDiscoveryTrait
$effectiveMinimumStability $effectiveMinimumStability
)); ));
} }
// Check whether the required version was the problem
if (is_string($requiredVersion) && false !== ($package = $versionSelector->findBestCandidate($name, null, $preferredStability, $platformRequirementFilter))) {
// we must first verify if a valid package would be found in a lower priority repository
if (false !== ($allReposPackage = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, PlatformRequirementFilterFactory::ignoreNothing(), RepositorySet::ALLOW_SHADOWED_REPOSITORIES))) {
throw new \InvalidArgumentException(
'Package '.$name.' exists in '.$allReposPackage->getRepository()->getRepoName().' and '.$package->getRepository()->getRepoName().' which has a higher repository priority. The packages from the higher priority repository do not match your constraint and are therefore not installable. That repository is canonical so the lower priority repo\'s packages are not installable. See https://getcomposer.org/repoprio for details and assistance.'
);
}
throw new \InvalidArgumentException(sprintf(
'Could not find package %s in a version matching "%s" and a stability matching "'.$effectiveMinimumStability.'".',
$name,
$requiredVersion
));
}
// Check whether the PHP version was the problem for all versions // Check whether the PHP version was the problem for all versions
if (!$platformRequirementFilter instanceof IgnoreAllPlatformRequirementFilter && false !== ($candidate = $versionSelector->findBestCandidate($name, null, $preferredStability, PlatformRequirementFilterFactory::ignoreAll(), RepositorySet::ALLOW_UNACCEPTABLE_STABILITIES))) { if (!$platformRequirementFilter instanceof IgnoreAllPlatformRequirementFilter && false !== ($candidate = $versionSelector->findBestCandidate($name, null, $preferredStability, PlatformRequirementFilterFactory::ignoreAll(), RepositorySet::ALLOW_UNACCEPTABLE_STABILITIES))) {
$additional = ''; $additional = '';

View File

@ -187,7 +187,7 @@ EOT
// init repos // init repos
$platformOverrides = array(); $platformOverrides = array();
if ($composer) { if ($composer) {
$platformOverrides = $composer->getConfig()->get('platform') ?: array(); $platformOverrides = $composer->getConfig()->get('platform');
} }
$platformRepo = new PlatformRepository(array(), $platformOverrides); $platformRepo = new PlatformRepository(array(), $platformOverrides);
$lockedRepo = null; $lockedRepo = null;

View File

@ -65,7 +65,7 @@ EOT
$installedRepos[] = new PlatformRepository(array(), $locker->getPlatformOverrides()); $installedRepos[] = new PlatformRepository(array(), $locker->getPlatformOverrides());
$installedRepos[] = $locker->getLockedRepository(!$input->getOption('no-dev')); $installedRepos[] = $locker->getLockedRepository(!$input->getOption('no-dev'));
} else { } else {
$installedRepos[] = new PlatformRepository(array(), $composer->getConfig()->get('platform') ?: array()); $installedRepos[] = new PlatformRepository(array(), $composer->getConfig()->get('platform'));
$installedRepos[] = $composer->getRepositoryManager()->getLocalRepository(); $installedRepos[] = $composer->getRepositoryManager()->getLocalRepository();
} }

View File

@ -59,7 +59,7 @@ class InputArgument extends BaseInputArgument
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{ {
$values = $this->suggestedValues; $values = $this->suggestedValues;
if ($values instanceof \Closure && !\is_array($values = $values($input, $suggestions))) { if ($values instanceof \Closure && !\is_array($values = $values($input, $suggestions))) { // @phpstan-ignore-line
throw new LogicException(sprintf('Closure for option "%s" must return an array. Got "%s".', $this->getName(), get_debug_type($values))); throw new LogicException(sprintf('Closure for option "%s" must return an array. Got "%s".', $this->getName(), get_debug_type($values)));
} }
if ([] !== $values) { if ([] !== $values) {

View File

@ -62,7 +62,7 @@ class InputOption extends BaseInputOption
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{ {
$values = $this->suggestedValues; $values = $this->suggestedValues;
if ($values instanceof \Closure && !\is_array($values = $values($input, $suggestions))) { if ($values instanceof \Closure && !\is_array($values = $values($input, $suggestions))) { // @phpstan-ignore-line
throw new LogicException(sprintf('Closure for argument "%s" must return an array. Got "%s".', $this->getName(), get_debug_type($values))); throw new LogicException(sprintf('Closure for argument "%s" must return an array. Got "%s".', $this->getName(), get_debug_type($values)));
} }
if ([] !== $values) { if ([] !== $values) {

View File

@ -27,34 +27,34 @@ class CompletionFunctionalTest extends TestCase
*/ */
public function getCommandSuggestions(): iterable public function getCommandSuggestions(): iterable
{ {
$randomProject = '104corp/cache'; $randomVendor = 'a/';
$installedPackages = ['composer/semver', 'psr/log']; $installedPackages = ['composer/semver', 'psr/log'];
$preferInstall = ['dist', 'source', 'auto']; $preferInstall = ['dist', 'source', 'auto'];
yield ['archive ', [$randomProject]]; yield ['archive ', [$randomVendor]];
yield ['archive symfony/http-', ['symfony/http-kernel', 'symfony/http-foundation']]; yield ['archive symfony/http-', ['symfony/http-kernel', 'symfony/http-foundation']];
yield ['archive --format ', ['tar', 'zip']]; yield ['archive --format ', ['tar', 'zip']];
yield ['create-project ', [$randomProject]]; yield ['create-project ', [$randomVendor]];
yield ['create-project symfony/skeleton --prefer-install ', $preferInstall]; yield ['create-project symfony/skeleton --prefer-install ', $preferInstall];
yield ['depends ', $installedPackages]; yield ['depends ', $installedPackages];
yield ['why ', $installedPackages]; yield ['why ', $installedPackages];
yield ['exec ', ['composer', 'compile']]; yield ['exec ', ['composer', 'jsonlint', 'phpstan', 'phpstan.phar', 'simple-phpunit', 'validate-json']];
yield ['browse ', $installedPackages]; yield ['browse ', $installedPackages];
yield ['home -H ', $installedPackages]; yield ['home -H ', $installedPackages];
yield ['init --require ', [$randomProject]]; yield ['init --require ', [$randomVendor]];
yield ['init --require-dev foo/bar --require-dev ', [$randomProject]]; yield ['init --require-dev foo/bar --require-dev ', [$randomVendor]];
yield ['install --prefer-install ', $preferInstall]; yield ['install --prefer-install ', $preferInstall];
yield ['install ', $installedPackages]; yield ['install ', $installedPackages];
yield ['outdated ', $installedPackages]; yield ['outdated ', $installedPackages];
yield ['prohibits ', [$randomProject]]; yield ['prohibits ', [$randomVendor]];
yield ['why-not symfony/http-ker', ['symfony/http-kernel']]; yield ['why-not symfony/http-ker', ['symfony/http-kernel']];
yield ['reinstall --prefer-install ', $preferInstall]; yield ['reinstall --prefer-install ', $preferInstall];
@ -63,7 +63,7 @@ class CompletionFunctionalTest extends TestCase
yield ['remove ', $installedPackages]; yield ['remove ', $installedPackages];
yield ['require --prefer-install ', $preferInstall]; yield ['require --prefer-install ', $preferInstall];
yield ['require ', [$randomProject]]; yield ['require ', [$randomVendor]];
yield ['require --dev symfony/http-', ['symfony/http-kernel', 'symfony/http-foundation']]; yield ['require --dev symfony/http-', ['symfony/http-kernel', 'symfony/http-foundation']];
yield ['run-script ', ['compile', 'test', 'phpstan']]; yield ['run-script ', ['compile', 'test', 'phpstan']];