From bbc442b0ade931cc1fcf4f7ee99a8368932f18af Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 23 Nov 2021 16:02:34 +0100 Subject: [PATCH] Undo changes to providers, only unlock replacers when unlocking a given name --- .../DependencyResolver/PoolBuilder.php | 56 ++++++++----------- ...tial-update-with-dependencies-provide.test | 14 ++--- .../partial-update-with-deps-warns-root.test | 2 - 3 files changed, 31 insertions(+), 41 deletions(-) diff --git a/src/Composer/DependencyResolver/PoolBuilder.php b/src/Composer/DependencyResolver/PoolBuilder.php index cc211b9e7..f05a62fc4 100644 --- a/src/Composer/DependencyResolver/PoolBuilder.php +++ b/src/Composer/DependencyResolver/PoolBuilder.php @@ -156,10 +156,10 @@ class PoolBuilder foreach ($request->getLockedRepository()->getPackages() as $lockedPackage) { if (!$this->isUpdateAllowed($lockedPackage)) { $request->lockPackage($lockedPackage); - $lockedName = $lockedPackage->getName(); + $this->skippedLoad[$lockedPackage->getName()][] = $lockedPackage; // remember which packages we skipped loading remote content for in this partial update - foreach ($lockedPackage->getNames() as $name) { - $this->skippedLoad[$name][] = $lockedPackage; + foreach ($lockedPackage->getReplaces() as $link) { + $this->skippedLoad[$link->getTarget()][] = $lockedPackage; } } } @@ -493,33 +493,25 @@ class PoolBuilder if (isset($rootRequires[$name])) { return array_map(function (PackageInterface $package) use ($name) { if ($name !== $package->getName()) { - foreach ($package->getReplaces() as $link) { - if ($link->getTarget() === $name) { - return $package->getName() .' (via replace of '.$name.')'; - } - } - return $package->getName() .' (via provide of '.$name.')'; + return $package->getName() .' (via replace of '.$name.')'; } return $package->getName(); }, $this->skippedLoad[$name]); } - foreach ($this->skippedLoad[$name] as $providedBy) { - foreach ($providedBy->getNames() as $providedName) { - if (isset($rootRequires[$providedName])) { - if ($name !== $providedBy->getName()) { - foreach ($providedBy->getReplaces() as $link) { - if ($link->getTarget() === $name) { - $matches[] = $providedBy->getName() .' (via replace of '.$name.')'; - continue 2; - } - } - $matches[] = $providedBy->getName() .' (via provide of '.$name.')'; - continue; + foreach ($this->skippedLoad[$name] as $packageOrReplacer) { + if (isset($rootRequires[$packageOrReplacer->getName()])) { + $matches[] = $packageOrReplacer->getName(); + } + foreach ($packageOrReplacer->getReplaces() as $link) { + if (isset($rootRequires[$link->getTarget()])) { + if ($name !== $packageOrReplacer->getName()) { + $matches[] = $packageOrReplacer->getName() .' (via replace of '.$name.')'; + } else { + $matches[] = $packageOrReplacer->getName(); } - - $matches[] = $providedBy->getName(); + break; } } } @@ -590,21 +582,21 @@ class PoolBuilder */ private function unlockPackage(Request $request, $name) { - foreach ($this->skippedLoad[$name] as $providedBy) { - $providedBy = $providedBy->getName(); + foreach ($this->skippedLoad[$name] as $packageOrReplacer) { // if we unfixed a replaced package name, we also need to unfix the replacer itself // as long as it was not unfixed yet - if ($providedBy !== $name && isset($this->skippedLoad[$providedBy])) { - if ($request->getUpdateAllowTransitiveRootDependencies() || (!$this->isRootRequire($request, $name) && !$this->isRootRequire($request, $providedBy))) { - $this->unlockPackage($request, $providedBy); + if ($packageOrReplacer->getName() !== $name && isset($this->skippedLoad[$packageOrReplacer->getName()])) { + $replacerName = $packageOrReplacer->getName(); + if ($request->getUpdateAllowTransitiveRootDependencies() || (!$this->isRootRequire($request, $name) && !$this->isRootRequire($request, $replacerName))) { + $this->unlockPackage($request, $replacerName); - if ($this->isRootRequire($request, $providedBy)) { - $this->markPackageNameForLoading($request, $providedBy, new MatchAllConstraint); + if ($this->isRootRequire($request, $replacerName)) { + $this->markPackageNameForLoading($request, $replacerName, new MatchAllConstraint); } else { foreach ($this->packages as $loadedPackage) { $requires = $loadedPackage->getRequires(); - if (isset($requires[$providedBy])) { - $this->markPackageNameForLoading($request, $providedBy, $requires[$providedBy]->getConstraint()); + if (isset($requires[$replacerName])) { + $this->markPackageNameForLoading($request, $replacerName, $requires[$replacerName]->getConstraint()); } } } diff --git a/tests/Composer/Test/Fixtures/installer/partial-update-with-dependencies-provide.test b/tests/Composer/Test/Fixtures/installer/partial-update-with-dependencies-provide.test index 8d45e9cd9..c332ca045 100644 --- a/tests/Composer/Test/Fixtures/installer/partial-update-with-dependencies-provide.test +++ b/tests/Composer/Test/Fixtures/installer/partial-update-with-dependencies-provide.test @@ -1,5 +1,5 @@ --TEST-- -Ensure a partial update of a dependency updates dependencies which provide its requirements. +Ensure a partial update of a dependency does NOT update dependencies which provide its requirements. --COMPOSER-- { @@ -44,9 +44,9 @@ update root/req1 --with-dependencies --EXPECT-LOCK-- { "packages": [ - {"name": "dep/pkg1", "version": "1.2.0", "type": "library", "provide": {"virtual/pkg1": "2.0.0"}}, - {"name": "dep/pkg2", "version": "1.2.0", "type": "library", "provide": {"virtual/pkg1": "2.0.0"}}, - {"name": "root/req1", "version": "2.0.0", "type": "library", "require": {"virtual/pkg1": "2.*"}}, + {"name": "dep/pkg1", "version": "1.0.0", "type": "library", "provide": {"virtual/pkg1": "1.0.0"}}, + {"name": "dep/pkg2", "version": "1.0.0", "type": "library", "provide": {"virtual/pkg1": "1.0.0"}}, + {"name": "root/req1", "version": "1.0.0", "type": "library", "require": {"virtual/pkg1": "1.*"}}, {"name": "root/req2", "version": "1.0.0", "type": "library", "require": {"dep/pkg1": "1.*", "dep/pkg2": "1.*"}} ], "packages-dev": [], @@ -59,7 +59,7 @@ update root/req1 --with-dependencies "platform-dev": [] } --EXPECT-- -Installing dep/pkg1 (1.2.0) -Installing dep/pkg2 (1.2.0) -Installing root/req1 (2.0.0) +Installing dep/pkg1 (1.0.0) +Installing dep/pkg2 (1.0.0) +Installing root/req1 (1.0.0) Installing root/req2 (1.0.0) diff --git a/tests/Composer/Test/Fixtures/installer/partial-update-with-deps-warns-root.test b/tests/Composer/Test/Fixtures/installer/partial-update-with-deps-warns-root.test index b1aa96b84..d8d49a246 100644 --- a/tests/Composer/Test/Fixtures/installer/partial-update-with-deps-warns-root.test +++ b/tests/Composer/Test/Fixtures/installer/partial-update-with-deps-warns-root.test @@ -110,8 +110,6 @@ update update/pkg1 --with-dependencies --EXPECT-OUTPUT-- Loading composer repositories with package information Dependency root/pkg3 is also a root requirement. Package has not been listed as an update argument, so keeping locked at old version. Use --with-all-dependencies (-W) to include root dependencies. -Dependency dep/pkg5 (via provide of root/provided-pkg4) is also a root requirement. Package has not been listed as an update argument, so keeping locked at old version. Use --with-all-dependencies (-W) to include root dependencies. -Dependency dep/pkg6 (via provide of root/provided-pkg4) is also a root requirement. Package has not been listed as an update argument, so keeping locked at old version. Use --with-all-dependencies (-W) to include root dependencies. Dependency dep/pkg9 (via replace of root/replaced-pkg8) is also a root requirement. Package has not been listed as an update argument, so keeping locked at old version. Use --with-all-dependencies (-W) to include root dependencies. Updating dependencies Lock file operations: 0 installs, 2 updates, 0 removals