Implement update mirrors/nothing/lock as its own installer mode

These special commands no longer (ab)use the partial update mechanism
but rather create a special install request for all current lock file
contents and later override any modified code references to the
originals. This leads to up to date remote metadata but no other
changes.
main
Nils Adermann 5 years ago
parent eaae360ce6
commit 6925005ac9

@ -121,6 +121,19 @@ EOT
}
}
// the arguments lock/nothing/mirrors are not package names but trigger a mirror update instead
// they are further mutually exclusive with listing actual package names
$filteredPackages = array_filter($packages, function ($package) {
return !in_array($package, array('lock', 'nothing', 'mirrors'), true);
});
$updateMirrors = $input->getOption('lock') || count($filteredPackages) != count($packages);
$packages = $filteredPackages;
if ($updateMirrors && !empty($packages)) {
$io->writeError('<error>You cannot simultaneously update only a selection of packages and regenerate the lock file metadata.</error>');
return -1;
}
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'update', $input, $output);
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
@ -146,7 +159,8 @@ EOT
->setClassMapAuthoritative($authoritative)
->setApcuAutoloader($apcu)
->setUpdate(true)
->setUpdateWhitelist($input->getOption('lock') ? array('lock') : $packages)
->setUpdateMirrors($updateMirrors)
->setUpdateWhitelist($packages)
->setWhitelistTransitiveDependencies($input->getOption('with-dependencies'))
->setWhitelistAllDependencies($input->getOption('with-all-dependencies'))
->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs'))

@ -152,11 +152,19 @@ class LockTransaction
}
// TODO additionalFixedRepository needs to be looked at here as well?
public function getNewLockPackages($devMode)
public function getNewLockPackages($devMode, $updateMirrors = false)
{
$packages = array();
foreach ($this->resultPackages[$devMode ? 'dev' : 'non-dev'] as $package) {
if (!($package instanceof AliasPackage) && !($package instanceof RootAliasPackage)) {
// 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
if ($updateMirrors && !isset($this->presentMap[spl_object_hash($package)])) {
foreach ($this->presentMap as $presentPackage) {
if ($package->getName() == $presentPackage->getName() && $package->getVersion() == $presentPackage->getVersion() && $presentPackage->getSourceReference()) {
$package->setSourceDistReferences($presentPackage->getSourceReference());
}
}
}
$packages[] = $package;
}
}

@ -184,7 +184,7 @@ class PoolBuilder
if (isset($this->rootReferences[$name])) {
// do not modify the references on already locked packages
if (!$request->isFixedPackage($package)) {
$this->setReferences($package, $this->rootReferences[$name]);
$package->setSourceDistReferences($this->rootReferences[$name]);
}
}
@ -225,19 +225,5 @@ class PoolBuilder
return $loadNames;
}
private function setReferences(Package $package, $reference)
{
$package->setSourceReference($reference);
// only bitbucket, github and gitlab have auto generated dist URLs that easily allow replacing the reference in the dist URL
// TODO generalize this a bit for self-managed/on-prem versions? Some kind of replace token in dist urls which allow this?
if (preg_match('{^https?://(?:(?:www\.)?bitbucket\.org|(api\.)?github\.com|(?:www\.)?gitlab\.com)/}i', $package->getDistUrl())) {
$package->setDistReference($reference);
$package->setDistUrl(preg_replace('{(?<=/|sha=)[a-f0-9]{40}(?=/|$)}i', $reference, $package->getDistUrl()));
} elseif ($package->getDistReference()) { // update the dist reference if there was one, but if none was provided ignore it
$package->setDistReference($reference);
}
}
}

