diff --git a/src/Composer/DependencyResolver/LocalRepoTransaction.php b/src/Composer/DependencyResolver/LocalRepoTransaction.php index 98c0b05d7..4ac747243 100644 --- a/src/Composer/DependencyResolver/LocalRepoTransaction.php +++ b/src/Composer/DependencyResolver/LocalRepoTransaction.php @@ -62,9 +62,10 @@ class LocalRepoTransaction // do we need to update? if ($package->getVersion() != $localPackageMap[$package->getName()]->getVersion()) { $operations[] = new Operation\UpdateOperation($source, $package); - } else { - // TODO do we need to update metadata? force update based on reference? + } elseif ($package->isDev() && $package->getSourceReference() !== $localPackageMap[$package->getName()]->getSourceReference()) { + $operations[] = new Operation\UpdateOperation($source, $package); } + unset($removeMap[$package->getName()]); } else { $operations[] = new Operation\InstallOperation($package); unset($removeMap[$package->getName()]); diff --git a/src/Composer/DependencyResolver/LockTransaction.php b/src/Composer/DependencyResolver/LockTransaction.php index ad25f8fc1..e113988bd 100644 --- a/src/Composer/DependencyResolver/LockTransaction.php +++ b/src/Composer/DependencyResolver/LockTransaction.php @@ -108,7 +108,7 @@ class LockTransaction } // TODO additionalFixedRepository needs to be looked at here as well? - public function getNewLockNonDevPackages(array $rootForceReferences) + public function getNewLockNonDevPackages() { $packages = array(); foreach ($this->decisions as $i => $decision) { @@ -117,14 +117,6 @@ class LockTransaction if ($literal > 0) { $package = $this->pool->literalToPackage($literal); if (!isset($this->unlockableMap[$package->id]) && !($package instanceof AliasPackage) && !($package instanceof RootAliasPackage)) { - - echo "rootRef? ".$package->getName()."\n"; - // TODO can we really just do this for all of them here? What if we're doing a partial update, should this change anyway? - if (isset($rootForceReferences[$package->getName()])) { - echo "rootRef! ".$package->getName()."\n"; - $package->setSourceReference($rootForceReferences[$package->getName()]); - } - $packages[] = $package; } } @@ -135,6 +127,7 @@ class LockTransaction public function getNewLockDevPackages() { + // TODO this is empty? $packages = array(); return $packages; } diff --git a/src/Composer/DependencyResolver/PoolBuilder.php b/src/Composer/DependencyResolver/PoolBuilder.php index 8f164df71..f9a7541c3 100644 --- a/src/Composer/DependencyResolver/PoolBuilder.php +++ b/src/Composer/DependencyResolver/PoolBuilder.php @@ -14,11 +14,11 @@ namespace Composer\DependencyResolver; use Composer\Package\AliasPackage; use Composer\Package\BasePackage; +use Composer\Package\Package; use Composer\Package\PackageInterface; use Composer\Repository\AsyncRepositoryInterface; use Composer\Repository\ComposerRepository; use Composer\Repository\InstalledRepositoryInterface; -use Composer\Repository\LockArrayRepository; use Composer\Repository\PlatformRepository; use Composer\Semver\Constraint\Constraint; use Composer\Semver\Constraint\MultiConstraint; @@ -31,6 +31,7 @@ class PoolBuilder private $isPackageAcceptableCallable; private $filterRequires; private $rootAliases; + private $rootReferences; private $aliasMap = array(); private $nameConstraints = array(); @@ -46,16 +47,17 @@ class PoolBuilder $this->filterRequires = $filterRequires; } - public function buildPool(array $repositories, array $rootAliases, Request $request) + public function buildPool(array $repositories, array $rootAliases, array $rootReferences, Request $request) { $pool = new Pool($this->filterRequires); $this->rootAliases = $rootAliases; + $this->rootReferences = $rootReferences; // TODO do we really want the request here? kind of want a root requirements thingy instead $loadNames = array(); foreach ($request->getFixedPackages() as $package) { // TODO can actually use very specific constraint - $loadNames[$package->getname()] = null; + $loadNames[$package->getName()] = null; } foreach ($request->getJobs() as $job) { switch ($job['cmd']) { @@ -94,7 +96,7 @@ class PoolBuilder foreach ($packages as $package) { if (call_user_func($this->isPackageAcceptableCallable, $package->getNames(), $package->getStability())) { - $newLoadNames += $this->loadPackage($package, $key); + $newLoadNames += $this->loadPackage($request, $package, $key); } } } @@ -132,7 +134,7 @@ class PoolBuilder if ($repository instanceof PlatformRepository || $repository instanceof InstalledRepositoryInterface) { foreach ($repository->getPackages() as $package) { - $this->loadPackage($package, $key); + $this->loadPackage($request, $package, $key); } } } @@ -146,7 +148,7 @@ class PoolBuilder return $pool; } - private function loadPackage(PackageInterface $package, $repoIndex) + private function loadPackage(Request $request, PackageInterface $package, $repoIndex) { $index = count($this->packages); $this->packages[] = $package; @@ -156,8 +158,18 @@ class PoolBuilder $this->aliasMap[spl_object_hash($package->getAliasOf())][$index] = $package; } - // handle root package aliases $name = $package->getName(); + + // we're simply setting the root references on all versions for a name here and rely on the solver to pick the + // right version. It'd be more work to figure out which versions and which aliases of those versions this may + // apply to + if (isset($this->rootReferences[$name])) { + // do not modify the references on already locked packages + if (!$request->isFixedPackage($package)) { + $this->setReferences($package, $this->rootReferences[$name]); + } + } + if (isset($this->rootAliases[$name][$package->getVersion()])) { $alias = $this->rootAliases[$name][$package->getVersion()]; if ($package instanceof AliasPackage) { @@ -194,5 +206,19 @@ 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); + } + } } diff --git a/src/Composer/DependencyResolver/Request.php b/src/Composer/DependencyResolver/Request.php index a225e33b6..166ebbe07 100644 --- a/src/Composer/DependencyResolver/Request.php +++ b/src/Composer/DependencyResolver/Request.php @@ -52,7 +52,7 @@ class Request $package = $package->getAliasOf(); } - $this->fixedPackages[] = $package; + $this->fixedPackages[spl_object_hash($package)] = $package; if (!$lockable) { $this->unlockables[] = $package; @@ -80,6 +80,11 @@ class Request return $this->fixedPackages; } + public function isFixedPackage(PackageInterface $package) + { + return isset($this->fixedPackages[spl_object_hash($package)]); + } + public function getPresentMap() { $presentMap = array(); diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index c07fc44c9..a59a4dc4c 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -39,6 +39,7 @@ use Composer\Package\CompletePackage; use Composer\Package\Link; use Composer\Package\Loader\ArrayLoader; use Composer\Package\Dumper\ArrayDumper; +use Composer\Package\Package; use Composer\Repository\RepositorySet; use Composer\Semver\Constraint\Constraint; use Composer\Package\Locker; @@ -375,25 +376,21 @@ class Installer // to the version specified in the lock if ($this->updateWhitelist) { foreach ($lockedRepository->getPackages() as $lockedPackage) { + // TODO should this really be checking acceptability here? if (!$this->isUpdateable($lockedPackage) && $repositorySet->isPackageAcceptable($lockedPackage->getNames(), $lockedPackage->getStability())) { - // need to actually allow for metadata updates at all times, so we want to fix the most recent prefered package in the repo set instead - $packages = $repositorySet->findPackages($lockedPackage->getName(), new Constraint('=', $lockedPackage->getVersion())); - $lockedPackage = isset($packages[0]) ? $packages[0] : $lockedPackage; - - // in how far do we need to reset requirements here, theoretically it's the same version so nothing should have changed, but for a dev version it could have? - - // TODO add reason for fix? $request->fixPackage($lockedPackage); } } } + // TODO reenable events //$this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, $this->devMode, $policy, $repositorySet, $installedRepo, $request); $pool = $repositorySet->createPool($request); // TODO ensure that the solver always picks most recent reference for dev packages, so they get updated even when just a new commit is pushed but version is unchanged + // should already be solved by using the remote package in all cases in the pool // solve dependencies $solver = new Solver($policy, $pool, $this->io); @@ -426,7 +423,7 @@ class Installer $platformDevReqs = $this->extractPlatformRequirements($this->package->getDevRequires()); $updatedLock = $this->locker->setLockData( - $lockTransaction->getNewLockNonDevPackages($this->package->getReferences()), + $lockTransaction->getNewLockNonDevPackages(), $lockTransaction->getNewLockDevPackages(), $platformReqs, $platformDevReqs, @@ -504,6 +501,8 @@ class Installer } } + $this->io->write('foo'); + if ($doInstall) { // TODO ensure lock is used from locker as-is, since it may not have been written to disk in case of executeOperations == false return $this->doInstall($localRepo, true); @@ -703,7 +702,7 @@ class Installer $this->fixedRootPackage->setRequires(array()); $this->fixedRootPackage->setDevRequires(array()); - $repositorySet = new RepositorySet($rootAliases, $minimumStability, $stabilityFlags, $rootConstraints); + $repositorySet = new RepositorySet($rootAliases, $this->package->getReferences(), $minimumStability, $stabilityFlags, $rootConstraints); $repositorySet->addRepository(new InstalledArrayRepository(array($this->fixedRootPackage))); $repositorySet->addRepository($platformRepo); if ($this->additionalFixedRepository) { @@ -793,28 +792,7 @@ class Installer return $normalizedAliases; } - private function updatePackageUrl(PackageInterface $package, $sourceUrl, $sourceType, $sourceReference, $distUrl) - { - $oldSourceRef = $package->getSourceReference(); - - if ($package->getSourceUrl() !== $sourceUrl) { - $package->setSourceType($sourceType); - $package->setSourceUrl($sourceUrl); - $package->setSourceReference($sourceReference); - } - - // only update dist url for github/bitbucket/gitlab dists as they use a combination of dist url + dist reference to install - // but for other urls this is ambiguous and could result in bad outcomes - if (preg_match('{^https?://(?:(?:www\.)?bitbucket\.org|(api\.)?github\.com|(?:www\.)?gitlab\.com)/}i', $distUrl)) { - $package->setDistUrl($distUrl); - $this->updateInstallReferences($package, $sourceReference); - } - - if ($this->updateWhitelist && !$this->isUpdateable($package)) { - $this->updateInstallReferences($package, $oldSourceRef); - } - } - + // TODO do we still need this function? private function updateInstallReferences(PackageInterface $package, $reference) { if (!$reference) { @@ -910,7 +888,7 @@ class Installer } } - $repositorySet = new RepositorySet(array(), 'dev'); + $repositorySet = new RepositorySet(array(), array(), 'dev'); $repositorySet->addRepository($lockRepo); $seen = array(); diff --git a/src/Composer/Repository/RepositorySet.php b/src/Composer/Repository/RepositorySet.php index 6a232630d..f7f8a57f8 100644 --- a/src/Composer/Repository/RepositorySet.php +++ b/src/Composer/Repository/RepositorySet.php @@ -29,6 +29,8 @@ class RepositorySet { /** @var array */ private $rootAliases; + /** @var array */ + private $rootReferences; /** @var RepositoryInterface[] */ private $repositories = array(); @@ -40,9 +42,10 @@ class RepositorySet /** @var Pool */ private $pool; - public function __construct(array $rootAliases = array(), $minimumStability = 'stable', array $stabilityFlags = array(), array $filterRequires = array()) + public function __construct(array $rootAliases = array(), array $rootReferences = array(), $minimumStability = 'stable', array $stabilityFlags = array(), array $filterRequires = array()) { $this->rootAliases = $rootAliases; + $this->rootReferences = $rootReferences; $this->acceptableStabilities = array(); foreach (BasePackage::$stabilities as $stability => $value) { @@ -151,7 +154,7 @@ class RepositorySet { $poolBuilder = new PoolBuilder(array($this, 'isPackageAcceptable'), $this->filterRequires); - return $this->pool = $poolBuilder->buildPool($this->repositories, $this->rootAliases, $request); + return $this->pool = $poolBuilder->buildPool($this->repositories, $this->rootAliases, $this->rootReferences, $request); } // TODO unify this with above in some simpler version without "request"? diff --git a/tests/Composer/Test/DependencyResolver/SolverTest.php b/tests/Composer/Test/DependencyResolver/SolverTest.php index 76abd958a..3491f9c05 100644 --- a/tests/Composer/Test/DependencyResolver/SolverTest.php +++ b/tests/Composer/Test/DependencyResolver/SolverTest.php @@ -930,7 +930,7 @@ class SolverTest extends TestCase protected function createSolver() { - $this->solver = new Solver($this->policy, $this->repoSet->createPool($this->request), $this->repoInstalled, new NullIO()); + $this->solver = new Solver($this->policy, $this->repoSet->createPool($this->request), new NullIO()); } protected function checkSolverResult(array $expected) diff --git a/tests/Composer/Test/Fixtures/installer/update-changes-url.test b/tests/Composer/Test/Fixtures/installer/update-changes-url.test index ec108c7b9..c9df288f6 100644 --- a/tests/Composer/Test/Fixtures/installer/update-changes-url.test +++ b/tests/Composer/Test/Fixtures/installer/update-changes-url.test @@ -3,10 +3,10 @@ Update updates URLs for updated packages if they have changed a/a is dev and gets everything updated as it updates to a new ref b/b is a tag and gets everything updated by updating the package URL directly -c/c is a tag and not whitelisted and gets the new URL but keeps its old ref +c/c is a tag and not whitelisted and remains unchanged d/d is dev but with a #ref so it should get URL updated but not the reference e/e is dev and newly installed with a #ref so it should get the correct URL but with the #111 ref -e/e is dev but not whitelisted and gets the new URL but keeps its old ref +f/f is dev but not whitelisted and remains unchanged g/g is dev and installed in a different ref than the #ref, so it gets updated and gets the new URL but not the new ref --COMPOSER-- { @@ -161,8 +161,8 @@ g/g is dev and installed in a different ref than the #ref, so it gets updated an }, { "name": "c/c", "version": "1.0.0", - "source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/c/newc", "type": "git" }, - "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/c/newc/zipball/1111111111111111111111111111111111111111", "type": "zip" }, + "source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/c/c", "type": "git" }, + "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/c/c/zipball/1111111111111111111111111111111111111111", "type": "zip" }, "type": "library" }, { @@ -179,8 +179,8 @@ g/g is dev and installed in a different ref than the #ref, so it gets updated an }, { "name": "f/f", "version": "dev-master", - "source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/f/newf", "type": "git" }, - "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/f/newf/zipball/1111111111111111111111111111111111111111", "type": "zip" }, + "source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/f/f", "type": "git" }, + "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/f/f/zipball/1111111111111111111111111111111111111111", "type": "zip" }, "type": "library" }, { @@ -208,6 +208,6 @@ g/g is dev and installed in a different ref than the #ref, so it gets updated an --RUN-- update a/a b/b d/d g/g --EXPECT-- -Installing e/e (dev-master 1111111) Updating a/a (dev-master 1111111) to a/a (dev-master 2222222) +Installing e/e (dev-master 1111111) Updating g/g (dev-master 0000000) to g/g (dev-master 1111111) diff --git a/tests/Composer/Test/Fixtures/installer/update-mirrors-changes-url.test b/tests/Composer/Test/Fixtures/installer/update-mirrors-changes-url.test new file mode 100644 index 000000000..9d88870b0 --- /dev/null +++ b/tests/Composer/Test/Fixtures/installer/update-mirrors-changes-url.test @@ -0,0 +1,213 @@ +--TEST-- +Update mirrors updates URLs for all packages if they have changed without updating versions + +a/a is dev and gets everything updated as it updates to a new ref +b/b is a tag and gets everything updated by updating the package URL directly +c/c is a tag and not whitelisted and gets the new URL but keeps its old ref +d/d is dev but with a #ref so it should get URL updated but not the reference +e/e is dev and newly installed with a #ref so it should get the correct URL but with the #111 ref +e/e is dev but not whitelisted and gets the new URL but keeps its old ref +g/g is dev and installed in a different ref than the #ref, so it gets updated and gets the new URL but not the new ref +--COMPOSER-- +{ + "repositories": [ + { + "type": "package", + "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" } + }, + { + "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" } + }, + { + "name": "c/c", "version": "1.0.0", + "source": { "reference": "2222222222222222222222222222222222222222", "url": "https://github.com/c/newc", "type": "git" }, + "dist": { "reference": "2222222222222222222222222222222222222222", "url": "https://api.github.com/repos/c/newc/zipball/2222222222222222222222222222222222222222", "type": "zip" } + }, + { + "name": "d/d", "version": "dev-master", + "source": { "reference": "2222222222222222222222222222222222222222", "url": "https://github.com/d/newd", "type": "git" }, + "dist": { "reference": "2222222222222222222222222222222222222222", "url": "https://api.github.com/repos/d/newd/zipball/2222222222222222222222222222222222222222", "type": "zip" } + }, + { + "name": "e/e", "version": "dev-master", + "source": { "reference": "2222222222222222222222222222222222222222", "url": "https://github.com/e/newe", "type": "git" }, + "dist": { "reference": "2222222222222222222222222222222222222222", "url": "https://api.github.com/repos/e/newe/zipball/2222222222222222222222222222222222222222", "type": "zip" } + }, + { + "name": "f/f", "version": "dev-master", + "source": { "reference": "2222222222222222222222222222222222222222", "url": "https://github.com/f/newf", "type": "git" }, + "dist": { "reference": "2222222222222222222222222222222222222222", "url": "https://api.github.com/repos/f/newf/zipball/2222222222222222222222222222222222222222", "type": "zip" } + }, + { + "name": "g/g", "version": "dev-master", + "source": { "reference": "2222222222222222222222222222222222222222", "url": "https://github.com/g/newg", "type": "git" }, + "dist": { "reference": "2222222222222222222222222222222222222222", "url": "https://api.github.com/repos/g/newg/zipball/2222222222222222222222222222222222222222", "type": "zip" } + } + ] + } + ], + "require": { + "a/a": "dev-master", + "b/b": "2.0.3", + "c/c": "1.0.0", + "d/d": "dev-master#1111111111111111111111111111111111111111", + "e/e": "dev-master#1111111111111111111111111111111111111111", + "f/f": "dev-master", + "g/g": "dev-master#1111111111111111111111111111111111111111" + } +} +--INSTALLED-- +[ + { + "name": "a/a", "version": "dev-master", + "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" } + }, + { + "name": "b/b", "version": "2.0.3", + "source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/b/b", "type": "git" }, + "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/b/b/zipball/1111111111111111111111111111111111111111", "type": "zip" } + }, + { + "name": "c/c", "version": "1.0.0", + "source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/c/c", "type": "git" }, + "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/c/c/zipball/1111111111111111111111111111111111111111", "type": "zip" } + }, + { + "name": "d/d", "version": "dev-master", + "source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/d/d", "type": "git" }, + "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/d/d/zipball/1111111111111111111111111111111111111111", "type": "zip" } + }, + { + "name": "f/f", "version": "dev-master", + "source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/f/f", "type": "git" }, + "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/f/f/zipball/1111111111111111111111111111111111111111", "type": "zip" } + }, + { + "name": "g/g", "version": "dev-master", + "source": { "reference": "0000000000000000000000000000000000000000", "url": "https://github.com/g/g", "type": "git" }, + "dist": { "reference": "0000000000000000000000000000000000000000", "url": "https://api.github.com/repos/g/g/zipball/0000000000000000000000000000000000000000", "type": "zip" } + } +] +--LOCK-- +{ + "packages": [ + { + "name": "a/a", "version": "dev-master", + "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" }, + "type": "library" + }, + { + "name": "b/b", "version": "2.0.3", + "source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/b/b", "type": "git" }, + "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/b/b/zipball/1111111111111111111111111111111111111111", "type": "zip" }, + "type": "library" + }, + { + "name": "c/c", "version": "1.0.0", + "source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/c/c", "type": "git" }, + "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/c/c/zipball/1111111111111111111111111111111111111111", "type": "zip" }, + "type": "library" + }, + { + "name": "d/d", "version": "dev-master", + "source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/d/d", "type": "git" }, + "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/d/d/zipball/1111111111111111111111111111111111111111", "type": "zip" }, + "type": "library" + }, + { + "name": "f/f", "version": "dev-master", + "source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/f/f", "type": "git" }, + "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/f/f/zipball/1111111111111111111111111111111111111111", "type": "zip" }, + "type": "library" + }, + { + "name": "g/g", "version": "dev-master", + "source": { "reference": "0000000000000000000000000000000000000000", "url": "https://github.com/g/g", "type": "git" }, + "dist": { "reference": "0000000000000000000000000000000000000000", "url": "https://api.github.com/repos/g/g/zipball/0000000000000000000000000000000000000000", "type": "zip" }, + "type": "library" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} +--EXPECT-LOCK-- +{ + "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" }, + "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" }, + "type": "library" + }, + { + "name": "c/c", "version": "1.0.0", + "source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/c/newc", "type": "git" }, + "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/c/newc/zipball/1111111111111111111111111111111111111111", "type": "zip" }, + "type": "library" + }, + { + "name": "d/d", "version": "dev-master", + "source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/d/newd", "type": "git" }, + "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" }, + "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/f/newf/zipball/1111111111111111111111111111111111111111", "type": "zip" }, + "type": "library" + }, + { + "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" }, + "type": "library" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": { + "a/a": 20, + "d/d": 20, + "e/e": 20, + "f/f": 20, + "g/g": 20 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} +--RUN-- +update a/a b/b d/d g/g +--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)