diff --git a/src/Composer/DependencyResolver/LockTransaction.php b/src/Composer/DependencyResolver/LockTransaction.php index fbe543522..3b0255304 100644 --- a/src/Composer/DependencyResolver/LockTransaction.php +++ b/src/Composer/DependencyResolver/LockTransaction.php @@ -62,6 +62,7 @@ class LockTransaction extends Transaction if ($literal > 0) { $package = $pool->literalToPackage($literal); + $this->resultPackages['all'][] = $package; if (!isset($this->unlockableMap[$package->id])) { $this->resultPackages['non-dev'][] = $package; diff --git a/src/Composer/DependencyResolver/PoolBuilder.php b/src/Composer/DependencyResolver/PoolBuilder.php index 15995a9cd..a245a50c3 100644 --- a/src/Composer/DependencyResolver/PoolBuilder.php +++ b/src/Composer/DependencyResolver/PoolBuilder.php @@ -123,13 +123,16 @@ class PoolBuilder public function buildPool(array $repositories, Request $request) { + $singleVersionPackages = $request->getFixedPackages(); + if ($request->getUpdateAllowList()) { $this->updateAllowList = $request->getUpdateAllowList(); $this->warnAboutNonMatchingUpdateAllowList($request); foreach ($request->getLockedRepository()->getPackages() as $lockedPackage) { if (!$this->isUpdateAllowed($lockedPackage)) { - $request->fixPackage($lockedPackage); + //$request->fixPackage($lockedPackage); + $singleVersionPackages[] = $lockedPackage; $lockedName = $lockedPackage->getName(); // remember which packages we skipped loading remote content for in this partial update $this->skippedLoad[$lockedName] = $lockedName; @@ -140,7 +143,7 @@ class PoolBuilder } } - foreach ($request->getFixedPackages() as $package) { + foreach ($singleVersionPackages as $package) { // using MatchAllConstraint here because fixed packages do not need to retrigger // loading any packages $this->loadedPackages[$package->getName()] = new MatchAllConstraint(); @@ -345,7 +348,7 @@ class PoolBuilder // apply to if (isset($this->rootReferences[$name])) { // do not modify the references on already locked packages - if (!$request->isFixedPackage($package)) { + if ($request->getLockedRepository() !== $package->getRepository() && !$request->isFixedPackage($package)) { $package->setSourceDistReferences($this->rootReferences[$name]); } } @@ -473,7 +476,7 @@ class PoolBuilder foreach ($request->getLockedRepository()->getPackages() as $lockedPackage) { if (!($lockedPackage instanceof AliasPackage) && $lockedPackage->getName() === $name) { if (false !== $index = array_search($lockedPackage, $this->packages, true)) { - $request->unfixPackage($lockedPackage); + //$request->unfixPackage($lockedPackage); $this->removeLoadedPackage($request, $lockedPackage, $index); } } @@ -496,7 +499,7 @@ class PoolBuilder unset($this->packages[$index]); if (isset($this->aliasMap[spl_object_hash($package)])) { foreach ($this->aliasMap[spl_object_hash($package)] as $aliasIndex => $aliasPackage) { - $request->unfixPackage($aliasPackage); + //$request->unfixPackage($aliasPackage); unset($this->packages[$aliasIndex]); } unset($this->aliasMap[spl_object_hash($package)]); diff --git a/tests/Composer/Test/Fixtures/installer/remove-deletes-unused-deps.test b/tests/Composer/Test/Fixtures/installer/remove-deletes-unused-deps.test new file mode 100644 index 000000000..8a81d02e9 --- /dev/null +++ b/tests/Composer/Test/Fixtures/installer/remove-deletes-unused-deps.test @@ -0,0 +1,46 @@ +--TEST-- +Removing a package deletes unused dependencies and does not update other dependencies +--COMPOSER-- +{ + "repositories": [ + { + "type": "package", + "package": [ + { "name": "root/a", "version": "1.0.0", "require": { "dep/c": "*", "dep/d": "*"} }, + { "name": "remove/b", "version": "1.0.0", "require": { "dep/c": "*", "dep/e": "*"} }, + { "name": "dep/c", "version": "1.0.0" }, + { "name": "dep/c", "version": "1.2.0" }, + { "name": "dep/d", "version": "1.0.0" }, + { "name": "dep/d", "version": "1.2.0" }, + { "name": "dep/e", "version": "1.0.0" }, + { "name": "unrelated/f", "version": "1.0.0" } + ] + } + ], + "require": { + "root/a": "*" + } +} +--LOCK-- +{ + "packages": [ + { "name": "root/a", "version": "1.0.0", "require": { "dep/c": "*", "dep/d": "*"} }, + { "name": "remove/b", "version": "1.0.0", "require": { "dep/c": "*", "dep/e": "*"} }, + { "name": "dep/c", "version": "1.0.0" }, + { "name": "dep/d", "version": "1.0.0" }, + { "name": "dep/e", "version": "1.0.0" }, + { "name": "unrelated/f", "version": "1.0.0" } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false +} +--RUN-- +update remove/b +--EXPECT-- +Installing dep/d (1.0.0) +Installing dep/c (1.0.0) +Installing root/a (1.0.0) diff --git a/tests/Composer/Test/Fixtures/installer/remove-does-nothing-if-removal-requires-update-of-dep.test b/tests/Composer/Test/Fixtures/installer/remove-does-nothing-if-removal-requires-update-of-dep.test new file mode 100644 index 000000000..5df46f118 --- /dev/null +++ b/tests/Composer/Test/Fixtures/installer/remove-does-nothing-if-removal-requires-update-of-dep.test @@ -0,0 +1,39 @@ +--TEST-- +Removing a package has no effect if another package would require an update in order to find a correct set of dependencies without the removed package +--COMPOSER-- +{ + "repositories": [ + { + "type": "package", + "package": [ + { "name": "root/a", "version": "1.0.0", "require": { "remove/b": "*", "dep/c": "*"} }, + { "name": "remove/b", "version": "1.0.0", "require": { "dep/c": "*"} }, + { "name": "dep/c", "version": "1.0.0" }, + { "name": "dep/c", "version": "1.2.0", "replace": { "remove/b": "1.0.0"} } + ] + } + ], + "require": { + "root/a": "*" + } +} +--LOCK-- +{ + "packages": [ + { "name": "root/a", "version": "1.0.0", "require": { "remove/b": "*", "dep/c": "*"} }, + { "name": "remove/b", "version": "1.0.0", "require": { "dep/c": "*"} }, + { "name": "dep/c", "version": "1.0.0" } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false +} +--RUN-- +update remove/b +--EXPECT-- +Installing dep/c (1.0.0) +Installing remove/b (1.0.0) +Installing root/a (1.0.0)