diff --git a/src/Composer/DependencyResolver/LockTransaction.php b/src/Composer/DependencyResolver/LockTransaction.php index 3d5204067..a0aa4cd7e 100644 --- a/src/Composer/DependencyResolver/LockTransaction.php +++ b/src/Composer/DependencyResolver/LockTransaction.php @@ -137,6 +137,7 @@ class LockTransaction foreach ($packages as $package) { foreach ($this->resultPackages['dev'] as $i => $resultPackage) { + // TODO this comparison is probably insufficient, aliases, what about modified versions? I guess they aren't possible? if ($package->getName() == $resultPackage->getName()) { $this->resultPackages['non-dev'][] = $resultPackage; unset($this->resultPackages['dev'][$i]); diff --git a/src/Composer/DependencyResolver/Problem.php b/src/Composer/DependencyResolver/Problem.php index e07d4d0c1..2c1c7236a 100644 --- a/src/Composer/DependencyResolver/Problem.php +++ b/src/Composer/DependencyResolver/Problem.php @@ -90,7 +90,7 @@ class Problem $packages = array(); } - if ($job && $job['cmd'] === 'install' && empty($packages)) { + if ($job && ($job['cmd'] === 'install' || $job['cmd'] === 'fix') && empty($packages)) { // handle php/hhvm if ($packageName === 'php' || $packageName === 'php-64bit' || $packageName === 'hhvm') { @@ -208,6 +208,13 @@ class Problem $packageName = $job['packageName']; $constraint = $job['constraint']; switch ($job['cmd']) { + case 'fix': + $package = $job['package']; + if ($job['lockable']) { + return 'Package '.$package->getPrettyName().' is locked to version '.$package->getPrettyVersion(); + } else { + return 'Package '.$package->getPrettyName().' is present at version '.$package->getPrettyVersion() . ' and cannot be modified by Composer'; + } case 'install': $packages = $this->pool->whatProvides($packageName, $constraint); if (!$packages) { diff --git a/src/Composer/DependencyResolver/RuleSetGenerator.php b/src/Composer/DependencyResolver/RuleSetGenerator.php index 64cb27b11..0c7350cdd 100644 --- a/src/Composer/DependencyResolver/RuleSetGenerator.php +++ b/src/Composer/DependencyResolver/RuleSetGenerator.php @@ -12,9 +12,11 @@ namespace Composer\DependencyResolver; +use Composer\Package\LinkConstraint\VersionConstraint; use Composer\Package\PackageInterface; use Composer\Package\AliasPackage; use Composer\Repository\PlatformRepository; +use Composer\Semver\Constraint\Constraint; /** * @author Nils Adermann @@ -254,8 +256,10 @@ class RuleSetGenerator return $impossible; } - protected function addRulesForRequest($request, $ignorePlatformReqs) + protected function addRulesForRequest(Request $request, $ignorePlatformReqs) { + $unlockableMap = $request->getUnlockableMap(); + foreach ($request->getFixedPackages() as $package) { $this->addRulesForPackage($package, $ignorePlatformReqs); @@ -263,6 +267,8 @@ class RuleSetGenerator 'cmd' => 'fix', 'packageName' => $package->getName(), 'constraint' => null, + 'package' => $package, + 'lockable' => !isset($unlockableMap[$package->id]), 'fixed' => true )); $this->addRule(RuleSet::TYPE_JOB, $rule); diff --git a/tests/Composer/Test/Fixtures/installer/install-from-lock-removes-package.test b/tests/Composer/Test/Fixtures/installer/install-from-lock-removes-package.test index 6063abfee..83569bfe7 100644 --- a/tests/Composer/Test/Fixtures/installer/install-from-lock-removes-package.test +++ b/tests/Composer/Test/Fixtures/installer/install-from-lock-removes-package.test @@ -25,7 +25,7 @@ Install from a lock file that deleted a package { "name": "whitelisted", "version": "1.1.0" }, { "name": "fixed-dependency", "version": "1.0.0" } ], - "packages-dev": null, + "packages-dev": [], "aliases": [], "minimum-stability": "dev", "stability-flags": [], diff --git a/tests/Composer/Test/Fixtures/installer/partial-update-without-lock.test b/tests/Composer/Test/Fixtures/installer/partial-update-without-lock.test index e931a1f7d..845005649 100644 --- a/tests/Composer/Test/Fixtures/installer/partial-update-without-lock.test +++ b/tests/Composer/Test/Fixtures/installer/partial-update-without-lock.test @@ -28,6 +28,23 @@ Partial update without lock file should update everything whitelisted, remove ov { "name": "c/uptodate", "version": "1.0.0" }, { "name": "d/removed", "version": "1.0.0" } ] +--LOCK-- +{ + "packages": [ + { "name": "a/old", "version": "1.0.0" }, + { "name": "b/unstable", "version": "1.1.0-alpha" }, + { "name": "c/uptodate", "version": "1.0.0" }, + { "name": "d/removed", "version": "1.0.0" } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} --RUN-- update b/unstable --EXPECT-LOCK-- diff --git a/tests/Composer/Test/Fixtures/installer/solver-problems.test b/tests/Composer/Test/Fixtures/installer/solver-problems.test index 8b1336db2..b6d2180db 100644 --- a/tests/Composer/Test/Fixtures/installer/solver-problems.test +++ b/tests/Composer/Test/Fixtures/installer/solver-problems.test @@ -30,6 +30,21 @@ Test the error output of solver problems. { "name": "stable-requiree-excluded/pkg", "version": "1.0.0" } ] +--LOCK-- +{ + "packages": [ + { "name": "stable-requiree-excluded/pkg", "version": "1.0.0" } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} + --RUN-- update unstable/package requirer/pkg dependency/pkg @@ -38,7 +53,7 @@ update unstable/package requirer/pkg dependency/pkg --EXPECT-OUTPUT-- Loading composer repositories with package information -Updating dependencies (including require-dev) +Updating dependencies Your requirements could not be resolved to an installable set of packages. Problem 1 diff --git a/tests/Composer/Test/Fixtures/installer/update-with-all-dependencies.test b/tests/Composer/Test/Fixtures/installer/update-with-all-dependencies.test index c0019e6ca..14d8e13d8 100644 --- a/tests/Composer/Test/Fixtures/installer/update-with-all-dependencies.test +++ b/tests/Composer/Test/Fixtures/installer/update-with-all-dependencies.test @@ -28,15 +28,33 @@ When `--with-all-dependencies` is used, Composer\Installer::whitelistUpdateDepen { "name": "a/a", "version": "1.0.0" }, { "name": "b/b", "version": "1.0.0", "require": { "a/a": "~1.0" } } ] - +--LOCK-- +{ + "packages": [ + { "name": "a/a", "version": "1.0.0" }, + { "name": "b/b", "version": "1.0.0", "require": { "a/a": "~1.0" } } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} --RUN-- update b/b --with-all-dependencies --EXPECT-OUTPUT-- Loading composer repositories with package information -Updating dependencies (including require-dev) -Package operations: 0 installs, 2 updates, 0 removals +Updating dependencies +Lock file operations: 0 installs, 2 updates, 0 removals + - Updating b/b (1.0.0) to b/b (1.1.0) + - Updating a/a (1.0.0) to a/a (1.1.0) Writing lock file +Installing dependencies from lock file (including require-dev) +Package operations: 0 installs, 2 updates, 0 removals Generating autoload files --EXPECT--