@ -38,6 +38,7 @@ use Composer\Package\AliasPackage;
use Composer\Package\BasePackage;
use Composer\Package\CompletePackage;
use Composer\Package\Link;
use Composer\Package\LinkConstraint\VersionConstraint;
use Composer\Package\Loader\ArrayLoader;
use Composer\Package\Dumper\ArrayDumper;
use Composer\Package\Package;
@ -137,6 +138,7 @@ class Installer
*
* @var array|null
*/
protected $updateMirrors = false;
protected $updateWhitelist = null;
protected $whitelistTransitiveDependencies = false;
protected $whitelistAllDependencies = false;
@ -192,6 +194,10 @@ class Installer
gc_collect_cycles();
gc_disable();
if ($this->updateWhitelist && $this->updateMirrors) {
throw new \RuntimeException("The installer options updateMirrors and updateWhitelist are mutually exclusive.");
}
// Force update if there is no lock file present
if (!$this->update && !$this->locker->isLocked()) {
// TODO throw an error instead?
@ -370,8 +376,15 @@ class Installer
$links = array_merge($this->package->getRequires(), $this->package->getDevRequires());
foreach ($links as $link) {
$request->install($link->getTarget(), $link->getConstraint());
// if we're updating mirrors we want to keep exactly the same versions installed which are in the lock file, but we want current remote metadata
if ($this->updateMirrors) {
foreach ($lockedRepository->getPackages() as $lockedPackage) {
$request->install($lockedPackage->getName(), new Constraint('==', $lockedPackage->getVersion()));
}
} else {
foreach ($links as $link) {
$request->install($link->getTarget(), $link->getConstraint());
}
}
// if the updateWhitelist is enabled, packages not in it are also fixed
@ -489,8 +502,8 @@ class Installer
}
$updatedLock = $this->locker->setLockData(
$lockTransaction->getNewLockPackages(false),
$lockTransaction->getNewLockPackages(true),
$lockTransaction->getNewLockPackages(false, $this->updateMirrors),
$lockTransaction->getNewLockPackages(true, $this->updateMirrors),
$platformReqs,
$platformDevReqs,
$aliases,
@ -912,23 +925,6 @@ class Installer
return $normalizedAliases;
}
// TODO do we still need this function?
private function updateInstallReferences(PackageInterface $package, $reference)
{
if (!$reference) {
return;
}
$package->setSourceReference($reference);
if (preg_match('{^https?://(?:(?:www\.)?bitbucket\.org|(api\.)?github\.com|(?:www\.)?gitlab\.com)/}i', $package->getDistUrl())) {
$package->setDistReference($reference);
$package->setDistUrl(preg_replace('{(?<=/|sha=)[a-f0-9]{40}(?=/|$)}i', $reference, $package->getDistUrl()));
} elseif ($package->getDistReference()) { // update the dist reference if there was one, but if none was provided ignore it
$package->setDistReference($reference);
}
}
/**
* @param PlatformRepository $platformRepo
* @param array $aliases
@ -1044,7 +1040,7 @@ class Installer
$depPackages = array_merge($depPackages, call_user_func_array('array_merge', $matchesByPattern));
}
if (count($depPackages) == 0 && !$nameMatchesRequiredPackage && !in_array($packageName, array('nothing', 'lock', 'mirrors'))) {
if (count($depPackages) == 0 && !$nameMatchesRequiredPackage) {
$this->io->writeError('<warning>Package "' . $packageName . '" listed for update is not installed. Ignoring.</warning>');
}
@ -1347,6 +1343,19 @@ class Installer
return $this;
}
/**
* Update the lock file to the exact same versions and references but use current remote metadata like URLs and mirror info
*
* @param bool $updateMirrors
* @return Installer
*/
public function setUpdateMirrors($updateMirrors)
{
$this->updateMirrors = $updateMirrors;
return $this;
}
/**
* restrict the update operation to a few packages, all other packages
* that are already installed will be kept at their current version

@ -411,4 +411,9 @@ class AliasPackage extends BasePackage implements CompletePackageInterface
{
return $this->aliasOf->setDistType($type);
}
public function setSourceDistReferences($reference)
{
return $this->aliasOf->setSourceDistReferences($reference);
}
}

@ -569,6 +569,23 @@ class Package extends BasePackage
return $this->archiveExcludes;
}
/**
* {@inheritDoc}
*/
public function setSourceDistReferences($reference)
{
$this->setSourceReference($reference);
// only bitbucket, github and gitlab have auto generated dist URLs that easily allow replacing the reference in the dist URL
// TODO generalize this a bit for self-managed/on-prem versions? Some kind of replace token in dist urls which allow this?
if (preg_match('{^https?://(?:(?:www\.)?bitbucket\.org|(api\.)?github\.com|(?:www\.)?gitlab\.com)/}i', $this->getDistUrl())) {
$this->setDistReference($reference);
$this->setDistUrl(preg_replace('{(?<=/|sha=)[a-f0-9]{40}(?=/|$)}i', $reference, $this->getDistUrl()));
} elseif ($this->getDistReference()) { // update the dist reference if there was one, but if none was provided ignore it
$this->setDistReference($reference);
}
}
/**
* Replaces current version and pretty version with passed values.
* It also sets stability.

@ -386,4 +386,13 @@ interface PackageInterface
* @return void
*/
public function setDistReference($reference);
/**
* Set dist and source references and update dist URL for ones that contain a reference
*
* @param string $reference
*
* @return void
*/
public function setSourceDistReferences($reference);
}

