From 4a0feb0189a08c1d2833672989e3296902c34a12 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 21 Nov 2014 14:01:01 +0100 Subject: [PATCH] add --prefer-lowest-stable to update command --- src/Composer/Command/UpdateCommand.php | 2 + .../DependencyResolver/DefaultPolicy.php | 7 +++- src/Composer/Installer.php | 23 ++++++++++- .../DependencyResolver/DefaultPolicyTest.php | 16 ++++++++ .../update-prefer-lowest-stable.test | 40 +++++++++++++++++++ tests/Composer/Test/InstallerTest.php | 1 + 6 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 tests/Composer/Test/Fixtures/installer/update-prefer-lowest-stable.test diff --git a/src/Composer/Command/UpdateCommand.php b/src/Composer/Command/UpdateCommand.php index ebfd4cb2a..cf3cf8ca2 100644 --- a/src/Composer/Command/UpdateCommand.php +++ b/src/Composer/Command/UpdateCommand.php @@ -47,6 +47,7 @@ class UpdateCommand extends Command 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-reqs', null, InputOption::VALUE_NONE, 'Ignore platform requirements (php & ext- packages).'), + new InputOption('prefer-lowest-stable', null, InputOption::VALUE_NONE, 'Forces all packages to their lowest stable version.'), )) ->setHelp(<<update command reads the composer.json file from the @@ -121,6 +122,7 @@ EOT ->setUpdateWhitelist($input->getOption('lock') ? array('lock') : $input->getArgument('packages')) ->setWhitelistDependencies($input->getOption('with-dependencies')) ->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs')) + ->setPreferLowestStable($input->getOption('prefer-lowest-stable')) ; if ($input->getOption('no-plugins')) { diff --git a/src/Composer/DependencyResolver/DefaultPolicy.php b/src/Composer/DependencyResolver/DefaultPolicy.php index 10cbe101e..5ae6b2c31 100644 --- a/src/Composer/DependencyResolver/DefaultPolicy.php +++ b/src/Composer/DependencyResolver/DefaultPolicy.php @@ -24,10 +24,12 @@ use Composer\Package\LinkConstraint\VersionConstraint; class DefaultPolicy implements PolicyInterface { private $preferStable; + private $preferLowest; - public function __construct($preferStable = false) + public function __construct($preferStable = false, $preferLowest = false) { $this->preferStable = $preferStable; + $this->preferLowest = $preferLowest; } public function versionCompare(PackageInterface $a, PackageInterface $b, $operator) @@ -195,6 +197,7 @@ class DefaultPolicy implements PolicyInterface protected function pruneToBestVersion(Pool $pool, $literals) { + $operator = $this->preferLowest ? '<' : '>'; $bestLiterals = array($literals[0]); $bestPackage = $pool->literalToPackage($literals[0]); foreach ($literals as $i => $literal) { @@ -204,7 +207,7 @@ class DefaultPolicy implements PolicyInterface $package = $pool->literalToPackage($literal); - if ($this->versionCompare($package, $bestPackage, '>')) { + if ($this->versionCompare($package, $bestPackage, $operator)) { $bestPackage = $package; $bestLiterals = array($literal); } elseif ($this->versionCompare($package, $bestPackage, '==')) { diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index 9e2c07021..cfc995fe2 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -107,6 +107,7 @@ class Installer protected $update = false; protected $runScripts = true; protected $ignorePlatformReqs = false; + protected $preferLowestStable = false; /** * Array of package names/globs flagged for update * @@ -693,6 +694,7 @@ class Installer private function createPolicy() { + $preferLowest = false; $preferStable = null; if (!$this->update && $this->locker->isLocked()) { $preferStable = $this->locker->getPreferStable(); @@ -700,10 +702,14 @@ class Installer // old lock file without prefer stable will return null // so in this case we use the composer.json info if (null === $preferStable) { - $preferStable = $this->package->getPreferStable(); + if ($this->preferLowestStable) { + $preferStable = $preferLowest = true; + } else { + $preferStable = $this->package->getPreferStable(); + } } - return new DefaultPolicy($preferStable); + return new DefaultPolicy($preferStable, $preferLowest); } private function createRequest(Pool $pool, RootPackageInterface $rootPackage, PlatformRepository $platformRepo) @@ -1244,6 +1250,19 @@ class Installer return $this; } + /** + * Should packages be forced to their lowest stable version when updating? + * + * @param boolean $preferLowestStable + * @return Installer + */ + public function setPreferLowestStable($preferLowestStable = true) + { + $this->preferLowestStable = (boolean) $preferLowestStable; + + return $this; + } + /** * Disables plugins. * diff --git a/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php b/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php index 9e9952228..f06ba4437 100644 --- a/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php +++ b/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php @@ -247,4 +247,20 @@ class DefaultPolicyTest extends TestCase return $map; } + + public function testSelectLowest() + { + $policy = new DefaultPolicy(false, true); + + $this->repo->addPackage($packageA1 = $this->getPackage('A', '1.0')); + $this->repo->addPackage($packageA2 = $this->getPackage('A', '2.0')); + $this->pool->addRepository($this->repo); + + $literals = array($packageA1->getId(), $packageA2->getId()); + $expected = array($packageA1->getId()); + + $selected = $policy->selectPreferedPackages($this->pool, array(), $literals); + + $this->assertEquals($expected, $selected); + } } diff --git a/tests/Composer/Test/Fixtures/installer/update-prefer-lowest-stable.test b/tests/Composer/Test/Fixtures/installer/update-prefer-lowest-stable.test new file mode 100644 index 000000000..b511fdf72 --- /dev/null +++ b/tests/Composer/Test/Fixtures/installer/update-prefer-lowest-stable.test @@ -0,0 +1,40 @@ +--TEST-- +Updates packages to their lowest stable version +--COMPOSER-- +{ + "repositories": [ + { + "type": "package", + "package": [ + { "name": "a/a", "version": "1.0.0-rc1" }, + { "name": "a/a", "version": "1.0.1" }, + { "name": "a/a", "version": "1.1.0" }, + + { "name": "a/b", "version": "1.0.0" }, + { "name": "a/b", "version": "1.0.1" }, + { "name": "a/b", "version": "2.0.0" }, + + { "name": "a/c", "version": "1.0.0" }, + { "name": "a/c", "version": "2.0.0" } + ] + } + ], + "require": { + "a/a": "~1.0@dev", + "a/c": "2.*" + }, + "require-dev": { + "a/b": "*" + } +} +--INSTALLED-- +[ + { "name": "a/a", "version": "1.0.0-rc1" }, + { "name": "a/c", "version": "2.0.0" }, + { "name": "a/b", "version": "1.0.1" } +] +--RUN-- +update --prefer-lowest-stable +--EXPECT-- +Updating a/a (1.0.0-rc1) to a/a (1.0.1) +Updating a/b (1.0.1) to a/b (1.0.0) diff --git a/tests/Composer/Test/InstallerTest.php b/tests/Composer/Test/InstallerTest.php index 4dc0bf511..27e1d84b9 100644 --- a/tests/Composer/Test/InstallerTest.php +++ b/tests/Composer/Test/InstallerTest.php @@ -217,6 +217,7 @@ class InstallerTest extends TestCase ->setDryRun($input->getOption('dry-run')) ->setUpdateWhitelist($input->getArgument('packages')) ->setWhitelistDependencies($input->getOption('with-dependencies')) + ->setPreferLowestStable($input->getOption('prefer-lowest-stable')) ->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs')); return $installer->run();