1
0
Fork 0

Refactor ignore platform reqs checks (#10079)

Introduces a `PlatformRequirementFilter` with methods that help to decide if a requirement is ignored or not as discussed in #10045 but without changing behaviour.
pull/10083/head
Martin Herndl 2021-11-11 12:24:12 +01:00 committed by GitHub
parent 68847ed609
commit 3013674c92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 419 additions and 98 deletions

View File

@ -14,13 +14,15 @@ namespace Composer\Autoload;
use Composer\Config; use Composer\Config;
use Composer\EventDispatcher\EventDispatcher; use Composer\EventDispatcher\EventDispatcher;
use Composer\Filter\PlatformRequirementFilter\IgnoreAllPlatformRequirementFilter;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterInterface;
use Composer\Installer\InstallationManager; use Composer\Installer\InstallationManager;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Package\AliasPackage; use Composer\Package\AliasPackage;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Package\RootPackageInterface; use Composer\Package\RootPackageInterface;
use Composer\Repository\InstalledRepositoryInterface; use Composer\Repository\InstalledRepositoryInterface;
use Composer\Repository\PlatformRepository;
use Composer\Semver\Constraint\Bound; use Composer\Semver\Constraint\Bound;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
use Composer\Util\Platform; use Composer\Util\Platform;
@ -70,14 +72,16 @@ class AutoloadGenerator
private $runScripts = false; private $runScripts = false;
/** /**
* @var bool|string[] * @var PlatformRequirementFilterInterface
*/ */
private $ignorePlatformReqs = false; private $platformRequirementFilter;
public function __construct(EventDispatcher $eventDispatcher, IOInterface $io = null) public function __construct(EventDispatcher $eventDispatcher, IOInterface $io = null)
{ {
$this->eventDispatcher = $eventDispatcher; $this->eventDispatcher = $eventDispatcher;
$this->io = $io; $this->io = $io;
$this->platformRequirementFilter = PlatformRequirementFilterFactory::ignoreNothing();
} }
/** /**
@ -133,16 +137,22 @@ class AutoloadGenerator
* *
* @param bool|string[] $ignorePlatformReqs * @param bool|string[] $ignorePlatformReqs
* @return void * @return void
*
* @deprecated use setPlatformRequirementFilter instead
*/ */
public function setIgnorePlatformRequirements($ignorePlatformReqs) public function setIgnorePlatformRequirements($ignorePlatformReqs)
{ {
if (is_array($ignorePlatformReqs)) { trigger_error('AutoloadGenerator::setIgnorePlatformRequirements is deprecated since Composer 2.2, use setPlatformRequirementFilter instead.', E_USER_DEPRECATED);
$this->ignorePlatformReqs = array_filter($ignorePlatformReqs, function ($req) {
return PlatformRepository::isPlatformPackage($req); $this->setPlatformRequirementFilter(PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs));
}); }
} else {
$this->ignorePlatformReqs = (bool) $ignorePlatformReqs; /**
} * @return void
*/
public function setPlatformRequirementFilter(PlatformRequirementFilterInterface $platformRequirementFilter)
{
$this->platformRequirementFilter = $platformRequirementFilter;
} }
/** /**
@ -391,10 +401,10 @@ EOF;
unlink($includeFilesFilePath); unlink($includeFilesFilePath);
} }
$filesystem->filePutContentsIfModified($targetDir.'/autoload_static.php', $this->getStaticFile($suffix, $targetDir, $vendorPath, $basePath, $staticPhpVersion)); $filesystem->filePutContentsIfModified($targetDir.'/autoload_static.php', $this->getStaticFile($suffix, $targetDir, $vendorPath, $basePath, $staticPhpVersion));
$checkPlatform = $config->get('platform-check') && $this->ignorePlatformReqs !== true; $checkPlatform = $config->get('platform-check') && !($this->platformRequirementFilter instanceof IgnoreAllPlatformRequirementFilter);
$platformCheckContent = null; $platformCheckContent = null;
if ($checkPlatform) { if ($checkPlatform) {
$platformCheckContent = $this->getPlatformCheck($packageMap, $this->ignorePlatformReqs ?: array(), $config->get('platform-check'), $devPackageNames); $platformCheckContent = $this->getPlatformCheck($packageMap, $config->get('platform-check'), $devPackageNames);
if (null === $platformCheckContent) { if (null === $platformCheckContent) {
$checkPlatform = false; $checkPlatform = false;
} }
@ -740,12 +750,11 @@ EOF;
/** /**
* @param array<int, array{0: PackageInterface, 1: string}> $packageMap * @param array<int, array{0: PackageInterface, 1: string}> $packageMap
* @param string[] $ignorePlatformReqs
* @param bool $checkPlatform * @param bool $checkPlatform
* @param string[] $devPackageNames * @param string[] $devPackageNames
* @return ?string * @return ?string
*/ */
protected function getPlatformCheck(array $packageMap, array $ignorePlatformReqs, $checkPlatform, array $devPackageNames) protected function getPlatformCheck(array $packageMap, $checkPlatform, array $devPackageNames)
{ {
$lowestPhpVersion = Bound::zero(); $lowestPhpVersion = Bound::zero();
$requiredExtensions = array(); $requiredExtensions = array();
@ -768,7 +777,7 @@ EOF;
} }
foreach ($package->getRequires() as $link) { foreach ($package->getRequires() as $link) {
if (in_array($link->getTarget(), $ignorePlatformReqs, true)) { if ($this->platformRequirementFilter->isIgnored($link->getTarget())) {
continue; continue;
} }

View File

@ -14,6 +14,9 @@ namespace Composer\Command;
use Composer\Config; use Composer\Config;
use Composer\Factory; use Composer\Factory;
use Composer\Filter\PlatformRequirementFilter\IgnoreAllPlatformRequirementFilter;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterInterface;
use Composer\Installer; use Composer\Installer;
use Composer\Installer\ProjectInstaller; use Composer\Installer\ProjectInstaller;
use Composer\Installer\SuggestedPackagesReporter; use Composer\Installer\SuggestedPackagesReporter;
@ -159,7 +162,7 @@ EOT
$input->getOption('no-scripts'), $input->getOption('no-scripts'),
$input->getOption('no-progress'), $input->getOption('no-progress'),
$input->getOption('no-install'), $input->getOption('no-install'),
$ignorePlatformReqs, PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs),
!$input->getOption('no-secure-http'), !$input->getOption('no-secure-http'),
$input->getOption('add-repository') $input->getOption('add-repository')
); );
@ -178,14 +181,13 @@ EOT
* @param bool $noScripts * @param bool $noScripts
* @param bool $noProgress * @param bool $noProgress
* @param bool $noInstall * @param bool $noInstall
* @param bool $ignorePlatformReqs
* @param bool $secureHttp * @param bool $secureHttp
* @param bool $addRepository * @param bool $addRepository
* *
* @return int * @return int
* @throws \Exception * @throws \Exception
*/ */
public function installProject(IOInterface $io, Config $config, InputInterface $input, $packageName = null, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, $repositories = null, $disablePlugins = false, $noScripts = false, $noProgress = false, $noInstall = false, $ignorePlatformReqs = false, $secureHttp = true, $addRepository = false) public function installProject(IOInterface $io, Config $config, InputInterface $input, $packageName = null, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, $repositories = null, $disablePlugins = false, $noScripts = false, $noProgress = false, $noInstall = false, PlatformRequirementFilterInterface $platformRequirementFilter = null, $secureHttp = true, $addRepository = false)
{ {
$oldCwd = getcwd(); $oldCwd = getcwd();
@ -193,13 +195,15 @@ EOT
$repositories = (array) $repositories; $repositories = (array) $repositories;
} }
$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);
$this->suggestedPackagesReporter = new SuggestedPackagesReporter($io); $this->suggestedPackagesReporter = new SuggestedPackagesReporter($io);
if ($packageName !== null) { if ($packageName !== null) {
$installedFromVcs = $this->installRootPackage($io, $config, $packageName, $directory, $packageVersion, $stability, $preferSource, $preferDist, $installDevPackages, $repositories, $disablePlugins, $noScripts, $noProgress, $ignorePlatformReqs, $secureHttp); $installedFromVcs = $this->installRootPackage($io, $config, $packageName, $platformRequirementFilter, $directory, $packageVersion, $stability, $preferSource, $preferDist, $installDevPackages, $repositories, $disablePlugins, $noScripts, $noProgress, $secureHttp);
} else { } else {
$installedFromVcs = false; $installedFromVcs = false;
} }
@ -250,7 +254,7 @@ EOT
$installer->setPreferSource($preferSource) $installer->setPreferSource($preferSource)
->setPreferDist($preferDist) ->setPreferDist($preferDist)
->setDevMode($installDevPackages) ->setDevMode($installDevPackages)
->setIgnorePlatformRequirements($ignorePlatformReqs) ->setPlatformRequirementFilter($platformRequirementFilter)
->setSuggestedPackagesReporter($this->suggestedPackagesReporter) ->setSuggestedPackagesReporter($this->suggestedPackagesReporter)
->setOptimizeAutoloader($config->get('optimize-autoloader')) ->setOptimizeAutoloader($config->get('optimize-autoloader'))
->setClassMapAuthoritative($config->get('classmap-authoritative')) ->setClassMapAuthoritative($config->get('classmap-authoritative'))
@ -342,13 +346,12 @@ EOT
* @param bool $disablePlugins * @param bool $disablePlugins
* @param bool $noScripts * @param bool $noScripts
* @param bool $noProgress * @param bool $noProgress
* @param bool $ignorePlatformReqs
* @param bool $secureHttp * @param bool $secureHttp
* *
* @return bool * @return bool
* @throws \Exception * @throws \Exception
*/ */
protected function installRootPackage(IOInterface $io, Config $config, $packageName, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, array $repositories = null, $disablePlugins = false, $noScripts = false, $noProgress = false, $ignorePlatformReqs = false, $secureHttp = true) protected function installRootPackage(IOInterface $io, Config $config, $packageName, PlatformRequirementFilterInterface $platformRequirementFilter, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, array $repositories = null, $disablePlugins = false, $noScripts = false, $noProgress = false, $secureHttp = true)
{ {
if (!$secureHttp) { if (!$secureHttp) {
$config->merge(array('config' => array('secure-http' => false))); $config->merge(array('config' => array('secure-http' => false)));
@ -425,11 +428,11 @@ EOT
// find the latest version if there are multiple // find the latest version if there are multiple
$versionSelector = new VersionSelector($repositorySet, $platformRepo); $versionSelector = new VersionSelector($repositorySet, $platformRepo);
$package = $versionSelector->findBestCandidate($name, $packageVersion, $stability, $ignorePlatformReqs); $package = $versionSelector->findBestCandidate($name, $packageVersion, $stability, $platformRequirementFilter);
if (!$package) { if (!$package) {
$errorMessage = "Could not find package $name with " . ($packageVersion ? "version $packageVersion" : "stability $stability"); $errorMessage = "Could not find package $name with " . ($packageVersion ? "version $packageVersion" : "stability $stability");
if (true !== $ignorePlatformReqs && $versionSelector->findBestCandidate($name, $packageVersion, $stability, true)) { if (!($platformRequirementFilter instanceof IgnoreAllPlatformRequirementFilter) && $versionSelector->findBestCandidate($name, $packageVersion, $stability, PlatformRequirementFilterFactory::ignoreAll())) {
throw new \InvalidArgumentException($errorMessage .' in a version installable using your PHP version, PHP extensions and Composer version.'); throw new \InvalidArgumentException($errorMessage .' in a version installable using your PHP version, PHP extensions and Composer version.');
} }

View File

@ -12,6 +12,7 @@
namespace Composer\Command; namespace Composer\Command;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
use Composer\Plugin\CommandEvent; use Composer\Plugin\CommandEvent;
use Composer\Plugin\PluginEvents; use Composer\Plugin\PluginEvents;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
@ -97,7 +98,7 @@ EOT
$generator->setClassMapAuthoritative($authoritative); $generator->setClassMapAuthoritative($authoritative);
$generator->setRunScripts(true); $generator->setRunScripts(true);
$generator->setApcu($apcu, $apcuPrefix); $generator->setApcu($apcu, $apcuPrefix);
$generator->setIgnorePlatformRequirements($ignorePlatformReqs); $generator->setPlatformRequirementFilter(PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs));
$numberOfClasses = $generator->dump($config, $localRepo, $package, $installationManager, 'composer', $optimize); $numberOfClasses = $generator->dump($config, $localRepo, $package, $installationManager, 'composer', $optimize);
if ($authoritative) { if ($authoritative) {

View File

@ -13,6 +13,8 @@
namespace Composer\Command; namespace Composer\Command;
use Composer\Factory; use Composer\Factory;
use Composer\Filter\PlatformRequirementFilter\IgnoreAllPlatformRequirementFilter;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
use Composer\Json\JsonFile; use Composer\Json\JsonFile;
use Composer\Json\JsonValidationException; use Composer\Json\JsonValidationException;
use Composer\Package\BasePackage; use Composer\Package\BasePackage;
@ -890,22 +892,23 @@ EOT
if ($input->hasOption('ignore-platform-reqs') && $input->hasOption('ignore-platform-req')) { if ($input->hasOption('ignore-platform-reqs') && $input->hasOption('ignore-platform-req')) {
$ignorePlatformReqs = $input->getOption('ignore-platform-reqs') ?: ($input->getOption('ignore-platform-req') ?: false); $ignorePlatformReqs = $input->getOption('ignore-platform-reqs') ?: ($input->getOption('ignore-platform-req') ?: false);
} }
$platformRequirementFilter = PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs);
// find the latest version allowed in this repo set // find the latest version allowed in this repo set
$versionSelector = new VersionSelector($this->getRepositorySet($input, $minimumStability), $platformRepo); $versionSelector = new VersionSelector($this->getRepositorySet($input, $minimumStability), $platformRepo);
$effectiveMinimumStability = $minimumStability ?: $this->getMinimumStability($input); $effectiveMinimumStability = $minimumStability ?: $this->getMinimumStability($input);
$package = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, $ignorePlatformReqs); $package = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, $platformRequirementFilter);
if (!$package) { if (!$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 ((true === $ignorePlatformReqs || (is_array($ignorePlatformReqs) && in_array($name, $ignorePlatformReqs))) && PlatformRepository::isPlatformPackage($name)) { if ($platformRequirementFilter->isIgnored($name)) {
return array($name, $requiredVersion ?: '*'); return array($name, $requiredVersion ?: '*');
} }
// Check whether the package requirements were the problem // Check whether the package requirements were the problem
if (true !== $ignorePlatformReqs && ($candidate = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, true))) { if (!($platformRequirementFilter instanceof IgnoreAllPlatformRequirementFilter) && ($candidate = $versionSelector->findBestCandidate($name, $requiredVersion, $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%s has requirements incompatible with your PHP version, PHP extensions and Composer version' . $this->getPlatformExceptionDetails($candidate, $platformRepo),
$name, $name,
@ -913,9 +916,9 @@ EOT
)); ));
} }
// 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 ($package = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, $ignorePlatformReqs, RepositorySet::ALLOW_UNACCEPTABLE_STABILITIES)) { if ($package = $versionSelector->findBestCandidate($name, $requiredVersion, $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 ($allReposPackage = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, $ignorePlatformReqs, RepositorySet::ALLOW_SHADOWED_REPOSITORIES)) { if ($allReposPackage = $versionSelector->findBestCandidate($name, $requiredVersion, $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 with higher priority do not match your minimum-stability and are therefore 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 with higher priority do not match your minimum-stability and are therefore not installable. See https://getcomposer.org/repoprio for details and assistance.'
); );
@ -928,9 +931,9 @@ EOT
)); ));
} }
// Check whether the required version was the problem // Check whether the required version was the problem
if ($requiredVersion && $package = $versionSelector->findBestCandidate($name, null, $preferredStability, $ignorePlatformReqs)) { if ($requiredVersion && $package = $versionSelector->findBestCandidate($name, null, $preferredStability, $platformRequirementFilter)) {
// 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 ($allReposPackage = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, false, RepositorySet::ALLOW_SHADOWED_REPOSITORIES)) { if ($allReposPackage = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, PlatformRequirementFilterFactory::ignoreNothing(), 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 with higher priority do not match your constraint and are therefore 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 with higher priority do not match your constraint and are therefore not installable. See https://getcomposer.org/repoprio for details and assistance.'
); );
@ -943,9 +946,9 @@ EOT
)); ));
} }
// Check whether the PHP version was the problem for all versions // Check whether the PHP version was the problem for all versions
if (true !== $ignorePlatformReqs && ($candidate = $versionSelector->findBestCandidate($name, null, $preferredStability, true, RepositorySet::ALLOW_UNACCEPTABLE_STABILITIES))) { if (!($platformRequirementFilter instanceof IgnoreAllPlatformRequirementFilter) && ($candidate = $versionSelector->findBestCandidate($name, null, $preferredStability, PlatformRequirementFilterFactory::ignoreAll(), RepositorySet::ALLOW_UNACCEPTABLE_STABILITIES))) {
$additional = ''; $additional = '';
if (false === $versionSelector->findBestCandidate($name, null, $preferredStability, true)) { if (false === $versionSelector->findBestCandidate($name, null, $preferredStability, PlatformRequirementFilterFactory::ignoreAll())) {
$additional = PHP_EOL.PHP_EOL.'Additionally, the package was only found with a stability of "'.$candidate->getStability().'" while your minimum stability is "'.$effectiveMinimumStability.'".'; $additional = PHP_EOL.PHP_EOL.'Additionally, the package was only found with a stability of "'.$candidate->getStability().'" while your minimum stability is "'.$effectiveMinimumStability.'".';
} }

View File

@ -12,6 +12,7 @@
namespace Composer\Command; namespace Composer\Command;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
use Composer\Installer; use Composer\Installer;
use Composer\Plugin\CommandEvent; use Composer\Plugin\CommandEvent;
use Composer\Plugin\PluginEvents; use Composer\Plugin\PluginEvents;
@ -130,7 +131,7 @@ EOT
->setOptimizeAutoloader($optimize) ->setOptimizeAutoloader($optimize)
->setClassMapAuthoritative($authoritative) ->setClassMapAuthoritative($authoritative)
->setApcuAutoloader($apcu, $apcuPrefix) ->setApcuAutoloader($apcu, $apcuPrefix)
->setIgnorePlatformRequirements($ignorePlatformReqs) ->setPlatformRequirementFilter(PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs))
; ;
if ($input->getOption('no-plugins')) { if ($input->getOption('no-plugins')) {

View File

@ -15,6 +15,7 @@ namespace Composer\Command;
use Composer\DependencyResolver\Operation\InstallOperation; use Composer\DependencyResolver\Operation\InstallOperation;
use Composer\DependencyResolver\Operation\UninstallOperation; use Composer\DependencyResolver\Operation\UninstallOperation;
use Composer\DependencyResolver\Transaction; use Composer\DependencyResolver\Transaction;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
use Composer\Package\AliasPackage; use Composer\Package\AliasPackage;
use Composer\Package\BasePackage; use Composer\Package\BasePackage;
use Composer\Plugin\CommandEvent; use Composer\Plugin\CommandEvent;
@ -158,7 +159,7 @@ EOT
$generator = $composer->getAutoloadGenerator(); $generator = $composer->getAutoloadGenerator();
$generator->setClassMapAuthoritative($authoritative); $generator->setClassMapAuthoritative($authoritative);
$generator->setApcu($apcu, $apcuPrefix); $generator->setApcu($apcu, $apcuPrefix);
$generator->setIgnorePlatformRequirements($ignorePlatformReqs); $generator->setPlatformRequirementFilter(PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs));
$generator->dump($config, $localRepo, $package, $installationManager, 'composer', $optimize); $generator->dump($config, $localRepo, $package, $installationManager, 'composer', $optimize);
} }

