From 66acb84c12d1d2b3cce7b2967f8e25522f502e60 Mon Sep 17 00:00:00 2001 From: Pol Dellaiera Date: Tue, 5 Mar 2024 11:32:40 +0100 Subject: [PATCH] Fix update --lock to avoid updating all metadata except dist/source urls and mirrors (#11850) We now update the existing package instead of reverting changes in the updated package to ensure we keep all metadata intact, fixes #11787 Co-authored-by: Jordi Boggiano --- .../DependencyResolver/LockTransaction.php | 83 +++++++++++++------ .../installer/update-mirrors-changes-url.test | 12 ++- 2 files changed, 67 insertions(+), 28 deletions(-) diff --git a/src/Composer/DependencyResolver/LockTransaction.php b/src/Composer/DependencyResolver/LockTransaction.php index 70603b867..d77a21139 100644 --- a/src/Composer/DependencyResolver/LockTransaction.php +++ b/src/Composer/DependencyResolver/LockTransaction.php @@ -104,36 +104,71 @@ class LockTransaction extends Transaction { $packages = []; foreach ($this->resultPackages[$devMode ? 'dev' : 'non-dev'] as $package) { - if (!$package instanceof AliasPackage) { - // if we're just updating mirrors we need to reset references to the same as currently "present" packages' references to keep the lock file as-is - // we do not reset references if the currently present package didn't have any, or if the type of VCS has changed - if ($updateMirrors && !isset($this->presentMap[spl_object_hash($package)])) { - foreach ($this->presentMap as $presentPackage) { - if ($package->getName() === $presentPackage->getName() && $package->getVersion() === $presentPackage->getVersion()) { - if ($presentPackage->getSourceReference() && $presentPackage->getSourceType() === $package->getSourceType()) { - $package->setSourceDistReferences($presentPackage->getSourceReference()); - // if the dist url is not one of those handled gracefully by setSourceDistReferences then we should overwrite it with the old one - if ($package->getDistUrl() !== null && !Preg::isMatch('{^https?://(?:(?:www\.)?bitbucket\.org|(api\.)?github\.com|(?:www\.)?gitlab\.com)/}i', $package->getDistUrl())) { - $package->setDistUrl($presentPackage->getDistUrl()); - } - $package->setDistType($presentPackage->getDistType()); - if ($package instanceof Package) { - $package->setDistSha1Checksum($presentPackage->getDistSha1Checksum()); - } - } - if ($presentPackage->getReleaseDate() !== null && $package instanceof Package) { - $package->setReleaseDate($presentPackage->getReleaseDate()); - } - } - } - } - $packages[] = $package; + if ($package instanceof AliasPackage) { + continue; } + + // if we're just updating mirrors we need to reset everything to the same as currently "present" packages' references to keep the lock file as-is + if ($updateMirrors === true && !array_key_exists(spl_object_hash($package), $this->presentMap)) { + $package = $this->updateMirrorAndUrls($package); + } + + $packages[] = $package; } return $packages; } + /** + * Try to return the original package from presentMap with updated URLs/mirrors + * + * If the type of source/dist changed, then we do not update those and keep them as they were + */ + private function updateMirrorAndUrls(BasePackage $package): BasePackage + { + foreach ($this->presentMap as $presentPackage) { + if ($package->getName() !== $presentPackage->getName()) { + continue; + } + + if ($package->getVersion() !== $presentPackage->getVersion()) { + continue; + } + + if ($presentPackage->getSourceReference() === null) { + continue; + } + + if ($presentPackage->getSourceType() !== $package->getSourceType()) { + continue; + } + + if ($presentPackage instanceof Package) { + $presentPackage->setSourceUrl($package->getSourceUrl()); + $presentPackage->setSourceMirrors($package->getSourceMirrors()); + } + + // if the dist type changed, we only update the source url/mirrors + if ($presentPackage->getDistType() !== $package->getDistType()) { + return $presentPackage; + } + + // update dist url if it is in a known format + if ( + $package->getDistUrl() !== null + && $presentPackage->getDistReference() !== null + && Preg::isMatch('{^https?://(?:(?:www\.)?bitbucket\.org|(api\.)?github\.com|(?:www\.)?gitlab\.com)/}i', $package->getDistUrl()) + ) { + $presentPackage->setDistUrl(Preg::replace('{(?<=/|sha=)[a-f0-9]{40}(?=/|$)}i', $presentPackage->getDistReference(), $package->getDistUrl())); + } + $presentPackage->setDistMirrors($package->getDistMirrors()); + + return $presentPackage; + } + + return $package; + } + /** * Checks which of the given aliases from composer.json are actually in use for the lock file * @param list $aliases diff --git a/tests/Composer/Test/Fixtures/installer/update-mirrors-changes-url.test b/tests/Composer/Test/Fixtures/installer/update-mirrors-changes-url.test index edb821f8c..d002d2c94 100644 --- a/tests/Composer/Test/Fixtures/installer/update-mirrors-changes-url.test +++ b/tests/Composer/Test/Fixtures/installer/update-mirrors-changes-url.test @@ -16,8 +16,9 @@ g/g is dev and installed in a different ref than the #ref, so it gets updated an "package": [ { "name": "a/a", "version": "dev-master", - "source": { "reference": "2222222222222222222222222222222222222222", "url": "https://github.com/a/newa", "type": "git" }, - "dist": { "reference": "2222222222222222222222222222222222222222", "url": "https://api.github.com/repos/a/newa/zipball/2222222222222222222222222222222222222222", "type": "zip" }, + "require": { "b/b": "^2.0.1" }, + "source": { "reference": "2222222222222222222222222222222222222222", "url": "https://github.com/a/newa", "type": "git", "mirrors": [{"url": "https://example.org/src/%package%/%version%/r%reference%.%type%", "preferred": true}] }, + "dist": { "reference": "2222222222222222222222222222222222222222", "url": "https://api.github.com/repos/a/newa/zipball/2222222222222222222222222222222222222222", "type": "zip", "mirrors": [{"url": "https://example.org/dists/%package%/%version%/r%reference%.%type%", "preferred": true}] }, "time": "2021-03-27T14:32:16+00:00" }, { @@ -67,6 +68,7 @@ g/g is dev and installed in a different ref than the #ref, so it gets updated an [ { "name": "a/a", "version": "dev-master", + "require": { "b/b": "^2" }, "source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/a/a", "type": "git" }, "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/a/a/zipball/1111111111111111111111111111111111111111", "type": "zip" }, "time": "2021-03-14T16:24:37+00:00" @@ -102,6 +104,7 @@ g/g is dev and installed in a different ref than the #ref, so it gets updated an "packages": [ { "name": "a/a", "version": "dev-master", + "require": { "b/b": "^2" }, "source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/a/a", "type": "git" }, "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/a/a/zipball/1111111111111111111111111111111111111111", "type": "zip" }, "time": "2021-03-14T16:24:37+00:00", @@ -152,8 +155,9 @@ g/g is dev and installed in a different ref than the #ref, so it gets updated an "packages": [ { "name": "a/a", "version": "dev-master", - "source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/a/newa", "type": "git" }, - "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/a/newa/zipball/1111111111111111111111111111111111111111", "type": "zip" }, + "require": { "b/b": "^2" }, + "source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/a/newa", "type": "git", "mirrors": [{"url": "https://example.org/src/%package%/%version%/r%reference%.%type%", "preferred": true}] }, + "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/a/newa/zipball/1111111111111111111111111111111111111111", "type": "zip", "mirrors": [{"url": "https://example.org/dists/%package%/%version%/r%reference%.%type%", "preferred": true}] }, "time": "2021-03-14T16:24:37+00:00", "type": "library" },