@ -149,14 +149,14 @@ 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": "2222222222222222222222222222222222222222", "url": "https://github.com/a/newa", "type": "git" },
"dist": { "reference": "2222222222222222222222222222222222222222", "url": "https://api.github.com/repos/a/newa/zipball/2222222222222222222222222222222222222222", "type": "zip" },
"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" },
"type": "library"
},
{
"name": "b/b", "version": "2.0.3",
"source": { "reference": "2222222222222222222222222222222222222222", "url": "https://github.com/b/newb", "type": "git" },
"dist": { "reference": "2222222222222222222222222222222222222222", "url": "https://api.github.com/repos/b/newb/zipball/2222222222222222222222222222222222222222", "type": "zip" },
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/b/newb", "type": "git" },
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/b/newb/zipball/1111111111111111111111111111111111111111", "type": "zip" },
"type": "library"
},
{
@ -171,12 +171,6 @@ g/g is dev and installed in a different ref than the #ref, so it gets updated an
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/d/newd/zipball/1111111111111111111111111111111111111111", "type": "zip" },
"type": "library"
},
{
"name": "e/e", "version": "dev-master",
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/e/newe", "type": "git" },
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/e/newe/zipball/1111111111111111111111111111111111111111", "type": "zip" },
"type": "library"
},
{
"name": "f/f", "version": "dev-master",
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/f/newf", "type": "git" },
@ -185,8 +179,8 @@ g/g is dev and installed in a different ref than the #ref, so it gets updated an
},
{
"name": "g/g", "version": "dev-master",
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/g/newg", "type": "git" },
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/g/newg/zipball/1111111111111111111111111111111111111111", "type": "zip" },
"source": { "reference": "0000000000000000000000000000000000000000", "url": "https://github.com/g/newg", "type": "git" },
"dist": { "reference": "0000000000000000000000000000000000000000", "url": "https://api.github.com/repos/g/newg/zipball/0000000000000000000000000000000000000000", "type": "zip" },
"type": "library"
}
],
@ -206,8 +200,5 @@ g/g is dev and installed in a different ref than the #ref, so it gets updated an
"platform-dev": []
}
--RUN--
update a/a b/b d/d g/g
update mirrors
--EXPECT--
Installing e/e (dev-master 1111111)
Updating a/a (dev-master 1111111) to a/a (dev-master 2222222)
Updating g/g (dev-master 0000000) to g/g (dev-master 1111111)

@ -42,7 +42,7 @@ Converting from one VCS type to another (including an URL change) should update
"platform-dev": []
}
--RUN--
update
update mirrors
--EXPECT-LOCK--
{
"packages": [

@ -269,11 +269,19 @@ class InstallerTest extends TestCase
});
$application->get('update')->setCode(function ($input, $output) use ($installer) {
$packages = $input->getArgument('packages');
$filteredPackages = array_filter($packages, function ($package) {
return !in_array($package, array('lock', 'nothing', 'mirrors'), true);
});
$updateMirrors = $input->getOption('lock') || count($filteredPackages) != count($packages);
$packages = $filteredPackages;
$installer
->setDevMode(!$input->getOption('no-dev'))
->setUpdate(true)
->setDryRun($input->getOption('dry-run'))
->setUpdateWhitelist($input->getArgument('packages'))
->setUpdateMirrors($updateMirrors)
->setUpdateWhitelist($packages)
->setWhitelistTransitiveDependencies($input->getOption('with-dependencies'))
->setWhitelistAllDependencies($input->getOption('with-all-dependencies'))
->setPreferStable($input->getOption('prefer-stable'))

Loading…
Cancel
Save