From 7eca450d9bbcb1c379fe380064d0c045fa445dc8 Mon Sep 17 00:00:00 2001 From: Martin Herndl Date: Thu, 11 Nov 2021 15:56:38 +0100 Subject: [PATCH] Add wildcard support to ignore-platform-req, fixes #10045 (#10083) --- doc/03-cli.md | 13 +++++---- .../IgnoreListPlatformRequirementFilter.php | 9 +++--- src/Composer/Package/BasePackage.php | 19 ++++++++++++ src/Composer/Repository/FilterRepository.php | 8 ++--- .../Test/Autoload/AutoloadGeneratorTest.php | 14 +++++++++ ...gnoreListPlatformRequirementFilterTest.php | 8 +++++ ...ore-platform-package-requirement-list.test | 22 ++++++++++++++ ...platform-package-requirement-wildcard.test | 22 ++++++++++++++ ...ore-platform-package-requirement-list.test | 26 +++++++++++++++++ ...platform-package-requirement-wildcard.test | 26 +++++++++++++++++ .../Composer/Test/Package/BasePackageTest.php | 29 +++++++++++++++++++ 11 files changed, 180 insertions(+), 16 deletions(-) create mode 100644 tests/Composer/Test/Fixtures/installer/install-ignore-platform-package-requirement-list.test create mode 100644 tests/Composer/Test/Fixtures/installer/install-ignore-platform-package-requirement-wildcard.test create mode 100644 tests/Composer/Test/Fixtures/installer/update-ignore-platform-package-requirement-list.test create mode 100644 tests/Composer/Test/Fixtures/installer/update-ignore-platform-package-requirement-wildcard.test diff --git a/doc/03-cli.md b/doc/03-cli.md index e9b78e593..e8ea3672c 100644 --- a/doc/03-cli.md +++ b/doc/03-cli.md @@ -117,7 +117,7 @@ resolution. See also the [`platform`](06-config.md#platform) config option. * **--ignore-platform-req:** ignore a specific platform requirement(`php`, `hhvm`, `lib-*` and `ext-*`) and force the installation even if the local machine - does not fulfill it. + does not fulfill it. Multiple requirements can be ignored via wildcard. ## update / u @@ -202,7 +202,7 @@ php composer.phar update vendor/package:2.0.1 vendor/package2:3.0.* See also the [`platform`](06-config.md#platform) config option. * **--ignore-platform-req:** ignore a specific platform requirement(`php`, `hhvm`, `lib-*` and `ext-*`) and force the installation even if the local machine - does not fulfill it. + does not fulfill it. Multiple requirements can be ignored via wildcard. * **--prefer-stable:** Prefer stable versions of dependencies. * **--prefer-lowest:** Prefer lowest versions of dependencies. Useful for testing minimal versions of requirements, generally used with `--prefer-stable`. @@ -258,7 +258,7 @@ If you do not specify a package, Composer will prompt you to search for a packag See also the [`platform`](06-config.md#platform) config option. * **--ignore-platform-req:** ignore a specific platform requirement(`php`, `hhvm`, `lib-*` and `ext-*`) and force the installation even if the local machine - does not fulfill it. + does not fulfill it. Multiple requirements can be ignored via wildcard. * **--prefer-stable:** Prefer stable versions of dependencies. * **--prefer-lowest:** Prefer lowest versions of dependencies. Useful for testing minimal versions of requirements, generally used with `--prefer-stable`. @@ -303,7 +303,7 @@ uninstalled. See also the [`platform`](06-config.md#platform) config option. * **--ignore-platform-req:** ignore a specific platform requirement(`php`, `hhvm`, `lib-*` and `ext-*`) and force the installation even if the local machine - does not fulfill it. + does not fulfill it. Multiple requirements can be ignored via wildcard. * **--optimize-autoloader (-o):** Convert PSR-0/4 autoloading to classmap to 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. @@ -358,7 +358,7 @@ php composer.phar reinstall "acme/*" reinstall command. * **--ignore-platform-req:** ignore a specific platform requirement. This only has an effect in the context of the autoloader generation for the - reinstall command. + reinstall command. Multiple requirements can be ignored via wildcard. ## check-platform-reqs @@ -839,7 +839,7 @@ By default the command checks for the packages on packagist.org. See also the [`platform`](06-config.md#platform) config option. * **--ignore-platform-req:** ignore a specific platform requirement(`php`, `hhvm`, `lib-*` and `ext-*`) and force the installation even if the local machine - does not fulfill it. + does not fulfill it. Multiple requirements can be ignored via wildcard. * **--ask:** Ask user to provide target directory for new project. ## dump-autoload (dumpautoload) @@ -874,6 +874,7 @@ performance. See also the [`platform`](06-config.md#platform) config option. * **--ignore-platform-req:** ignore a specific platform requirement (`php`, `hhvm`, `lib-*` and `ext-*`) and skip the [platform check](07-runtime.md#platform-check) for it. + Multiple requirements can be ignored via wildcard. ## clear-cache / clearcache / cc diff --git a/src/Composer/Filter/PlatformRequirementFilter/IgnoreListPlatformRequirementFilter.php b/src/Composer/Filter/PlatformRequirementFilter/IgnoreListPlatformRequirementFilter.php index c366d827c..d9b0c018d 100644 --- a/src/Composer/Filter/PlatformRequirementFilter/IgnoreListPlatformRequirementFilter.php +++ b/src/Composer/Filter/PlatformRequirementFilter/IgnoreListPlatformRequirementFilter.php @@ -2,21 +2,22 @@ namespace Composer\Filter\PlatformRequirementFilter; +use Composer\Package\BasePackage; use Composer\Repository\PlatformRepository; final class IgnoreListPlatformRequirementFilter implements PlatformRequirementFilterInterface { /** - * @var string[] + * @var string */ - private $reqList; + private $regexp; /** * @param string[] $reqList */ public function __construct(array $reqList) { - $this->reqList = $reqList; + $this->regexp = BasePackage::packageNamesToRegexp($reqList); } /** @@ -29,6 +30,6 @@ final class IgnoreListPlatformRequirementFilter implements PlatformRequirementFi return false; } - return in_array($req, $this->reqList, true); + return 1 === preg_match($this->regexp, $req); } } diff --git a/src/Composer/Package/BasePackage.php b/src/Composer/Package/BasePackage.php index 27a1edb48..2a7a913a6 100644 --- a/src/Composer/Package/BasePackage.php +++ b/src/Composer/Package/BasePackage.php @@ -263,4 +263,23 @@ abstract class BasePackage implements PackageInterface return sprintf($wrap, $cleanedAllowPattern); } + + /** + * Build a regexp from package names, expanding * globs as required + * + * @param string[] $packageNames + * @param string $wrap + * @return string + */ + public static function packageNamesToRegexp(array $packageNames, $wrap = '{^(?:%s)$}iD') + { + $packageNames = array_map( + function ($packageName) { + return BasePackage::packageNameToRegexp($packageName, '%s'); + }, + $packageNames + ); + + return sprintf($wrap, implode('|', $packageNames)); + } } diff --git a/src/Composer/Repository/FilterRepository.php b/src/Composer/Repository/FilterRepository.php index 429659129..83b49df2b 100644 --- a/src/Composer/Repository/FilterRepository.php +++ b/src/Composer/Repository/FilterRepository.php @@ -40,17 +40,13 @@ class FilterRepository implements RepositoryInterface if (!is_array($options['only'])) { throw new \InvalidArgumentException('"only" key for repository '.$repo->getRepoName().' should be an array'); } - $this->only = '{^(?:'.implode('|', array_map(function ($val) { - return BasePackage::packageNameToRegexp($val, '%s'); - }, $options['only'])) .')$}iD'; + $this->only = BasePackage::packageNamesToRegexp($options['only']); } if (isset($options['exclude'])) { if (!is_array($options['exclude'])) { throw new \InvalidArgumentException('"exclude" key for repository '.$repo->getRepoName().' should be an array'); } - $this->exclude = '{^(?:'.implode('|', array_map(function ($val) { - return BasePackage::packageNameToRegexp($val, '%s'); - }, $options['exclude'])) .')$}iD'; + $this->exclude = BasePackage::packageNamesToRegexp($options['exclude']); } if ($this->exclude && $this->only) { throw new \InvalidArgumentException('Only one of "only" and "exclude" can be specified for repository '.$repo->getRepoName()); diff --git a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php index 391bd5d08..04555516a 100644 --- a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php +++ b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php @@ -1808,6 +1808,20 @@ EOF; array(), array('php', 'ext-pdo'), ), + 'Via wildcard ignored platform requirements are not checked for' => array( + array( + new Link('a', 'php', $versionParser->parseConstraints('^7.2.8')), + new Link('a', 'ext-xml', $versionParser->parseConstraints('*')), + new Link('a', 'ext-json', $versionParser->parseConstraints('*')), + new Link('a', 'ext-fileinfo', $versionParser->parseConstraints('*')), + new Link('a', 'ext-filesystem', $versionParser->parseConstraints('*')), + new Link('a', 'ext-filter', $versionParser->parseConstraints('*')), + ), + 'no_php_required', + array(), + array(), + array('php', 'ext-fil*'), + ), 'No extensions required' => array( array( new Link('a', 'php', $versionParser->parseConstraints('^7.2')), diff --git a/tests/Composer/Test/Filter/PlatformRequirementFilter/IgnoreListPlatformRequirementFilterTest.php b/tests/Composer/Test/Filter/PlatformRequirementFilter/IgnoreListPlatformRequirementFilterTest.php index 4c2c5a8ab..6e043c48c 100644 --- a/tests/Composer/Test/Filter/PlatformRequirementFilter/IgnoreListPlatformRequirementFilterTest.php +++ b/tests/Composer/Test/Filter/PlatformRequirementFilter/IgnoreListPlatformRequirementFilterTest.php @@ -30,6 +30,14 @@ final class IgnoreListPlatformRequirementFilterTest extends TestCase '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), + 'ext-json is ignored if ext-* is listed' => array(array('ext-*'), 'ext-json', true), + 'php is ignored if php* is listed' => array(array('ext-*', 'php*'), 'php', true), + 'ext-json is ignored if * is listed' => array(array('foo', '*'), 'ext-json', true), + 'php is ignored if * is listed' => array(array('*', 'foo'), 'php', true), + 'monolog/monolog is not ignored even if * or monolog/* are listed' => array(array('*', 'monolog/*'), 'monolog/monolog', false), + 'empty list entry does not ignore' => array(array(''), 'ext-foo', false), + 'empty array does not ignore' => array(array(), 'ext-foo', false), + 'list entries are not completing each other' => array(array('ext-', 'foo'), 'ext-foo', false), ); } } diff --git a/tests/Composer/Test/Fixtures/installer/install-ignore-platform-package-requirement-list.test b/tests/Composer/Test/Fixtures/installer/install-ignore-platform-package-requirement-list.test new file mode 100644 index 000000000..6e189f870 --- /dev/null +++ b/tests/Composer/Test/Fixtures/installer/install-ignore-platform-package-requirement-list.test @@ -0,0 +1,22 @@ +--TEST-- +Install with ignore-platform-req list +--COMPOSER-- +{ + "repositories": [ + { + "type": "package", + "package": [ + { "name": "a/a", "version": "1.0.0", "require": { "ext-foo-bar": "*", "php": "98" } } + ] + } + ], + "require": { + "a/a": "1.0.0", + "php": "99.9", + "ext-foo-baz": "*" + } +} +--RUN-- +install --ignore-platform-req=php --ignore-platform-req=ext-foo-bar --ignore-platform-req=ext-foo-baz +--EXPECT-- +Installing a/a (1.0.0) diff --git a/tests/Composer/Test/Fixtures/installer/install-ignore-platform-package-requirement-wildcard.test b/tests/Composer/Test/Fixtures/installer/install-ignore-platform-package-requirement-wildcard.test new file mode 100644 index 000000000..32a71c69d --- /dev/null +++ b/tests/Composer/Test/Fixtures/installer/install-ignore-platform-package-requirement-wildcard.test @@ -0,0 +1,22 @@ +--TEST-- +Install with ignore-platform-req wildcard +--COMPOSER-- +{ + "repositories": [ + { + "type": "package", + "package": [ + { "name": "a/a", "version": "1.0.0", "require": { "ext-foo-bar": "*", "php": "98" } } + ] + } + ], + "require": { + "a/a": "1.0.0", + "php": "99.9", + "ext-foo-baz": "*" + } +} +--RUN-- +install --ignore-platform-req=php --ignore-platform-req=ext-foo-* +--EXPECT-- +Installing a/a (1.0.0) diff --git a/tests/Composer/Test/Fixtures/installer/update-ignore-platform-package-requirement-list.test b/tests/Composer/Test/Fixtures/installer/update-ignore-platform-package-requirement-list.test new file mode 100644 index 000000000..d2b802097 --- /dev/null +++ b/tests/Composer/Test/Fixtures/installer/update-ignore-platform-package-requirement-list.test @@ -0,0 +1,26 @@ +--TEST-- +Update with ignore-platform-req list +--COMPOSER-- +{ + "repositories": [ + { + "type": "package", + "package": [ + { "name": "a/a", "version": "1.0.1", "require": { "ext-foo-bar": "*" } } + ] + } + ], + "require": { + "a/a": "1.0.*", + "php": "99.9", + "ext-foo-baz": "9" + } +} +--INSTALLED-- +[ + { "name": "a/a", "version": "1.0.0" } +] +--RUN-- +update --ignore-platform-req=php --ignore-platform-req=ext-foo-bar --ignore-platform-req=ext-foo-baz +--EXPECT-- +Upgrading a/a (1.0.0 => 1.0.1) diff --git a/tests/Composer/Test/Fixtures/installer/update-ignore-platform-package-requirement-wildcard.test b/tests/Composer/Test/Fixtures/installer/update-ignore-platform-package-requirement-wildcard.test new file mode 100644 index 000000000..cb14bb0e6 --- /dev/null +++ b/tests/Composer/Test/Fixtures/installer/update-ignore-platform-package-requirement-wildcard.test @@ -0,0 +1,26 @@ +--TEST-- +Update with ignore-platform-req wildcard +--COMPOSER-- +{ + "repositories": [ + { + "type": "package", + "package": [ + { "name": "a/a", "version": "1.0.1", "require": { "ext-foo-bar": "*" } } + ] + } + ], + "require": { + "a/a": "1.0.*", + "php": "99.9", + "ext-foo-baz": "9" + } +} +--INSTALLED-- +[ + { "name": "a/a", "version": "1.0.0" } +] +--RUN-- +update --ignore-platform-req=php --ignore-platform-req=ext-foo-* +--EXPECT-- +Upgrading a/a (1.0.0 => 1.0.1) diff --git a/tests/Composer/Test/Package/BasePackageTest.php b/tests/Composer/Test/Package/BasePackageTest.php index 522722a47..7ecaa5de6 100644 --- a/tests/Composer/Test/Package/BasePackageTest.php +++ b/tests/Composer/Test/Package/BasePackageTest.php @@ -92,4 +92,33 @@ class BasePackageTest extends TestCase return array_map($createPackage, $data); } + + /** + * @param string[] $packageNames + * @param string $wrap + * @param string $expectedRegexp + * + * @dataProvider dataPackageNamesToRegexp + */ + public function testPackageNamesToRegexp(array $packageNames, $wrap, $expectedRegexp) + { + $regexp = BasePackage::packageNamesToRegexp($packageNames, $wrap); + + $this->assertSame($expectedRegexp, $regexp); + } + + /** + * @return mixed[][] + */ + public function dataPackageNamesToRegexp() + { + return array( + array( + array('ext-*', 'monolog/monolog'), '{^%s$}i', '{^ext\-.*|monolog/monolog$}i', + array('php'), '{^%s$}i', '{^php$}i', + array('*'), '{^%s$}i', '{^.*$}i', + array('foo', 'bar'), '§%s§', '§foo|bar§', + ) + ); + } }