1
0
Fork 0

Add a way to ignore only some packages in --ignore-platform-reqs, and make the platform check ignore those packages which were ignored as requirements, fixes #8861

pull/8916/head
Jordi Boggiano 2020-06-01 15:43:24 +02:00
parent 21e708f2c4
commit e85da00dff
No known key found for this signature in database
GPG Key ID: 7BBD42C429EC80BC
15 changed files with 146 additions and 56 deletions

View File

@ -114,7 +114,9 @@ resolution.
* **--apcu-autoloader:** Use APCu to cache found/not-found classes. * **--apcu-autoloader:** Use APCu to cache found/not-found classes.
* **--ignore-platform-reqs:** ignore `php`, `hhvm`, `lib-*` and `ext-*` * **--ignore-platform-reqs:** ignore `php`, `hhvm`, `lib-*` and `ext-*`
requirements and force the installation even if the local machine does not requirements and force the installation even if the local machine does not
fulfill these. See also the [`platform`](06-config.md#platform) config option. fulfill these. You can also ignore specific packages only using
`--ignore-platform-reqs=ext-foo --ignore-platform-reqs=ext-bar`.
See also the [`platform`](06-config.md#platform) config option.
## update / u ## update / u
@ -187,7 +189,9 @@ php composer.phar update vendor/package:2.0.1 vendor/package2:3.0.*
* **--apcu-autoloader:** Use APCu to cache found/not-found classes. * **--apcu-autoloader:** Use APCu to cache found/not-found classes.
* **--ignore-platform-reqs:** ignore `php`, `hhvm`, `lib-*` and `ext-*` * **--ignore-platform-reqs:** ignore `php`, `hhvm`, `lib-*` and `ext-*`
requirements and force the installation even if the local machine does not requirements and force the installation even if the local machine does not
fulfill these. See also the [`platform`](06-config.md#platform) config option. fulfill these. You can also ignore specific packages only using
`--ignore-platform-reqs=ext-foo --ignore-platform-reqs=ext-bar`.
See also the [`platform`](06-config.md#platform) config option.
* **--prefer-stable:** Prefer stable versions of dependencies. * **--prefer-stable:** Prefer stable versions of dependencies.
* **--prefer-lowest:** Prefer lowest versions of dependencies. Useful for testing minimal * **--prefer-lowest:** Prefer lowest versions of dependencies. Useful for testing minimal
versions of requirements, generally used with `--prefer-stable`. versions of requirements, generally used with `--prefer-stable`.
@ -233,7 +237,9 @@ If you do not specify a package, composer will prompt you to search for a packag
* **--update-with-all-dependencies:** Also update dependencies of the newly required packages, including those that are root requirements. * **--update-with-all-dependencies:** Also update dependencies of the newly required packages, including those that are root requirements.
* **--ignore-platform-reqs:** ignore `php`, `hhvm`, `lib-*` and `ext-*` * **--ignore-platform-reqs:** ignore `php`, `hhvm`, `lib-*` and `ext-*`
requirements and force the installation even if the local machine does not requirements and force the installation even if the local machine does not
fulfill these. See also the [`platform`](06-config.md#platform) config option. fulfill these. You can also ignore specific packages only using
`--ignore-platform-reqs=ext-foo --ignore-platform-reqs=ext-bar`.
See also the [`platform`](06-config.md#platform) config option.
* **--prefer-stable:** Prefer stable versions of dependencies. * **--prefer-stable:** Prefer stable versions of dependencies.
* **--prefer-lowest:** Prefer lowest versions of dependencies. Useful for testing minimal * **--prefer-lowest:** Prefer lowest versions of dependencies. Useful for testing minimal
versions of requirements, generally used with `--prefer-stable`. versions of requirements, generally used with `--prefer-stable`.
@ -269,7 +275,9 @@ uninstalled.
* **--update-with-dependencies:** Also update dependencies of the removed packages. * **--update-with-dependencies:** Also update dependencies of the removed packages.
* **--ignore-platform-reqs:** ignore `php`, `hhvm`, `lib-*` and `ext-*` * **--ignore-platform-reqs:** ignore `php`, `hhvm`, `lib-*` and `ext-*`
requirements and force the installation even if the local machine does not requirements and force the installation even if the local machine does not
fulfill these. See also the [`platform`](06-config.md#platform) config option. fulfill these. You can also ignore specific packages only using
`--ignore-platform-reqs=ext-foo --ignore-platform-reqs=ext-bar`.
See also the [`platform`](06-config.md#platform) config option.
* **--optimize-autoloader (-o):** Convert PSR-0/4 autoloading to classmap to * **--optimize-autoloader (-o):** Convert PSR-0/4 autoloading to classmap to
get a faster autoloader. This is recommended especially for production, but get a faster autoloader. This is recommended especially for production, but
can take a bit of time to run so it is currently not done by default. can take a bit of time to run so it is currently not done by default.
@ -724,7 +732,9 @@ By default the command checks for the packages on packagist.org.
* **--no-install:** Disables installation of the vendors. * **--no-install:** Disables installation of the vendors.
* **--ignore-platform-reqs:** ignore `php`, `hhvm`, `lib-*` and `ext-*` * **--ignore-platform-reqs:** ignore `php`, `hhvm`, `lib-*` and `ext-*`
requirements and force the installation even if the local machine does not requirements and force the installation even if the local machine does not
fulfill these. fulfill these. You can also ignore specific packages only using
`--ignore-platform-reqs=ext-foo --ignore-platform-reqs=ext-bar`.
See also the [`platform`](06-config.md#platform) config option.
## dump-autoload (dumpautoload) ## dump-autoload (dumpautoload)
@ -748,6 +758,10 @@ performance.
Implicitly enables `--optimize`. Implicitly enables `--optimize`.
* **--apcu:** Use APCu to cache found/not-found classes. * **--apcu:** Use APCu to cache found/not-found classes.
* **--no-dev:** Disables autoload-dev rules. * **--no-dev:** Disables autoload-dev rules.
* **--ignore-platform-reqs:** ignore `php`, `hhvm`, `lib-*` and `ext-*`
requirements and skip the [platform check](07-runtime.md#platform-check) for these.
You can also ignore specific packages only using `--ignore-platform-reqs=ext-foo --ignore-platform-reqs=ext-bar`.
See also the [`platform`](06-config.md#platform) config option.
## clear-cache / clearcache / cc ## clear-cache / clearcache / cc

View File

@ -61,6 +61,11 @@ class AutoloadGenerator
*/ */
private $runScripts = false; private $runScripts = false;
/**
* @var bool|array
*/
private $ignorePlatformReqs = false;
public function __construct(EventDispatcher $eventDispatcher, IOInterface $io = null) public function __construct(EventDispatcher $eventDispatcher, IOInterface $io = null)
{ {
$this->eventDispatcher = $eventDispatcher; $this->eventDispatcher = $eventDispatcher;
@ -103,6 +108,26 @@ class AutoloadGenerator
$this->runScripts = (bool) $runScripts; $this->runScripts = (bool) $runScripts;
} }
/**
* Sets whether platform requirements should be ignored
*
* If this is set to true, the platform check file will not be generated
* If this is set to false, the platform check file will be generated with all requirements
* If this is set to string[], those packages will be ignored from the platform check file
*
* @param array|bool $ignorePlatformReqs
*/
public function setIgnorePlatformRequirements($ignorePlatformReqs)
{
if (is_array($ignorePlatformReqs)) {
$this->ignorePlatformReqs = array_filter($ignorePlatformReqs, function ($req) {
return (bool) preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $req);
});
} else {
$this->ignorePlatformReqs = (bool) $ignorePlatformReqs;
}
}
public function dump(Config $config, InstalledRepositoryInterface $localRepo, PackageInterface $mainPackage, InstallationManager $installationManager, $targetDir, $scanPsrPackages = false, $suffix = '') public function dump(Config $config, InstalledRepositoryInterface $localRepo, PackageInterface $mainPackage, InstallationManager $installationManager, $targetDir, $scanPsrPackages = false, $suffix = '')
{ {
if ($this->classMapAuthoritative) { if ($this->classMapAuthoritative) {
@ -314,9 +339,9 @@ 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'); $checkPlatform = $config->get('platform-check') && $this->ignorePlatformReqs !== true;
if ($checkPlatform) { if ($checkPlatform) {
$platformCheckContent = $this->getPlatformCheck($packageMap); $platformCheckContent = $this->getPlatformCheck($packageMap, $this->ignorePlatformReqs ?: array());
if (null === $platformCheckContent) { if (null === $platformCheckContent) {
$checkPlatform = false; $checkPlatform = false;
} }
@ -575,7 +600,7 @@ EOF;
return $baseDir . (($path !== false) ? var_export($path, true) : ""); return $baseDir . (($path !== false) ? var_export($path, true) : "");
} }
protected function getPlatformCheck($packageMap) protected function getPlatformCheck($packageMap, array $ignorePlatformReqs)
{ {
$lowestPhpVersion = Bound::zero(); $lowestPhpVersion = Bound::zero();
$requiredExtensions = array(); $requiredExtensions = array();
@ -593,6 +618,10 @@ EOF;
foreach ($packageMap as $item) { foreach ($packageMap as $item) {
list($package, $installPath) = $item; list($package, $installPath) = $item;
foreach ($package->getRequires() as $link) { foreach ($package->getRequires() as $link) {
if (in_array($link->getTarget(), $ignorePlatformReqs, true)) {
continue;
}
if ('php' === $link->getTarget() && ($constraint = $link->getConstraint())) { if ('php' === $link->getTarget() && ($constraint = $link->getConstraint())) {
if ($constraint->getLowerBound()->compareTo($lowestPhpVersion, '>')) { if ($constraint->getLowerBound()->compareTo($lowestPhpVersion, '>')) {
$lowestPhpVersion = $constraint->getLowerBound(); $lowestPhpVersion = $constraint->getLowerBound();

View File

@ -80,7 +80,7 @@ class CreateProjectCommand extends BaseCommand
new InputOption('keep-vcs', null, InputOption::VALUE_NONE, 'Whether to prevent deleting the vcs folder.'), new InputOption('keep-vcs', null, InputOption::VALUE_NONE, 'Whether to prevent deleting the vcs folder.'),
new InputOption('remove-vcs', null, InputOption::VALUE_NONE, 'Whether to force deletion of the vcs folder without prompting.'), new InputOption('remove-vcs', null, InputOption::VALUE_NONE, 'Whether to force deletion of the vcs folder without prompting.'),
new InputOption('no-install', null, InputOption::VALUE_NONE, 'Whether to skip installation of the package dependencies.'), new InputOption('no-install', null, InputOption::VALUE_NONE, 'Whether to skip installation of the package dependencies.'),
new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore platform requirements (php & ext- packages).'), new InputOption('ignore-platform-reqs', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Ignore platform requirements (php & ext- packages), optionally can take a package name to ignore specific package(s).'),
)) ))
->setHelp( ->setHelp(
<<<EOT <<<EOT
@ -127,6 +127,10 @@ EOT
$input->setOption('no-plugins', true); $input->setOption('no-plugins', true);
} }
$ignorePlatformReqs = $input->getOption('ignore-platform-reqs')
? (array_filter($input->getOption('ignore-platform-reqs')) ? $input->getOption('ignore-platform-reqs') : true)
: false;
return $this->installProject( return $this->installProject(
$io, $io,
$config, $config,
@ -143,7 +147,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'),
$input->getOption('ignore-platform-reqs'), $ignorePlatformReqs,
!$input->getOption('no-secure-http'), !$input->getOption('no-secure-http'),
$input->getOption('add-repository') $input->getOption('add-repository')
); );
@ -336,19 +340,16 @@ EOT
$repositorySet = new RepositorySet($stability); $repositorySet = new RepositorySet($stability);
$repositorySet->addRepository($sourceRepo); $repositorySet->addRepository($sourceRepo);
$platformRepo = null;
if (!$ignorePlatformReqs) {
$platformOverrides = $config->get('platform') ?: array(); $platformOverrides = $config->get('platform') ?: array();
$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
$versionSelector = new VersionSelector($repositorySet, $platformRepo); $versionSelector = new VersionSelector($repositorySet, $platformRepo);
$package = $versionSelector->findBestCandidate($name, $packageVersion, $stability); $package = $versionSelector->findBestCandidate($name, $packageVersion, $stability, $ignorePlatformReqs);
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 ($platformRepo && $versionSelector->findBestCandidate($name, $packageVersion, $stability, true)) { if (true !== $ignorePlatformReqs && $versionSelector->findBestCandidate($name, $packageVersion, $stability, true)) {
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

@ -35,6 +35,7 @@ class DumpAutoloadCommand extends BaseCommand
new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize`.'), new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize`.'),
new InputOption('apcu', null, InputOption::VALUE_NONE, 'Use APCu to cache found/not-found classes.'), new InputOption('apcu', null, InputOption::VALUE_NONE, 'Use APCu to cache found/not-found classes.'),
new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables autoload-dev rules.'), new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables autoload-dev rules.'),
new InputOption('ignore-platform-reqs', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Ignore platform requirements (php & ext- packages), optionally can take a package name to ignore specific package(s) from the platform check.'),
)) ))
->setHelp( ->setHelp(
<<<EOT <<<EOT
@ -70,11 +71,16 @@ EOT
$this->getIO()->write('<info>Generating autoload files</info>'); $this->getIO()->write('<info>Generating autoload files</info>');
} }
$ignorePlatformReqs = $input->getOption('ignore-platform-reqs')
? (array_filter($input->getOption('ignore-platform-reqs')) ? $input->getOption('ignore-platform-reqs') : true)
: false;
$generator = $composer->getAutoloadGenerator(); $generator = $composer->getAutoloadGenerator();
$generator->setDevMode(!$input->getOption('no-dev')); $generator->setDevMode(!$input->getOption('no-dev'));
$generator->setClassMapAuthoritative($authoritative); $generator->setClassMapAuthoritative($authoritative);
$generator->setApcu($apcu); $generator->setApcu($apcu);
$generator->setRunScripts(!$input->getOption('no-scripts')); $generator->setRunScripts(!$input->getOption('no-scripts'));
$generator->setIgnorePlatformRequirements($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

@ -723,26 +723,28 @@ EOT
*/ */
private function findBestVersionAndNameForPackage(InputInterface $input, $name, PlatformRepository $platformRepo = null, $preferredStability = 'stable', $requiredVersion = null, $minimumStability = null, $fixed = null) private function findBestVersionAndNameForPackage(InputInterface $input, $name, PlatformRepository $platformRepo = null, $preferredStability = 'stable', $requiredVersion = null, $minimumStability = null, $fixed = null)
{ {
// ignore platform repo if platform requirements are ignored // handle ignore-platform-reqs flag if present
$ignorePlatformReqs = $input->hasOption('ignore-platform-reqs') && $input->getOption('ignore-platform-reqs'); $ignorePlatformReqs = false;
if ($ignorePlatformReqs) { if ($input->hasOption('ignore-platform-reqs')) {
$platformRepo = null; $ignorePlatformReqs = $input->getOption('ignore-platform-reqs')
? (array_filter($input->getOption('ignore-platform-reqs')) ? $input->getOption('ignore-platform-reqs') : true)
: false;
} }
// 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);
$package = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability); $package = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, $ignorePlatformReqs);
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 ($ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name)) { if ((true === $ignorePlatformReqs || (is_array($ignorePlatformReqs) && in_array($name, $ignorePlatformReqs))) && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name)) {
return array($name, $requiredVersion ?: '*'); return array($name, $requiredVersion ?: '*');
} }
// Check whether the PHP version was the problem // Check whether the PHP version was the problem
if ($platformRepo && $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, true)) { if (true !== $ignorePlatformReqs && $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, true)) {
throw new \InvalidArgumentException(sprintf( throw new \InvalidArgumentException(sprintf(
'Package %s at version %s has a PHP requirement incompatible with your PHP version, PHP extensions and Composer version', 'Package %s at version %s has a PHP requirement incompatible with your PHP version, PHP extensions and Composer version',
$name, $name,
@ -750,7 +752,7 @@ EOT
)); ));
} }
// Check whether the required version was the problem // Check whether the required version was the problem
if ($requiredVersion && $versionSelector->findBestCandidate($name, null, $preferredStability)) { if ($requiredVersion && $versionSelector->findBestCandidate($name, null, $preferredStability, $ignorePlatformReqs)) {
throw new \InvalidArgumentException(sprintf( throw new \InvalidArgumentException(sprintf(
'Could not find package %s in a version matching %s', 'Could not find package %s in a version matching %s',
$name, $name,
@ -758,7 +760,7 @@ EOT
)); ));
} }
// Check whether the PHP version was the problem for all versions // Check whether the PHP version was the problem for all versions
if ($platformRepo && $versionSelector->findBestCandidate($name, null, $preferredStability, true)) { if (true !== $ignorePlatformReqs && $versionSelector->findBestCandidate($name, null, $preferredStability, true)) {
throw new \InvalidArgumentException(sprintf( throw new \InvalidArgumentException(sprintf(
'Could not find package %s in any version matching your PHP version, PHP extensions and Composer version', 'Could not find package %s in any version matching your PHP version, PHP extensions and Composer version',
$name $name

View File

@ -49,7 +49,7 @@ class InstallCommand extends BaseCommand
new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump'), new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump'),
new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize-autoloader`.'), new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize-autoloader`.'),
new InputOption('apcu-autoloader', null, InputOption::VALUE_NONE, 'Use APCu to cache found/not-found classes.'), new InputOption('apcu-autoloader', null, InputOption::VALUE_NONE, 'Use APCu to cache found/not-found classes.'),
new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore platform requirements (php & ext- packages).'), new InputOption('ignore-platform-reqs', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Ignore platform requirements (php & ext- packages), optionally can take a package name to ignore specific package(s).'),
new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Should not be provided, use composer require instead to add a given package to composer.json.'), new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Should not be provided, use composer require instead to add a given package to composer.json.'),
)) ))
->setHelp( ->setHelp(
@ -103,6 +103,10 @@ EOT
$authoritative = $input->getOption('classmap-authoritative') || $config->get('classmap-authoritative'); $authoritative = $input->getOption('classmap-authoritative') || $config->get('classmap-authoritative');
$apcu = $input->getOption('apcu-autoloader') || $config->get('apcu-autoloader'); $apcu = $input->getOption('apcu-autoloader') || $config->get('apcu-autoloader');
$ignorePlatformReqs = $input->getOption('ignore-platform-reqs')
? (array_filter($input->getOption('ignore-platform-reqs')) ? $input->getOption('ignore-platform-reqs') : true)
: false;
$install $install
->setDryRun($input->getOption('dry-run')) ->setDryRun($input->getOption('dry-run'))
->setVerbose($input->getOption('verbose')) ->setVerbose($input->getOption('verbose'))
@ -114,7 +118,7 @@ EOT
->setOptimizeAutoloader($optimize) ->setOptimizeAutoloader($optimize)
->setClassMapAuthoritative($authoritative) ->setClassMapAuthoritative($authoritative)
->setApcuAutoloader($apcu) ->setApcuAutoloader($apcu)
->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs')) ->setIgnorePlatformRequirements($ignorePlatformReqs)
; ;
if ($input->getOption('no-plugins')) { if ($input->getOption('no-plugins')) {

View File

@ -50,7 +50,7 @@ class RemoveCommand extends BaseCommand
new InputOption('with-all-dependencies', null, InputOption::VALUE_NONE, 'Alias for --update-with-all-dependencies'), new InputOption('with-all-dependencies', null, InputOption::VALUE_NONE, 'Alias for --update-with-all-dependencies'),
new InputOption('no-update-with-dependencies', null, InputOption::VALUE_NONE, 'Does not allow inherited dependencies to be updated with explicit dependencies.'), new InputOption('no-update-with-dependencies', null, InputOption::VALUE_NONE, 'Does not allow inherited dependencies to be updated with explicit dependencies.'),
new InputOption('unused', null, InputOption::VALUE_NONE, 'Remove all packages which are locked but not required by any other package.'), new InputOption('unused', null, InputOption::VALUE_NONE, 'Remove all packages which are locked but not required by any other package.'),
new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore platform requirements (php & ext- packages).'), new InputOption('ignore-platform-reqs', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Ignore platform requirements (php & ext- packages), optionally can take a package name to ignore specific package(s).'),
new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump'), new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump'),
new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize-autoloader`.'), new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize-autoloader`.'),
new InputOption('apcu-autoloader', null, InputOption::VALUE_NONE, 'Use APCu to cache found/not-found classes.'), new InputOption('apcu-autoloader', null, InputOption::VALUE_NONE, 'Use APCu to cache found/not-found classes.'),
@ -238,6 +238,10 @@ EOT
$io->writeError('<info>Running composer update '.implode(' ', $packages).$flags); $io->writeError('<info>Running composer update '.implode(' ', $packages).$flags);
$ignorePlatformReqs = $input->getOption('ignore-platform-reqs')
? (array_filter($input->getOption('ignore-platform-reqs')) ? $input->getOption('ignore-platform-reqs') : true)
: false;
$install $install
->setVerbose($input->getOption('verbose')) ->setVerbose($input->getOption('verbose'))
->setDevMode($updateDevMode) ->setDevMode($updateDevMode)
@ -248,7 +252,7 @@ EOT
->setInstall(!$input->getOption('no-install')) ->setInstall(!$input->getOption('no-install'))
->setUpdateAllowList($packages) ->setUpdateAllowList($packages)
->setUpdateAllowTransitiveDependencies($updateAllowTransitiveDependencies) ->setUpdateAllowTransitiveDependencies($updateAllowTransitiveDependencies)
->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs')) ->setIgnorePlatformRequirements($ignorePlatformReqs)
->setRunScripts(!$input->getOption('no-scripts')) ->setRunScripts(!$input->getOption('no-scripts'))
->setDryRun($dryRun) ->setDryRun($dryRun)
; ;

View File

@ -69,7 +69,7 @@ class RequireCommand extends InitCommand
new InputOption('update-with-all-dependencies', null, InputOption::VALUE_NONE, 'Allows all inherited dependencies to be updated, including those that are root requirements.'), new InputOption('update-with-all-dependencies', null, InputOption::VALUE_NONE, 'Allows all inherited dependencies to be updated, including those that are root requirements.'),
new InputOption('with-dependencies', null, InputOption::VALUE_NONE, 'Alias for --update-with-dependencies'), new InputOption('with-dependencies', null, InputOption::VALUE_NONE, 'Alias for --update-with-dependencies'),
new InputOption('with-all-dependencies', null, InputOption::VALUE_NONE, 'Alias for --update-with-all-dependencies'), new InputOption('with-all-dependencies', null, InputOption::VALUE_NONE, 'Alias for --update-with-all-dependencies'),
new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore platform requirements (php & ext- packages).'), new InputOption('ignore-platform-reqs', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Ignore platform requirements (php & ext- packages), optionally can take a package name to ignore specific package(s).'),
new InputOption('prefer-stable', null, InputOption::VALUE_NONE, 'Prefer stable versions of dependencies.'), new InputOption('prefer-stable', null, InputOption::VALUE_NONE, 'Prefer stable versions of dependencies.'),
new InputOption('prefer-lowest', null, InputOption::VALUE_NONE, 'Prefer lowest versions of dependencies.'), new InputOption('prefer-lowest', null, InputOption::VALUE_NONE, 'Prefer lowest versions of dependencies.'),
new InputOption('sort-packages', null, InputOption::VALUE_NONE, 'Sorts packages when adding/updating a new dependency'), new InputOption('sort-packages', null, InputOption::VALUE_NONE, 'Sorts packages when adding/updating a new dependency'),
@ -181,7 +181,7 @@ EOT
$input, $input,
$output, $output,
$input->getArgument('packages'), $input->getArgument('packages'),
$input->getOption('ignore-platform-reqs') ? null : $platformRepo, $platformRepo,
$preferredStability, $preferredStability,
!$input->getOption('no-update'), !$input->getOption('no-update'),
$input->getOption('fixed') $input->getOption('fixed')
@ -287,6 +287,10 @@ EOT
$install = Installer::create($io, $composer); $install = Installer::create($io, $composer);
$ignorePlatformReqs = $input->getOption('ignore-platform-reqs')
? (array_filter($input->getOption('ignore-platform-reqs')) ? $input->getOption('ignore-platform-reqs') : true)
: false;
$install $install
->setDryRun($input->getOption('dry-run')) ->setDryRun($input->getOption('dry-run'))
->setVerbose($input->getOption('verbose')) ->setVerbose($input->getOption('verbose'))
@ -300,7 +304,7 @@ EOT
->setUpdate(true) ->setUpdate(true)
->setInstall(!$input->getOption('no-install')) ->setInstall(!$input->getOption('no-install'))
->setUpdateAllowTransitiveDependencies($updateAllowTransitiveDependencies) ->setUpdateAllowTransitiveDependencies($updateAllowTransitiveDependencies)
->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs')) ->setIgnorePlatformRequirements($ignorePlatformReqs)
->setPreferStable($input->getOption('prefer-stable')) ->setPreferStable($input->getOption('prefer-stable'))
->setPreferLowest($input->getOption('prefer-lowest')) ->setPreferLowest($input->getOption('prefer-lowest'))
; ;

View File

@ -60,7 +60,7 @@ class UpdateCommand extends BaseCommand
new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump.'), new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump.'),
new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize-autoloader`.'), new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize-autoloader`.'),
new InputOption('apcu-autoloader', null, InputOption::VALUE_NONE, 'Use APCu to cache found/not-found classes.'), new InputOption('apcu-autoloader', null, InputOption::VALUE_NONE, 'Use APCu to cache found/not-found classes.'),
new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore platform requirements (php & ext- packages).'), new InputOption('ignore-platform-reqs', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Ignore platform requirements (php & ext- packages), optionally can take a package name to ignore specific package(s).'),
new InputOption('prefer-stable', null, InputOption::VALUE_NONE, 'Prefer stable versions of dependencies.'), new InputOption('prefer-stable', null, InputOption::VALUE_NONE, 'Prefer stable versions of dependencies.'),
new InputOption('prefer-lowest', null, InputOption::VALUE_NONE, 'Prefer lowest versions of dependencies.'), new InputOption('prefer-lowest', null, InputOption::VALUE_NONE, 'Prefer lowest versions of dependencies.'),
new InputOption('interactive', 'i', InputOption::VALUE_NONE, 'Interactive interface with autocompletion to select the packages to update.'), new InputOption('interactive', 'i', InputOption::VALUE_NONE, 'Interactive interface with autocompletion to select the packages to update.'),
@ -196,6 +196,10 @@ EOT
$updateAllowTransitiveDependencies = Request::UPDATE_LISTED_WITH_TRANSITIVE_DEPS_NO_ROOT_REQUIRE; $updateAllowTransitiveDependencies = Request::UPDATE_LISTED_WITH_TRANSITIVE_DEPS_NO_ROOT_REQUIRE;
} }
$ignorePlatformReqs = $input->getOption('ignore-platform-reqs')
? (array_filter($input->getOption('ignore-platform-reqs')) ? $input->getOption('ignore-platform-reqs') : true)
: false;
$install $install
->setDryRun($input->getOption('dry-run')) ->setDryRun($input->getOption('dry-run'))
->setVerbose($input->getOption('verbose')) ->setVerbose($input->getOption('verbose'))
@ -212,7 +216,7 @@ EOT
->setUpdateMirrors($updateMirrors) ->setUpdateMirrors($updateMirrors)
->setUpdateAllowList($packages) ->setUpdateAllowList($packages)
->setUpdateAllowTransitiveDependencies($updateAllowTransitiveDependencies) ->setUpdateAllowTransitiveDependencies($updateAllowTransitiveDependencies)
->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs')) ->setIgnorePlatformRequirements($ignorePlatformReqs)
->setPreferStable($input->getOption('prefer-stable')) ->setPreferStable($input->getOption('prefer-stable'))
->setPreferLowest($input->getOption('prefer-lowest')) ->setPreferLowest($input->getOption('prefer-lowest'))
; ;

View File

@ -169,7 +169,7 @@ class RuleSetGenerator
} }
foreach ($package->getRequires() as $link) { foreach ($package->getRequires() as $link) {
if ($ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $link->getTarget())) { if ((true === $ignorePlatformReqs || (is_array($ignorePlatformReqs) && in_array($link->getTarget(), $ignorePlatformReqs, true))) && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $link->getTarget())) {
continue; continue;
} }
@ -193,7 +193,7 @@ class RuleSetGenerator
continue; continue;
} }
if ($ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $link->getTarget())) { if ((true === $ignorePlatformReqs || (is_array($ignorePlatformReqs) && in_array($link->getTarget(), $ignorePlatformReqs, true))) && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $link->getTarget())) {
continue; continue;
} }
@ -253,7 +253,7 @@ class RuleSetGenerator
} }
foreach ($request->getRequires() as $packageName => $constraint) { foreach ($request->getRequires() as $packageName => $constraint) {
if ($ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $packageName)) { if ((true === $ignorePlatformReqs || (is_array($ignorePlatformReqs) && in_array($packageName, $ignorePlatformReqs, true))) && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $packageName)) {
continue; continue;
} }
@ -272,6 +272,9 @@ class RuleSetGenerator
} }
} }
/**
* @param bool|array $ignorePlatformReqs
*/
public function getRulesFor(Request $request, $ignorePlatformReqs = false) public function getRulesFor(Request $request, $ignorePlatformReqs = false)
{ {
$this->rules = new RuleSet; $this->rules = new RuleSet;

View File

@ -165,12 +165,12 @@ class Solver
/** /**
* @param Request $request * @param Request $request
* @param bool $ignorePlatformReqs * @param bool|array $ignorePlatformReqs
*/ */
protected function checkForRootRequireProblems($request, $ignorePlatformReqs) protected function checkForRootRequireProblems(Request $request, $ignorePlatformReqs)
{ {
foreach ($request->getRequires() as $packageName => $constraint) { foreach ($request->getRequires() as $packageName => $constraint) {
if ($ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $packageName)) { if ((true === $ignorePlatformReqs || (is_array($ignorePlatformReqs) && in_array($packageName, $ignorePlatformReqs, true))) && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $packageName)) {
continue; continue;
} }
@ -184,7 +184,7 @@ class Solver
/** /**
* @param Request $request * @param Request $request
* @param bool $ignorePlatformReqs * @param bool|array $ignorePlatformReqs
* @return LockTransaction * @return LockTransaction
*/ */
public function solve(Request $request, $ignorePlatformReqs = false) public function solve(Request $request, $ignorePlatformReqs = false)

View File

@ -74,7 +74,7 @@ class SolverProblemsException extends \RuntimeException
// TODO remove before 2.0 final // TODO remove before 2.0 final
if (!class_exists('PHPUnit\Framework\TestCase', false)) { if (!class_exists('PHPUnit\Framework\TestCase', false)) {
if (strpos($text, 'found composer-plugin-api[2.0.0] but it does not match')) { if (strpos($text, 'found composer-plugin-api[2.0.0] but it does not match')) {
$hints[] = "You are using a snapshot build of Composer 2, which some of your plugins seem to be incompatible with. Make sure you update your plugins or report an issue to them to ask them to support Composer 2. To work around this you can run Composer with --ignore-platform-reqs, but this will also ignore your PHP version and may result in bigger problems down the line."; $hints[] = "You are using a snapshot build of Composer 2, which some of your plugins seem to be incompatible with. Make sure you update your plugins or report an issue to them to ask them to support Composer 2. To work around this you can run Composer with --ignore-platform-reqs=composer-plugin-api, but this may result in broken plugins and bigger problems down the line.";
} else { } else {
$hints[] = "You are using a snapshot build of Composer 2, which may be the cause of the problem. Run `composer self-update --stable` and then try again. In case it solves the problem, please report an issue mentioning Composer 2."; $hints[] = "You are using a snapshot build of Composer 2, which may be the cause of the problem. Run `composer self-update --stable` and then try again. In case it solves the problem, please report an issue mentioning Composer 2.";
} }

View File

@ -308,6 +308,7 @@ class Installer
$this->autoloadGenerator->setClassMapAuthoritative($this->classMapAuthoritative); $this->autoloadGenerator->setClassMapAuthoritative($this->classMapAuthoritative);
$this->autoloadGenerator->setApcu($this->apcuAutoloader); $this->autoloadGenerator->setApcu($this->apcuAutoloader);
$this->autoloadGenerator->setRunScripts($this->runScripts); $this->autoloadGenerator->setRunScripts($this->runScripts);
$this->autoloadGenerator->setIgnorePlatformRequirements($this->ignorePlatformReqs);
$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);
} }
@ -737,7 +738,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 ($this->ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $req)) { if ((true === $this->ignorePlatformReqs || (is_array($this->ignorePlatformReqs) && in_array($req, $this->ignorePlatformReqs, true))) && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $req)) {
continue; continue;
} }
if ($constraint instanceof Link) { if ($constraint instanceof Link) {
@ -1117,12 +1118,22 @@ class Installer
/** /**
* set ignore Platform Package requirements * set ignore Platform Package requirements
* *
* @param bool $ignorePlatformReqs * If this is set to true, all platform requirements are ignored
* If this is set to false, no platform requirements are ignored
* If this is set to string[], those packages will be ignored
*
* @param bool|array $ignorePlatformReqs
* @return Installer * @return Installer
*/ */
public function setIgnorePlatformRequirements($ignorePlatformReqs = false) public function setIgnorePlatformRequirements($ignorePlatformReqs = false)
{ {
if (is_array($ignorePlatformReqs)) {
$this->ignorePlatformReqs = array_filter($ignorePlatformReqs, function ($req) {
return (bool) preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $req);
});
} else {
$this->ignorePlatformReqs = (bool) $ignorePlatformReqs; $this->ignorePlatformReqs = (bool) $ignorePlatformReqs;
}
return $this; return $this;
} }

View File

@ -33,7 +33,7 @@ class VersionSelector
{ {
private $repositorySet; private $repositorySet;
private $platformConstraints; private $platformConstraints = array();
private $parser; private $parser;
@ -44,7 +44,6 @@ class VersionSelector
{ {
$this->repositorySet = $repositorySet; $this->repositorySet = $repositorySet;
if ($platformRepo) { if ($platformRepo) {
$this->platformConstraints = array();
foreach ($platformRepo->getPackages() as $package) { foreach ($platformRepo->getPackages() as $package) {
$this->platformConstraints[$package->getName()][] = new Constraint('==', $package->getVersion()); $this->platformConstraints[$package->getName()][] = new Constraint('==', $package->getVersion());
} }
@ -58,7 +57,7 @@ class VersionSelector
* @param string $packageName * @param string $packageName
* @param string $targetPackageVersion * @param string $targetPackageVersion
* @param string $preferredStability * @param string $preferredStability
* @param bool $ignorePlatformReqs * @param bool|array $ignorePlatformReqs
* @return PackageInterface|false * @return PackageInterface|false
*/ */
public function findBestCandidate($packageName, $targetPackageVersion = null, $preferredStability = 'stable', $ignorePlatformReqs = false) public function findBestCandidate($packageName, $targetPackageVersion = null, $preferredStability = 'stable', $ignorePlatformReqs = false)
@ -71,13 +70,14 @@ class VersionSelector
$constraint = $targetPackageVersion ? $this->getParser()->parseConstraints($targetPackageVersion) : null; $constraint = $targetPackageVersion ? $this->getParser()->parseConstraints($targetPackageVersion) : null;
$candidates = $this->repositorySet->findPackages(strtolower($packageName), $constraint); $candidates = $this->repositorySet->findPackages(strtolower($packageName), $constraint);
if ($this->platformConstraints && !$ignorePlatformReqs) { if ($this->platformConstraints && true !== $ignorePlatformReqs) {
$platformConstraints = $this->platformConstraints; $platformConstraints = $this->platformConstraints;
$candidates = array_filter($candidates, function ($pkg) use ($platformConstraints) { $ignorePlatformReqs = $ignorePlatformReqs ?: array();
$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 (isset($platformConstraints[$name])) { if (!in_array($name, $ignorePlatformReqs, true) && isset($platformConstraints[$name])) {
foreach ($platformConstraints[$name] as $constraint) { foreach ($platformConstraints[$name] as $constraint) {
if ($link->getConstraint()->matches($constraint)) { if ($link->getConstraint()->matches($constraint)) {
continue 2; continue 2;

View File

@ -264,10 +264,14 @@ class InstallerTest extends TestCase
$application = new Application; $application = new Application;
$application->get('install')->setCode(function ($input, $output) use ($installer) { $application->get('install')->setCode(function ($input, $output) use ($installer) {
$ignorePlatformReqs = $input->getOption('ignore-platform-reqs')
? (array_filter($input->getOption('ignore-platform-reqs')) ? $input->getOption('ignore-platform-reqs') : true)
: false;
$installer $installer
->setDevMode(!$input->getOption('no-dev')) ->setDevMode(!$input->getOption('no-dev'))
->setDryRun($input->getOption('dry-run')) ->setDryRun($input->getOption('dry-run'))
->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs')); ->setIgnorePlatformRequirements($ignorePlatformReqs);
return $installer->run(); return $installer->run();
}); });
@ -287,6 +291,10 @@ class InstallerTest extends TestCase
$updateAllowTransitiveDependencies = Request::UPDATE_LISTED_WITH_TRANSITIVE_DEPS_NO_ROOT_REQUIRE; $updateAllowTransitiveDependencies = Request::UPDATE_LISTED_WITH_TRANSITIVE_DEPS_NO_ROOT_REQUIRE;
} }
$ignorePlatformReqs = $input->getOption('ignore-platform-reqs')
? (array_filter($input->getOption('ignore-platform-reqs')) ? $input->getOption('ignore-platform-reqs') : true)
: false;
$installer $installer
->setDevMode(!$input->getOption('no-dev')) ->setDevMode(!$input->getOption('no-dev'))
->setUpdate(true) ->setUpdate(true)
@ -297,7 +305,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($input->getOption('ignore-platform-reqs')); ->setIgnorePlatformRequirements($ignorePlatformReqs);
return $installer->run(); return $installer->run();
}); });