1
0
Fork 0

Merge remote-tracking branch 'szeber/master'

pull/3960/merge
Jordi Boggiano 2015-09-12 22:53:27 +01:00
commit 74e56fd5c6
4 changed files with 117 additions and 18 deletions

View File

@ -308,7 +308,7 @@ class Factory
$lockFile = "json" === pathinfo($composerFile, PATHINFO_EXTENSION) $lockFile = "json" === pathinfo($composerFile, PATHINFO_EXTENSION)
? substr($composerFile, 0, -4).'lock' ? substr($composerFile, 0, -4).'lock'
: $composerFile . '.lock'; : $composerFile . '.lock';
$locker = new Package\Locker($io, new JsonFile($lockFile, new RemoteFilesystem($io, $config)), $rm, $im, md5_file($composerFile)); $locker = new Package\Locker($io, new JsonFile($lockFile, new RemoteFilesystem($io, $config)), $rm, $im, file_get_contents($composerFile));
$composer->setLocker($locker); $composer->setLocker($locker);
} }

View File

@ -34,6 +34,7 @@ class Locker
private $repositoryManager; private $repositoryManager;
private $installationManager; private $installationManager;
private $hash; private $hash;
private $contentHash;
private $loader; private $loader;
private $dumper; private $dumper;
private $process; private $process;
@ -43,17 +44,18 @@ class Locker
* Initializes packages locker. * Initializes packages locker.
* *
* @param IOInterface $io * @param IOInterface $io
* @param JsonFile $lockFile lockfile loader * @param JsonFile $lockFile lockfile loader
* @param RepositoryManager $repositoryManager repository manager instance * @param RepositoryManager $repositoryManager repository manager instance
* @param InstallationManager $installationManager installation manager instance * @param InstallationManager $installationManager installation manager instance
* @param string $hash unique hash of the current composer configuration * @param string $composerFileContents The contents of the composer file
*/ */
public function __construct(IOInterface $io, JsonFile $lockFile, RepositoryManager $repositoryManager, InstallationManager $installationManager, $hash) public function __construct(IOInterface $io, JsonFile $lockFile, RepositoryManager $repositoryManager, InstallationManager $installationManager, $composerFileContents)
{ {
$this->lockFile = $lockFile; $this->lockFile = $lockFile;
$this->repositoryManager = $repositoryManager; $this->repositoryManager = $repositoryManager;
$this->installationManager = $installationManager; $this->installationManager = $installationManager;
$this->hash = $hash; $this->hash = md5($composerFileContents);
$this->contentHash = $this->getContentHash($composerFileContents);
$this->loader = new ArrayLoader(null, true); $this->loader = new ArrayLoader(null, true);
$this->dumper = new ArrayDumper(); $this->dumper = new ArrayDumper();
$this->process = new ProcessExecutor($io); $this->process = new ProcessExecutor($io);
@ -84,6 +86,11 @@ class Locker
{ {
$lock = $this->lockFile->read(); $lock = $this->lockFile->read();
if (!empty($lock['content-hash'])) {
// There is a content hash key, use that instead of the file hash
return $this->contentHash === $lock['content-hash'];
}
return $this->hash === $lock['hash']; return $this->hash === $lock['hash'];
} }
@ -239,6 +246,7 @@ class Locker
'Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file', 'Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file',
'This file is @gener'.'ated automatically'), 'This file is @gener'.'ated automatically'),
'hash' => $this->hash, 'hash' => $this->hash,
'content-hash' => $this->contentHash,
'packages' => null, 'packages' => null,
'packages-dev' => null, 'packages-dev' => null,
'aliases' => array(), 'aliases' => array(),
@ -376,4 +384,39 @@ class Locker
return $datetime ? $datetime->format('Y-m-d H:i:s') : null; return $datetime ? $datetime->format('Y-m-d H:i:s') : null;
} }
/**
* Returns the md5 hash of the sorted content of the composer file.
*
* @param string $composerFileContents The contents of the composer file.
*
* @return string
*/
private function getContentHash($composerFileContents)
{
$content = json_decode($composerFileContents, true);
$relevantKeys = array(
'require',
'require-dev',
'conflict',
'replace',
'provide',
'minimum-stability',
'prefer-stable',
'repositories',
'extra',
'version',
'name',
);
$relevantContent = array();
foreach (array_intersect($relevantKeys, array_keys($content)) as $key) {
$relevantContent[$key] = $content[$key];
}
ksort($relevantContent);
return md5(json_encode($relevantContent));
}
} }

