diff --git a/src/Composer/DependencyResolver/PoolBuilder.php b/src/Composer/DependencyResolver/PoolBuilder.php index bd06af28b..7840d13bf 100644 --- a/src/Composer/DependencyResolver/PoolBuilder.php +++ b/src/Composer/DependencyResolver/PoolBuilder.php @@ -535,7 +535,19 @@ class PoolBuilder // as long as it was not unfixed yet && isset($this->skippedLoad[$this->skippedLoad[$name]]) ) { - $this->unlockPackage($request, $this->skippedLoad[$name]); + $replacerName = $this->skippedLoad[$name]; + $this->unlockPackage($request, $replacerName); + + if ($this->isRootRequire($request, $replacerName)) { + $this->markPackageNameForLoading($request, $replacerName, new MatchAllConstraint); + } else { + foreach ($this->packages as $loadedPackage) { + $requires = $loadedPackage->getRequires(); + if (isset($requires[$replacerName])) { + $this->markPackageNameForLoading($request, $replacerName, $requires[$replacerName]->getConstraint()); + } + } + } } unset($this->skippedLoad[$name], $this->loadedPackages[$name], $this->maxExtendedReqs[$name]); @@ -551,11 +563,14 @@ class PoolBuilder // also loaded, as they were previously ignored because the locked (now unlocked) package already // satisfied their requirements foreach ($request->getFixedOrLockedPackages() as $fixedOrLockedPackage) { - if ($fixedOrLockedPackage !== $lockedPackage && isset($this->skippedLoad[$fixedOrLockedPackage->getName()])) { - foreach ($fixedOrLockedPackage->getRequires() as $requireLink) { - if ($requireLink->getTarget() === $lockedPackage->getName()) { - $this->markPackageNameForLoading($request, $lockedPackage->getName(), $requireLink->getConstraint()); - } + if ($fixedOrLockedPackage === $lockedPackage) { + continue; + } + + if (isset($this->skippedLoad[$fixedOrLockedPackage->getName()])) { + $requires = $fixedOrLockedPackage->getRequires(); + if (isset($requires[$lockedPackage->getName()])) { + $this->markPackageNameForLoading($request, $lockedPackage->getName(), $requires[$lockedPackage->getName()]->getConstraint()); } } } diff --git a/tests/Composer/Test/DependencyResolver/Fixtures/poolbuilder/partial-update-unfixing-replacers.test b/tests/Composer/Test/DependencyResolver/Fixtures/poolbuilder/partial-update-unfixing-replacers.test new file mode 100644 index 000000000..26176228e --- /dev/null +++ b/tests/Composer/Test/DependencyResolver/Fixtures/poolbuilder/partial-update-unfixing-replacers.test @@ -0,0 +1,102 @@ +--TEST-- +Partially updating with deps a root requirement which depends on packages should load all available versions for the path repo packages' dependencies. + +--REQUEST-- +{ + "require": { + "root/update": "*", + "root-required/replacer": "*", + "replacer/pkg": "*", + "root/noupdate": "*" + }, + "locked": [ + { + "name": "replacer/pkg", + "version": "1.0.0", + "require": { + "root-required/replacer-replaced": "1.*", + "transitive/dep-of-replacer": "1.*", + "transitive/replacer-replaced": "1.*" + }, + "replace": { + "replaced/pkg": "1.0.0" + } + }, + { + "name": "pkg/with-replaced-deps", + "version": "1.0.0", + "require": { + "transitive/dep": "1.*", + "root-required/replacer-replaced": "1.*", + "transitive/replacer-replaced": "1.*" + } + }, + {"name": "root/update", "version": "1.0.1", "require": {"pkg/with-replaced-deps": ">=1.0.1", "replaced/pkg": "*"}}, + {"name": "root/noupdate", "version": "1.0.1", "require": {"transitive/replacer": "^2"}}, + {"name": "transitive/dep", "version": "1.0.0"}, + {"name": "root-required/replacer", "version": "1.0.0", "replace": {"root-required/replacer-replaced": "1.0.0"}}, + {"name": "transitive/dep-of-replacer", "version": "1.0.0"}, + {"name": "transitive/replacer", "version": "1.0.0", "replace": {"transitive/replacer-replaced": "1.0.0"}} + ], + "allowList": [ + "root/update" + ], + "allowTransitiveDeps": true +} + +--FIXED-- +[ +] + +--PACKAGE-REPOS-- +[ + [ + { + "name": "replacer/pkg", + "version": "2.0.0", + "require": { + "root-required/replacer-replaced": ">=1.0.3", + "transitive/dep-of-replacer": "2.*", + "transitive/replacer-replaced": "2.*" + }, + "replace": { + "replaced/pkg": "2.0.0" + } + }, + { + "name": "pkg/with-replaced-deps", + "version": "2.0.0", + "require": { + "transitive/dep": "2.*", + "root-required/replacer-replaced": "2.*", + "transitive/replacer-replaced": ">=1.0.3" + } + }, + {"name": "root/update", "version": "1.0.4", "require": {"pkg/with-replaced-deps": ">=1.0.1", "replaced/pkg": "*"}}, + {"name": "root/noupdate", "version": "1.0.1", "require": {"transitive/replacer": "^2"}}, + {"name": "transitive/dep", "version": "1.0.0"}, + {"name": "transitive/dep", "version": "2.0.2"}, + {"name": "root-required/replacer", "version": "1.0.0", "replace": {"root-required/replacer-replaced": "1.0.0"}}, + {"name": "root-required/replacer", "version": "1.0.3", "replace": {"root-required/replacer-replaced": "1.0.3"}}, + {"name": "root-required/replacer", "version": "2.0.4", "replace": {"root-required/replacer-replaced": "2.0.4"}}, + {"name": "transitive/dep-of-replacer", "version": "1.0.0"}, + {"name": "transitive/dep-of-replacer", "version": "2.0.2"}, + {"name": "transitive/replacer", "version": "1.0.0", "replace": {"transitive/replacer-replaced": "1.0.0"}}, + {"name": "transitive/replacer", "version": "1.0.3", "replace": {"transitive/replacer-replaced": "1.0.3"}}, + {"name": "transitive/replacer", "version": "2.0.4", "replace": {"transitive/replacer-replaced": "2.0.4"}} + ] +] + +--EXPECT-- +[ + "root/noupdate-1.0.1.0 (locked)", + "root/update-1.0.4.0", + "replacer/pkg-2.0.0.0", + "pkg/with-replaced-deps-2.0.0.0", + "transitive/dep-2.0.2.0", + "root-required/replacer-1.0.0.0", + "root-required/replacer-1.0.3.0", + "root-required/replacer-2.0.4.0", + "transitive/dep-of-replacer-2.0.2.0", + "transitive/replacer-2.0.4.0" +]