From 443553423bbfa8e966df1c9299419885d4cc8a55 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Fri, 27 Mar 2020 22:59:00 +0100 Subject: [PATCH] Mark replaced packages for update when using --with-dependencies This is necessary to allow the requiring of new packages which replace packages currently locked without requiring explicitly listing them as an argument, so simplifies the composer require command --- .../DependencyResolver/PoolBuilder.php | 18 +++++++- ...with-dependencies-require-new-replace.test | 44 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 tests/Composer/Test/Fixtures/installer/update-allow-list-with-dependencies-require-new-replace.test diff --git a/src/Composer/DependencyResolver/PoolBuilder.php b/src/Composer/DependencyResolver/PoolBuilder.php index e458c6222..e715c26a5 100644 --- a/src/Composer/DependencyResolver/PoolBuilder.php +++ b/src/Composer/DependencyResolver/PoolBuilder.php @@ -215,7 +215,6 @@ class PoolBuilder // apply to if (isset($this->rootReferences[$name])) { // do not modify the references on already locked packages - // TODO what about unfix on allow update? if (!$request->isFixedPackage($package)) { $package->setSourceDistReferences($this->rootReferences[$name]); } @@ -266,6 +265,23 @@ class PoolBuilder } } + // if we're doing a partial update with deps and we're not loading an initial fixed package + // we also need to trigger an update for transitive deps which are being replaced + if ($propagateUpdate && $request->getUpdateAllowTransitiveDependencies()) { + foreach ($package->getReplaces() as $link) { + $replace = $link->getTarget(); + if (isset($this->loadedNames[$replace]) && isset($this->skippedLoad[$replace])) { + if ($request->getUpdateAllowTransitiveRootDependencies() || !$this->isRootRequire($request, $replace)) { + $this->unfixPackage($request, $replace); + $loadNames[$replace] = null; + } elseif (!$request->getUpdateAllowTransitiveRootDependencies() && $this->isRootRequire($request, $replace) && !isset($this->updateAllowWarned[$require]) && $this->io) { + $this->updateAllowWarned[$replace] = true; + $this->io->writeError('Dependency "'.$require.'" is also a root requirement. Package has not been listed as an update argument, so keeping locked at old version. Use --with-all-dependencies to include root dependencies.'); + } + } + } + } + return $loadNames; } diff --git a/tests/Composer/Test/Fixtures/installer/update-allow-list-with-dependencies-require-new-replace.test b/tests/Composer/Test/Fixtures/installer/update-allow-list-with-dependencies-require-new-replace.test new file mode 100644 index 000000000..8bb676e76 --- /dev/null +++ b/tests/Composer/Test/Fixtures/installer/update-allow-list-with-dependencies-require-new-replace.test @@ -0,0 +1,44 @@ +--TEST-- +Require a new package in the composer.json and updating with its name as an argument and with-dependencies should remove packages it replaces which are not root requirements +--COMPOSER-- +{ + "repositories": [ + { + "type": "package", + "package": [ + { "name": "current/pkg", "version": "1.0.0", "require": { "current/dep": "*" } }, + { "name": "current/dep", "version": "1.0.0" }, + { "name": "new/pkg", "version": "1.0.0", "replace": { "current/dep": "1.0.0" } } + ] + } + ], + "require": { + "current/pkg": "1.*", + "new/pkg": "1.*" + } +} +--INSTALLED-- +[ + { "name": "current/pkg", "version": "1.0.0", "require": { "current/dep": "*" } }, + { "name": "current/dep", "version": "1.0.0" } +] +--LOCK-- +{ + "packages": [ + { "name": "current/pkg", "version": "1.0.0", "require": { "current/dep": "*" } }, + { "name": "current/dep", "version": "1.0.0" } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} +--RUN-- +update new/pkg --with-dependencies +--EXPECT-- +Removing current/dep (1.0.0) +Installing new/pkg (1.0.0)