View File

@ -190,7 +190,8 @@ class InstallerTest extends TestCase
})); }));
} }
$locker = new Locker($io, $lockJsonMock, $repositoryManager, $composer->getInstallationManager(), md5(json_encode($composerConfig))); $contents = json_encode($composerConfig);
$locker = new Locker($io, $lockJsonMock, $repositoryManager, $composer->getInstallationManager(), $contents);
$composer->setLocker($locker); $composer->setLocker($locker);
$eventDispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')->disableOriginalConstructor()->getMock(); $eventDispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')->disableOriginalConstructor()->getMock();
@ -236,6 +237,7 @@ class InstallerTest extends TestCase
if ($expectLock) { if ($expectLock) {
unset($actualLock['hash']); unset($actualLock['hash']);
unset($actualLock['content-hash']);
unset($actualLock['_readme']); unset($actualLock['_readme']);
$this->assertEquals($expectLock, $actualLock); $this->assertEquals($expectLock, $actualLock);
} }

View File

@ -20,7 +20,8 @@ class LockerTest extends \PHPUnit_Framework_TestCase
public function testIsLocked() public function testIsLocked()
{ {
$json = $this->createJsonFileMock(); $json = $this->createJsonFileMock();
$locker = new Locker(new NullIO, $json, $this->createRepositoryManagerMock(), $this->createInstallationManagerMock(), 'md5'); $locker = new Locker(new NullIO, $json, $this->createRepositoryManagerMock(), $this->createInstallationManagerMock(),
$this->getJsonContent());
$json $json
->expects($this->any()) ->expects($this->any())
@ -40,7 +41,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase
$repo = $this->createRepositoryManagerMock(); $repo = $this->createRepositoryManagerMock();
$inst = $this->createInstallationManagerMock(); $inst = $this->createInstallationManagerMock();
$locker = new Locker(new NullIO, $json, $repo, $inst, 'md5'); $locker = new Locker(new NullIO, $json, $repo, $inst, $this->getJsonContent());
$json $json
->expects($this->once()) ->expects($this->once())
@ -58,7 +59,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase
$repo = $this->createRepositoryManagerMock(); $repo = $this->createRepositoryManagerMock();
$inst = $this->createInstallationManagerMock(); $inst = $this->createInstallationManagerMock();
$locker = new Locker(new NullIO, $json, $repo, $inst, 'md5'); $locker = new Locker(new NullIO, $json, $repo, $inst, $this->getJsonContent());
$json $json
->expects($this->once()) ->expects($this->once())
@ -85,7 +86,8 @@ class LockerTest extends \PHPUnit_Framework_TestCase
$repo = $this->createRepositoryManagerMock(); $repo = $this->createRepositoryManagerMock();
$inst = $this->createInstallationManagerMock(); $inst = $this->createInstallationManagerMock();
$locker = new Locker(new NullIO, $json, $repo, $inst, 'md5'); $jsonContent = $this->getJsonContent() . ' ';
$locker = new Locker(new NullIO, $json, $repo, $inst, $jsonContent);
$package1 = $this->createPackageMock(); $package1 = $this->createPackageMock();
$package2 = $this->createPackageMock(); $package2 = $this->createPackageMock();
@ -116,6 +118,9 @@ class LockerTest extends \PHPUnit_Framework_TestCase
->method('getVersion') ->method('getVersion')
->will($this->returnValue('0.1.10.0')); ->will($this->returnValue('0.1.10.0'));
$hash = md5($jsonContent);
$contentHash = md5(trim($jsonContent));
$json $json
->expects($this->once()) ->expects($this->once())
->method('write') ->method('write')
@ -123,7 +128,8 @@ class LockerTest extends \PHPUnit_Framework_TestCase
'_readme' => array('This file locks the dependencies of your project to a known state', '_readme' => array('This file locks the dependencies of your project to a known state',
'Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file', 'Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file',
'This file is @gener'.'ated automatically'), 'This file is @gener'.'ated automatically'),
'hash' => 'md5', 'hash' => $hash,
'content-hash' => $contentHash,
'packages' => array( 'packages' => array(
array('name' => 'pkg1', 'version' => '1.0.0-beta'), array('name' => 'pkg1', 'version' => '1.0.0-beta'),
array('name' => 'pkg2', 'version' => '0.1.10') array('name' => 'pkg2', 'version' => '0.1.10')
@ -148,7 +154,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase
$repo = $this->createRepositoryManagerMock(); $repo = $this->createRepositoryManagerMock();
$inst = $this->createInstallationManagerMock(); $inst = $this->createInstallationManagerMock();
$locker = new Locker(new NullIO, $json, $repo, $inst, 'md5'); $locker = new Locker(new NullIO, $json, $repo, $inst, $this->getJsonContent());
$package1 = $this->createPackageMock(); $package1 = $this->createPackageMock();
$package1 $package1
@ -167,12 +173,13 @@ class LockerTest extends \PHPUnit_Framework_TestCase
$repo = $this->createRepositoryManagerMock(); $repo = $this->createRepositoryManagerMock();
$inst = $this->createInstallationManagerMock(); $inst = $this->createInstallationManagerMock();
$locker = new Locker(new NullIO, $json, $repo, $inst, 'md5'); $jsonContent = $this->getJsonContent();
$locker = new Locker(new NullIO, $json, $repo, $inst, $jsonContent);
$json $json
->expects($this->once()) ->expects($this->once())
->method('read') ->method('read')
->will($this->returnValue(array('hash' => 'md5'))); ->will($this->returnValue(array('hash' => md5($jsonContent))));
$this->assertTrue($locker->isFresh()); $this->assertTrue($locker->isFresh());
} }
@ -183,12 +190,47 @@ class LockerTest extends \PHPUnit_Framework_TestCase
$repo = $this->createRepositoryManagerMock(); $repo = $this->createRepositoryManagerMock();
$inst = $this->createInstallationManagerMock(); $inst = $this->createInstallationManagerMock();
$locker = new Locker(new NullIO, $json, $repo, $inst, 'md5'); $locker = new Locker(new NullIO, $json, $repo, $inst, $this->getJsonContent());
$json $json
->expects($this->once()) ->expects($this->once())
->method('read') ->method('read')
->will($this->returnValue(array('hash' => 'oldmd5'))); ->will($this->returnValue(array('hash' => $this->getJsonContent(array('name' => 'test2')))));
$this->assertFalse($locker->isFresh());
}
public function testIsFreshWithContentHash()
{
$json = $this->createJsonFileMock();
$repo = $this->createRepositoryManagerMock();
$inst = $this->createInstallationManagerMock();
$jsonContent = $this->getJsonContent();
$locker = new Locker(new NullIO, $json, $repo, $inst, $jsonContent);
$json
->expects($this->once())
->method('read')
->will($this->returnValue(array('hash' => md5($jsonContent . ' '), 'content-hash' => md5($jsonContent))));
$this->assertTrue($locker->isFresh());
}
public function testIsFreshFalseWithContentHash()
{
$json = $this->createJsonFileMock();
$repo = $this->createRepositoryManagerMock();
$inst = $this->createInstallationManagerMock();
$locker = new Locker(new NullIO, $json, $repo, $inst, $this->getJsonContent());
$differentHash = md5($this->getJsonContent(array('name' => 'test2')));
$json
->expects($this->once())
->method('read')
->will($this->returnValue(array('hash' => $differentHash, 'content-hash' => $differentHash)));
$this->assertFalse($locker->isFresh()); $this->assertFalse($locker->isFresh());
} }
@ -227,4 +269,16 @@ class LockerTest extends \PHPUnit_Framework_TestCase
return $this->getMockBuilder('Composer\Package\PackageInterface') return $this->getMockBuilder('Composer\Package\PackageInterface')
->getMock(); ->getMock();
} }
private function getJsonContent(array $customData = array())
{
$data = array_merge(array(
'minimum-stability' => 'beta',
'name' => 'test',
), $customData);
ksort($data);
return json_encode($data);
}
} }