From 8b5254688ce94d8e26536c34a4ecf0439d30ead9 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 16 Feb 2022 15:13:21 +0100 Subject: [PATCH 1/2] Drop early package name validation if a version is provided to require/init command, fixes #10489 --- src/Composer/Command/InitCommand.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Composer/Command/InitCommand.php b/src/Composer/Command/InitCommand.php index 30ef1fd0c1e2..55d966d3172e 100644 --- a/src/Composer/Command/InitCommand.php +++ b/src/Composer/Command/InitCommand.php @@ -543,12 +543,6 @@ final protected function determineRequirements(InputInterface $input, OutputInte $requirement['version'], $requirement['name'] )); - } else { - // check that the specified version/constraint exists before we proceed - list($name) = $this->findBestVersionAndNameForPackage($input, $requirement['name'], $platformRepo, $preferredStability, $checkProvidedVersions ? $requirement['version'] : null, 'dev', $fixed); - - // replace package name from packagist.org - $requirement['name'] = $name; } $result[] = $requirement['name'] . ' ' . $requirement['version']; From 2a2440c2a1690c8a29f45f9a94af9f15b423e27c Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 16 Feb 2022 15:44:43 +0100 Subject: [PATCH 2/2] Fix handling of virtual packages when searching for packages or when looking up the preferred version (init & require command), refs #10489 --- src/Composer/Command/InitCommand.php | 57 ++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/src/Composer/Command/InitCommand.php b/src/Composer/Command/InitCommand.php index 55d966d3172e..75bc92dd2df1 100644 --- a/src/Composer/Command/InitCommand.php +++ b/src/Composer/Command/InitCommand.php @@ -577,21 +577,9 @@ final protected function determineRequirements(InputInterface $input, OutputInte } $matches = array_values($matches); - $exactMatch = null; - $choices = array(); - foreach ($matches as $position => $foundPackage) { - $abandoned = ''; - if (isset($foundPackage['abandoned'])) { - if (is_string($foundPackage['abandoned'])) { - $replacement = sprintf('Use %s instead', $foundPackage['abandoned']); - } else { - $replacement = 'No replacement was suggested'; - } - $abandoned = sprintf('Abandoned. %s.', $replacement); - } - - $choices[] = sprintf(' %5s %s %s', "[$position]", $foundPackage['name'], $abandoned); - if ($foundPackage['name'] === $package) { + $exactMatch = false; + foreach ($matches as $match) { + if ($match['name'] === $package) { $exactMatch = true; break; } @@ -599,6 +587,26 @@ final protected function determineRequirements(InputInterface $input, OutputInte // no match, prompt which to pick if (!$exactMatch) { + $providers = $this->getRepos()->getProviders($package); + if (count($providers) > 0) { + array_unshift($matches, array('name' => $package, 'description' => '')); + } + + $choices = array(); + foreach ($matches as $position => $foundPackage) { + $abandoned = ''; + if (isset($foundPackage['abandoned'])) { + if (is_string($foundPackage['abandoned'])) { + $replacement = sprintf('Use %s instead', $foundPackage['abandoned']); + } else { + $replacement = 'No replacement was suggested'; + } + $abandoned = sprintf('Abandoned. %s.', $replacement); + } + + $choices[] = sprintf(' %5s %s %s', "[$position]", $foundPackage['name'], $abandoned); + } + $io->writeError(array( '', sprintf('Found %s packages matching %s', count($matches), $package), @@ -893,7 +901,8 @@ private function findBestVersionAndNameForPackage(InputInterface $input, $name, $platformRequirementFilter = PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs); // find the latest version allowed in this repo set - $versionSelector = new VersionSelector($this->getRepositorySet($input, $minimumStability), $platformRepo); + $repoSet = $this->getRepositorySet($input, $minimumStability); + $versionSelector = new VersionSelector($repoSet, $platformRepo); $effectiveMinimumStability = $minimumStability ?: $this->getMinimumStability($input); $package = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, $platformRequirementFilter); @@ -905,6 +914,22 @@ private function findBestVersionAndNameForPackage(InputInterface $input, $name, return array($name, $requiredVersion ?: '*'); } + // Check if it is a virtual package provided by others + $providers = $repoSet->getProviders($name); + if (count($providers) > 0) { + $constraint = '*'; + if ($input->isInteractive()) { + $constraint = $this->getIO()->askAndValidate('Package "'.$name.'" does not exist but is provided by '.count($providers).' packages. Which version constraint would you like to use? [*] ', function ($value) { + $parser = new VersionParser(); + $parser->parseConstraints($value); + + return $value; + }, 3, '*'); + } + + return array($name, $constraint); + } + // Check whether the package requirements were the problem if (!($platformRequirementFilter instanceof IgnoreAllPlatformRequirementFilter) && ($candidate = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, PlatformRequirementFilterFactory::ignoreAll()))) { throw new \InvalidArgumentException(sprintf(