Browse Source

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
Nils Adermann 5 years ago
parent
commit
443553423b

+ 17 - 1
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('<warning>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.</warning>');
+                    }
+                }
+            }
+        }
+
         return $loadNames;
     }
 

+ 44 - 0
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)