Преглед изворни кода

PoolBuilder: On partial update of a new dep with mutual replace, unfix replacer

Test also verifies provider does not get uninstalled in partial update
for another package name
Nils Adermann пре 5 година
родитељ
комит
5ad93959cf

+ 10 - 4
src/Composer/DependencyResolver/PoolBuilder.php

@@ -67,10 +67,11 @@ class PoolBuilder
             foreach ($request->getLockedRepository()->getPackages() as $lockedPackage) {
                 if (!$this->isUpdateAllowed($lockedPackage)) {
                     $request->fixPackage($lockedPackage);
+                    $lockedName = $lockedPackage->getName();
                     // remember which packages we skipped loading remote content for in this partial update
-                    $this->skippedLoad[$lockedPackage->getName()] = true;
+                    $this->skippedLoad[$lockedPackage->getName()] = $lockedName;
                     foreach ($lockedPackage->getReplaces() as $link) {
-                        $this->skippedLoad[$link->getTarget()] = true;
+                        $this->skippedLoad[$link->getTarget()] = $lockedName;
                     }
                 }
             }
@@ -244,7 +245,7 @@ class PoolBuilder
             // if this is a partial update with transitive dependencies we need to unfix the package we now know is a
             // dependency of another package which we are trying to update, and then attempt to load it again
             } elseif ($propagateUpdate && $request->getUpdateAllowTransitiveDependencies() && isset($this->skippedLoad[$require])) {
-                if ($request->getUpdateAllowTransitiveRootDependencies() || !$this->isRootRequire($request, $require)) {
+                if ($request->getUpdateAllowTransitiveRootDependencies() || !$this->isRootRequire($request, $this->skippedLoad[$require])) {
                     $this->unfixPackage($request, $require);
                     $loadNames[$require] = null;
                 } elseif (!$request->getUpdateAllowTransitiveRootDependencies() && $this->isRootRequire($request, $require) && !isset($this->updateAllowWarned[$require])) {
@@ -273,7 +274,7 @@ class PoolBuilder
             foreach ($package->getReplaces() as $link) {
                 $replace = $link->getTarget();
                 if (isset($this->loadedNames[$replace]) && isset($this->skippedLoad[$replace])) {
-                    if ($request->getUpdateAllowTransitiveRootDependencies() || !$this->isRootRequire($request, $replace)) {
+                    if ($request->getUpdateAllowTransitiveRootDependencies() || !$this->isRootRequire($request, $this->skippedLoad[$replace])) {
                         $this->unfixPackage($request, $replace);
                         $loadNames[$replace] = null;
                         // TODO should we try to merge constraints here?
@@ -363,6 +364,11 @@ class PoolBuilder
             }
         }
 
+        // if we unfixed a replaced package name, we also need to unfix the replacer itself
+        if ($this->skippedLoad[$name] !== $name) {
+            $this->unfixPackage($request, $this->skippedLoad[$name]);
+        }
+
         unset($this->skippedLoad[$name]);
         unset($this->loadedNames[$name]);
     }

+ 50 - 0
tests/Composer/Test/Fixtures/installer/update-allow-list-with-dependencies-require-new-replace-mutual.test

@@ -0,0 +1,50 @@
+--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": { "mutual/target": "*", "mutual/target-provide": "*" } },
+                { "name": "current/dep", "version": "1.0.0", "replace": { "mutual/target": "1.0.0" } },
+                { "name": "new/pkg", "version": "1.0.0", "replace": { "mutual/target": "1.0.0" } },
+                { "name": "current/dep-provide", "version": "1.0.0", "provide": { "mutual/target-provide": "1.0.0" } },
+                { "name": "new/pkg-provide", "version": "1.0.0", "provide": { "mutual/target-provide": "1.0.0" } }
+            ]
+        }
+    ],
+    "require": {
+        "current/pkg": "1.*",
+        "new/pkg": "1.*",
+        "new/pkg-provide": "1.*"
+    }
+}
+--INSTALLED--
+[
+    { "name": "current/pkg", "version": "1.0.0", "require": { "mutual/target": "*" } },
+    { "name": "current/dep", "version": "1.0.0", "replace": { "mutual/target": "1.0.0" } },
+    { "name": "current/dep-provide", "version": "1.0.0", "provide": { "mutual/target-provide": "1.0.0" } }
+]
+--LOCK--
+{
+    "packages": [
+        { "name": "current/pkg", "version": "1.0.0", "require": { "mutual/target": "*" } },
+        { "name": "current/dep", "version": "1.0.0", "replace": { "mutual/target": "1.0.0" } },
+        { "name": "current/dep-provide", "version": "1.0.0", "provide": { "mutual/target-provide": "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)
+Installing new/pkg-provide (1.0.0)