From 83239aa338d79479a6a92dbff6c5dce8ba506133 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 14 Sep 2012 16:43:56 +0200 Subject: [PATCH] Update lock file to contain the complete package info, fixes #890 --- composer.lock | 196 +++++++++++++++++- src/Composer/Installer.php | 58 ++---- src/Composer/Package/Locker.php | 55 +++-- .../Fixtures/installer/update-alias-lock.test | 8 +- tests/Composer/Test/Package/LockerTest.php | 26 ++- 5 files changed, 262 insertions(+), 81 deletions(-) diff --git a/composer.lock b/composer.lock index 776fd92af..83aa81a1b 100644 --- a/composer.lock +++ b/composer.lock @@ -2,24 +2,200 @@ "hash": "1023850095295cc1307c2219a0382930", "packages": [ { - "package": "justinrainbow/json-schema", - "version": "1.1.0" + "name": "justinrainbow/json-schema", + "version": "1.1.0", + "source": { + "type": "git", + "url": "git://github.com/justinrainbow/json-schema.git", + "reference": "v1.1.0" + }, + "dist": { + "type": "zip", + "url": "https://github.com/justinrainbow/json-schema/zipball/v1.1.0", + "reference": "v1.1.0", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2012-01-02 22:33:17", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "JsonSchema": "src/" + } + } }, { - "package": "seld/jsonlint", - "version": "1.0.0" + "name": "seld/jsonlint", + "version": "1.0.0", + "source": { + "type": "git", + "url": "http://github.com/Seldaek/jsonlint", + "reference": "1.0.0" + }, + "dist": { + "type": "zip", + "url": "https://github.com/Seldaek/jsonlint/zipball/1.0.0", + "reference": "1.0.0", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2012-03-12 05:52:32", + "bin": [ + "bin/jsonlint" + ], + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "Seld\\JsonLint": "src/" + } + } }, { - "package": "symfony/console", - "version": "v2.1.0" + "name": "symfony/console", + "version": "v2.1.1", + "target-dir": "Symfony/Component/Console", + "source": { + "type": "git", + "url": "https://github.com/symfony/Console", + "reference": "v2.1.1" + }, + "dist": { + "type": "zip", + "url": "https://github.com/symfony/Console/zipball/v2.1.1", + "reference": "v2.1.1", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "time": "2012-08-22 11:48:41", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Symfony\\Component\\Console": "" + } + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "http://symfony.com" }, { - "package": "symfony/finder", - "version": "v2.1.0" + "name": "symfony/finder", + "version": "v2.1.1", + "target-dir": "Symfony/Component/Finder", + "source": { + "type": "git", + "url": "https://github.com/symfony/Finder", + "reference": "v2.1.0-RC2" + }, + "dist": { + "type": "zip", + "url": "https://github.com/symfony/Finder/zipball/v2.1.0-RC2", + "reference": "v2.1.0-RC2", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "time": "2012-08-22 11:48:41", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Symfony\\Component\\Finder": "" + } + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony Finder Component", + "homepage": "http://symfony.com" }, { - "package": "symfony/process", - "version": "v2.1.0" + "name": "symfony/process", + "version": "v2.1.1", + "target-dir": "Symfony/Component/Process", + "source": { + "type": "git", + "url": "https://github.com/symfony/Process", + "reference": "v2.1.1" + }, + "dist": { + "type": "zip", + "url": "https://github.com/symfony/Process/zipball/v2.1.1", + "reference": "v2.1.1", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "time": "2012-08-30 10:49:05", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Symfony\\Component\\Process": "" + } + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony Process Component", + "homepage": "http://symfony.com" } ], "packages-dev": null, diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index db26fdfed..373787cd9 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -234,8 +234,10 @@ class Installer $stabilityFlags = $this->package->getStabilityFlags(); // initialize locker to create aliased packages + $installFromLock = false; if (!$this->update && $this->locker->isLocked($devMode)) { - $lockedPackages = $this->locker->getLockedPackages($devMode); + $installFromLock = true; + $lockedRepository = $this->locker->getLockedRepository($devMode); $minimumStability = $this->locker->getMinimumStability(); $stabilityFlags = $this->locker->getStabilityFlags(); } @@ -252,13 +254,15 @@ class Installer // creating repository pool $pool = new Pool($minimumStability, $stabilityFlags); $pool->addRepository($installedRepo, $aliases); + if ($installFromLock) { + $pool->addRepository($lockedRepository); + } $repositories = $this->repositoryManager->getRepositories(); foreach ($repositories as $repository) { $pool->addRepository($repository, $aliases); } // creating requirements request - $installFromLock = false; $request = new Request($pool); $constraint = new VersionConstraint('=', $this->package->getVersion()); @@ -274,15 +278,14 @@ class Installer foreach ($links as $link) { $request->install($link->getTarget(), $link->getConstraint()); } - } elseif ($this->locker->isLocked($devMode)) { - $installFromLock = true; + } elseif ($installFromLock) { $this->io->write('Installing '.($devMode ? 'dev ': '').'dependencies from lock file'); if (!$this->locker->isFresh() && !$devMode) { $this->io->write('Your lock file is out of sync with your composer.json, run "composer.phar update" to update dependencies'); } - foreach ($lockedPackages as $package) { + foreach ($lockedRepository->getPackages() as $package) { $version = $package->getVersion(); if (isset($aliases[$package->getName()][$version])) { $version = $aliases[$package->getName()][$version]['alias_normalized']; @@ -316,7 +319,7 @@ class Installer // to the version specified in the lock, or their currently installed version if ($this->update && $this->updateWhitelist) { if ($this->locker->isLocked($devMode)) { - $currentPackages = $this->locker->getLockedPackages($devMode); + $currentPackages = $this->locker->getLockedRepository($devMode)->getPackages(); } else { $currentPackages = $installedRepo->getPackages(); } @@ -381,18 +384,20 @@ class Installer // force update to locked version if it does not match the installed version if ($installFromLock) { - $lockData = $this->locker->getLockData(); unset($lockedReference); - foreach ($lockData['packages'] as $lockedPackage) { - if (!empty($lockedPackage['source-reference']) && strtolower($lockedPackage['package']) === $package->getName()) { - $lockedReference = $lockedPackage['source-reference']; + foreach ($lockedRepository->findPackages($package->getName()) as $lockedPackage) { + if ( + $lockedPackage->isDev() + && $lockedPackage->getSourceReference() + && $lockedPackage->getSourceReference() !== $package->getSourceReference() + ) { + $newPackage = clone $package; + $newPackage->setSourceReference($lockedPackage->getSourceReference()); + $operations[] = new UpdateOperation($package, $newPackage); + break; } } - if (isset($lockedReference) && $lockedReference !== $package->getSourceReference()) { - // changing the source ref to update to will be handled in the operations loop below - $operations[] = new UpdateOperation($package, clone $package); - } } else { // force update to latest on update if ($this->update) { @@ -455,29 +460,8 @@ class Installer $this->eventDispatcher->dispatchPackageEvent(constant($event), $operation); } - // if installing from lock, restore dev packages' references to their locked state - if ($installFromLock) { - $package = null; - if ('update' === $operation->getJobType()) { - $package = $operation->getTargetPackage(); - } elseif ('install' === $operation->getJobType()) { - $package = $operation->getPackage(); - } - if ($package && $package->isDev()) { - $lockData = $this->locker->getLockData(); - foreach ($lockData['packages'] as $lockedPackage) { - if (!empty($lockedPackage['source-reference']) && strtolower($lockedPackage['package']) === $package->getName()) { - // update commit date to allow recovery in case the commit disappeared - if (!empty($lockedPackage['commit-date'])) { - $package->setReleaseDate(new \DateTime('@'.$lockedPackage['commit-date'])); - } - $package->setSourceReference($lockedPackage['source-reference']); - break; - } - } - } - } else { - // not installing from lock, force dev packages' references if they're in root package refs + // not installing from lock, force dev packages' references if they're in root package refs + if (!$installFromLock) { $package = null; if ('update' === $operation->getJobType()) { $package = $operation->getTargetPackage(); diff --git a/src/Composer/Package/Locker.php b/src/Composer/Package/Locker.php index d193fa1c5..ac00a14bc 100644 --- a/src/Composer/Package/Locker.php +++ b/src/Composer/Package/Locker.php @@ -17,6 +17,9 @@ use Composer\Installer\InstallationManager; use Composer\Repository\RepositoryManager; use Composer\Util\ProcessExecutor; use Composer\Package\AliasPackage; +use Composer\Repository\ArrayRepository; +use Composer\Package\Dumper\ArrayDumper; +use Composer\Package\Loader\ArrayLoader; /** * Reads/writes project lockfile (composer.lock). @@ -30,6 +33,8 @@ class Locker private $repositoryManager; private $installationManager; private $hash; + private $loader; + private $dumper; private $lockDataCache; /** @@ -46,6 +51,8 @@ class Locker $this->repositoryManager = $repositoryManager; $this->installationManager = $installationManager; $this->hash = $hash; + $this->loader = new ArrayLoader(); + $this->dumper = new ArrayDumper(); } /** @@ -84,16 +91,29 @@ class Locker * Searches and returns an array of locked packages, retrieved from registered repositories. * * @param bool $dev true to retrieve the locked dev packages - * @return array + * @return \Composer\Repository\RepositoryInterface */ - public function getLockedPackages($dev = false) + public function getLockedRepository($dev = false) { $lockData = $this->getLockData(); - $packages = array(); + $packages = new ArrayRepository(); $lockedPackages = $dev ? $lockData['packages-dev'] : $lockData['packages']; - $repo = $dev ? $this->repositoryManager->getLocalDevRepository() : $this->repositoryManager->getLocalRepository(); + if (empty($lockedPackages)) { + return $packages; + } + + if (isset($lockedPackages[0]['name'])) { + foreach ($lockedPackages as $info) { + $packages->addPackage($this->loader->load($info)); + } + + return $packages; + } + + // legacy lock file support + $repo = $dev ? $this->repositoryManager->getLocalDevRepository() : $this->repositoryManager->getLocalRepository(); foreach ($lockedPackages as $info) { $resolvedVersion = !empty($info['alias-version']) ? $info['alias-version'] : $info['version']; @@ -122,7 +142,7 @@ class Locker )); } - $packages[] = $package; + $packages->addPackage(clone $package); } return $packages; @@ -221,11 +241,8 @@ class Locker $locked = array(); foreach ($packages as $package) { - $alias = null; - if ($package instanceof AliasPackage) { - $alias = $package; - $package = $package->getAliasOf(); + continue; } $name = $package->getPrettyName(); @@ -237,38 +254,30 @@ class Locker )); } - $spec = array('package' => $name, 'version' => $version); + $spec = $this->dumper->dump($package); + unset($spec['version_normalized']); - if ($package->isDev() && !$alias) { - $spec['source-reference'] = $package->getSourceReference(); + if ($package->isDev()) { if ('git' === $package->getSourceType() && $path = $this->installationManager->getInstallPath($package)) { $process = new ProcessExecutor(); if (0 === $process->execute('git log -n1 --pretty=%ct '.escapeshellarg($package->getSourceReference()), $output, $path)) { - $spec['commit-date'] = trim($output); + $spec['time'] = trim($output); } } } - if ($alias) { - $spec['alias-pretty-version'] = $alias->getPrettyVersion(); - $spec['alias-version'] = $alias->getVersion(); - } - $locked[] = $spec; } usort($locked, function ($a, $b) { - $comparison = strcmp($a['package'], $b['package']); + $comparison = strcmp($a['name'], $b['name']); if (0 !== $comparison) { return $comparison; } // If it is the same package, compare the versions to make the order deterministic - $aVersion = isset($a['alias-version']) ? $a['alias-version'] : $a['version']; - $bVersion = isset($b['alias-version']) ? $b['alias-version'] : $b['version']; - - return strcmp($aVersion, $bVersion); + return strcmp($a['version'], $b['version']); }); return $locked; diff --git a/tests/Composer/Test/Fixtures/installer/update-alias-lock.test b/tests/Composer/Test/Fixtures/installer/update-alias-lock.test index 03744bcfd..f30f3a17f 100644 --- a/tests/Composer/Test/Fixtures/installer/update-alias-lock.test +++ b/tests/Composer/Test/Fixtures/installer/update-alias-lock.test @@ -53,8 +53,12 @@ update --EXPECT-LOCK-- { "packages": [ - { "package": "a/a", "version": "dev-master", "alias-pretty-version": "1.0.x-dev", "alias-version": "1.0.9999999.9999999-dev" }, - { "package": "a/a", "version": "dev-master", "source-reference": "master" } + { + "name": "a/a", "version": "dev-master", + "extra": { "branch-alias": { "dev-master": "1.0.x-dev" } }, + "source": { "reference": "master", "type": "git", "url": "" }, + "type": "library" + } ], "packages-dev": null, "aliases": [], diff --git a/tests/Composer/Test/Package/LockerTest.php b/tests/Composer/Test/Package/LockerTest.php index 2f93d77e2..b9b1950c9 100644 --- a/tests/Composer/Test/Package/LockerTest.php +++ b/tests/Composer/Test/Package/LockerTest.php @@ -48,7 +48,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase $this->setExpectedException('LogicException'); - $locker->getLockedPackages(); + $locker->getLockedRepository(); } public function testGetLockedPackages() @@ -82,7 +82,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase ->with($this->logicalOr('pkg1', 'pkg2'), $this->logicalOr('1.0.0-beta', '0.1.10')) ->will($this->onConsecutiveCalls($package1, $package2)); - $this->assertEquals(array($package1, $package2), $locker->getLockedPackages()); + $this->assertEquals(array($package1, $package2), $locker->getLockedRepository()->getPackages()); } public function testGetPackagesWithoutRepo() @@ -118,7 +118,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase $this->setExpectedException('LogicException'); - $locker->getLockedPackages(); + $locker->getLockedRepository(); } public function testSetLockData() @@ -133,22 +133,30 @@ class LockerTest extends \PHPUnit_Framework_TestCase $package2 = $this->createPackageMock(); $package1 - ->expects($this->once()) + ->expects($this->atLeastOnce()) ->method('getPrettyName') ->will($this->returnValue('pkg1')); $package1 - ->expects($this->once()) + ->expects($this->atLeastOnce()) ->method('getPrettyVersion') ->will($this->returnValue('1.0.0-beta')); + $package1 + ->expects($this->atLeastOnce()) + ->method('getVersion') + ->will($this->returnValue('1.0.0.0-beta')); $package2 - ->expects($this->once()) + ->expects($this->atLeastOnce()) ->method('getPrettyName') ->will($this->returnValue('pkg2')); $package2 - ->expects($this->once()) + ->expects($this->atLeastOnce()) ->method('getPrettyVersion') ->will($this->returnValue('0.1.10')); + $package2 + ->expects($this->atLeastOnce()) + ->method('getVersion') + ->will($this->returnValue('0.1.10.0')); $json ->expects($this->once()) @@ -156,8 +164,8 @@ class LockerTest extends \PHPUnit_Framework_TestCase ->with(array( 'hash' => 'md5', 'packages' => array( - array('package' => 'pkg1', 'version' => '1.0.0-beta'), - array('package' => 'pkg2', 'version' => '0.1.10') + array('name' => 'pkg1', 'version' => '1.0.0-beta'), + array('name' => 'pkg2', 'version' => '0.1.10') ), 'packages-dev' => array(), 'aliases' => array(),