|
@@ -36,6 +36,7 @@ class PluginManager
|
|
|
protected $io;
|
|
|
protected $globalComposer;
|
|
|
protected $versionParser;
|
|
|
+ protected $disablePlugins = false;
|
|
|
|
|
|
protected $plugins = array();
|
|
|
protected $registeredPlugins = array();
|
|
@@ -48,13 +49,15 @@ class PluginManager
|
|
|
* @param IOInterface $io
|
|
|
* @param Composer $composer
|
|
|
* @param Composer $globalComposer
|
|
|
+ * @param bool $disablePlugins
|
|
|
*/
|
|
|
- public function __construct(IOInterface $io, Composer $composer, Composer $globalComposer = null)
|
|
|
+ public function __construct(IOInterface $io, Composer $composer, Composer $globalComposer = null, $disablePlugins = false)
|
|
|
{
|
|
|
$this->io = $io;
|
|
|
$this->composer = $composer;
|
|
|
$this->globalComposer = $globalComposer;
|
|
|
$this->versionParser = new VersionParser();
|
|
|
+ $this->disablePlugins = $disablePlugins;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -62,6 +65,10 @@ class PluginManager
|
|
|
*/
|
|
|
public function loadInstalledPlugins()
|
|
|
{
|
|
|
+ if ($this->disablePlugins) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
$repo = $this->composer->getRepositoryManager()->getLocalRepository();
|
|
|
$globalRepo = $this->globalComposer ? $this->globalComposer->getRepositoryManager()->getLocalRepository() : null;
|
|
|
if ($repo) {
|
|
@@ -72,12 +79,106 @@ class PluginManager
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Gets all currently active plugin instances
|
|
|
+ *
|
|
|
+ * @return array plugins
|
|
|
+ */
|
|
|
+ public function getPlugins()
|
|
|
+ {
|
|
|
+ return $this->plugins;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Register a plugin package, activate it etc.
|
|
|
+ *
|
|
|
+ * If it's of type composer-installer it is registered as an installer
|
|
|
+ * instead for BC
|
|
|
+ *
|
|
|
+ * @param PackageInterface $package
|
|
|
+ * @param bool $failOnMissingClasses By default this silently skips plugins that can not be found, but if set to true it fails with an exception
|
|
|
+ *
|
|
|
+ * @throws \UnexpectedValueException
|
|
|
+ */
|
|
|
+ public function registerPackage(PackageInterface $package, $failOnMissingClasses = false)
|
|
|
+ {
|
|
|
+ if ($this->disablePlugins) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ $oldInstallerPlugin = ($package->getType() === 'composer-installer');
|
|
|
+
|
|
|
+ if (in_array($package->getName(), $this->registeredPlugins)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ $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']);
|
|
|
+
|
|
|
+ $localRepo = $this->composer->getRepositoryManager()->getLocalRepository();
|
|
|
+ $globalRepo = $this->globalComposer ? $this->globalComposer->getRepositoryManager()->getLocalRepository() : null;
|
|
|
+
|
|
|
+ $pool = new Pool('dev');
|
|
|
+ $pool->addRepository($localRepo);
|
|
|
+ if ($globalRepo) {
|
|
|
+ $pool->addRepository($globalRepo);
|
|
|
+ }
|
|
|
+
|
|
|
+ $autoloadPackages = array($package->getName() => $package);
|
|
|
+ $autoloadPackages = $this->collectDependencies($pool, $autoloadPackages, $package);
|
|
|
+
|
|
|
+ $generator = $this->composer->getAutoloadGenerator();
|
|
|
+ $autoloads = array();
|
|
|
+ foreach ($autoloadPackages as $autoloadPackage) {
|
|
|
+ $downloadPath = $this->getInstallPath($autoloadPackage, ($globalRepo && $globalRepo->hasPackage($autoloadPackage)));
|
|
|
+ $autoloads[] = array($autoloadPackage, $downloadPath);
|
|
|
+ }
|
|
|
+
|
|
|
+ $map = $generator->parseAutoloads($autoloads, 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++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($oldInstallerPlugin) {
|
|
|
+ $installer = new $class($this->io, $this->composer);
|
|
|
+ $this->composer->getInstallationManager()->addInstaller($installer);
|
|
|
+ } elseif (class_exists($class)) {
|
|
|
+ $plugin = new $class();
|
|
|
+ $this->addPlugin($plugin);
|
|
|
+ $this->registeredPlugins[] = $package->getName();
|
|
|
+ } elseif ($failOnMissingClasses) {
|
|
|
+ throw new \UnexpectedValueException('Plugin '.$package->getName().' could not be initialized, class not found: '.$class);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns the version of the internal composer-plugin-api package.
|
|
|
+ *
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ protected function getPluginApiVersion()
|
|
|
+ {
|
|
|
+ return PluginInterface::PLUGIN_API_VERSION;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* Adds a plugin, activates it and registers it with the event dispatcher
|
|
|
*
|
|
|
* @param PluginInterface $plugin plugin instance
|
|
|
*/
|
|
|
- public function addPlugin(PluginInterface $plugin)
|
|
|
+ private function addPlugin(PluginInterface $plugin)
|
|
|
{
|
|
|
if ($this->io->isDebug()) {
|
|
|
$this->io->writeError('Loading plugin '.get_class($plugin));
|
|
@@ -90,16 +191,6 @@ class PluginManager
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Gets all currently active plugin instances
|
|
|
- *
|
|
|
- * @return array plugins
|
|
|
- */
|
|
|
- public function getPlugins()
|
|
|
- {
|
|
|
- return $this->plugins;
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* Load all plugins and installers from a repository
|
|
|
*
|
|
@@ -111,7 +202,7 @@ class PluginManager
|
|
|
*
|
|
|
* @throws \RuntimeException
|
|
|
*/
|
|
|
- public function loadRepository(RepositoryInterface $repo)
|
|
|
+ private function loadRepository(RepositoryInterface $repo)
|
|
|
{
|
|
|
foreach ($repo->getPackages() as $package) { /** @var PackageInterface $package */
|
|
|
if ($package instanceof AliasPackage) {
|
|
@@ -156,7 +247,7 @@ class PluginManager
|
|
|
*
|
|
|
* @return array Map of package names to packages
|
|
|
*/
|
|
|
- protected function collectDependencies(Pool $pool, array $collected, PackageInterface $package)
|
|
|
+ private function collectDependencies(Pool $pool, array $collected, PackageInterface $package)
|
|
|
{
|
|
|
$requires = array_merge(
|
|
|
$package->getRequires(),
|
|
@@ -184,83 +275,13 @@ class PluginManager
|
|
|
*
|
|
|
* @return PackageInterface|null The found package
|
|
|
*/
|
|
|
- protected function lookupInstalledPackage(Pool $pool, Link $link)
|
|
|
+ private function lookupInstalledPackage(Pool $pool, Link $link)
|
|
|
{
|
|
|
$packages = $pool->whatProvides($link->getTarget(), $link->getConstraint());
|
|
|
|
|
|
return (!empty($packages)) ? $packages[0] : null;
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Register a plugin package, activate it etc.
|
|
|
- *
|
|
|
- * If it's of type composer-installer it is registered as an installer
|
|
|
- * instead for BC
|
|
|
- *
|
|
|
- * @param PackageInterface $package
|
|
|
- * @param bool $failOnMissingClasses By default this silently skips plugins that can not be found, but if set to true it fails with an exception
|
|
|
- *
|
|
|
- * @throws \UnexpectedValueException
|
|
|
- */
|
|
|
- public function registerPackage(PackageInterface $package, $failOnMissingClasses = false)
|
|
|
- {
|
|
|
- $oldInstallerPlugin = ($package->getType() === 'composer-installer');
|
|
|
-
|
|
|
- if (in_array($package->getName(), $this->registeredPlugins)) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- $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']);
|
|
|
-
|
|
|
- $localRepo = $this->composer->getRepositoryManager()->getLocalRepository();
|
|
|
- $globalRepo = $this->globalComposer ? $this->globalComposer->getRepositoryManager()->getLocalRepository() : null;
|
|
|
-
|
|
|
- $pool = new Pool('dev');
|
|
|
- $pool->addRepository($localRepo);
|
|
|
- if ($globalRepo) {
|
|
|
- $pool->addRepository($globalRepo);
|
|
|
- }
|
|
|
-
|
|
|
- $autoloadPackages = array($package->getName() => $package);
|
|
|
- $autoloadPackages = $this->collectDependencies($pool, $autoloadPackages, $package);
|
|
|
-
|
|
|
- $generator = $this->composer->getAutoloadGenerator();
|
|
|
- $autoloads = array();
|
|
|
- foreach ($autoloadPackages as $autoloadPackage) {
|
|
|
- $downloadPath = $this->getInstallPath($autoloadPackage, ($globalRepo && $globalRepo->hasPackage($autoloadPackage)));
|
|
|
- $autoloads[] = array($autoloadPackage, $downloadPath);
|
|
|
- }
|
|
|
-
|
|
|
- $map = $generator->parseAutoloads($autoloads, 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++;
|
|
|
- }
|
|
|
-
|
|
|
- if ($oldInstallerPlugin) {
|
|
|
- $installer = new $class($this->io, $this->composer);
|
|
|
- $this->composer->getInstallationManager()->addInstaller($installer);
|
|
|
- } elseif (class_exists($class)) {
|
|
|
- $plugin = new $class();
|
|
|
- $this->addPlugin($plugin);
|
|
|
- $this->registeredPlugins[] = $package->getName();
|
|
|
- } elseif ($failOnMissingClasses) {
|
|
|
- throw new \UnexpectedValueException('Plugin '.$package->getName().' could not be initialized, class not found: '.$class);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* Retrieves the path a package is installed to.
|
|
|
*
|
|
@@ -269,7 +290,7 @@ class PluginManager
|
|
|
*
|
|
|
* @return string Install path
|
|
|
*/
|
|
|
- public function getInstallPath(PackageInterface $package, $global = false)
|
|
|
+ private function getInstallPath(PackageInterface $package, $global = false)
|
|
|
{
|
|
|
if (!$global) {
|
|
|
return $this->composer->getInstallationManager()->getInstallPath($package);
|
|
@@ -277,14 +298,4 @@ class PluginManager
|
|
|
|
|
|
return $this->globalComposer->getInstallationManager()->getInstallPath($package);
|
|
|
}
|
|
|
-
|
|
|
- /**
|
|
|
- * Returns the version of the internal composer-plugin-api package.
|
|
|
- *
|
|
|
- * @return string
|
|
|
- */
|
|
|
- protected function getPluginApiVersion()
|
|
|
- {
|
|
|
- return PluginInterface::PLUGIN_API_VERSION;
|
|
|
- }
|
|
|
}
|