diff --git a/src/Composer/Command/InstallCommand.php b/src/Composer/Command/InstallCommand.php index b65e08f0f..43a169e7d 100644 --- a/src/Composer/Command/InstallCommand.php +++ b/src/Composer/Command/InstallCommand.php @@ -45,7 +45,7 @@ class InstallCommand extends Command new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'), new InputOption('verbose', 'v|vv|vvv', InputOption::VALUE_NONE, 'Shows more details including new commits pulled in when updating packages.'), new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump'), - new InputOption('ignore-platform-package-requirements', null, InputOption::VALUE_NONE, 'Ignore PHP Extention requirements.'), + new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore platform requirements (php & ext- packages).'), 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(<<setDevMode(!$input->getOption('no-dev')) ->setRunScripts(!$input->getOption('no-scripts')) ->setOptimizeAutoloader($optimize) - ->setIgnorePlatformPackage($input->getOption('ignore-platform-package-requirements')); + ->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs')); ; if ($input->getOption('no-plugins')) { diff --git a/src/Composer/Command/UpdateCommand.php b/src/Composer/Command/UpdateCommand.php index 131390dd7..9d1e95dd0 100644 --- a/src/Composer/Command/UpdateCommand.php +++ b/src/Composer/Command/UpdateCommand.php @@ -46,7 +46,7 @@ class UpdateCommand extends Command new InputOption('with-dependencies', null, InputOption::VALUE_NONE, 'Add also all dependencies of whitelisted packages to the whitelist.'), new InputOption('verbose', 'v|vv|vvv', InputOption::VALUE_NONE, 'Shows more details including new commits pulled in when updating packages.'), new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump.'), - new InputOption('ignore-platform-package-requirements', null, InputOption::VALUE_NONE, 'Ignore PHP Extention requirements.'), + new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore platform requirements (php & ext- packages).'), )) ->setHelp(<<update command reads the composer.json file from the @@ -120,7 +120,7 @@ EOT ->setUpdate(true) ->setUpdateWhitelist($input->getOption('lock') ? array('lock') : $input->getArgument('packages')) ->setWhitelistDependencies($input->getOption('with-dependencies')) - ->setIgnorePlatformPackage($input->getOption('ignore-platform-package-requirements')); + ->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs')); ; if ($input->getOption('no-plugins')) { diff --git a/src/Composer/DependencyResolver/Request.php b/src/Composer/DependencyResolver/Request.php index bf74318f6..79904a3a1 100644 --- a/src/Composer/DependencyResolver/Request.php +++ b/src/Composer/DependencyResolver/Request.php @@ -43,7 +43,17 @@ class Request $this->addJob($packageName, 'remove', $constraint); } - protected function addJob($packageName, $cmd, LinkConstraintInterface $constraint = null) + /** + * Mark an existing package as being installed and having to remain installed + * + * These jobs will not be tempered with by the solver + */ + public function fix($packageName, LinkConstraintInterface $constraint = null) + { + $this->addJob($packageName, 'install', $constraint, true); + } + + protected function addJob($packageName, $cmd, LinkConstraintInterface $constraint = null, $fixed = false) { $packageName = strtolower($packageName); @@ -51,6 +61,7 @@ class Request 'cmd' => $cmd, 'packageName' => $packageName, 'constraint' => $constraint, + 'fixed' => $fixed ); } diff --git a/src/Composer/DependencyResolver/RuleSetGenerator.php b/src/Composer/DependencyResolver/RuleSetGenerator.php index 5bcf9a079..fa58687ea 100644 --- a/src/Composer/DependencyResolver/RuleSetGenerator.php +++ b/src/Composer/DependencyResolver/RuleSetGenerator.php @@ -14,6 +14,7 @@ namespace Composer\DependencyResolver; use Composer\Package\PackageInterface; use Composer\Package\AliasPackage; +use Composer\Repository\PlatformRepository; /** * @author Nils Adermann @@ -178,7 +179,7 @@ class RuleSetGenerator } } - protected function addRulesForPackage(PackageInterface $package) + protected function addRulesForPackage(PackageInterface $package, $ignorePlatformReqs) { $workQueue = new \SplQueue; $workQueue->enqueue($package); @@ -192,6 +193,10 @@ class RuleSetGenerator $this->addedMap[$package->getId()] = true; foreach ($package->getRequires() as $link) { + if ($ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $link->getTarget())) { + continue; + } + $possibleRequires = $this->pool->whatProvides($link->getTarget(), $link->getConstraint()); $this->addRule(RuleSet::TYPE_PACKAGE, $rule = $this->createRequireRule($package, $possibleRequires, Rule::RULE_PACKAGE_REQUIRES, $link)); @@ -264,12 +269,12 @@ class RuleSetGenerator * @param PackageInterface $package Rules for this package's updates are to * be added */ - private function addRulesForUpdatePackages(PackageInterface $package) + private function addRulesForUpdatePackages(PackageInterface $package, $ignorePlatformReqs) { $updates = $this->policy->findUpdatePackages($this->pool, $this->installedMap, $package); foreach ($updates as $update) { - $this->addRulesForPackage($update); + $this->addRulesForPackage($update, $ignorePlatformReqs); } } @@ -296,16 +301,20 @@ class RuleSetGenerator } } - protected function addRulesForJobs() + protected function addRulesForJobs($ignorePlatformReqs) { foreach ($this->jobs as $job) { switch ($job['cmd']) { case 'install': + if (!$job['fixed'] && $ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $job['packageName'])) { + continue; + } + $packages = $this->pool->whatProvides($job['packageName'], $job['constraint']); if ($packages) { foreach ($packages as $package) { if (!isset($this->installedMap[$package->getId()])) { - $this->addRulesForPackage($package); + $this->addRulesForPackage($package, $ignorePlatformReqs); } } @@ -326,7 +335,7 @@ class RuleSetGenerator } } - public function getRulesFor($jobs, $installedMap) + public function getRulesFor($jobs, $installedMap, $ignorePlatformReqs = false) { $this->jobs = $jobs; $this->rules = new RuleSet; @@ -343,11 +352,11 @@ class RuleSetGenerator $this->addedMap = array(); foreach ($this->installedMap as $package) { - $this->addRulesForPackage($package); - $this->addRulesForUpdatePackages($package); + $this->addRulesForPackage($package, $ignorePlatformReqs); + $this->addRulesForUpdatePackages($package, $ignorePlatformReqs); } - $this->addRulesForJobs(); + $this->addRulesForJobs($ignorePlatformReqs); return $this->rules; } diff --git a/src/Composer/DependencyResolver/Solver.php b/src/Composer/DependencyResolver/Solver.php index c6ad2b17a..2a0256e40 100644 --- a/src/Composer/DependencyResolver/Solver.php +++ b/src/Composer/DependencyResolver/Solver.php @@ -130,7 +130,7 @@ class Solver } } - protected function checkForRootRequireProblems($ignorePlatformPackageRequirements) + protected function checkForRootRequireProblems($ignorePlatformReqs) { foreach ($this->jobs as $job) { switch ($job['cmd']) { @@ -150,7 +150,7 @@ class Solver break; case 'install': - if ($ignorePlatformPackageRequirements && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $job['packageName'])) { + if ($ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $job['packageName'])) { break; } @@ -164,24 +164,16 @@ class Solver } } - public function solve(Request $request, $ignorePlatformPackage = false) + public function solve(Request $request, $ignorePlatformReqs = false) { $this->jobs = $request->getJobs(); $this->setupInstalledMap(); - $this->rules = $this->ruleSetGenerator->getRulesFor($this->jobs, $this->installedMap); - $this->checkForRootRequireProblems($ignorePlatformPackage); + $this->rules = $this->ruleSetGenerator->getRulesFor($this->jobs, $this->installedMap, $ignorePlatformReqs); + $this->checkForRootRequireProblems($ignorePlatformReqs); $this->decisions = new Decisions($this->pool); $this->watchGraph = new RuleWatchGraph; - if ($ignorePlatformPackage) { - foreach ($this->rules as $rule) { - if ($rule->getReason() === Rule::RULE_PACKAGE_REQUIRES && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $rule->getRequiredPackage())) { - $rule->disable(); - } - } - } - foreach ($this->rules as $rule) { $this->watchGraph->insert(new RuleWatchNode($rule)); } diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index 6c232a060..4fb58e07f 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -105,7 +105,7 @@ class Installer protected $verbose = false; protected $update = false; protected $runScripts = true; - protected $ignorePlatformPackage = false; + protected $ignorePlatformReqs = false; /** * Array of package names/globs flagged for update * @@ -264,7 +264,7 @@ class Installer $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, $policy, $pool, $installedRepo, $request); $solver = new Solver($policy, $pool, $installedRepo); - $ops = $solver->solve($request, $this->ignorePlatformPackage); + $ops = $solver->solve($request, $this->ignorePlatformReqs); $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, $policy, $pool, $installedRepo, $request, $ops); foreach ($ops as $op) { if ($op->getJobType() === 'uninstall') { @@ -471,7 +471,7 @@ class Installer $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, $policy, $pool, $installedRepo, $request); $solver = new Solver($policy, $pool, $installedRepo); try { - $operations = $solver->solve($request, $this->ignorePlatformPackage); + $operations = $solver->solve($request, $this->ignorePlatformReqs); $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, $policy, $pool, $installedRepo, $request, $operations); } catch (SolverProblemsException $e) { $this->io->write('Your requirements could not be resolved to an installable set of packages.'); @@ -658,6 +658,10 @@ class Installer } $rootConstraints = array(); foreach ($requires as $req => $constraint) { + // skip platform requirements from the root package to avoid filtering out existing platform packages + if ($this->ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $req)) { + continue; + } $rootConstraints[$req] = $constraint->getConstraint(); } @@ -705,7 +709,7 @@ class Installer || !isset($provided[$package->getName()]) || !$provided[$package->getName()]->getConstraint()->matches($constraint) ) { - $request->install($package->getName(), $constraint); + $request->fix($package->getName(), $constraint); } } @@ -1180,12 +1184,12 @@ class Installer /** * set ignore Platform Package requirements * - * @param boolean $ignorePlatformPackage + * @param boolean $ignorePlatformReqs * @return Installer */ - public function setIgnorePlatformPackage($ignorePlatformPackage = false) + public function setIgnorePlatformRequirements($ignorePlatformReqs = false) { - $this->ignorePlatformPackage = (boolean) $ignorePlatformPackage; + $this->ignorePlatformReqs = (boolean) $ignorePlatformReqs; return $this; } diff --git a/tests/Composer/Test/DependencyResolver/RequestTest.php b/tests/Composer/Test/DependencyResolver/RequestTest.php index 0ba43ca73..78a1da962 100644 --- a/tests/Composer/Test/DependencyResolver/RequestTest.php +++ b/tests/Composer/Test/DependencyResolver/RequestTest.php @@ -34,14 +34,14 @@ class RequestTest extends TestCase $request = new Request($pool); $request->install('foo'); - $request->install('bar'); + $request->fix('bar'); $request->remove('foobar'); $this->assertEquals( array( - array('cmd' => 'install', 'packageName' => 'foo', 'constraint' => null), - array('cmd' => 'install', 'packageName' => 'bar', 'constraint' => null), - array('cmd' => 'remove', 'packageName' => 'foobar', 'constraint' => null), + array('cmd' => 'install', 'packageName' => 'foo', 'constraint' => null, 'fixed' => false), + array('cmd' => 'install', 'packageName' => 'bar', 'constraint' => null, 'fixed' => true), + array('cmd' => 'remove', 'packageName' => 'foobar', 'constraint' => null, 'fixed' => false), ), $request->getJobs()); } @@ -66,7 +66,7 @@ class RequestTest extends TestCase $this->assertEquals( array( - array('cmd' => 'install', 'packageName' => 'foo', 'constraint' => $constraint), + array('cmd' => 'install', 'packageName' => 'foo', 'constraint' => $constraint, 'fixed' => false), ), $request->getJobs() ); diff --git a/tests/Composer/Test/Fixtures/installer/install-ignore-platform-package-requirements.test b/tests/Composer/Test/Fixtures/installer/install-ignore-platform-package-requirements.test index 88f5d1a5d..7959b6e07 100644 --- a/tests/Composer/Test/Fixtures/installer/install-ignore-platform-package-requirements.test +++ b/tests/Composer/Test/Fixtures/installer/install-ignore-platform-package-requirements.test @@ -1,20 +1,22 @@ --TEST-- -Install in ignore-platform-package-requirements mode +Install in ignore-platform-reqs mode --COMPOSER-- { "repositories": [ { "type": "package", "package": [ - { "name": "a/a", "version": "1.0.0", "require": { "ext-testdummy": "*" } } + { "name": "a/a", "version": "1.0.0", "require": { "ext-testdummy": "*", "php": "98" } } ] } ], "require": { - "a/a": "1.0.0" + "a/a": "1.0.0", + "php": "99.9", + "ext-dummy2": "3" } } --RUN-- -install --ignore-platform-package-requirements +install --ignore-platform-reqs --EXPECT-- Installing a/a (1.0.0) diff --git a/tests/Composer/Test/Fixtures/installer/update-ignore-platform-package-requirements.test b/tests/Composer/Test/Fixtures/installer/update-ignore-platform-package-requirements.test index 87e4f1297..02f94cd6e 100644 --- a/tests/Composer/Test/Fixtures/installer/update-ignore-platform-package-requirements.test +++ b/tests/Composer/Test/Fixtures/installer/update-ignore-platform-package-requirements.test @@ -1,5 +1,5 @@ --TEST-- -Update in ignore-platform-package-requirements mode +Update in ignore-platform-reqs mode --COMPOSER-- { "repositories": [ @@ -11,7 +11,9 @@ Update in ignore-platform-package-requirements mode } ], "require": { - "a/a": "1.0.*" + "a/a": "1.0.*", + "php": "99.9", + "ext-dummy2": "9" } } --INSTALLED-- @@ -19,6 +21,6 @@ Update in ignore-platform-package-requirements mode { "name": "a/a", "version": "1.0.0" } ] --RUN-- -update --ignore-platform-package-requirements +update --ignore-platform-reqs --EXPECT-- Updating a/a (1.0.0) to a/a (1.0.1) diff --git a/tests/Composer/Test/InstallerTest.php b/tests/Composer/Test/InstallerTest.php index c31fee0ed..cc12cb3ef 100644 --- a/tests/Composer/Test/InstallerTest.php +++ b/tests/Composer/Test/InstallerTest.php @@ -205,7 +205,7 @@ class InstallerTest extends TestCase $installer ->setDevMode(!$input->getOption('no-dev')) ->setDryRun($input->getOption('dry-run')) - ->setIgnorePlatformPackage($input->getOption('ignore-platform-package-requirements')); + ->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs')); return $installer->run(); }); @@ -217,7 +217,7 @@ class InstallerTest extends TestCase ->setDryRun($input->getOption('dry-run')) ->setUpdateWhitelist($input->getArgument('packages')) ->setWhitelistDependencies($input->getOption('with-dependencies')) - ->setIgnorePlatformPackage($input->getOption('ignore-platform-package-requirements')); + ->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs')); return $installer->run(); });