1
0
Fork 0

Load installed plugins at appropriate time and adapt tests accordingly

pull/2179/head
Nils Adermann 2013-08-13 19:13:17 +02:00
parent 3e41977be7
commit 2f43e9aefb
9 changed files with 122 additions and 119 deletions

View File

@ -55,7 +55,7 @@ class Composer
private $installationManager; private $installationManager;
/** /**
* * @var Plugin\PluginManager
*/ */
private $pluginManager; private $pluginManager;

View File

@ -249,6 +249,9 @@ class Factory
$generator = new AutoloadGenerator($dispatcher); $generator = new AutoloadGenerator($dispatcher);
$composer->setAutoloadGenerator($generator); $composer->setAutoloadGenerator($generator);
$pm = $this->createPluginManager($composer, $io);
$composer->setPluginManager($pm);
// add installers to the manager // add installers to the manager
$this->createDefaultInstallers($im, $composer, $io); $this->createDefaultInstallers($im, $composer, $io);
@ -264,9 +267,7 @@ class Factory
$composer->setLocker($locker); $composer->setLocker($locker);
} }
$pm = $this->createPluginManager($composer); $pm->loadInstalledPlugins();
$composer->setPluginManager($pm);
return $composer; return $composer;
} }
@ -360,9 +361,9 @@ class Factory
/** /**
* @return Plugin\PluginManager * @return Plugin\PluginManager
*/ */
protected function createPluginManager(Composer $composer) protected function createPluginManager(Composer $composer, IOInterface $io)
{ {
return new Plugin\PluginManager($composer); return new Plugin\PluginManager($composer, $io);
} }
/** /**

View File

@ -37,15 +37,17 @@ class PluginInstaller extends LibraryInstaller
*/ */
public function __construct(IOInterface $io, Composer $composer, $type = 'library') public function __construct(IOInterface $io, Composer $composer, $type = 'library')
{ {
parent::__construct($io, $composer, $type); parent::__construct($io, $composer, 'composer-plugin');
$this->installationManager = $composer->getInstallationManager(); $this->installationManager = $composer->getInstallationManager();
$repo = $composer->getRepositoryManager()->getLocalRepository();
foreach ($repo->getPackages() as $package) {
if ('composer-plugin' === $package->getType() || 'composer-installer' === $package->getType()) {
$this->registerPlugin($package);
}
} }
/**
* {@inheritDoc}
*/
public function supports($packageType)
{
return $packageType === 'composer-plugin' || $packageType === 'composer-installer';
} }
/** /**
@ -59,7 +61,7 @@ class PluginInstaller extends LibraryInstaller
} }
parent::install($repo, $package); parent::install($repo, $package);
$this->registerPlugin($package); $this->composer->getPluginManager()->registerPackage($package);
} }
/** /**
@ -73,39 +75,6 @@ class PluginInstaller extends LibraryInstaller
} }
parent::update($repo, $initial, $target); parent::update($repo, $initial, $target);
$this->registerPlugin($target); $this->composer->getPluginManager()->registerPackage($target);
}
private function registerPlugin(PackageInterface $package)
{
$oldInstallerPlugin = ($package->getType() === 'composer-installer');
$downloadPath = $this->getInstallPath($package);
$extra = $package->getExtra();
$classes = is_array($extra['class']) ? $extra['class'] : array($extra['class']);
$generator = $this->composer->getAutoloadGenerator();
$map = $generator->parseAutoloads(array(array($package, $downloadPath)), new Package('dummy', '1.0.0.0', '1.0.0'));
$classLoader = $generator->createLoader($map);
$classLoader->register();
foreach ($classes as $class) {
if (class_exists($class, false)) {
$code = file_get_contents($classLoader->findFile($class));
$code = preg_replace('{^(\s*)class\s+(\S+)}mi', '$1class $2_composer_tmp'.self::$classCounter, $code);
eval('?>'.$code);
$class .= '_composer_tmp'.self::$classCounter;
self::$classCounter++;
}
$plugin = new $class($this->io, $this->composer);
if ($oldInstallerPlugin) {
$this->installationManager->addInstaller($installer);
} else {
$this->composer->getPluginManager()->addPlugin($plugin);
}
}
} }
} }

View File

@ -13,6 +13,8 @@
namespace Composer\Plugin; namespace Composer\Plugin;
use Composer\Composer; use Composer\Composer;
use Composer\Package\Package;
use Composer\IO\IOInterface;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
/** /**
@ -23,17 +25,34 @@ use Composer\Package\PackageInterface;
class PluginManager class PluginManager
{ {
protected $composer; protected $composer;
protected $io;
protected $plugins = array(); protected $plugins = array();
private static $classCounter = 0;
/** /**
* Initializes plugin manager * Initializes plugin manager
* *
* @param Composer $composer * @param Composer $composer
*/ */
public function __construct(Composer $composer) public function __construct(Composer $composer, IOInterface $io)
{ {
$this->composer = $composer; $this->composer = $composer;
$this->io = $io;
}
public function loadInstalledPlugins()
{
$repo = $this->composer->getRepositoryManager()->getLocalRepository();
if ($repo) {
foreach ($repo->getPackages() as $package) {
if ('composer-plugin' === $package->getType() || 'composer-installer' === $package->getType()) {
$this->registerPackage($package);
}
}
}
} }
/** /**
@ -46,4 +65,58 @@ class PluginManager
$this->plugins[] = $plugin; $this->plugins[] = $plugin;
$plugin->activate($this->composer); $plugin->activate($this->composer);
} }
public function getPlugins()
{
return $this->plugins;
}
public function registerPackage(PackageInterface $package)
{
$oldInstallerPlugin = ($package->getType() === 'composer-installer');
$downloadPath = $this->getInstallPath($package);
$extra = $package->getExtra();
if (empty($extra['class'])) {
throw new \UnexpectedValueException('Error while installing '.$package->getPrettyName().', composer-plugin packages should have a class defined in their extra key to be usable.');
}
$classes = is_array($extra['class']) ? $extra['class'] : array($extra['class']);
$generator = $this->composer->getAutoloadGenerator();
$map = $generator->parseAutoloads(array(array($package, $downloadPath)), new Package('dummy', '1.0.0.0', '1.0.0'));
$classLoader = $generator->createLoader($map);
$classLoader->register();
foreach ($classes as $class) {
if (class_exists($class, false)) {
$code = file_get_contents($classLoader->findFile($class));
$code = preg_replace('{^(\s*)class\s+(\S+)}mi', '$1class $2_composer_tmp'.self::$classCounter, $code);
eval('?>'.$code);
$class .= '_composer_tmp'.self::$classCounter;
self::$classCounter++;
}
$plugin = new $class($this->io, $this->composer);
if ($oldInstallerPlugin) {
$this->composer->getInstallationManager()->addInstaller($installer);
} else {
$this->addPlugin($plugin);
}
}
}
public function getInstallPath(PackageInterface $package)
{
$targetDir = $package->getTargetDir();
return $this->getPackageBasePath($package) . ($targetDir ? '/'.$targetDir : '');
}
protected function getPackageBasePath(PackageInterface $package)
{
$vendorDir = rtrim($this->composer->getConfig()->get('vendor-dir'), '/');
return ($vendorDir ? $vendorDir.'/' : '') . $package->getPrettyName();
}
} }

View File

@ -1,5 +1,5 @@
{ {
"name": "", "name": "plugin-v1",
"version": "1.0.0", "version": "1.0.0",
"type": "composer-plugin", "type": "composer-plugin",
"autoload": { "psr-0": { "Installer": "" } }, "autoload": { "psr-0": { "Installer": "" } },

View File

@ -1,5 +1,5 @@
{ {
"name": "", "name": "plugin-v2",
"version": "2.0.0", "version": "2.0.0",
"type": "composer-plugin", "type": "composer-plugin",
"autoload": { "psr-0": { "Installer": "" } }, "autoload": { "psr-0": { "Installer": "" } },

View File

@ -1,5 +1,5 @@
{ {
"name": "", "name": "plugin-v3",
"version": "3.0.0", "version": "3.0.0",
"type": "composer-plugin", "type": "composer-plugin",
"autoload": { "psr-0": { "Installer": "" } }, "autoload": { "psr-0": { "Installer": "" } },

View File

@ -1,5 +1,5 @@
{ {
"name": "", "name": "plugin-v4",
"version": "4.0.0", "version": "4.0.0",
"type": "composer-plugin", "type": "composer-plugin",
"autoload": { "psr-0": { "Installer": "" } }, "autoload": { "psr-0": { "Installer": "" } },

View File

@ -42,14 +42,6 @@ class PluginInstallerTest extends \PHPUnit_Framework_TestCase
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();
$this->im = $this->getMockBuilder('Composer\Installer\InstallationManager')
->disableOriginalConstructor()
->getMock();
$this->pm = $this->getMockBuilder('Composer\Plugin\PluginManager')
->disableOriginalConstructor()
->getMock();
$this->repository = $this->getMock('Composer\Repository\InstalledRepositoryInterface'); $this->repository = $this->getMock('Composer\Repository\InstalledRepositoryInterface');
$rm = $this->getMockBuilder('Composer\Repository\RepositoryManager') $rm = $this->getMockBuilder('Composer\Repository\RepositoryManager')
@ -68,11 +60,12 @@ class PluginInstallerTest extends \PHPUnit_Framework_TestCase
$config = new Config(); $config = new Config();
$this->composer->setConfig($config); $this->composer->setConfig($config);
$this->composer->setDownloadManager($dm); $this->composer->setDownloadManager($dm);
$this->composer->setInstallationManager($this->im);
$this->composer->setPluginManager($this->pm);
$this->composer->setRepositoryManager($rm); $this->composer->setRepositoryManager($rm);
$this->composer->setAutoloadGenerator($this->autoloadGenerator); $this->composer->setAutoloadGenerator($this->autoloadGenerator);
$this->pm = new \Composer\Plugin\PluginManager($this->composer, $this->io);
$this->composer->setPluginManager($this->pm);
$config->merge(array( $config->merge(array(
'config' => array( 'config' => array(
'vendor-dir' => __DIR__.'/Fixtures/', 'vendor-dir' => __DIR__.'/Fixtures/',
@ -87,17 +80,13 @@ class PluginInstallerTest extends \PHPUnit_Framework_TestCase
->expects($this->once()) ->expects($this->once())
->method('getPackages') ->method('getPackages')
->will($this->returnValue(array())); ->will($this->returnValue(array()));
$installer = new PluginInstallerMock($this->io, $this->composer); $installer = new PluginInstaller($this->io, $this->composer);
$this->pm->loadInstalledPlugins();
$test = $this;
$this->pm
->expects($this->once())
->method('addPlugin')
->will($this->returnCallback(function ($installer) use ($test) {
$test->assertEquals('installer-v1', $installer->version);
}));
$installer->install($this->repository, $this->packages[0]); $installer->install($this->repository, $this->packages[0]);
$plugins = $this->pm->getPlugins();
$this->assertEquals('installer-v1', $plugins[0]->version);
} }
public function testInstallMultiplePlugins() public function testInstallMultiplePlugins()
@ -106,28 +95,16 @@ class PluginInstallerTest extends \PHPUnit_Framework_TestCase
->expects($this->once()) ->expects($this->once())
->method('getPackages') ->method('getPackages')
->will($this->returnValue(array())); ->will($this->returnValue(array()));
$installer = new PluginInstaller($this->io, $this->composer);
$installer = new PluginInstallerMock($this->io, $this->composer); $this->pm->loadInstalledPlugins();
$test = $this;
$this->pm
->expects($this->at(0))
->method('addPlugin')
->will($this->returnCallback(function ($plugin) use ($test) {
$test->assertEquals('plugin1', $plugin->name);
$test->assertEquals('installer-v4', $plugin->version);
}));
$this->pm
->expects($this->at(1))
->method('addPlugin')
->will($this->returnCallback(function ($plugin) use ($test) {
$test->assertEquals('plugin2', $plugin->name);
$test->assertEquals('installer-v4', $plugin->version);
}));
$installer->install($this->repository, $this->packages[3]); $installer->install($this->repository, $this->packages[3]);
$plugins = $this->pm->getPlugins();
$this->assertEquals('plugin1', $plugins[0]->name);
$this->assertEquals('installer-v4', $plugins[0]->version);
$this->assertEquals('plugin2', $plugins[1]->name);
$this->assertEquals('installer-v4', $plugins[1]->version);
} }
public function testUpgradeWithNewClassName() public function testUpgradeWithNewClassName()
@ -140,17 +117,13 @@ class PluginInstallerTest extends \PHPUnit_Framework_TestCase
->expects($this->exactly(2)) ->expects($this->exactly(2))
->method('hasPackage') ->method('hasPackage')
->will($this->onConsecutiveCalls(true, false)); ->will($this->onConsecutiveCalls(true, false));
$installer = new PluginInstallerMock($this->io, $this->composer); $installer = new PluginInstaller($this->io, $this->composer);
$this->pm->loadInstalledPlugins();
$test = $this;
$this->pm
->expects($this->once())
->method('addPlugin')
->will($this->returnCallback(function ($plugin) use ($test) {
$test->assertEquals('installer-v2', $plugin->version);
}));
$installer->update($this->repository, $this->packages[0], $this->packages[1]); $installer->update($this->repository, $this->packages[0], $this->packages[1]);
$plugins = $this->pm->getPlugins();
$this->assertEquals('installer-v2', $plugins[1]->version);
} }
public function testUpgradeWithSameClassName() public function testUpgradeWithSameClassName()
@ -163,26 +136,13 @@ class PluginInstallerTest extends \PHPUnit_Framework_TestCase
->expects($this->exactly(2)) ->expects($this->exactly(2))
->method('hasPackage') ->method('hasPackage')
->will($this->onConsecutiveCalls(true, false)); ->will($this->onConsecutiveCalls(true, false));
$installer = new PluginInstallerMock($this->io, $this->composer); $installer = new PluginInstaller($this->io, $this->composer);
$this->pm->loadInstalledPlugins();
$test = $this;
$this->pm
->expects($this->once())
->method('addPlugin')
->will($this->returnCallback(function ($plugin) use ($test) {
$test->assertEquals('installer-v3', $plugin->version);
}));
$installer->update($this->repository, $this->packages[1], $this->packages[2]); $installer->update($this->repository, $this->packages[1], $this->packages[2]);
$plugins = $this->pm->getPlugins();
$this->assertEquals('installer-v3', $plugins[1]->version);
} }
} }
class PluginInstallerMock extends PluginInstaller
{
public function getInstallPath(PackageInterface $package)
{
$version = $package->getVersion();
return __DIR__.'/Fixtures/plugin-v'.$version[0].'/';
}
}