View File

@ -14,6 +14,7 @@ namespace Composer\Command;
use Composer\Config\JsonConfigSource; use Composer\Config\JsonConfigSource;
use Composer\DependencyResolver\Request; use Composer\DependencyResolver\Request;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
use Composer\Installer; use Composer\Installer;
use Composer\Plugin\CommandEvent; use Composer\Plugin\CommandEvent;
use Composer\Plugin\PluginEvents; use Composer\Plugin\PluginEvents;
@ -265,7 +266,7 @@ EOT
->setUpdate(true) ->setUpdate(true)
->setInstall(!$input->getOption('no-install')) ->setInstall(!$input->getOption('no-install'))
->setUpdateAllowTransitiveDependencies($updateAllowTransitiveDependencies) ->setUpdateAllowTransitiveDependencies($updateAllowTransitiveDependencies)
->setIgnorePlatformRequirements($ignorePlatformReqs) ->setPlatformRequirementFilter(PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs))
->setDryRun($dryRun) ->setDryRun($dryRun)
; ;

View File

@ -13,6 +13,7 @@
namespace Composer\Command; namespace Composer\Command;
use Composer\DependencyResolver\Request; use Composer\DependencyResolver\Request;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputArgument;
@ -413,7 +414,7 @@ EOT
->setUpdate(true) ->setUpdate(true)
->setInstall(!$input->getOption('no-install')) ->setInstall(!$input->getOption('no-install'))
->setUpdateAllowTransitiveDependencies($updateAllowTransitiveDependencies) ->setUpdateAllowTransitiveDependencies($updateAllowTransitiveDependencies)
->setIgnorePlatformRequirements($ignorePlatformReqs) ->setPlatformRequirementFilter(PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs))
->setPreferStable($input->getOption('prefer-stable')) ->setPreferStable($input->getOption('prefer-stable'))
->setPreferLowest($input->getOption('prefer-lowest')) ->setPreferLowest($input->getOption('prefer-lowest'))
; ;

