diff --git a/bin/composer b/bin/composer index d6ee9cf51..201363092 100755 --- a/bin/composer +++ b/bin/composer @@ -24,8 +24,8 @@ $dm->setDownloader('zip', new Downloader\ZipDownloader()); // initialize installation manager $im = new Installer\InstallationManager(); -$im->setInstaller('library', new Installer\LibraryInstaller('vendor', $dm, $rm->getLocalRepository())); -$im->setInstaller('symfony-bundle', new Installer\LibraryInstaller('vendor/bundles', $dm, $rm->getLocalRepository())); +$im->addInstaller(new Installer\LibraryInstaller('vendor', $dm, $rm->getLocalRepository())); +$im->addInstaller(new Installer\LibraryInstaller('vendor/bundles', $dm, $rm->getLocalRepository(), 'symfony-bundle')); // load package $loader = new Package\Loader\JsonLoader(); diff --git a/src/Composer/Installer/InstallationManager.php b/src/Composer/Installer/InstallationManager.php index 74f108b25..ac59805fb 100644 --- a/src/Composer/Installer/InstallationManager.php +++ b/src/Composer/Installer/InstallationManager.php @@ -22,20 +22,22 @@ use Composer\DependencyResolver\Operation\UninstallOperation; * Package operation manager. * * @author Konstantin Kudryashov + * @author Jordi Boggiano */ class InstallationManager { private $installers = array(); + private $cache = array(); /** - * Sets installer for a specific package type. + * Adds installer * - * @param string $type package type (library f.e.) * @param InstallerInterface $installer installer instance */ - public function setInstaller($type, InstallerInterface $installer) + public function addInstaller(InstallerInterface $installer) { - $this->installers[$type] = $installer; + array_unshift($this->installers, $installer); + $this->cache = array(); } /** @@ -49,11 +51,17 @@ class InstallationManager */ public function getInstaller($type) { - if (!isset($this->installers[$type])) { - throw new \InvalidArgumentException('Unknown installer type: '.$type); + if (isset($this->cache[$type])) { + return $this->cache[$type]; } - return $this->installers[$type]; + foreach ($this->installers as $installer) { + if ($installer->supports($type)) { + return $this->cache[$type] = $installer; + } + } + + throw new \InvalidArgumentException('Unknown installer type: '.$type); } /** @@ -129,6 +137,12 @@ class InstallationManager $installer->uninstall($operation->getPackage()); } + /** + * Returns the installation path of a package + * + * @param PackageInterface $package + * @return string path + */ public function getInstallPath(PackageInterface $package) { $installer = $this->getInstaller($package->getType()); diff --git a/src/Composer/Installer/InstallerInterface.php b/src/Composer/Installer/InstallerInterface.php index f144c2828..36c023b3b 100644 --- a/src/Composer/Installer/InstallerInterface.php +++ b/src/Composer/Installer/InstallerInterface.php @@ -22,6 +22,14 @@ use Composer\Package\PackageInterface; */ interface InstallerInterface { + /** + * Decides if the installer supports the given type + * + * @param string $packageType + * @return Boolean + */ + function supports($packageType); + /** * Checks that provided package is installed. * diff --git a/src/Composer/Installer/LibraryInstaller.php b/src/Composer/Installer/LibraryInstaller.php index a5064fde1..99af14f6e 100644 --- a/src/Composer/Installer/LibraryInstaller.php +++ b/src/Composer/Installer/LibraryInstaller.php @@ -35,8 +35,9 @@ class LibraryInstaller implements InstallerInterface * @param string $dir relative path for packages home * @param DownloadManager $dm download manager * @param WritableRepositoryInterface $repository repository controller + * @param string $type package type that this installer handles */ - public function __construct($directory, DownloadManager $dm, WritableRepositoryInterface $repository) + public function __construct($directory, DownloadManager $dm, WritableRepositoryInterface $repository, $type = 'library') { $this->directory = $directory; $this->downloadManager = $dm; @@ -57,6 +58,14 @@ class LibraryInstaller implements InstallerInterface $this->repository = $repository; } + /** + * {@inheritDoc} + */ + public function supports($packageType) + { + return $packageType === $this->type; + } + /** * {@inheritDoc} */ diff --git a/tests/Composer/Test/Installer/InstallationManagerTest.php b/tests/Composer/Test/Installer/InstallationManagerTest.php index a8b1a9818..99c2f8bdf 100644 --- a/tests/Composer/Test/Installer/InstallationManagerTest.php +++ b/tests/Composer/Test/Installer/InstallationManagerTest.php @@ -19,12 +19,20 @@ use Composer\DependencyResolver\Operation\UninstallOperation; class InstallationManagerTest extends \PHPUnit_Framework_TestCase { - public function testSetGetInstaller() + public function testAddGetInstaller() { $installer = $this->createInstallerMock(); + + $installer + ->expects($this->exactly(2)) + ->method('supports') + ->will($this->returnCallback(function ($arg) { + return $arg === 'vendor'; + })); + $manager = new InstallationManager(); - $manager->setInstaller('vendor', $installer); + $manager->addInstaller($installer); $this->assertSame($installer, $manager->getInstaller('vendor')); $this->setExpectedException('InvalidArgumentException'); @@ -65,7 +73,7 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase { $installer = $this->createInstallerMock(); $manager = new InstallationManager(); - $manager->setInstaller('library', $installer); + $manager->addInstaller($installer); $package = $this->createPackageMock(); $operation = new InstallOperation($package, 'test'); @@ -75,6 +83,12 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase ->method('getType') ->will($this->returnValue('library')); + $installer + ->expects($this->once()) + ->method('supports') + ->with('library') + ->will($this->returnValue(true)); + $installer ->expects($this->once()) ->method('install') @@ -87,7 +101,7 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase { $installer = $this->createInstallerMock(); $manager = new InstallationManager(); - $manager->setInstaller('library', $installer); + $manager->addInstaller($installer); $initial = $this->createPackageMock(); $target = $this->createPackageMock(); @@ -102,6 +116,12 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase ->method('getType') ->will($this->returnValue('library')); + $installer + ->expects($this->once()) + ->method('supports') + ->with('library') + ->will($this->returnValue(true)); + $installer ->expects($this->once()) ->method('update') @@ -112,11 +132,11 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase public function testUpdateWithNotEqualTypes() { - $installer1 = $this->createInstallerMock(); - $installer2 = $this->createInstallerMock(); + $libInstaller = $this->createInstallerMock(); + $bundleInstaller = $this->createInstallerMock(); $manager = new InstallationManager(); - $manager->setInstaller('library', $installer1); - $manager->setInstaller('bundles', $installer2); + $manager->addInstaller($libInstaller); + $manager->addInstaller($bundleInstaller); $initial = $this->createPackageMock(); $target = $this->createPackageMock(); @@ -131,12 +151,25 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase ->method('getType') ->will($this->returnValue('bundles')); - $installer1 + $bundleInstaller + ->expects($this->exactly(2)) + ->method('supports') + ->will($this->returnCallback(function ($arg) { + return $arg === 'bundles'; + })); + + $libInstaller + ->expects($this->once()) + ->method('supports') + ->with('library') + ->will($this->returnValue(true)); + + $libInstaller ->expects($this->once()) ->method('uninstall') ->with($initial); - $installer2 + $bundleInstaller ->expects($this->once()) ->method('install') ->with($target); @@ -148,7 +181,7 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase { $installer = $this->createInstallerMock(); $manager = new InstallationManager(); - $manager->setInstaller('library', $installer); + $manager->addInstaller($installer); $package = $this->createPackageMock(); $operation = new UninstallOperation($package, 'test'); @@ -163,6 +196,12 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase ->method('uninstall') ->with($package); + $installer + ->expects($this->once()) + ->method('supports') + ->with('library') + ->will($this->returnValue(true)); + $manager->uninstall($operation); }