Browse Source

Merge pull request #174 from Seldaek/lockdetect

Detect lock file changes and warn users on install, fixes #75
Nils Adermann 13 years ago
parent
commit
35c62f67be

+ 10 - 5
src/Composer/Command/InstallCommand.php

@@ -85,7 +85,7 @@ EOT
         // creating requirements request
         $request = new Request($pool);
         if ($update) {
-            $output->writeln('<info>Updating dependencies.</info>');
+            $output->writeln('<info>Updating dependencies</info>');
             $installedPackages = $installedRepo->getPackages();
             $links = $this->collectLinks($input, $composer->getPackage());
 
@@ -100,7 +100,11 @@ EOT
                 $request->install($link->getTarget(), $link->getConstraint());
             }
         } elseif ($composer->getLocker()->isLocked()) {
-            $output->writeln('<info>Installing from lockfile.</info> (Run "composer update" to add or update packages)');
+            $output->writeln('<info>Installing from lock file</info>');
+
+            if (!$composer->getLocker()->isFresh()) {
+                $output->writeln('<warning>Your lock file is out of sync with your composer.json, run "composer.phar update" to update dependencies</warning>');
+            }
 
             foreach ($composer->getLocker()->getLockedPackages() as $package) {
                 $constraint = new VersionConstraint('=', $package->getVersion());
@@ -150,6 +154,9 @@ EOT
         }
 
         // execute operations
+        if (!$operations) {
+            $output->writeln('<info>Nothing to install/update</info>');
+        }
         foreach ($operations as $operation) {
             if ($verbose) {
                 $output->writeln((string) $operation);
@@ -162,7 +169,7 @@ EOT
         if (!$dryRun) {
             if ($update || !$composer->getLocker()->isLocked()) {
                 $composer->getLocker()->lockPackages($localRepo->getPackages());
-                $output->writeln('<info>Locked</info>');
+                $output->writeln('<info>Writing lock file</info>');
             }
 
             $localRepo->write();
@@ -171,8 +178,6 @@ EOT
             $generator = new AutoloadGenerator;
             $generator->dump($localRepo, $composer->getPackage(), $installationManager, $installationManager->getVendorPath().'/.composer');
         }
-
-        $output->writeln('<info>Done</info>');
     }
 
     private function collectLinks(InputInterface $input, PackageInterface $package)

+ 2 - 1
src/Composer/Console/Application.php

@@ -49,6 +49,7 @@ class Application extends BaseApplication
     {
         if (null === $output) {
             $styles['highlight'] = new OutputFormatterStyle('red');
+            $styles['warning'] = new OutputFormatterStyle('black', 'yellow');
             $formatter = new OutputFormatter(null, $styles);
             $output = new ConsoleOutput(ConsoleOutput::VERBOSITY_NORMAL, null, $formatter);
         }
@@ -152,7 +153,7 @@ class Application extends BaseApplication
 
         // init locker
         $lockFile = substr($composerFile, -5) === '.json' ? substr($composerFile, 0, -4).'lock' : $composerFile . '.lock';
-        $locker = new Package\Locker(new JsonFile($lockFile), $rm);
+        $locker = new Package\Locker(new JsonFile($lockFile), $rm, md5_file($composerFile));
 
         // initialize composer
         $composer = new Composer();

+ 28 - 10
src/Composer/Package/Locker.php

@@ -24,33 +24,48 @@ class Locker
 {
     private $lockFile;
     private $repositoryManager;
+    private $hash;
 
     /**
      * Initializes packages locker.
      *
-     * @param   JsonFile            $lockFile           lockfile loader
-     * @param   RepositoryManager   $repositoryManager  repository manager instance
+     * @param JsonFile            $lockFile           lockfile loader
+     * @param RepositoryManager   $repositoryManager  repository manager instance
+     * @param string              $hash               unique hash of the current composer configuration
      */
-    public function __construct(JsonFile $lockFile, RepositoryManager $repositoryManager)
+    public function __construct(JsonFile $lockFile, RepositoryManager $repositoryManager, $hash)
     {
         $this->lockFile          = $lockFile;
         $this->repositoryManager = $repositoryManager;
+        $this->hash = $hash;
     }
 
     /**
      * Checks whether locker were been locked (lockfile found).
      *
-     * @return  Boolean
+     * @return Boolean
      */
     public function isLocked()
     {
         return $this->lockFile->exists();
     }
 
+    /**
+     * Checks whether the lock file is still up to date with the current hash
+     *
+     * @return Boolean
+     */
+    public function isFresh()
+    {
+        $lock = $this->lockFile->read();
+
+        return $this->hash === $lock['hash'];
+    }
+
     /**
      * Searches and returns an array of locked packages, retrieved from registered repositories.
      *
-     * @return  array
+     * @return array
      */
     public function getLockedPackages()
     {
@@ -60,7 +75,7 @@ class Locker
 
         $lockList = $this->lockFile->read();
         $packages = array();
-        foreach ($lockList as $info) {
+        foreach ($lockList['packages'] as $info) {
             $package = $this->repositoryManager->getLocalRepository()->findPackage($info['package'], $info['version']);
 
             if (!$package) {
@@ -83,11 +98,14 @@ class Locker
     /**
      * Locks provided packages into lockfile.
      *
-     * @param   array   $packages   array of packages
+     * @param array $packages array of packages
      */
     public function lockPackages(array $packages)
     {
-        $hash = array();
+        $lock = array(
+            'hash' => $this->hash,
+            'packages' => array(),
+        );
         foreach ($packages as $package) {
             $name    = $package->getPrettyName();
             $version = $package->getPrettyVersion();
@@ -98,9 +116,9 @@ class Locker
                 ));
             }
 
-            $hash[] = array('package' => $name, 'version' => $version);
+            $lock['packages'][] = array('package' => $name, 'version' => $version);
         }
 
-        $this->lockFile->write($hash);
+        $this->lockFile->write($lock);
     }
 }

+ 49 - 12
tests/Composer/Test/Package/LockerTest.php

@@ -19,7 +19,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase
     public function testIsLocked()
     {
         $json   = $this->createJsonFileMock();
-        $locker = new Locker($json, $this->createRepositoryManagerMock());
+        $locker = new Locker($json, $this->createRepositoryManagerMock(), 'md5');
 
         $json
             ->expects($this->once())
@@ -34,7 +34,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase
         $json = $this->createJsonFileMock();
         $repo = $this->createRepositoryManagerMock();
 
-        $locker = new Locker($json, $repo);
+        $locker = new Locker($json, $repo, 'md5');
 
         $json
             ->expects($this->once())
@@ -51,7 +51,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase
         $json = $this->createJsonFileMock();
         $repo = $this->createRepositoryManagerMock();
 
-        $locker = new Locker($json, $repo);
+        $locker = new Locker($json, $repo, 'md5');
 
         $json
             ->expects($this->once())
@@ -61,8 +61,10 @@ class LockerTest extends \PHPUnit_Framework_TestCase
             ->expects($this->once())
             ->method('read')
             ->will($this->returnValue(array(
-                array('package' => 'pkg1', 'version' => '1.0.0-beta'),
-                array('package' => 'pkg2', 'version' => '0.1.10')
+                'packages' => array(
+                    array('package' => 'pkg1', 'version' => '1.0.0-beta'),
+                    array('package' => 'pkg2', 'version' => '0.1.10')
+                )
             )));
 
         $package1 = $this->createPackageMock();
@@ -82,7 +84,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase
         $json = $this->createJsonFileMock();
         $repo = $this->createRepositoryManagerMock();
 
-        $locker = new Locker($json, $repo);
+        $locker = new Locker($json, $repo, 'md5');
 
         $json
             ->expects($this->once())
@@ -92,8 +94,10 @@ class LockerTest extends \PHPUnit_Framework_TestCase
             ->expects($this->once())
             ->method('read')
             ->will($this->returnValue(array(
-                array('package' => 'pkg1', 'version' => '1.0.0-beta'),
-                array('package' => 'pkg2', 'version' => '0.1.10')
+                'packages' => array(
+                    array('package' => 'pkg1', 'version' => '1.0.0-beta'),
+                    array('package' => 'pkg2', 'version' => '0.1.10')
+                )
             )));
 
         $package1 = $this->createPackageMock();
@@ -115,7 +119,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase
         $json = $this->createJsonFileMock();
         $repo = $this->createRepositoryManagerMock();
 
-        $locker = new Locker($json, $repo);
+        $locker = new Locker($json, $repo, 'md5');
 
         $package1 = $this->createPackageMock();
         $package2 = $this->createPackageMock();
@@ -142,8 +146,11 @@ class LockerTest extends \PHPUnit_Framework_TestCase
             ->expects($this->once())
             ->method('write')
             ->with(array(
-                array('package' => 'pkg1', 'version' => '1.0.0-beta'),
-                array('package' => 'pkg2', 'version' => '0.1.10')
+                'hash' => 'md5',
+                'packages' => array(
+                    array('package' => 'pkg1', 'version' => '1.0.0-beta'),
+                    array('package' => 'pkg2', 'version' => '0.1.10')
+                ),
             ));
 
         $locker->lockPackages(array($package1, $package2));
@@ -154,7 +161,7 @@ class LockerTest extends \PHPUnit_Framework_TestCase
         $json = $this->createJsonFileMock();
         $repo = $this->createRepositoryManagerMock();
 
-        $locker = new Locker($json, $repo);
+        $locker = new Locker($json, $repo, 'md5');
 
         $package1 = $this->createPackageMock();
         $package1
@@ -167,6 +174,36 @@ class LockerTest extends \PHPUnit_Framework_TestCase
         $locker->lockPackages(array($package1));
     }
 
+    public function testIsFresh()
+    {
+        $json = $this->createJsonFileMock();
+        $repo = $this->createRepositoryManagerMock();
+
+        $locker = new Locker($json, $repo, 'md5');
+
+        $json
+            ->expects($this->once())
+            ->method('read')
+            ->will($this->returnValue(array('hash' => 'md5')));
+
+        $this->assertTrue($locker->isFresh());
+    }
+
+    public function testIsFreshFalse()
+    {
+        $json = $this->createJsonFileMock();
+        $repo = $this->createRepositoryManagerMock();
+
+        $locker = new Locker($json, $repo, 'md5');
+
+        $json
+            ->expects($this->once())
+            ->method('read')
+            ->will($this->returnValue(array('hash' => 'oldmd5')));
+
+        $this->assertFalse($locker->isFresh());
+    }
+
     private function createJsonFileMock()
     {
         return $this->getMockBuilder('Composer\Json\JsonFile')