View File

@ -14,6 +14,7 @@ namespace Composer\Command;
use Composer\Composer; use Composer\Composer;
use Composer\DependencyResolver\Request; use Composer\DependencyResolver\Request;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
use Composer\Installer; use Composer\Installer;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Package\Loader\RootPackageLoader; use Composer\Package\Loader\RootPackageLoader;
@ -236,7 +237,7 @@ EOT
->setUpdateMirrors($updateMirrors) ->setUpdateMirrors($updateMirrors)
->setUpdateAllowList($packages) ->setUpdateAllowList($packages)
->setUpdateAllowTransitiveDependencies($updateAllowTransitiveDependencies) ->setUpdateAllowTransitiveDependencies($updateAllowTransitiveDependencies)
->setIgnorePlatformRequirements($ignorePlatformReqs) ->setPlatformRequirementFilter(PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs))
->setPreferStable($input->getOption('prefer-stable')) ->setPreferStable($input->getOption('prefer-stable'))
->setPreferLowest($input->getOption('prefer-lowest')) ->setPreferLowest($input->getOption('prefer-lowest'))
; ;

View File

@ -12,6 +12,8 @@
namespace Composer\DependencyResolver; namespace Composer\DependencyResolver;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterInterface;
use Composer\Package\BasePackage; use Composer\Package\BasePackage;
use Composer\Package\AliasPackage; use Composer\Package\AliasPackage;
use Composer\Repository\PlatformRepository; use Composer\Repository\PlatformRepository;
@ -160,10 +162,9 @@ class RuleSetGenerator
} }
/** /**
* @param bool|string[] $ignorePlatformReqs
* @return void * @return void
*/ */
protected function addRulesForPackage(BasePackage $package, $ignorePlatformReqs) protected function addRulesForPackage(BasePackage $package, PlatformRequirementFilterInterface $platformRequirementFilter)
{ {
/** @var \SplQueue<BasePackage> */ /** @var \SplQueue<BasePackage> */
$workQueue = new \SplQueue; $workQueue = new \SplQueue;
@ -196,7 +197,7 @@ class RuleSetGenerator
} }
foreach ($package->getRequires() as $link) { foreach ($package->getRequires() as $link) {
if ((true === $ignorePlatformReqs || (is_array($ignorePlatformReqs) && in_array($link->getTarget(), $ignorePlatformReqs, true))) && PlatformRepository::isPlatformPackage($link->getTarget())) { if ($platformRequirementFilter->isIgnored($link->getTarget())) {
continue; continue;
} }
@ -212,10 +213,9 @@ class RuleSetGenerator
} }
/** /**
* @param bool|string[] $ignorePlatformReqs
* @return void * @return void
*/ */
protected function addConflictRules($ignorePlatformReqs = false) protected function addConflictRules(PlatformRequirementFilterInterface $platformRequirementFilter)
{ {
/** @var BasePackage $package */ /** @var BasePackage $package */
foreach ($this->addedMap as $package) { foreach ($this->addedMap as $package) {
@ -225,7 +225,7 @@ class RuleSetGenerator
continue; continue;
} }
if ((true === $ignorePlatformReqs || (is_array($ignorePlatformReqs) && in_array($link->getTarget(), $ignorePlatformReqs, true))) && PlatformRepository::isPlatformPackage($link->getTarget())) { if ($platformRequirementFilter->isIgnored($link->getTarget())) {
continue; continue;
} }
@ -251,10 +251,9 @@ class RuleSetGenerator
} }
/** /**
* @param bool|string[] $ignorePlatformReqs
* @return void * @return void
*/ */
protected function addRulesForRequest(Request $request, $ignorePlatformReqs) protected function addRulesForRequest(Request $request, PlatformRequirementFilterInterface $platformRequirementFilter)
{ {
foreach ($request->getFixedPackages() as $package) { foreach ($request->getFixedPackages() as $package) {
if ($package->id == -1) { if ($package->id == -1) {
@ -267,7 +266,7 @@ class RuleSetGenerator
throw new \LogicException("Fixed package ".$package->getPrettyString()." was not added to solver pool."); throw new \LogicException("Fixed package ".$package->getPrettyString()." was not added to solver pool.");
} }
$this->addRulesForPackage($package, $ignorePlatformReqs); $this->addRulesForPackage($package, $platformRequirementFilter);
$rule = $this->createInstallOneOfRule(array($package), Rule::RULE_FIXED, array( $rule = $this->createInstallOneOfRule(array($package), Rule::RULE_FIXED, array(
'package' => $package, 'package' => $package,
@ -276,14 +275,14 @@ class RuleSetGenerator
} }
foreach ($request->getRequires() as $packageName => $constraint) { foreach ($request->getRequires() as $packageName => $constraint) {
if ((true === $ignorePlatformReqs || (is_array($ignorePlatformReqs) && in_array($packageName, $ignorePlatformReqs, true))) && PlatformRepository::isPlatformPackage($packageName)) { if ($platformRequirementFilter->isIgnored($packageName)) {
continue; continue;
} }
$packages = $this->pool->whatProvides($packageName, $constraint); $packages = $this->pool->whatProvides($packageName, $constraint);
if ($packages) { if ($packages) {
foreach ($packages as $package) { foreach ($packages as $package) {
$this->addRulesForPackage($package, $ignorePlatformReqs); $this->addRulesForPackage($package, $platformRequirementFilter);
} }
$rule = $this->createInstallOneOfRule($packages, Rule::RULE_ROOT_REQUIRE, array( $rule = $this->createInstallOneOfRule($packages, Rule::RULE_ROOT_REQUIRE, array(
@ -296,10 +295,9 @@ class RuleSetGenerator
} }
/** /**
* @param bool|string[] $ignorePlatformReqs
* @return void * @return void
*/ */
protected function addRulesForRootAliases($ignorePlatformReqs) protected function addRulesForRootAliases(PlatformRequirementFilterInterface $platformRequirementFilter)
{ {
foreach ($this->pool->getPackages() as $package) { foreach ($this->pool->getPackages() as $package) {
// ensure that rules for root alias packages and aliases of packages which were loaded are also loaded // ensure that rules for root alias packages and aliases of packages which were loaded are also loaded
@ -309,22 +307,23 @@ class RuleSetGenerator
$package instanceof AliasPackage && $package instanceof AliasPackage &&
($package->isRootPackageAlias() || isset($this->addedMap[$package->getAliasOf()->id])) ($package->isRootPackageAlias() || isset($this->addedMap[$package->getAliasOf()->id]))
) { ) {
$this->addRulesForPackage($package, $ignorePlatformReqs); $this->addRulesForPackage($package, $platformRequirementFilter);
} }
} }
} }
/** /**
* @param bool|string[] $ignorePlatformReqs
* @return RuleSet * @return RuleSet
*/ */
public function getRulesFor(Request $request, $ignorePlatformReqs = false) public function getRulesFor(Request $request, PlatformRequirementFilterInterface $platformRequirementFilter = null)
{ {
$this->addRulesForRequest($request, $ignorePlatformReqs); $platformRequirementFilter = $platformRequirementFilter ?: PlatformRequirementFilterFactory::ignoreNothing();
$this->addRulesForRootAliases($ignorePlatformReqs); $this->addRulesForRequest($request, $platformRequirementFilter);
$this->addConflictRules($ignorePlatformReqs); $this->addRulesForRootAliases($platformRequirementFilter);
$this->addConflictRules($platformRequirementFilter);
// Remove references to packages // Remove references to packages
$this->addedMap = $this->addedPackagesByNames = array(); $this->addedMap = $this->addedPackagesByNames = array();

View File

@ -12,9 +12,10 @@
namespace Composer\DependencyResolver; namespace Composer\DependencyResolver;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterInterface;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Package\BasePackage; use Composer\Package\BasePackage;
use Composer\Repository\PlatformRepository;
/** /**
* @author Nils Adermann <naderman@naderman.de> * @author Nils Adermann <naderman@naderman.de>
@ -166,13 +167,12 @@ class Solver
} }
/** /**
* @param bool|string[] $ignorePlatformReqs
* @return void * @return void
*/ */
protected function checkForRootRequireProblems(Request $request, $ignorePlatformReqs) protected function checkForRootRequireProblems(Request $request, PlatformRequirementFilterInterface $platformRequirementFilter)
{ {
foreach ($request->getRequires() as $packageName => $constraint) { foreach ($request->getRequires() as $packageName => $constraint) {
if ((true === $ignorePlatformReqs || (is_array($ignorePlatformReqs) && in_array($packageName, $ignorePlatformReqs, true))) && PlatformRepository::isPlatformPackage($packageName)) { if ($platformRequirementFilter->isIgnored($packageName)) {
continue; continue;
} }
@ -185,18 +185,19 @@ class Solver
} }
/** /**
* @param bool|string[] $ignorePlatformReqs
* @return LockTransaction * @return LockTransaction
*/ */
public function solve(Request $request, $ignorePlatformReqs = false) public function solve(Request $request, PlatformRequirementFilterInterface $platformRequirementFilter = null)
{ {
$platformRequirementFilter = $platformRequirementFilter ?: PlatformRequirementFilterFactory::ignoreNothing();
$this->setupFixedMap($request); $this->setupFixedMap($request);
$this->io->writeError('Generating rules', true, IOInterface::DEBUG); $this->io->writeError('Generating rules', true, IOInterface::DEBUG);
$ruleSetGenerator = new RuleSetGenerator($this->policy, $this->pool); $ruleSetGenerator = new RuleSetGenerator($this->policy, $this->pool);
$this->rules = $ruleSetGenerator->getRulesFor($request, $ignorePlatformReqs); $this->rules = $ruleSetGenerator->getRulesFor($request, $platformRequirementFilter);
unset($ruleSetGenerator); unset($ruleSetGenerator);
$this->checkForRootRequireProblems($request, $ignorePlatformReqs); $this->checkForRootRequireProblems($request, $platformRequirementFilter);
$this->decisions = new Decisions($this->pool); $this->decisions = new Decisions($this->pool);
$this->watchGraph = new RuleWatchGraph; $this->watchGraph = new RuleWatchGraph;

View File

@ -0,0 +1,17 @@
<?php
namespace Composer\Filter\PlatformRequirementFilter;
use Composer\Repository\PlatformRepository;
final class IgnoreAllPlatformRequirementFilter implements PlatformRequirementFilterInterface
{
/**
* @param string $req
* @return bool
*/
public function isIgnored($req)
{
return PlatformRepository::isPlatformPackage($req);
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace Composer\Filter\PlatformRequirementFilter;
use Composer\Repository\PlatformRepository;
final class IgnoreListPlatformRequirementFilter implements PlatformRequirementFilterInterface
{
/**
* @var string[]
*/
private $reqList;
/**
* @param string[] $reqList
*/
public function __construct(array $reqList)
{
$this->reqList = $reqList;
}
/**
* @param string $req
* @return bool
*/
public function isIgnored($req)
{
if (!PlatformRepository::isPlatformPackage($req)) {
return false;
}
return in_array($req, $this->reqList, true);
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace Composer\Filter\PlatformRequirementFilter;
final class IgnoreNothingPlatformRequirementFilter implements PlatformRequirementFilterInterface
{
/**
* @param string $req
* @return false
*/
public function isIgnored($req)
{
return false;
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace Composer\Filter\PlatformRequirementFilter;
final class PlatformRequirementFilterFactory
{
/**
* @param mixed $boolOrList
*
* @return PlatformRequirementFilterInterface
*/
public static function fromBoolOrList($boolOrList)
{
if (is_bool($boolOrList)) {
return $boolOrList ? self::ignoreAll() : self::ignoreNothing();
}
if (is_array($boolOrList)) {
return new IgnoreListPlatformRequirementFilter($boolOrList);
}
throw new \InvalidArgumentException(
sprintf(
'PlatformRequirementFilter: Unknown $boolOrList parameter %s. Please report at https://github.com/composer/composer/issues/new.',
gettype($boolOrList)
)
);
}
/**
* @return PlatformRequirementFilterInterface
*/
public static function ignoreAll()
{
return new IgnoreAllPlatformRequirementFilter();
}
/**
* @return PlatformRequirementFilterInterface
*/
public static function ignoreNothing()
{
return new IgnoreNothingPlatformRequirementFilter();
}
}

View File

@ -0,0 +1,12 @@
<?php
namespace Composer\Filter\PlatformRequirementFilter;
interface PlatformRequirementFilterInterface
{
/**
* @param string $req
* @return bool
*/
public function isIgnored($req);
}

View File

@ -27,6 +27,8 @@ use Composer\DependencyResolver\SolverProblemsException;
use Composer\DependencyResolver\PolicyInterface; use Composer\DependencyResolver\PolicyInterface;
use Composer\Downloader\DownloadManager; use Composer\Downloader\DownloadManager;
use Composer\EventDispatcher\EventDispatcher; use Composer\EventDispatcher\EventDispatcher;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterInterface;
use Composer\Installer\InstallationManager; use Composer\Installer\InstallationManager;
use Composer\Installer\InstallerEvents; use Composer\Installer\InstallerEvents;
use Composer\Installer\SuggestedPackagesReporter; use Composer\Installer\SuggestedPackagesReporter;
@ -150,8 +152,6 @@ class Installer
protected $dumpAutoloader = true; protected $dumpAutoloader = true;
/** @var bool */ /** @var bool */
protected $runScripts = true; protected $runScripts = true;
/** @var bool|string[] */
protected $ignorePlatformReqs = false;
/** @var bool */ /** @var bool */
protected $preferStable = false; protected $preferStable = false;
/** @var bool */ /** @var bool */
@ -177,6 +177,11 @@ class Installer
*/ */
protected $suggestedPackagesReporter; protected $suggestedPackagesReporter;
/**
* @var PlatformRequirementFilterInterface
*/
protected $platformRequirementFilter;
/** /**
* @var ?RepositoryInterface * @var ?RepositoryInterface
*/ */
@ -207,6 +212,7 @@ class Installer
$this->eventDispatcher = $eventDispatcher; $this->eventDispatcher = $eventDispatcher;
$this->autoloadGenerator = $autoloadGenerator; $this->autoloadGenerator = $autoloadGenerator;
$this->suggestedPackagesReporter = new SuggestedPackagesReporter($this->io); $this->suggestedPackagesReporter = new SuggestedPackagesReporter($this->io);
$this->platformRequirementFilter = PlatformRequirementFilterFactory::ignoreNothing();
$this->writeLock = $config->get('lock'); $this->writeLock = $config->get('lock');
} }
@ -329,7 +335,7 @@ class Installer
$this->autoloadGenerator->setClassMapAuthoritative($this->classMapAuthoritative); $this->autoloadGenerator->setClassMapAuthoritative($this->classMapAuthoritative);
$this->autoloadGenerator->setApcu($this->apcuAutoloader, $this->apcuAutoloaderPrefix); $this->autoloadGenerator->setApcu($this->apcuAutoloader, $this->apcuAutoloaderPrefix);
$this->autoloadGenerator->setRunScripts($this->runScripts); $this->autoloadGenerator->setRunScripts($this->runScripts);
$this->autoloadGenerator->setIgnorePlatformRequirements($this->ignorePlatformReqs); $this->autoloadGenerator->setPlatformRequirementFilter($this->platformRequirementFilter);
$this->autoloadGenerator->dump($this->config, $localRepo, $this->package, $this->installationManager, 'composer', $this->optimizeAutoloader); $this->autoloadGenerator->dump($this->config, $localRepo, $this->package, $this->installationManager, 'composer', $this->optimizeAutoloader);
} }
@ -431,7 +437,7 @@ class Installer
// solve dependencies // solve dependencies
$solver = new Solver($policy, $pool, $this->io); $solver = new Solver($policy, $pool, $this->io);
try { try {
$lockTransaction = $solver->solve($request, $this->ignorePlatformReqs); $lockTransaction = $solver->solve($request, $this->platformRequirementFilter);
$ruleSetSize = $solver->getRuleSetSize(); $ruleSetSize = $solver->getRuleSetSize();
$solver = null; $solver = null;
} catch (SolverProblemsException $e) { } catch (SolverProblemsException $e) {
@ -609,7 +615,7 @@ class Installer
$solver = new Solver($policy, $pool, $this->io); $solver = new Solver($policy, $pool, $this->io);
try { try {
$nonDevLockTransaction = $solver->solve($request, $this->ignorePlatformReqs); $nonDevLockTransaction = $solver->solve($request, $this->platformRequirementFilter);
$solver = null; $solver = null;
} catch (SolverProblemsException $e) { } catch (SolverProblemsException $e) {
$err = 'Unable to find a compatible set of packages based on your non-dev requirements alone.'; $err = 'Unable to find a compatible set of packages based on your non-dev requirements alone.';
@ -674,7 +680,7 @@ class Installer
// solve dependencies // solve dependencies
$solver = new Solver($policy, $pool, $this->io); $solver = new Solver($policy, $pool, $this->io);
try { try {
$lockTransaction = $solver->solve($request, $this->ignorePlatformReqs); $lockTransaction = $solver->solve($request, $this->platformRequirementFilter);
$solver = null; $solver = null;
// installing the locked packages on this platform resulted in lock modifying operations, there wasn't a conflict, but the lock file as-is seems to not work on this system // installing the locked packages on this platform resulted in lock modifying operations, there wasn't a conflict, but the lock file as-is seems to not work on this system
@ -799,7 +805,7 @@ class Installer
$rootRequires = array(); $rootRequires = array();
foreach ($requires as $req => $constraint) { foreach ($requires as $req => $constraint) {
// skip platform requirements from the root package to avoid filtering out existing platform packages // skip platform requirements from the root package to avoid filtering out existing platform packages
if ((true === $this->ignorePlatformReqs || (is_array($this->ignorePlatformReqs) && in_array($req, $this->ignorePlatformReqs, true))) && PlatformRepository::isPlatformPackage($req)) { if ($this->platformRequirementFilter->isIgnored($req)) {
continue; continue;
} }
if ($constraint instanceof Link) { if ($constraint instanceof Link) {
@ -1242,16 +1248,23 @@ class Installer
* @param bool|string[] $ignorePlatformReqs * @param bool|string[] $ignorePlatformReqs
* *
* @return Installer * @return Installer
*
* @deprecated use setPlatformRequirementFilter instead
*/ */
public function setIgnorePlatformRequirements($ignorePlatformReqs) public function setIgnorePlatformRequirements($ignorePlatformReqs)
{ {
if (is_array($ignorePlatformReqs)) { trigger_error('Installer::setIgnorePlatformRequirements is deprecated since Composer 2.2, use setPlatformRequirementFilter instead.', E_USER_DEPRECATED);
$this->ignorePlatformReqs = array_filter($ignorePlatformReqs, function ($req) {
return PlatformRepository::isPlatformPackage($req); return $this->setPlatformRequirementFilter(PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs));
}); }
} else {
$this->ignorePlatformReqs = (bool) $ignorePlatformReqs; /**
} * @param PlatformRequirementFilterInterface $platformRequirementFilter
* @return Installer
*/
public function setPlatformRequirementFilter(PlatformRequirementFilterInterface $platformRequirementFilter)
{
$this->platformRequirementFilter = $platformRequirementFilter;
return $this; return $this;
} }

View File

@ -12,6 +12,9 @@
namespace Composer\Package\Version; namespace Composer\Package\Version;
use Composer\Filter\PlatformRequirementFilter\IgnoreAllPlatformRequirementFilter;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterInterface;
use Composer\Package\BasePackage; use Composer\Package\BasePackage;
use Composer\Package\AliasPackage; use Composer\Package\AliasPackage;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
@ -57,32 +60,37 @@ class VersionSelector
* Given a package name and optional version, returns the latest PackageInterface * Given a package name and optional version, returns the latest PackageInterface
* that matches. * that matches.
* *
* @param string $packageName * @param string $packageName
* @param string $targetPackageVersion * @param string $targetPackageVersion
* @param string $preferredStability * @param string $preferredStability
* @param bool|string[] $ignorePlatformReqs * @param PlatformRequirementFilterInterface|bool|string[] $platformRequirementFilter
* @param int $repoSetFlags * @param int $repoSetFlags*
*
* @return PackageInterface|false * @return PackageInterface|false
*/ */
public function findBestCandidate($packageName, $targetPackageVersion = null, $preferredStability = 'stable', $ignorePlatformReqs = false, $repoSetFlags = 0) public function findBestCandidate($packageName, $targetPackageVersion = null, $preferredStability = 'stable', $platformRequirementFilter = null, $repoSetFlags = 0)
{ {
if (!isset(BasePackage::$stabilities[$preferredStability])) { if (!isset(BasePackage::$stabilities[$preferredStability])) {
// If you get this, maybe you are still relying on the Composer 1.x signature where the 3rd arg was the php version // If you get this, maybe you are still relying on the Composer 1.x signature where the 3rd arg was the php version
throw new \UnexpectedValueException('Expected a valid stability name as 3rd argument, got '.$preferredStability); throw new \UnexpectedValueException('Expected a valid stability name as 3rd argument, got '.$preferredStability);
} }
if (null === $platformRequirementFilter) {
$platformRequirementFilter = PlatformRequirementFilterFactory::ignoreNothing();
} elseif (!($platformRequirementFilter instanceof PlatformRequirementFilterInterface)) {
trigger_error('VersionSelector::findBestCandidate with ignored platform reqs as bool|array is deprecated since Composer 2.2, use an instance of PlatformRequirementFilterInterface instead.', E_USER_DEPRECATED);
$platformRequirementFilter = PlatformRequirementFilterFactory::fromBoolOrList($platformRequirementFilter);
}
$constraint = $targetPackageVersion ? $this->getParser()->parseConstraints($targetPackageVersion) : null; $constraint = $targetPackageVersion ? $this->getParser()->parseConstraints($targetPackageVersion) : null;
$candidates = $this->repositorySet->findPackages(strtolower($packageName), $constraint, $repoSetFlags); $candidates = $this->repositorySet->findPackages(strtolower($packageName), $constraint, $repoSetFlags);
if ($this->platformConstraints && true !== $ignorePlatformReqs) { if ($this->platformConstraints && !($platformRequirementFilter instanceof IgnoreAllPlatformRequirementFilter)) {
$platformConstraints = $this->platformConstraints; $platformConstraints = $this->platformConstraints;
$ignorePlatformReqs = $ignorePlatformReqs ?: array(); $candidates = array_filter($candidates, function ($pkg) use ($platformConstraints, $platformRequirementFilter) {
$candidates = array_filter($candidates, function ($pkg) use ($platformConstraints, $ignorePlatformReqs) {
$reqs = $pkg->getRequires(); $reqs = $pkg->getRequires();
foreach ($reqs as $name => $link) { foreach ($reqs as $name => $link) {
if (!in_array($name, $ignorePlatformReqs, true)) { if (!$platformRequirementFilter->isIgnored($name)) {
if (isset($platformConstraints[$name])) { if (isset($platformConstraints[$name])) {
foreach ($platformConstraints[$name] as $constraint) { foreach ($platformConstraints[$name] as $constraint) {
if ($link->getConstraint()->matches($constraint)) { if ($link->getConstraint()->matches($constraint)) {

View File

@ -13,6 +13,7 @@
namespace Composer\Test\Autoload; namespace Composer\Test\Autoload;
use Composer\Autoload\AutoloadGenerator; use Composer\Autoload\AutoloadGenerator;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
use Composer\Package\Link; use Composer\Package\Link;
use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionParser;
use Composer\Semver\Constraint\Constraint; use Composer\Semver\Constraint\Constraint;
@ -1731,7 +1732,7 @@ EOF;
->method('getCanonicalPackages') ->method('getCanonicalPackages')
->will($this->returnValue(array())); ->will($this->returnValue(array()));
$this->generator->setIgnorePlatformRequirements($ignorePlatformReqs); $this->generator->setPlatformRequirementFilter(PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs));
$this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', true, '_1'); $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', true, '_1');
if (null === $expectedFixture) { if (null === $expectedFixture) {

View File

@ -0,0 +1,33 @@
<?php
namespace Composer\Test\Filter\PlatformRequirementFilter;
use Composer\Filter\PlatformRequirementFilter\IgnoreAllPlatformRequirementFilter;
use Composer\Test\TestCase;
final class IgnoreAllPlatformRequirementFilterTest extends TestCase
{
/**
* @dataProvider dataIsIgnored
*
* @param string $req
* @param bool $expectIgnored
*/
public function testIsIgnored($req, $expectIgnored)
{
$platformRequirementFilter = new IgnoreAllPlatformRequirementFilter();
$this->assertSame($expectIgnored, $platformRequirementFilter->isIgnored($req));
}
/**
* @return array<string, mixed[]>
*/
public function dataIsIgnored()
{
return array(
'php is ignored' => array('php', true),
'monolog/monolog is not ignored' => array('monolog/monolog', false),
);
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace Composer\Test\Filter\PlatformRequirementFilter;
use Composer\Filter\PlatformRequirementFilter\IgnoreListPlatformRequirementFilter;
use Composer\Test\TestCase;
final class IgnoreListPlatformRequirementFilterTest extends TestCase
{
/**
* @dataProvider dataIsIgnored
*
* @param string[] $reqList
* @param string $req
* @param bool $expectIgnored
*/
public function testIsIgnored(array $reqList, $req, $expectIgnored)
{
$platformRequirementFilter = new IgnoreListPlatformRequirementFilter($reqList);
$this->assertSame($expectIgnored, $platformRequirementFilter->isIgnored($req));
}
/**
* @return array<string, mixed[]>
*/
public function dataIsIgnored()
{
return array(
'ext-json is ignored if listed' => array(array('ext-json', 'monolog/monolog'), 'ext-json', true),
'php is not ignored if not listed' => array(array('ext-json', 'monolog/monolog'), 'php', false),
'monolog/monolog is not ignored even if listed' => array(array('ext-json', 'monolog/monolog'), 'monolog/monolog', false),
);
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace Composer\Test\Filter\PlatformRequirementFilter;
use Composer\Filter\PlatformRequirementFilter\IgnoreNothingPlatformRequirementFilter;
use Composer\Test\TestCase;
final class IgnoreNothingPlatformRequirementFilterTest extends TestCase
{
/**
* @dataProvider dataIsIgnored
*
* @param string $req
*/
public function testIsIgnored($req)
{
$platformRequirementFilter = new IgnoreNothingPlatformRequirementFilter();
$this->assertFalse($platformRequirementFilter->isIgnored($req));
}
/**
* @return array<string, mixed[]>
*/
public function dataIsIgnored()
{
return array(
'php is not ignored' => array('php'),
'monolog/monolog is not ignored' => array('monolog/monolog'),
);
}
}

View File

@ -0,0 +1,53 @@
<?php
namespace Composer\Test\Filter\PlatformRequirementFilter;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
use Composer\Test\TestCase;
final class PlatformRequirementFilterFactoryTest extends TestCase
{
/**
* @dataProvider dataFromBoolOrList
*
* @param mixed $boolOrList
* @param class-string $expectedInstance
*/
public function testFromBoolOrList($boolOrList, $expectedInstance)
{
$this->assertInstanceOf($expectedInstance, PlatformRequirementFilterFactory::fromBoolOrList($boolOrList));
}
/**
* @return array<string, mixed[]>
*/
public function dataFromBoolOrList()
{
return array(
'true creates IgnoreAllFilter' => array(true, 'Composer\Filter\PlatformRequirementFilter\IgnoreAllPlatformRequirementFilter'),
'false creates IgnoreNothingFilter' => array(false, 'Composer\Filter\PlatformRequirementFilter\IgnoreNothingPlatformRequirementFilter'),
'list creates IgnoreListFilter' => array(array('php', 'ext-json'), 'Composer\Filter\PlatformRequirementFilter\IgnoreListPlatformRequirementFilter'),
);
}
public function testFromBoolThrowsExceptionIfTypeIsUnknown()
{
$this->setExpectedException('InvalidArgumentException', 'PlatformRequirementFilter: Unknown $boolOrList parameter NULL. Please report at https://github.com/composer/composer/issues/new.');
PlatformRequirementFilterFactory::fromBoolOrList(null);
}
public function testIgnoreAll()
{
$platformRequirementFilter = PlatformRequirementFilterFactory::ignoreAll();
$this->assertInstanceOf('Composer\Filter\PlatformRequirementFilter\IgnoreAllPlatformRequirementFilter', $platformRequirementFilter);
}
public function testIgnoreNothing()
{
$platformRequirementFilter = PlatformRequirementFilterFactory::ignoreNothing();
$this->assertInstanceOf('Composer\Filter\PlatformRequirementFilter\IgnoreNothingPlatformRequirementFilter', $platformRequirementFilter);
}
}

View File

@ -13,6 +13,7 @@
namespace Composer\Test; namespace Composer\Test;
use Composer\DependencyResolver\Request; use Composer\DependencyResolver\Request;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
use Composer\Installer; use Composer\Installer;
use Symfony\Component\Console\Application; use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\Command;
@ -340,7 +341,7 @@ class InstallerTest extends TestCase
$installer $installer
->setDevMode(!$input->getOption('no-dev')) ->setDevMode(!$input->getOption('no-dev'))
->setDryRun($input->getOption('dry-run')) ->setDryRun($input->getOption('dry-run'))
->setIgnorePlatformRequirements($ignorePlatformReqs); ->setPlatformRequirementFilter(PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs));
return $installer->run(); return $installer->run();
}); });
@ -385,7 +386,7 @@ class InstallerTest extends TestCase
->setUpdateAllowTransitiveDependencies($updateAllowTransitiveDependencies) ->setUpdateAllowTransitiveDependencies($updateAllowTransitiveDependencies)
->setPreferStable($input->getOption('prefer-stable')) ->setPreferStable($input->getOption('prefer-stable'))
->setPreferLowest($input->getOption('prefer-lowest')) ->setPreferLowest($input->getOption('prefer-lowest'))
->setIgnorePlatformRequirements($ignorePlatformReqs); ->setPlatformRequirementFilter(PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs));
return $installer->run(); return $installer->run();
}); });

View File

@ -12,6 +12,7 @@
namespace Composer\Test\Package\Version; namespace Composer\Test\Package\Version;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
use Composer\Package\Version\VersionSelector; use Composer\Package\Version\VersionSelector;
use Composer\Package\Package; use Composer\Package\Package;
use Composer\Package\Link; use Composer\Package\Link;
@ -70,7 +71,7 @@ class VersionSelectorTest extends TestCase
$best = $versionSelector->findBestCandidate($packageName); $best = $versionSelector->findBestCandidate($packageName);
$this->assertSame($package1, $best, 'Latest version supporting php 5.5 should be returned (1.0.0)'); $this->assertSame($package1, $best, 'Latest version supporting php 5.5 should be returned (1.0.0)');
$best = $versionSelector->findBestCandidate($packageName, null, 'stable', true); $best = $versionSelector->findBestCandidate($packageName, null, 'stable', PlatformRequirementFilterFactory::ignoreAll());
$this->assertSame($package2, $best, 'Latest version should be returned when ignoring platform reqs (2.0.0)'); $this->assertSame($package2, $best, 'Latest version should be returned when ignoring platform reqs (2.0.0)');
} }
@ -96,7 +97,7 @@ class VersionSelectorTest extends TestCase
$best = $versionSelector->findBestCandidate($packageName); $best = $versionSelector->findBestCandidate($packageName);
$this->assertSame($package1, $best, 'Latest version supporting ext-zip 5.3.0 should be returned (1.0.0)'); $this->assertSame($package1, $best, 'Latest version supporting ext-zip 5.3.0 should be returned (1.0.0)');
$best = $versionSelector->findBestCandidate($packageName, null, 'stable', true); $best = $versionSelector->findBestCandidate($packageName, null, 'stable', PlatformRequirementFilterFactory::ignoreAll());
$this->assertSame($package2, $best, 'Latest version should be returned when ignoring platform reqs (2.0.0)'); $this->assertSame($package2, $best, 'Latest version should be returned when ignoring platform reqs (2.0.0)');
} }
@ -121,7 +122,7 @@ class VersionSelectorTest extends TestCase
$best = $versionSelector->findBestCandidate($packageName); $best = $versionSelector->findBestCandidate($packageName);
$this->assertSame($package1, $best, 'Latest version not requiring ext-barfoo should be returned (1.0.0)'); $this->assertSame($package1, $best, 'Latest version not requiring ext-barfoo should be returned (1.0.0)');
$best = $versionSelector->findBestCandidate($packageName, null, 'stable', true); $best = $versionSelector->findBestCandidate($packageName, null, 'stable', PlatformRequirementFilterFactory::ignoreAll());
$this->assertSame($package2, $best, 'Latest version should be returned when ignoring platform reqs (2.0.0)'); $this->assertSame($package2, $best, 'Latest version should be returned when ignoring platform reqs (2.0.0)');
} }
@ -147,7 +148,7 @@ class VersionSelectorTest extends TestCase
$best = $versionSelector->findBestCandidate($packageName); $best = $versionSelector->findBestCandidate($packageName);
$this->assertSame($package1, $best, 'Latest version supporting composer 1 should be returned (1.0.0)'); $this->assertSame($package1, $best, 'Latest version supporting composer 1 should be returned (1.0.0)');
$best = $versionSelector->findBestCandidate($packageName, null, 'stable', true); $best = $versionSelector->findBestCandidate($packageName, null, 'stable', PlatformRequirementFilterFactory::ignoreAll());
$this->assertSame($package2, $best, 'Latest version should be returned when ignoring platform reqs (1.1.0)'); $this->assertSame($package2, $best, 'Latest version should be returned when ignoring platform reqs (1.1.0)');
} }