commit
242c58c789
|
@ -99,7 +99,7 @@ Out of the box, composer supports three types:
|
|||
their installation, but contains no files and will not write anything to the
|
||||
filesystem. As such, it does not require a dist or source key to be
|
||||
installable.
|
||||
- **composer-installer:** A package of type `composer-installer` provides an
|
||||
- **composer-plugin:** A package of type `composer-plugin` may provide an
|
||||
installer for other packages that have a custom type. Read more in the
|
||||
[dedicated article](articles/custom-installers.md).
|
||||
|
||||
|
|
|
@ -29,8 +29,8 @@ An example use-case would be:
|
|||
|
||||
> phpDocumentor features Templates that need to be installed outside of the
|
||||
> default /vendor folder structure. As such they have chosen to adopt the
|
||||
> `phpdocumentor-template` [type][1] and create a Custom Installer to send
|
||||
> these templates to the correct folder.
|
||||
> `phpdocumentor-template` [type][1] and create a plugin providing the Custom
|
||||
> Installer to send these templates to the correct folder.
|
||||
|
||||
An example composer.json of such a template package would be:
|
||||
|
||||
|
@ -38,23 +38,24 @@ An example composer.json of such a template package would be:
|
|||
"name": "phpdocumentor/template-responsive",
|
||||
"type": "phpdocumentor-template",
|
||||
"require": {
|
||||
"phpdocumentor/template-installer": "*"
|
||||
"phpdocumentor/template-installer-plugin": "*"
|
||||
}
|
||||
}
|
||||
|
||||
> **IMPORTANT**: to make sure that the template installer is present at the
|
||||
> time the template package is installed, template packages should require
|
||||
> the installer package.
|
||||
> the plugin package.
|
||||
|
||||
## Creating an Installer
|
||||
|
||||
A Custom Installer is defined as a class that implements the
|
||||
[`Composer\Installer\InstallerInterface`][3] and is contained in a Composer
|
||||
package that has the [type][1] `composer-installer`.
|
||||
[`Composer\Installer\InstallerInterface`][3] and is usually distributed in a
|
||||
Composer Plugin.
|
||||
|
||||
A basic Installer would thus compose of two files:
|
||||
A basic Installer Plugin would thus compose of three files:
|
||||
|
||||
1. the package file: composer.json
|
||||
2. The Plugin class, e.g.: `My\Project\Composer\Plugin.php`, containing a class that implements `Composer\Plugin\PluginInterface`.
|
||||
2. The Installer class, e.g.: `My\Project\Composer\Installer.php`, containing a class that implements `Composer\Installer\InstallerInterface`.
|
||||
|
||||
### composer.json
|
||||
|
@ -62,35 +63,57 @@ A basic Installer would thus compose of two files:
|
|||
The package file is the same as any other package file but with the following
|
||||
requirements:
|
||||
|
||||
1. the [type][1] attribute must be `composer-installer`.
|
||||
1. the [type][1] attribute must be `composer-plugin`.
|
||||
2. the [extra][2] attribute must contain an element `class` defining the
|
||||
class name of the installer (including namespace). If a package contains
|
||||
multiple installers this can be array of class names.
|
||||
class name of the plugin (including namespace). If a package contains
|
||||
multiple plugins this can be array of class names.
|
||||
|
||||
Example:
|
||||
|
||||
{
|
||||
"name": "phpdocumentor/template-installer",
|
||||
"type": "composer-installer",
|
||||
"name": "phpdocumentor/template-installer-plugin",
|
||||
"type": "composer-installer-plugin",
|
||||
"license": "MIT",
|
||||
"autoload": {
|
||||
"psr-0": {"phpDocumentor\\Composer": "src/"}
|
||||
},
|
||||
"extra": {
|
||||
"class": "phpDocumentor\\Composer\\TemplateInstaller"
|
||||
"class": "phpDocumentor\\Composer\\TemplateInstallerPlugin"
|
||||
}
|
||||
}
|
||||
|
||||
### The Plugin class
|
||||
|
||||
The class defining the Composer plugin must implement the
|
||||
[`Composer\Plugin\PluginInterface`][3]. It can then register the Custom
|
||||
Installer in its `activate()` method.
|
||||
|
||||
The class may be placed in any location and have any name, as long as it is
|
||||
autoloadable and matches the `extra.class` element in the package definition.
|
||||
|
||||
Example:
|
||||
|
||||
namespace phpDocumentor\Composer;
|
||||
|
||||
use Composer\Composer;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Plugin\PluginInterface
|
||||
|
||||
class TemplateInstallerPlugin implements PluginInterface
|
||||
{
|
||||
public function activate(Composer $composer, IOInterface $io)
|
||||
{
|
||||
$installer = new TemplateInstaller($io, $composer);
|
||||
$composer->getInstallationManager()->addInstaller($installer);
|
||||
}
|
||||
}
|
||||
|
||||
### The Custom Installer class
|
||||
|
||||
The class that executes the custom installation should implement the
|
||||
[`Composer\Installer\InstallerInterface`][3] (or extend another installer that
|
||||
implements that interface).
|
||||
|
||||
The class may be placed in any location and have any name, as long as it is
|
||||
autoloadable and matches the `extra.class` element in the package definition.
|
||||
It will also define the [type][1] string as it will be recognized by packages
|
||||
that will use this installer in the `supports()` method.
|
||||
[`Composer\Installer\InstallerInterface`][4] (or extend another installer that
|
||||
implements that interface). It defines the [type][1] string as it will be
|
||||
recognized by packages that will use this installer in the `supports()` method.
|
||||
|
||||
> **NOTE**: _choose your [type][1] name carefully, it is recommended to follow
|
||||
> the format: `vendor-type`_. For example: `phpdocumentor-template`.
|
||||
|
@ -146,7 +169,7 @@ Example:
|
|||
}
|
||||
|
||||
The example demonstrates that it is quite simple to extend the
|
||||
[`Composer\Installer\LibraryInstaller`][4] class to strip a prefix
|
||||
[`Composer\Installer\LibraryInstaller`][5] class to strip a prefix
|
||||
(`phpdocumentor/template-`) and use the remaining part to assemble a completely
|
||||
different installation path.
|
||||
|
||||
|
@ -155,5 +178,6 @@ different installation path.
|
|||
|
||||
[1]: ../04-schema.md#type
|
||||
[2]: ../04-schema.md#extra
|
||||
[3]: https://github.com/composer/composer/blob/master/src/Composer/Installer/InstallerInterface.php
|
||||
[4]: https://github.com/composer/composer/blob/master/src/Composer/Installer/LibraryInstaller.php
|
||||
[3]: https://github.com/composer/composer/blob/master/src/Composer/Plugin/PluginInterface.php
|
||||
[4]: https://github.com/composer/composer/blob/master/src/Composer/Installer/InstallerInterface.php
|
||||
[5]: https://github.com/composer/composer/blob/master/src/Composer/Installer/LibraryInstaller.php
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
<!--
|
||||
tagline: Modify and extend Composer's functionality
|
||||
-->
|
||||
|
||||
# Setting up and using plugins
|
||||
|
||||
## Synopsis
|
||||
|
||||
You may wish to alter or expand Composer's functionality with your own. For
|
||||
example if your environment poses special requirements on the behaviour of
|
||||
Composer which do not apply to the majority of its users or if you wish to
|
||||
accomplish something with composer in a way that is not desired by most users.
|
||||
|
||||
In these cases you could consider creating a plugin to handle your
|
||||
specific logic.
|
||||
|
||||
## Creating a Plugin
|
||||
|
||||
A plugin is a regular composer package which ships its code as part of the
|
||||
package and may also depend on further packages.
|
||||
|
||||
### Plugin Package
|
||||
|
||||
The package file is the same as any other package file but with the following
|
||||
requirements:
|
||||
|
||||
1. the [type][1] attribute must be `composer-plugin`.
|
||||
2. the [extra][2] attribute must contain an element `class` defining the
|
||||
class name of the plugin (including namespace). If a package contains
|
||||
multiple plugins this can be array of class names.
|
||||
|
||||
Additionally you must require the special package called `composer-plugin-api`
|
||||
to define which composer API versions your plugin is compatible with. The
|
||||
current composer plugin API version is 1.0.0.
|
||||
|
||||
For example
|
||||
|
||||
{
|
||||
"name": "my/plugin-package",
|
||||
"type": "composer-plugin",
|
||||
"require": {
|
||||
"composer-plugin-api": "1.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
### Plugin Class
|
||||
|
||||
Every plugin has to supply a class which implements the
|
||||
[`Composer\Plugin\PluginInterface`][3]. The `activate()` method of the plugin
|
||||
is called after the plugin is loaded and receives an instance of
|
||||
[`Composer\Composer`][4] as well as an instance of
|
||||
[`Composer\IO\IOInterface`][5]. Using these two objects all configuration can
|
||||
be read and all internal objects and state can be manipulated as desired.
|
||||
|
||||
Example:
|
||||
|
||||
namespace phpDocumentor\Composer;
|
||||
|
||||
use Composer\Composer;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Plugin\PluginInterface
|
||||
|
||||
class TemplateInstallerPlugin implements PluginInterface
|
||||
{
|
||||
public function activate(Composer $composer, IOInterface $io)
|
||||
{
|
||||
$installer = new TemplateInstaller($io, $composer);
|
||||
$composer->getInstallationManager()->addInstaller($installer);
|
||||
}
|
||||
}
|
||||
|
||||
## Event Handler
|
||||
|
||||
Furthermore plugins may implement the
|
||||
[`Composer\EventDispatcher\EventSubscriberInterface`][6] in order to have its
|
||||
event handlers automatically registered with the `EventDispatcher` when the
|
||||
plugin is loaded.
|
||||
|
||||
The events available for plugins are:
|
||||
|
||||
* **COMMAND**, is called at the beginning of all commands that load plugins.
|
||||
It provides you with access to the input and output objects of the program.
|
||||
* **PRE_FILE_DOWNLOAD**, is triggered before files are downloaded and allows
|
||||
you to manipulate the `RemoteFilesystem` object prior to downloading files
|
||||
based on the URL to be downloaded.
|
||||
|
||||
Example:
|
||||
|
||||
namespace Naderman\Composer\AWS;
|
||||
|
||||
use Composer\Composer;
|
||||
use Composer\EventDispatcher\EventSubscriberInterface;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Plugin\PluginInterface;
|
||||
use Composer\Plugin\PluginEvents;
|
||||
use Composer\Plugin\PreFileDownloadEvent;
|
||||
|
||||
class AwsPlugin implements PluginInterface, EventSubscriberInterface
|
||||
{
|
||||
protected $composer;
|
||||
protected $io;
|
||||
|
||||
public function activate(Composer $composer, IOInterface $io)
|
||||
{
|
||||
$this->composer = $composer;
|
||||
$this->io = $io;
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
PluginEvents::PRE_FILE_DOWNLOAD => array(
|
||||
array('onPreFileDownload', 0)
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public function onPreFileDownload(PreFileDownloadEvent $event)
|
||||
{
|
||||
$protocol = parse_url($event->getProcessedUrl(), PHP_URL_SCHEME);
|
||||
|
||||
if ($protocol === 's3') {
|
||||
$awsClient = new AwsClient($this->io, $this->composer->getConfig());
|
||||
$s3RemoteFilesystem = new S3RemoteFilesystem($this->io, $event->getRemoteFilesystem()->getOptions(), $awsClient);
|
||||
$event->setRemoteFilesystem($s3RemoteFilesystem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
## Using Plugins
|
||||
|
||||
Plugin packages are automatically loaded as soon as they are installed and will
|
||||
be loaded when composer starts up if they are found in the current project's
|
||||
list of installed packages. Additionally all plugin packages installed in the
|
||||
`COMPOSER_HOME` directory using the composer global command are loaded before
|
||||
local project plugins are loaded.
|
||||
|
||||
> You may pass the `--no-plugins` option to composer commands to disable all
|
||||
> installed commands. This may be particularly helpful if any of the plugins
|
||||
> causes errors and you wish to update or uninstall it.
|
||||
|
||||
[1]: ../04-schema.md#type
|
||||
[2]: ../04-schema.md#extra
|
||||
[3]: https://github.com/composer/composer/blob/master/src/Composer/Plugin/PluginInterface.php
|
||||
[4]: https://github.com/composer/composer/blob/master/src/Composer/Composer.php
|
||||
[5]: https://github.com/composer/composer/blob/master/src/Composer/IO/IOInterface.php
|
||||
[6]: https://github.com/composer/composer/blob/master/src/Composer/EventDispatcher/EventSubscriberInterface.php
|
|
@ -9,7 +9,7 @@
|
|||
"required": true
|
||||
},
|
||||
"type": {
|
||||
"description": "Package type, either 'library' for common packages, 'composer-installer' for custom installers, 'metapackage' for empty packages, or a custom type ([a-z0-9-]+) defined by whatever project this package applies to.",
|
||||
"description": "Package type, either 'library' for common packages, 'composer-plugin' for plugins, 'metapackage' for empty packages, or a custom type ([a-z0-9-]+) defined by whatever project this package applies to.",
|
||||
"type": "string"
|
||||
},
|
||||
"target-dir": {
|
||||
|
@ -180,7 +180,7 @@
|
|||
},
|
||||
"extra": {
|
||||
"type": ["object", "array"],
|
||||
"description": "Arbitrary extra data that can be used by custom installers, for example, package of type composer-installer must have a 'class' key defining the installer class name.",
|
||||
"description": "Arbitrary extra data that can be used by plugins, for example, package of type composer-plugin may have a 'class' key defining an installer class name.",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"autoload": {
|
||||
|
|
|
@ -13,12 +13,12 @@
|
|||
namespace Composer\Autoload;
|
||||
|
||||
use Composer\Config;
|
||||
use Composer\EventDispatcher\EventDispatcher;
|
||||
use Composer\Installer\InstallationManager;
|
||||
use Composer\Package\AliasPackage;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Repository\InstalledRepositoryInterface;
|
||||
use Composer\Util\Filesystem;
|
||||
use Composer\Script\EventDispatcher;
|
||||
use Composer\Script\ScriptEvents;
|
||||
|
||||
/**
|
||||
|
@ -39,7 +39,7 @@ class AutoloadGenerator
|
|||
|
||||
public function dump(Config $config, InstalledRepositoryInterface $localRepo, PackageInterface $mainPackage, InstallationManager $installationManager, $targetDir, $scanPsr0Packages = false, $suffix = '')
|
||||
{
|
||||
$this->eventDispatcher->dispatch(ScriptEvents::PRE_AUTOLOAD_DUMP);
|
||||
$this->eventDispatcher->dispatchScript(ScriptEvents::PRE_AUTOLOAD_DUMP);
|
||||
|
||||
$filesystem = new Filesystem();
|
||||
$filesystem->ensureDirectoryExists($config->get('vendor-dir'));
|
||||
|
@ -191,7 +191,7 @@ EOF;
|
|||
fclose($targetLoader);
|
||||
unset($sourceLoader, $targetLoader);
|
||||
|
||||
$this->eventDispatcher->dispatch(ScriptEvents::POST_AUTOLOAD_DUMP);
|
||||
$this->eventDispatcher->dispatchScript(ScriptEvents::POST_AUTOLOAD_DUMP);
|
||||
}
|
||||
|
||||
public function buildPackageMap(InstallationManager $installationManager, PackageInterface $mainPackage, array $packages)
|
||||
|
|
|
@ -38,16 +38,17 @@ abstract class Command extends BaseCommand
|
|||
|
||||
/**
|
||||
* @param bool $required
|
||||
* @param bool $disablePlugins
|
||||
* @throws \RuntimeException
|
||||
* @return Composer
|
||||
*/
|
||||
public function getComposer($required = true)
|
||||
public function getComposer($required = true, $disablePlugins = false)
|
||||
{
|
||||
if (null === $this->composer) {
|
||||
$application = $this->getApplication();
|
||||
if ($application instanceof Application) {
|
||||
/* @var $application Application */
|
||||
$this->composer = $application->getComposer($required);
|
||||
$this->composer = $application->getComposer($required, $disablePlugins);
|
||||
} elseif ($required) {
|
||||
throw new \RuntimeException(
|
||||
'Could not create a Composer\Composer instance, you must inject '.
|
||||
|
|
|
@ -44,6 +44,7 @@ use Composer\Package\Version\VersionParser;
|
|||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @author Tobias Munk <schmunk@usrbin.de>
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
*/
|
||||
class CreateProjectCommand extends Command
|
||||
{
|
||||
|
@ -62,7 +63,8 @@ class CreateProjectCommand extends Command
|
|||
new InputOption('repository-url', null, InputOption::VALUE_REQUIRED, 'Pick a different repository url to look for the package.'),
|
||||
new InputOption('dev', null, InputOption::VALUE_NONE, 'Enables installation of require-dev packages (enabled by default, only present for BC).'),
|
||||
new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables installation of require-dev packages.'),
|
||||
new InputOption('no-custom-installers', null, InputOption::VALUE_NONE, 'Whether to disable custom installers.'),
|
||||
new InputOption('no-plugins', null, InputOption::VALUE_NONE, 'Whether to disable plugins.'),
|
||||
new InputOption('no-custom-installers', null, InputOption::VALUE_NONE, 'DEPRECATED: Use no-plugins instead.'),
|
||||
new InputOption('no-scripts', null, InputOption::VALUE_NONE, 'Whether to prevent execution of all defined scripts in the root package.'),
|
||||
new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'),
|
||||
new InputOption('keep-vcs', null, InputOption::VALUE_NONE, 'Whether to prevent deletion vcs folder.'),
|
||||
|
@ -116,6 +118,11 @@ EOT
|
|||
$preferDist = $input->getOption('prefer-dist');
|
||||
}
|
||||
|
||||
if ($input->getOption('no-custom-installers')) {
|
||||
$output->writeln('<warning>You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.</warning>');
|
||||
$input->setOption('no-plugins', true);
|
||||
}
|
||||
|
||||
return $this->installProject(
|
||||
$this->getIO(),
|
||||
$config,
|
||||
|
@ -127,24 +134,24 @@ EOT
|
|||
$preferDist,
|
||||
!$input->getOption('no-dev'),
|
||||
$input->getOption('repository-url'),
|
||||
$input->getOption('no-custom-installers'),
|
||||
$input->getOption('no-plugins'),
|
||||
$input->getOption('no-scripts'),
|
||||
$input->getOption('keep-vcs'),
|
||||
$input->getOption('no-progress')
|
||||
);
|
||||
}
|
||||
|
||||
public function installProject(IOInterface $io, $config, $packageName, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, $repositoryUrl = null, $disableCustomInstallers = false, $noScripts = false, $keepVcs = false, $noProgress = false)
|
||||
public function installProject(IOInterface $io, $config, $packageName, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, $repositoryUrl = null, $disablePlugins = false, $noScripts = false, $keepVcs = false, $noProgress = false)
|
||||
{
|
||||
$oldCwd = getcwd();
|
||||
|
||||
if ($packageName !== null) {
|
||||
$installedFromVcs = $this->installRootPackage($io, $config, $packageName, $directory, $packageVersion, $stability, $preferSource, $preferDist, $installDevPackages, $repositoryUrl, $disableCustomInstallers, $noScripts, $keepVcs, $noProgress);
|
||||
$installedFromVcs = $this->installRootPackage($io, $config, $packageName, $directory, $packageVersion, $stability, $preferSource, $preferDist, $installDevPackages, $repositoryUrl, $disablePlugins, $noScripts, $keepVcs, $noProgress);
|
||||
} else {
|
||||
$installedFromVcs = false;
|
||||
}
|
||||
|
||||
$composer = Factory::create($io);
|
||||
$composer = Factory::create($io, null, $disablePlugins);
|
||||
|
||||
if ($noScripts === false) {
|
||||
// dispatch event
|
||||
|
@ -158,8 +165,8 @@ EOT
|
|||
->setDevMode($installDevPackages)
|
||||
->setRunScripts( ! $noScripts);
|
||||
|
||||
if ($disableCustomInstallers) {
|
||||
$installer->disableCustomInstallers();
|
||||
if ($disablePlugins) {
|
||||
$installer->disablePlugins();
|
||||
}
|
||||
|
||||
if (!$installer->run()) {
|
||||
|
@ -226,7 +233,7 @@ EOT
|
|||
return 0;
|
||||
}
|
||||
|
||||
protected function installRootPackage(IOInterface $io, $config, $packageName, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, $repositoryUrl = null, $disableCustomInstallers = false, $noScripts = false, $keepVcs = false, $noProgress = false)
|
||||
protected function installRootPackage(IOInterface $io, $config, $packageName, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, $repositoryUrl = null, $disablePlugins = false, $noScripts = false, $keepVcs = false, $noProgress = false)
|
||||
{
|
||||
$stability = strtolower($stability);
|
||||
if ($stability === 'rc') {
|
||||
|
@ -285,8 +292,8 @@ EOT
|
|||
|
||||
$io->write('<info>Installing ' . $package->getName() . ' (' . VersionParser::formatVersion($package, false) . ')</info>');
|
||||
|
||||
if ($disableCustomInstallers) {
|
||||
$io->write('<info>Custom installers have been disabled.</info>');
|
||||
if ($disablePlugins) {
|
||||
$io->write('<info>Plugins have been disabled.</info>');
|
||||
}
|
||||
|
||||
if (0 === strpos($package->getPrettyVersion(), 'dev-') && in_array($package->getSourceType(), array('git', 'hg'))) {
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
namespace Composer\Command;
|
||||
|
||||
use Composer\DependencyResolver\Pool;
|
||||
use Composer\Plugin\CommandEvent;
|
||||
use Composer\Plugin\PluginEvents;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
@ -50,7 +52,12 @@ EOT
|
|||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$repo = $this->getComposer()->getRepositoryManager()->getLocalRepository();
|
||||
$composer = $this->getComposer();
|
||||
|
||||
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'depends', $input, $output);
|
||||
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
|
||||
|
||||
$repo = $composer->getRepositoryManager()->getLocalRepository();
|
||||
$needle = $input->getArgument('package');
|
||||
|
||||
$pool = new Pool();
|
||||
|
|
|
@ -15,6 +15,8 @@ namespace Composer\Command;
|
|||
use Composer\Composer;
|
||||
use Composer\Factory;
|
||||
use Composer\Downloader\TransportException;
|
||||
use Composer\Plugin\CommandEvent;
|
||||
use Composer\Plugin\PluginEvents;
|
||||
use Composer\Util\ConfigValidator;
|
||||
use Composer\Util\RemoteFilesystem;
|
||||
use Composer\Util\StreamContextFactory;
|
||||
|
@ -64,6 +66,9 @@ EOT
|
|||
|
||||
$composer = $this->getComposer(false);
|
||||
if ($composer) {
|
||||
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'diagnose', $input, $output);
|
||||
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
|
||||
|
||||
$output->write('Checking composer.json: ');
|
||||
$this->outputResult($output, $this->checkComposerSchema());
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
namespace Composer\Command;
|
||||
|
||||
use Composer\Plugin\CommandEvent;
|
||||
use Composer\Plugin\PluginEvents;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
@ -42,6 +44,10 @@ EOT
|
|||
$output->writeln('<info>Generating autoload files</info>');
|
||||
|
||||
$composer = $this->getComposer();
|
||||
|
||||
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'dump-autoload', $input, $output);
|
||||
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
|
||||
|
||||
$installationManager = $composer->getInstallationManager();
|
||||
$localRepo = $composer->getRepositoryManager()->getLocalRepository();
|
||||
$package = $composer->getPackage();
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
namespace Composer\Command;
|
||||
|
||||
use Composer\Installer;
|
||||
use Composer\Plugin\CommandEvent;
|
||||
use Composer\Plugin\PluginEvents;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
@ -21,6 +23,7 @@ use Symfony\Component\Console\Output\OutputInterface;
|
|||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @author Ryan Weaver <ryan@knplabs.com>
|
||||
* @author Konstantin Kudryashov <ever.zet@gmail.com>
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
*/
|
||||
class InstallCommand extends Command
|
||||
{
|
||||
|
@ -35,7 +38,8 @@ class InstallCommand extends Command
|
|||
new InputOption('dry-run', null, InputOption::VALUE_NONE, 'Outputs the operations but will not execute anything (implicitly enables --verbose).'),
|
||||
new InputOption('dev', null, InputOption::VALUE_NONE, 'Enables installation of require-dev packages (enabled by default, only present for BC).'),
|
||||
new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables installation of require-dev packages.'),
|
||||
new InputOption('no-custom-installers', null, InputOption::VALUE_NONE, 'Disables all custom installers.'),
|
||||
new InputOption('no-plugins', null, InputOption::VALUE_NONE, 'Disables all plugins.'),
|
||||
new InputOption('no-custom-installers', null, InputOption::VALUE_NONE, 'DEPRECATED: Use no-plugins instead.'),
|
||||
new InputOption('no-scripts', null, InputOption::VALUE_NONE, 'Skips the execution of all scripts defined in composer.json file.'),
|
||||
new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'),
|
||||
new InputOption('verbose', 'v|vv|vvv', InputOption::VALUE_NONE, 'Shows more details including new commits pulled in when updating packages.'),
|
||||
|
@ -56,9 +60,18 @@ EOT
|
|||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$composer = $this->getComposer();
|
||||
if ($input->getOption('no-custom-installers')) {
|
||||
$output->writeln('<warning>You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.</warning>');
|
||||
$input->setOption('no-plugins', true);
|
||||
}
|
||||
|
||||
$composer = $this->getComposer(true, $input->getOption('no-plugins'));
|
||||
$composer->getDownloadManager()->setOutputProgress(!$input->getOption('no-progress'));
|
||||
$io = $this->getIO();
|
||||
|
||||
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'install', $input, $output);
|
||||
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
|
||||
|
||||
$install = Installer::create($io, $composer);
|
||||
|
||||
$preferSource = false;
|
||||
|
@ -90,8 +103,8 @@ EOT
|
|||
->setOptimizeAutoloader($input->getOption('optimize-autoloader'))
|
||||
;
|
||||
|
||||
if ($input->getOption('no-custom-installers')) {
|
||||
$install->disableCustomInstallers();
|
||||
if ($input->getOption('no-plugins')) {
|
||||
$install->disablePlugins();
|
||||
}
|
||||
|
||||
return $install->run() ? 0 : 1;
|
||||
|
|
|
@ -15,6 +15,8 @@ namespace Composer\Command;
|
|||
use Composer\Package\PackageInterface;
|
||||
use Composer\Json\JsonFile;
|
||||
use Composer\Package\Version\VersionParser;
|
||||
use Composer\Plugin\CommandEvent;
|
||||
use Composer\Plugin\PluginEvents;
|
||||
use Symfony\Component\Console\Helper\TableHelper;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
|
@ -46,6 +48,10 @@ EOT
|
|||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$composer = $this->getComposer();
|
||||
|
||||
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'licenses', $input, $output);
|
||||
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
|
||||
|
||||
$root = $composer->getPackage();
|
||||
$repo = $composer->getRepositoryManager()->getLocalRepository();
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ use Composer\Installer;
|
|||
use Composer\Json\JsonFile;
|
||||
use Composer\Json\JsonManipulator;
|
||||
use Composer\Package\Version\VersionParser;
|
||||
use Composer\Plugin\CommandEvent;
|
||||
use Composer\Plugin\PluginEvents;
|
||||
|
||||
/**
|
||||
* @author Jérémy Romey <jeremy@free-agent.fr>
|
||||
|
@ -106,6 +108,10 @@ EOT
|
|||
$composer = $this->getComposer();
|
||||
$composer->getDownloadManager()->setOutputProgress(!$input->getOption('no-progress'));
|
||||
$io = $this->getIO();
|
||||
|
||||
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'require', $input, $output);
|
||||
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
|
||||
|
||||
$install = Installer::create($io, $composer);
|
||||
|
||||
$install
|
||||
|
|
|
@ -20,6 +20,8 @@ use Composer\Repository\CompositeRepository;
|
|||
use Composer\Repository\PlatformRepository;
|
||||
use Composer\Repository\RepositoryInterface;
|
||||
use Composer\Factory;
|
||||
use Composer\Plugin\CommandEvent;
|
||||
use Composer\Plugin\PluginEvents;
|
||||
|
||||
/**
|
||||
* @author Robert Schönthal <seroscho@googlemail.com>
|
||||
|
@ -65,6 +67,11 @@ EOT
|
|||
$repos = new CompositeRepository(array_merge(array($installedRepo), $defaultRepos));
|
||||
}
|
||||
|
||||
if ($composer) {
|
||||
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'search', $input, $output);
|
||||
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
|
||||
}
|
||||
|
||||
$onlyName = $input->getOption('only-name');
|
||||
|
||||
$flags = $onlyName ? RepositoryInterface::SEARCH_NAME : RepositoryInterface::SEARCH_FULLTEXT;
|
||||
|
|
|
@ -18,6 +18,8 @@ use Composer\DependencyResolver\DefaultPolicy;
|
|||
use Composer\Factory;
|
||||
use Composer\Package\CompletePackageInterface;
|
||||
use Composer\Package\Version\VersionParser;
|
||||
use Composer\Plugin\CommandEvent;
|
||||
use Composer\Plugin\PluginEvents;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
@ -94,6 +96,11 @@ EOT
|
|||
$repos = new CompositeRepository(array_merge(array($installedRepo), $defaultRepos));
|
||||
}
|
||||
|
||||
if ($composer) {
|
||||
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'show', $input, $output);
|
||||
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
|
||||
}
|
||||
|
||||
// show single package or single version
|
||||
if ($input->getArgument('package') || !empty($package)) {
|
||||
$versions = array();
|
||||
|
|
|
@ -17,6 +17,8 @@ use Symfony\Component\Console\Input\InputOption;
|
|||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Composer\Downloader\ChangeReportInterface;
|
||||
use Composer\Downloader\VcsDownloader;
|
||||
use Composer\Plugin\CommandEvent;
|
||||
use Composer\Plugin\PluginEvents;
|
||||
use Composer\Script\ScriptEvents;
|
||||
|
||||
/**
|
||||
|
@ -46,6 +48,10 @@ EOT
|
|||
{
|
||||
// init repos
|
||||
$composer = $this->getComposer();
|
||||
|
||||
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'status', $input, $output);
|
||||
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
|
||||
|
||||
$installedRepo = $composer->getRepositoryManager()->getLocalRepository();
|
||||
|
||||
$dm = $composer->getDownloadManager();
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
namespace Composer\Command;
|
||||
|
||||
use Composer\Installer;
|
||||
use Composer\Plugin\CommandEvent;
|
||||
use Composer\Plugin\PluginEvents;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
|
@ -20,6 +22,7 @@ use Symfony\Component\Console\Output\OutputInterface;
|
|||
|
||||
/**
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
*/
|
||||
class UpdateCommand extends Command
|
||||
{
|
||||
|
@ -36,7 +39,8 @@ class UpdateCommand extends Command
|
|||
new InputOption('dev', null, InputOption::VALUE_NONE, 'Enables installation of require-dev packages (enabled by default, only present for BC).'),
|
||||
new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables installation of require-dev packages.'),
|
||||
new InputOption('lock', null, InputOption::VALUE_NONE, 'Only updates the lock file hash to suppress warning about the lock file being out of date.'),
|
||||
new InputOption('no-custom-installers', null, InputOption::VALUE_NONE, 'Disables all custom installers.'),
|
||||
new InputOption('no-plugins', null, InputOption::VALUE_NONE, 'Disables all plugins.'),
|
||||
new InputOption('no-custom-installers', null, InputOption::VALUE_NONE, 'DEPRECATED: Use no-plugins instead.'),
|
||||
new InputOption('no-scripts', null, InputOption::VALUE_NONE, 'Skips the execution of all scripts defined in composer.json file.'),
|
||||
new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'),
|
||||
new InputOption('verbose', 'v|vv|vvv', InputOption::VALUE_NONE, 'Shows more details including new commits pulled in when updating packages.'),
|
||||
|
@ -60,9 +64,18 @@ EOT
|
|||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$composer = $this->getComposer();
|
||||
if ($input->getOption('no-custom-installers')) {
|
||||
$output->writeln('<warning>You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.</warning>');
|
||||
$input->setOption('no-plugins', true);
|
||||
}
|
||||
|
||||
$composer = $this->getComposer(true, $input->getOption('no-plugins'));
|
||||
$composer->getDownloadManager()->setOutputProgress(!$input->getOption('no-progress'));
|
||||
$io = $this->getIO();
|
||||
|
||||
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'update', $input, $output);
|
||||
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
|
||||
|
||||
$install = Installer::create($io, $composer);
|
||||
|
||||
$preferSource = false;
|
||||
|
@ -96,8 +109,8 @@ EOT
|
|||
->setUpdateWhitelist($input->getOption('lock') ? array('lock') : $input->getArgument('packages'))
|
||||
;
|
||||
|
||||
if ($input->getOption('no-custom-installers')) {
|
||||
$install->disableCustomInstallers();
|
||||
if ($input->getOption('no-plugins')) {
|
||||
$install->disablePlugins();
|
||||
}
|
||||
|
||||
return $install->run() ? 0 : 1;
|
||||
|
|
|
@ -16,13 +16,15 @@ use Composer\Package\RootPackageInterface;
|
|||
use Composer\Package\Locker;
|
||||
use Composer\Repository\RepositoryManager;
|
||||
use Composer\Installer\InstallationManager;
|
||||
use Composer\Plugin\PluginManager;
|
||||
use Composer\Downloader\DownloadManager;
|
||||
use Composer\Script\EventDispatcher;
|
||||
use Composer\EventDispatcher\EventDispatcher;
|
||||
use Composer\Autoload\AutoloadGenerator;
|
||||
|
||||
/**
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @author Konstantin Kudryashiv <ever.zet@gmail.com>
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
*/
|
||||
class Composer
|
||||
{
|
||||
|
@ -53,13 +55,18 @@ class Composer
|
|||
*/
|
||||
private $installationManager;
|
||||
|
||||
/**
|
||||
* @var Plugin\PluginManager
|
||||
*/
|
||||
private $pluginManager;
|
||||
|
||||
/**
|
||||
* @var Config
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* @var Script\EventDispatcher
|
||||
* @var EventDispatcher\EventDispatcher
|
||||
*/
|
||||
private $eventDispatcher;
|
||||
|
||||
|
@ -166,7 +173,23 @@ class Composer
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Script\EventDispatcher $eventDispatcher
|
||||
* @param Plugin\PluginManager $manager
|
||||
*/
|
||||
public function setPluginManager(PluginManager $manager)
|
||||
{
|
||||
$this->pluginManager = $manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Plugin\PluginManager
|
||||
*/
|
||||
public function getPluginManager()
|
||||
{
|
||||
return $this->pluginManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param EventDispatcher\EventDispatcher $eventDispatcher
|
||||
*/
|
||||
public function setEventDispatcher(EventDispatcher $eventDispatcher)
|
||||
{
|
||||
|
@ -174,7 +197,7 @@ class Composer
|
|||
}
|
||||
|
||||
/**
|
||||
* @return Script\EventDispatcher
|
||||
* @return EventDispatcher\EventDispatcher
|
||||
*/
|
||||
public function getEventDispatcher()
|
||||
{
|
||||
|
|
|
@ -165,14 +165,15 @@ class Application extends BaseApplication
|
|||
|
||||
/**
|
||||
* @param bool $required
|
||||
* @param bool $disablePlugins
|
||||
* @throws JsonValidationException
|
||||
* @return \Composer\Composer
|
||||
*/
|
||||
public function getComposer($required = true)
|
||||
public function getComposer($required = true, $disablePlugins = false)
|
||||
{
|
||||
if (null === $this->composer) {
|
||||
try {
|
||||
$this->composer = Factory::create($this->io);
|
||||
$this->composer = Factory::create($this->io, null, $disablePlugins);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
if ($required) {
|
||||
$this->io->write($e->getMessage());
|
||||
|
|
|
@ -17,6 +17,9 @@ use Composer\Cache;
|
|||
use Composer\IO\IOInterface;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Package\Version\VersionParser;
|
||||
use Composer\Plugin\PluginEvents;
|
||||
use Composer\Plugin\PreFileDownloadEvent;
|
||||
use Composer\EventDispatcher\EventDispatcher;
|
||||
use Composer\Util\Filesystem;
|
||||
use Composer\Util\GitHub;
|
||||
use Composer\Util\RemoteFilesystem;
|
||||
|
@ -27,6 +30,7 @@ use Composer\Util\RemoteFilesystem;
|
|||
* @author Kirill chEbba Chebunin <iam@chebba.org>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @author François Pluchino <francois.pluchino@opendisplay.com>
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
*/
|
||||
class FileDownloader implements DownloaderInterface
|
||||
{
|
||||
|
@ -43,14 +47,16 @@ class FileDownloader implements DownloaderInterface
|
|||
*
|
||||
* @param IOInterface $io The IO instance
|
||||
* @param Config $config The config
|
||||
* @param EventDispatcher $eventDispatcher The event dispatcher
|
||||
* @param Cache $cache Optional cache instance
|
||||
* @param RemoteFilesystem $rfs The remote filesystem
|
||||
* @param Filesystem $filesystem The filesystem
|
||||
*/
|
||||
public function __construct(IOInterface $io, Config $config, Cache $cache = null, RemoteFilesystem $rfs = null, Filesystem $filesystem = null)
|
||||
public function __construct(IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null, Cache $cache = null, RemoteFilesystem $rfs = null, Filesystem $filesystem = null)
|
||||
{
|
||||
$this->io = $io;
|
||||
$this->config = $config;
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
$this->rfs = $rfs ?: new RemoteFilesystem($io);
|
||||
$this->filesystem = $filesystem ?: new Filesystem();
|
||||
$this->cache = $cache;
|
||||
|
@ -89,6 +95,12 @@ class FileDownloader implements DownloaderInterface
|
|||
$processedUrl = $this->processUrl($package, $url);
|
||||
$hostname = parse_url($processedUrl, PHP_URL_HOST);
|
||||
|
||||
$preFileDownloadEvent = new PreFileDownloadEvent(PluginEvents::PRE_FILE_DOWNLOAD, $this->rfs, $processedUrl);
|
||||
if ($this->eventDispatcher) {
|
||||
$this->eventDispatcher->dispatch($preFileDownloadEvent->getName(), $preFileDownloadEvent);
|
||||
}
|
||||
$rfs = $preFileDownloadEvent->getRemoteFilesystem();
|
||||
|
||||
if (strpos($hostname, '.github.com') === (strlen($hostname) - 11)) {
|
||||
$hostname = 'github.com';
|
||||
}
|
||||
|
@ -104,7 +116,7 @@ class FileDownloader implements DownloaderInterface
|
|||
$retries = 3;
|
||||
while ($retries--) {
|
||||
try {
|
||||
$this->rfs->copy($hostname, $processedUrl, $fileName, $this->outputProgress);
|
||||
$rfs->copy($hostname, $processedUrl, $fileName, $this->outputProgress);
|
||||
break;
|
||||
} catch (TransportException $e) {
|
||||
// if we got an http response with a proper code, then requesting again will probably not help, abort
|
||||
|
@ -125,15 +137,18 @@ class FileDownloader implements DownloaderInterface
|
|||
$this->io->write(' Loading from cache');
|
||||
}
|
||||
} catch (TransportException $e) {
|
||||
if (in_array($e->getCode(), array(404, 403)) && 'github.com' === $hostname && !$this->io->hasAuthentication($hostname)) {
|
||||
if (!in_array($e->getCode(), array(404, 403, 412))) {
|
||||
throw $e;
|
||||
}
|
||||
if ('github.com' === $hostname && !$this->io->hasAuthentication($hostname)) {
|
||||
$message = "\n".'Could not fetch '.$processedUrl.', enter your GitHub credentials '.($e->getCode() === 404 ? 'to access private repos' : 'to go over the API rate limit');
|
||||
$gitHubUtil = new GitHub($this->io, $this->config, null, $this->rfs);
|
||||
$gitHubUtil = new GitHub($this->io, $this->config, null, $rfs);
|
||||
if (!$gitHubUtil->authorizeOAuth($hostname)
|
||||
&& (!$this->io->isInteractive() || !$gitHubUtil->authorizeOAuthInteractively($hostname, $message))
|
||||
) {
|
||||
throw $e;
|
||||
}
|
||||
$this->rfs->copy($hostname, $processedUrl, $fileName, $this->outputProgress);
|
||||
$rfs->copy($hostname, $processedUrl, $fileName, $this->outputProgress);
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ namespace Composer\Downloader;
|
|||
|
||||
use Composer\Config;
|
||||
use Composer\Cache;
|
||||
use Composer\EventDispatcher\EventDispatcher;
|
||||
use Composer\Util\ProcessExecutor;
|
||||
use Composer\IO\IOInterface;
|
||||
use ZipArchive;
|
||||
|
@ -25,10 +26,10 @@ class ZipDownloader extends ArchiveDownloader
|
|||
{
|
||||
protected $process;
|
||||
|
||||
public function __construct(IOInterface $io, Config $config, Cache $cache = null, ProcessExecutor $process = null)
|
||||
public function __construct(IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null, Cache $cache = null, ProcessExecutor $process = null)
|
||||
{
|
||||
$this->process = $process ?: new ProcessExecutor($io);
|
||||
parent::__construct($io, $config, $cache);
|
||||
parent::__construct($io, $config, $eventDispatcher, $cache);
|
||||
}
|
||||
|
||||
protected function extract($file, $path)
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\EventDispatcher;
|
||||
|
||||
/**
|
||||
* The base event class
|
||||
*
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
*/
|
||||
class Event
|
||||
{
|
||||
/**
|
||||
* @var string This event's name
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @var boolean Whether the event should not be passed to more listeners
|
||||
*/
|
||||
private $propagationStopped = false;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $name The event name
|
||||
*/
|
||||
public function __construct($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the event's name.
|
||||
*
|
||||
* @return string The event name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if stopPropagation has been called
|
||||
*
|
||||
* @return boolean Whether propagation has been stopped
|
||||
*/
|
||||
public function isPropagationStopped()
|
||||
{
|
||||
return $this->propagationStopped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevents the event from being passed to further listeners
|
||||
*/
|
||||
public function stopPropagation()
|
||||
{
|
||||
$this->propagationStopped = true;
|
||||
}
|
||||
}
|
|
@ -10,11 +10,14 @@
|
|||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Script;
|
||||
namespace Composer\EventDispatcher;
|
||||
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Composer;
|
||||
use Composer\DependencyResolver\Operation\OperationInterface;
|
||||
use Composer\Script;
|
||||
use Composer\Script\CommandEvent;
|
||||
use Composer\Script\PackageEvent;
|
||||
use Composer\Util\ProcessExecutor;
|
||||
|
||||
/**
|
||||
|
@ -28,6 +31,7 @@ use Composer\Util\ProcessExecutor;
|
|||
*
|
||||
* @author François Pluchino <francois.pluchino@opendisplay.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
*/
|
||||
class EventDispatcher
|
||||
{
|
||||
|
@ -51,15 +55,30 @@ class EventDispatcher
|
|||
}
|
||||
|
||||
/**
|
||||
* Dispatch a script event.
|
||||
* Dispatch an event
|
||||
*
|
||||
* @param string $eventName The constant in ScriptEvents
|
||||
* @param string $eventName An event name
|
||||
* @param Event $event
|
||||
*/
|
||||
public function dispatch($eventName, Event $event = null)
|
||||
{
|
||||
if (null == $event) {
|
||||
$event = new Event($eventName, $this->composer, $this->io);
|
||||
$event = new Event($eventName);
|
||||
}
|
||||
|
||||
$this->doDispatch($event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a script event.
|
||||
*
|
||||
* @param string $eventName The constant in ScriptEvents
|
||||
* @param Event $event
|
||||
*/
|
||||
public function dispatchScript($eventName, Script\Event $event = null)
|
||||
{
|
||||
if (null == $event) {
|
||||
$event = new Script\Event($eventName, $this->composer, $this->io);
|
||||
}
|
||||
|
||||
$this->doDispatch($event);
|
||||
|
@ -100,7 +119,9 @@ class EventDispatcher
|
|||
$listeners = $this->getListeners($event);
|
||||
|
||||
foreach ($listeners as $callable) {
|
||||
if ($this->isPhpScript($callable)) {
|
||||
if (!is_string($callable) && is_callable($callable)) {
|
||||
call_user_func($callable, $event);
|
||||
} elseif ($this->isPhpScript($callable)) {
|
||||
$className = substr($callable, 0, strpos($callable, '::'));
|
||||
$methodName = substr($callable, strpos($callable, '::') + 2);
|
||||
|
||||
|
@ -127,6 +148,10 @@ class EventDispatcher
|
|||
throw new \RuntimeException('Error Output: '.$this->process->getErrorOutput(), $exitCode);
|
||||
}
|
||||
}
|
||||
|
||||
if ($event->isPropagationStopped()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,10 +166,67 @@ class EventDispatcher
|
|||
}
|
||||
|
||||
/**
|
||||
* Add a listener for a particular event
|
||||
*
|
||||
* @param string $eventName The event name - typically a constant
|
||||
* @param Callable $listener A callable expecting an event argument
|
||||
* @param integer $priority A higher value represents a higher priority
|
||||
*/
|
||||
protected function addListener($eventName, $listener, $priority = 0)
|
||||
{
|
||||
$this->listeners[$eventName][$priority][] = $listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds object methods as listeners for the events in getSubscribedEvents
|
||||
*
|
||||
* @see EventSubscriberInterface
|
||||
*
|
||||
* @param EventSubscriberInterface $subscriber
|
||||
*/
|
||||
public function addSubscriber(EventSubscriberInterface $subscriber)
|
||||
{
|
||||
foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
|
||||
if (is_string($params)) {
|
||||
$this->addListener($eventName, array($subscriber, $params));
|
||||
} elseif (is_string($params[0])) {
|
||||
$this->addListener($eventName, array($subscriber, $params[0]), isset($params[1]) ? $params[1] : 0);
|
||||
} else {
|
||||
foreach ($params as $listener) {
|
||||
$this->addListener($eventName, array($subscriber, $listener[0]), isset($listener[1]) ? $listener[1] : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all listeners for a given event
|
||||
*
|
||||
* @param Event $event
|
||||
* @return array All listeners: callables and scripts
|
||||
*/
|
||||
protected function getListeners(Event $event)
|
||||
{
|
||||
$scriptListeners = $this->getScriptListeners($event);
|
||||
|
||||
if (!isset($this->listeners[$event->getName()][0])) {
|
||||
$this->listeners[$event->getName()][0] = array();
|
||||
}
|
||||
krsort($this->listeners[$event->getName()]);
|
||||
|
||||
$listeners = $this->listeners;
|
||||
$listeners[$event->getName()][0] = array_merge($listeners[$event->getName()][0], $scriptListeners);
|
||||
|
||||
return call_user_func_array('array_merge', $listeners[$event->getName()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all listeners defined as scripts in the package
|
||||
*
|
||||
* @param Event $event Event object
|
||||
* @return array Listeners
|
||||
*/
|
||||
protected function getListeners(Event $event)
|
||||
protected function getScriptListeners(Event $event)
|
||||
{
|
||||
$package = $this->composer->getPackage();
|
||||
$scripts = $package->getScripts();
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\EventDispatcher;
|
||||
|
||||
/**
|
||||
* An EventSubscriber knows which events it is interested in.
|
||||
*
|
||||
* If an EventSubscriber is added to an EventDispatcher, the manager invokes
|
||||
* {@link getSubscribedEvents} and registers the subscriber as a listener for all
|
||||
* returned events.
|
||||
*
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* Returns an array of event names this subscriber wants to listen to.
|
||||
*
|
||||
* The array keys are event names and the value can be:
|
||||
*
|
||||
* * The method name to call (priority defaults to 0)
|
||||
* * An array composed of the method name to call and the priority
|
||||
* * An array of arrays composed of the method names to call and respective
|
||||
* priorities, or 0 if unset
|
||||
*
|
||||
* For instance:
|
||||
*
|
||||
* * array('eventName' => 'methodName')
|
||||
* * array('eventName' => array('methodName', $priority))
|
||||
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
|
||||
*
|
||||
* @return array The event names to listen to
|
||||
*/
|
||||
public static function getSubscribedEvents();
|
||||
}
|
|
@ -18,10 +18,11 @@ use Composer\IO\IOInterface;
|
|||
use Composer\Package\Archiver;
|
||||
use Composer\Repository\ComposerRepository;
|
||||
use Composer\Repository\RepositoryManager;
|
||||
use Composer\Repository\RepositoryInterface;
|
||||
use Composer\Util\ProcessExecutor;
|
||||
use Composer\Util\RemoteFilesystem;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
||||
use Composer\Script\EventDispatcher;
|
||||
use Composer\EventDispatcher\EventDispatcher;
|
||||
use Composer\Autoload\AutoloadGenerator;
|
||||
use Composer\Package\Version\VersionParser;
|
||||
|
||||
|
@ -31,6 +32,7 @@ use Composer\Package\Version\VersionParser;
|
|||
* @author Ryan Weaver <ryan@knplabs.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @author Igor Wiedler <igor@wiedler.ch>
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
*/
|
||||
class Factory
|
||||
{
|
||||
|
@ -176,11 +178,12 @@ class Factory
|
|||
* @param IOInterface $io IO instance
|
||||
* @param array|string|null $localConfig either a configuration array or a filename to read from, if null it will
|
||||
* read from the default filename
|
||||
* @param bool $disablePlugins Whether plugins should not be loaded
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \UnexpectedValueException
|
||||
* @return Composer
|
||||
*/
|
||||
public function createComposer(IOInterface $io, $localConfig = null)
|
||||
public function createComposer(IOInterface $io, $localConfig = null, $disablePlugins = false)
|
||||
{
|
||||
// load Composer configuration
|
||||
if (null === $localConfig) {
|
||||
|
@ -227,9 +230,6 @@ class Factory
|
|||
$loader = new Package\Loader\RootPackageLoader($rm, $config, $parser, new ProcessExecutor($io));
|
||||
$package = $loader->load($localConfig);
|
||||
|
||||
// initialize download manager
|
||||
$dm = $this->createDownloadManager($io, $config);
|
||||
|
||||
// initialize installation manager
|
||||
$im = $this->createInstallationManager();
|
||||
|
||||
|
@ -238,20 +238,32 @@ class Factory
|
|||
$composer->setConfig($config);
|
||||
$composer->setPackage($package);
|
||||
$composer->setRepositoryManager($rm);
|
||||
$composer->setDownloadManager($dm);
|
||||
$composer->setInstallationManager($im);
|
||||
|
||||
// initialize event dispatcher
|
||||
$dispatcher = new EventDispatcher($composer, $io);
|
||||
|
||||
// initialize download manager
|
||||
$dm = $this->createDownloadManager($io, $config, $dispatcher);
|
||||
|
||||
$composer->setDownloadManager($dm);
|
||||
$composer->setEventDispatcher($dispatcher);
|
||||
|
||||
// initialize autoload generator
|
||||
$generator = new AutoloadGenerator($dispatcher);
|
||||
$composer->setAutoloadGenerator($generator);
|
||||
|
||||
$globalRepository = $this->createGlobalRepository($config, $vendorDir);
|
||||
$pm = $this->createPluginManager($composer, $io, $globalRepository);
|
||||
$composer->setPluginManager($pm);
|
||||
|
||||
// add installers to the manager
|
||||
$this->createDefaultInstallers($im, $composer, $io);
|
||||
|
||||
if (!$disablePlugins) {
|
||||
$pm->loadInstalledPlugins();
|
||||
}
|
||||
|
||||
// purge packages if they have been deleted on the filesystem
|
||||
$this->purgePackages($rm, $im);
|
||||
|
||||
|
@ -296,12 +308,31 @@ class Factory
|
|||
$rm->setLocalRepository(new Repository\InstalledFilesystemRepository(new JsonFile($vendorDir.'/composer/installed.json')));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Config $config
|
||||
* @param string $vendorDir
|
||||
*/
|
||||
protected function createGlobalRepository(Config $config, $vendorDir)
|
||||
{
|
||||
if ($config->get('home') == $vendorDir) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$path = $config->get('home').'/vendor/composer/installed.json';
|
||||
if (!file_exists($path)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Repository\InstalledFilesystemRepository(new JsonFile($path));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param IO\IOInterface $io
|
||||
* @param Config $config
|
||||
* @param EventDispatcher $eventDispatcher
|
||||
* @return Downloader\DownloadManager
|
||||
*/
|
||||
public function createDownloadManager(IOInterface $io, Config $config)
|
||||
public function createDownloadManager(IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null)
|
||||
{
|
||||
$cache = null;
|
||||
if ($config->get('cache-files-ttl') > 0) {
|
||||
|
@ -325,10 +356,10 @@ class Factory
|
|||
$dm->setDownloader('git', new Downloader\GitDownloader($io, $config));
|
||||
$dm->setDownloader('svn', new Downloader\SvnDownloader($io, $config));
|
||||
$dm->setDownloader('hg', new Downloader\HgDownloader($io, $config));
|
||||
$dm->setDownloader('zip', new Downloader\ZipDownloader($io, $config, $cache));
|
||||
$dm->setDownloader('tar', new Downloader\TarDownloader($io, $config, $cache));
|
||||
$dm->setDownloader('phar', new Downloader\PharDownloader($io, $config, $cache));
|
||||
$dm->setDownloader('file', new Downloader\FileDownloader($io, $config, $cache));
|
||||
$dm->setDownloader('zip', new Downloader\ZipDownloader($io, $config, $eventDispatcher, $cache));
|
||||
$dm->setDownloader('tar', new Downloader\TarDownloader($io, $config, $eventDispatcher, $cache));
|
||||
$dm->setDownloader('phar', new Downloader\PharDownloader($io, $config, $eventDispatcher, $cache));
|
||||
$dm->setDownloader('file', new Downloader\FileDownloader($io, $config, $eventDispatcher, $cache));
|
||||
|
||||
return $dm;
|
||||
}
|
||||
|
@ -353,6 +384,14 @@ class Factory
|
|||
return $am;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Plugin\PluginManager
|
||||
*/
|
||||
protected function createPluginManager(Composer $composer, IOInterface $io, RepositoryInterface $globalRepository = null)
|
||||
{
|
||||
return new Plugin\PluginManager($composer, $io, $globalRepository);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Installer\InstallationManager
|
||||
*/
|
||||
|
@ -370,7 +409,7 @@ class Factory
|
|||
{
|
||||
$im->addInstaller(new Installer\LibraryInstaller($io, $composer, null));
|
||||
$im->addInstaller(new Installer\PearInstaller($io, $composer, 'pear-library'));
|
||||
$im->addInstaller(new Installer\InstallerInstaller($io, $composer));
|
||||
$im->addInstaller(new Installer\PluginInstaller($io, $composer));
|
||||
$im->addInstaller(new Installer\MetapackageInstaller($io));
|
||||
}
|
||||
|
||||
|
@ -392,12 +431,13 @@ class Factory
|
|||
* @param IOInterface $io IO instance
|
||||
* @param mixed $config either a configuration array or a filename to read from, if null it will read from
|
||||
* the default filename
|
||||
* @param bool $disablePlugins Whether plugins should not be loaded
|
||||
* @return Composer
|
||||
*/
|
||||
public static function create(IOInterface $io, $config = null)
|
||||
public static function create(IOInterface $io, $config = null, $disablePlugins = false)
|
||||
{
|
||||
$factory = new static();
|
||||
|
||||
return $factory->createComposer($io, $config);
|
||||
return $factory->createComposer($io, $config, $disablePlugins);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ use Composer\DependencyResolver\Rule;
|
|||
use Composer\DependencyResolver\Solver;
|
||||
use Composer\DependencyResolver\SolverProblemsException;
|
||||
use Composer\Downloader\DownloadManager;
|
||||
use Composer\EventDispatcher\EventDispatcher;
|
||||
use Composer\Installer\InstallationManager;
|
||||
use Composer\Config;
|
||||
use Composer\Installer\NoopInstaller;
|
||||
|
@ -41,13 +42,13 @@ use Composer\Repository\InstalledFilesystemRepository;
|
|||
use Composer\Repository\PlatformRepository;
|
||||
use Composer\Repository\RepositoryInterface;
|
||||
use Composer\Repository\RepositoryManager;
|
||||
use Composer\Script\EventDispatcher;
|
||||
use Composer\Script\ScriptEvents;
|
||||
|
||||
/**
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @author Beau Simensen <beau@dflydev.com>
|
||||
* @author Konstantin Kudryashov <ever.zet@gmail.com>
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
*/
|
||||
class Installer
|
||||
{
|
||||
|
@ -461,7 +462,7 @@ class Installer
|
|||
$this->io->write('Nothing to install or update');
|
||||
}
|
||||
|
||||
$operations = $this->moveCustomInstallersToFront($operations);
|
||||
$operations = $this->movePluginsToFront($operations);
|
||||
|
||||
foreach ($operations as $operation) {
|
||||
// collect suggestions
|
||||
|
@ -540,7 +541,7 @@ class Installer
|
|||
|
||||
|
||||
/**
|
||||
* Workaround: if your packages depend on custom installers, we must be sure
|
||||
* Workaround: if your packages depend on plugins, we must be sure
|
||||
* that those are installed / updated first; else it would lead to packages
|
||||
* being installed multiple times in different folders, when running Composer
|
||||
* twice.
|
||||
|
@ -552,7 +553,7 @@ class Installer
|
|||
* @param OperationInterface[] $operations
|
||||
* @return OperationInterface[] reordered operation list
|
||||
*/
|
||||
private function moveCustomInstallersToFront(array $operations)
|
||||
private function movePluginsToFront(array $operations)
|
||||
{
|
||||
$installerOps = array();
|
||||
foreach ($operations as $idx => $op) {
|
||||
|
@ -564,7 +565,7 @@ class Installer
|
|||
continue;
|
||||
}
|
||||
|
||||
if ($package->getRequires() === array() && $package->getType() === 'composer-installer') {
|
||||
if ($package->getRequires() === array() && ($package->getType() === 'composer-plugin' || $package->getType() === 'composer-installer')) {
|
||||
$installerOps[] = $op;
|
||||
unset($operations[$idx]);
|
||||
}
|
||||
|
@ -1055,7 +1056,7 @@ class Installer
|
|||
}
|
||||
|
||||
/**
|
||||
* Disables custom installers.
|
||||
* Disables plugins.
|
||||
*
|
||||
* Call this if you want to ensure that third-party code never gets
|
||||
* executed. The default is to automatically install, and execute
|
||||
|
@ -1063,9 +1064,9 @@ class Installer
|
|||
*
|
||||
* @return Installer
|
||||
*/
|
||||
public function disableCustomInstallers()
|
||||
public function disablePlugins()
|
||||
{
|
||||
$this->installationManager->disableCustomInstallers();
|
||||
$this->installationManager->disablePlugins();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ namespace Composer\Installer;
|
|||
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Package\AliasPackage;
|
||||
use Composer\Plugin\PluginInstaller;
|
||||
use Composer\Repository\RepositoryInterface;
|
||||
use Composer\Repository\InstalledRepositoryInterface;
|
||||
use Composer\DependencyResolver\Operation\OperationInterface;
|
||||
|
@ -29,6 +30,7 @@ use Composer\Util\StreamContextFactory;
|
|||
*
|
||||
* @author Konstantin Kudryashov <ever.zet@gmail.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
*/
|
||||
class InstallationManager
|
||||
{
|
||||
|
@ -66,16 +68,16 @@ class InstallationManager
|
|||
}
|
||||
|
||||
/**
|
||||
* Disables custom installers.
|
||||
* Disables plugins.
|
||||
*
|
||||
* We prevent any custom installers from being instantiated by simply
|
||||
* We prevent any plugins from being instantiated by simply
|
||||
* deactivating the installer for them. This ensure that no third-party
|
||||
* code is ever executed.
|
||||
*/
|
||||
public function disableCustomInstallers()
|
||||
public function disablePlugins()
|
||||
{
|
||||
foreach ($this->installers as $i => $installer) {
|
||||
if (!$installer instanceof InstallerInstaller) {
|
||||
if (!$installer instanceof PluginInstaller) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,104 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Installer;
|
||||
|
||||
use Composer\Composer;
|
||||
use Composer\Package\Package;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Repository\InstalledRepositoryInterface;
|
||||
use Composer\Package\PackageInterface;
|
||||
|
||||
/**
|
||||
* Installer installation manager.
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class InstallerInstaller extends LibraryInstaller
|
||||
{
|
||||
private $installationManager;
|
||||
private static $classCounter = 0;
|
||||
|
||||
/**
|
||||
* Initializes Installer installer.
|
||||
*
|
||||
* @param IOInterface $io
|
||||
* @param Composer $composer
|
||||
* @param string $type
|
||||
*/
|
||||
public function __construct(IOInterface $io, Composer $composer, $type = 'library')
|
||||
{
|
||||
parent::__construct($io, $composer, 'composer-installer');
|
||||
$this->installationManager = $composer->getInstallationManager();
|
||||
|
||||
$repo = $composer->getRepositoryManager()->getLocalRepository();
|
||||
foreach ($repo->getPackages() as $package) {
|
||||
if ('composer-installer' === $package->getType()) {
|
||||
$this->registerInstaller($package);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
|
||||
{
|
||||
$extra = $package->getExtra();
|
||||
if (empty($extra['class'])) {
|
||||
throw new \UnexpectedValueException('Error while installing '.$package->getPrettyName().', composer-installer packages should have a class defined in their extra key to be usable.');
|
||||
}
|
||||
|
||||
parent::install($repo, $package);
|
||||
$this->registerInstaller($package);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
|
||||
{
|
||||
$extra = $target->getExtra();
|
||||
if (empty($extra['class'])) {
|
||||
throw new \UnexpectedValueException('Error while installing '.$target->getPrettyName().', composer-installer packages should have a class defined in their extra key to be usable.');
|
||||
}
|
||||
|
||||
parent::update($repo, $initial, $target);
|
||||
$this->registerInstaller($target);
|
||||
}
|
||||
|
||||
private function registerInstaller(PackageInterface $package)
|
||||
{
|
||||
$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++;
|
||||
}
|
||||
|
||||
$installer = new $class($this->io, $this->composer);
|
||||
$this->installationManager->addInstaller($installer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Installer;
|
||||
|
||||
use Composer\Composer;
|
||||
use Composer\Package\Package;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Repository\InstalledRepositoryInterface;
|
||||
use Composer\Package\PackageInterface;
|
||||
|
||||
/**
|
||||
* Installer for plugin packages
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
*/
|
||||
class PluginInstaller extends LibraryInstaller
|
||||
{
|
||||
private $installationManager;
|
||||
private static $classCounter = 0;
|
||||
|
||||
/**
|
||||
* Initializes Plugin installer.
|
||||
*
|
||||
* @param IOInterface $io
|
||||
* @param Composer $composer
|
||||
* @param string $type
|
||||
*/
|
||||
public function __construct(IOInterface $io, Composer $composer, $type = 'library')
|
||||
{
|
||||
parent::__construct($io, $composer, 'composer-plugin');
|
||||
$this->installationManager = $composer->getInstallationManager();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function supports($packageType)
|
||||
{
|
||||
return $packageType === 'composer-plugin' || $packageType === 'composer-installer';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function install(InstalledRepositoryInterface $repo, PackageInterface $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.');
|
||||
}
|
||||
|
||||
parent::install($repo, $package);
|
||||
$this->composer->getPluginManager()->registerPackage($package);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
|
||||
{
|
||||
$extra = $target->getExtra();
|
||||
if (empty($extra['class'])) {
|
||||
throw new \UnexpectedValueException('Error while installing '.$target->getPrettyName().', composer-plugin packages should have a class defined in their extra key to be usable.');
|
||||
}
|
||||
|
||||
parent::update($repo, $initial, $target);
|
||||
$this->composer->getPluginManager()->registerPackage($target);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Plugin;
|
||||
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\EventDispatcher\Event;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* An event for all commands.
|
||||
*
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
*/
|
||||
class CommandEvent extends Event
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $commandName;
|
||||
|
||||
/**
|
||||
* @var InputInterface
|
||||
*/
|
||||
private $input;
|
||||
|
||||
/**
|
||||
* @var OutputInterface
|
||||
*/
|
||||
private $output;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $name The event name
|
||||
* @param string $commandName The command name
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
*/
|
||||
public function __construct($name, $commandName, $input, $output)
|
||||
{
|
||||
parent::__construct($name);
|
||||
$this->commandName = $commandName;
|
||||
$this->input = $input;
|
||||
$this->output = $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the command input interface
|
||||
*
|
||||
* @return InputInterface
|
||||
*/
|
||||
public function getInput()
|
||||
{
|
||||
return $this->input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the command output interface
|
||||
*
|
||||
* @return OutputInterface
|
||||
*/
|
||||
public function getOutput()
|
||||
{
|
||||
return $this->output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the name of the command being run
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCommandName()
|
||||
{
|
||||
return $this->commandName;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Plugin;
|
||||
|
||||
/**
|
||||
* The Plugin Events.
|
||||
*
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
*/
|
||||
class PluginEvents
|
||||
{
|
||||
/**
|
||||
* The COMMAND event occurs as a command begins
|
||||
*
|
||||
* The event listener method receives a
|
||||
* Composer\Plugin\CommandEvent instance.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const COMMAND = 'command';
|
||||
|
||||
/**
|
||||
* The PRE_FILE_DOWNLOAD event occurs before downloading a file
|
||||
*
|
||||
* The event listener method receives a
|
||||
* Composer\Plugin\PreFileDownloadEvent instance.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const PRE_FILE_DOWNLOAD = 'pre-file-download';
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Plugin;
|
||||
|
||||
use Composer\Composer;
|
||||
use Composer\IO\IOInterface;
|
||||
|
||||
/**
|
||||
* Plugin interface
|
||||
*
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
*/
|
||||
interface PluginInterface
|
||||
{
|
||||
/**
|
||||
* Version number of the fake composer-plugin-api package
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const PLUGIN_API_VERSION = '1.0.0';
|
||||
|
||||
/**
|
||||
* Apply plugin modifications to composer
|
||||
*
|
||||
* @param Composer $composer
|
||||
* @param IOInterface $io
|
||||
*/
|
||||
public function activate(Composer $composer, IOInterface $io);
|
||||
}
|
|
@ -0,0 +1,259 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Plugin;
|
||||
|
||||
use Composer\Composer;
|
||||
use Composer\EventDispatcher\EventSubscriberInterface;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Package\Package;
|
||||
use Composer\Package\Version\VersionParser;
|
||||
use Composer\Repository\RepositoryInterface;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Package\Link;
|
||||
use Composer\Package\LinkConstraint\VersionConstraint;
|
||||
use Composer\DependencyResolver\Pool;
|
||||
|
||||
/**
|
||||
* Plugin manager
|
||||
*
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
*/
|
||||
class PluginManager
|
||||
{
|
||||
protected $composer;
|
||||
protected $io;
|
||||
protected $globalRepository;
|
||||
protected $versionParser;
|
||||
|
||||
protected $plugins = array();
|
||||
|
||||
private static $classCounter = 0;
|
||||
|
||||
/**
|
||||
* Initializes plugin manager
|
||||
*
|
||||
* @param Composer $composer
|
||||
*/
|
||||
public function __construct(Composer $composer, IOInterface $io, RepositoryInterface $globalRepository = null)
|
||||
{
|
||||
$this->composer = $composer;
|
||||
$this->io = $io;
|
||||
$this->globalRepository = $globalRepository;
|
||||
$this->versionParser = new VersionParser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all plugins from currently installed plugin packages
|
||||
*/
|
||||
public function loadInstalledPlugins()
|
||||
{
|
||||
$repo = $this->composer->getRepositoryManager()->getLocalRepository();
|
||||
|
||||
if ($repo) {
|
||||
$this->loadRepository($repo);
|
||||
}
|
||||
if ($this->globalRepository) {
|
||||
$this->loadRepository($this->globalRepository);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a plugin, activates it and registers it with the event dispatcher
|
||||
*
|
||||
* @param PluginInterface $plugin plugin instance
|
||||
*/
|
||||
public function addPlugin(PluginInterface $plugin)
|
||||
{
|
||||
$this->plugins[] = $plugin;
|
||||
$plugin->activate($this->composer, $this->io);
|
||||
|
||||
if ($plugin instanceof EventSubscriberInterface) {
|
||||
$this->composer->getEventDispatcher()->addSubscriber($plugin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all currently active plugin instances
|
||||
*
|
||||
* @return array plugins
|
||||
*/
|
||||
public function getPlugins()
|
||||
{
|
||||
return $this->plugins;
|
||||
}
|
||||
|
||||
protected function loadRepository(RepositoryInterface $repo)
|
||||
{
|
||||
foreach ($repo->getPackages() as $package) {
|
||||
if ('composer-plugin' === $package->getType() || 'composer-installer' === $package->getType()) {
|
||||
$requiresComposer = null;
|
||||
foreach ($package->getRequires() as $link) {
|
||||
if ($link->getTarget() == 'composer-plugin-api') {
|
||||
$requiresComposer = $link->getConstraint();
|
||||
}
|
||||
}
|
||||
|
||||
if (!$requiresComposer) {
|
||||
throw new \RuntimeException("Plugin ".$package->getName()." is missing a require statement for a version of the composer-plugin-api package.");
|
||||
}
|
||||
|
||||
if (!$requiresComposer->matches(new VersionConstraint('==', $this->versionParser->normalize(PluginInterface::PLUGIN_API_VERSION)))) {
|
||||
$this->io->write("<warning>The plugin ".$package->getName()." requires a version of composer-plugin-api that does not match your composer installation. You may need to run composer update with the '--no-plugins' option.</warning>");
|
||||
}
|
||||
|
||||
$this->registerPackage($package);
|
||||
}
|
||||
// Backward compatability
|
||||
if ('composer-installer' === $package->getType()) {
|
||||
$this->registerPackage($package);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively generates a map of package names to packages for all deps
|
||||
*
|
||||
* @param Pool $pool Package pool of installed packages
|
||||
* @param array $collected Current state of the map for recursion
|
||||
* @param PackageInterface $package The package to analyze
|
||||
*
|
||||
* @return array Map of package names to packages
|
||||
*/
|
||||
protected function collectDependencies(Pool $pool, array $collected, PackageInterface $package)
|
||||
{
|
||||
$requires = array_merge(
|
||||
$package->getRequires(),
|
||||
$package->getDevRequires()
|
||||
);
|
||||
|
||||
foreach ($requires as $requireLink) {
|
||||
$requiredPackage = $this->lookupInstalledPackage($pool, $requireLink);
|
||||
if ($requiredPackage && !isset($collected[$requiredPackage->getName()])) {
|
||||
$collected[$requiredPackage->getName()] = $requiredPackage;
|
||||
$collected = $this->collectDependencies($pool, $collected, $requiredPackage);
|
||||
}
|
||||
}
|
||||
|
||||
return $collected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a package link to a package in the installed pool
|
||||
*
|
||||
* Since dependencies are already installed this should always find one.
|
||||
*
|
||||
* @param Pool $pool Pool of installed packages only
|
||||
* @param Link $link Package link to look up
|
||||
*
|
||||
* @return PackageInterface|null The found package
|
||||
*/
|
||||
protected 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
|
||||
*/
|
||||
public function registerPackage(PackageInterface $package)
|
||||
{
|
||||
$oldInstallerPlugin = ($package->getType() === 'composer-installer');
|
||||
|
||||
$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']);
|
||||
|
||||
$pool = new Pool('dev');
|
||||
$localRepo = $this->composer->getRepositoryManager()->getLocalRepository();
|
||||
$pool->addRepository($localRepo);
|
||||
if ($this->globalRepository) {
|
||||
$pool->addRepository($this->globalRepository);
|
||||
}
|
||||
|
||||
$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, ($this->globalRepository && $this->globalRepository->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);
|
||||
} else {
|
||||
$plugin = new $class();
|
||||
$this->addPlugin($plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the path a package is installed to.
|
||||
*
|
||||
* @param PackageInterface $package
|
||||
* @param bool $global Whether this is a global package
|
||||
*
|
||||
* @return string Install path
|
||||
*/
|
||||
public function getInstallPath(PackageInterface $package, $global = false)
|
||||
{
|
||||
$targetDir = $package->getTargetDir();
|
||||
|
||||
return $this->getPackageBasePath($package, $global) . ($targetDir ? '/'.$targetDir : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the base path a package gets installed into.
|
||||
*
|
||||
* Does not take targetDir into account.
|
||||
*
|
||||
* @param PackageInterface $package
|
||||
* @param bool $global Whether this is a global package
|
||||
*
|
||||
* @return string Base path
|
||||
*/
|
||||
protected function getPackageBasePath(PackageInterface $package, $global = false)
|
||||
{
|
||||
if ($global) {
|
||||
$vendorDir = $this->composer->getConfig()->get('home').'/vendor';
|
||||
} else {
|
||||
$vendorDir = rtrim($this->composer->getConfig()->get('vendor-dir'), '/');
|
||||
}
|
||||
return ($vendorDir ? $vendorDir.'/' : '') . $package->getPrettyName();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Plugin;
|
||||
|
||||
use Composer\Composer;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\EventDispatcher\Event;
|
||||
use Composer\Util\RemoteFilesystem;
|
||||
|
||||
/**
|
||||
* The pre file download event.
|
||||
*
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
*/
|
||||
class PreFileDownloadEvent extends Event
|
||||
{
|
||||
/**
|
||||
* @var RemoteFilesystem
|
||||
*/
|
||||
private $rfs;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $processedUrl;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $name The event name
|
||||
* @param RemoteFilesystem $rfs
|
||||
* @param string $processedUrl
|
||||
*/
|
||||
public function __construct($name, RemoteFilesystem $rfs, $processedUrl)
|
||||
{
|
||||
parent::__construct($name);
|
||||
$this->rfs = $rfs;
|
||||
$this->processedUrl = $processedUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the remote filesystem
|
||||
*
|
||||
* @return RemoteFilesystem
|
||||
*/
|
||||
public function getRemoteFilesystem()
|
||||
{
|
||||
return $this->rfs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the remote filesystem
|
||||
*
|
||||
* @param RemoteFilesystem $rfs
|
||||
*/
|
||||
public function setRemoteFilesystem(RemoteFilesystem $rfs)
|
||||
{
|
||||
$this->rfs = $rfs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the processed URL this remote filesystem will be used for
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getProcessedUrl()
|
||||
{
|
||||
return $this->processedUrl;
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@ namespace Composer\Repository;
|
|||
|
||||
use Composer\Package\CompletePackage;
|
||||
use Composer\Package\Version\VersionParser;
|
||||
use Composer\Plugin\PluginInterface;
|
||||
|
||||
/**
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
|
@ -28,6 +29,12 @@ class PlatformRepository extends ArrayRepository
|
|||
|
||||
$versionParser = new VersionParser();
|
||||
|
||||
$prettyVersion = PluginInterface::PLUGIN_API_VERSION;
|
||||
$version = $versionParser->normalize($prettyVersion);
|
||||
$composerPluginApi = new CompletePackage('composer-plugin-api', $version, $prettyVersion);
|
||||
$composerPluginApi->setDescription('The Composer Plugin API');
|
||||
parent::addPackage($composerPluginApi);
|
||||
|
||||
try {
|
||||
$prettyVersion = PHP_VERSION;
|
||||
$version = $versionParser->normalize($prettyVersion);
|
||||
|
@ -36,6 +43,7 @@ class PlatformRepository extends ArrayRepository
|
|||
$version = $versionParser->normalize($prettyVersion);
|
||||
}
|
||||
|
||||
|
||||
$php = new CompletePackage('php', $version, $prettyVersion);
|
||||
$php->setDescription('The PHP interpreter');
|
||||
parent::addPackage($php);
|
||||
|
|
|
@ -16,17 +16,13 @@ use Composer\Composer;
|
|||
use Composer\IO\IOInterface;
|
||||
|
||||
/**
|
||||
* The base event class
|
||||
* The script event class
|
||||
*
|
||||
* @author François Pluchino <francois.pluchino@opendisplay.com>
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
*/
|
||||
class Event
|
||||
class Event extends \Composer\EventDispatcher\Event
|
||||
{
|
||||
/**
|
||||
* @var string This event's name
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* @var Composer The composer instance
|
||||
*/
|
||||
|
@ -52,22 +48,12 @@ class Event
|
|||
*/
|
||||
public function __construct($name, Composer $composer, IOInterface $io, $devMode = false)
|
||||
{
|
||||
$this->name = $name;
|
||||
parent::__construct($name);
|
||||
$this->composer = $composer;
|
||||
$this->io = $io;
|
||||
$this->devMode = $devMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the event's name.
|
||||
*
|
||||
* @return string The event name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the composer instance.
|
||||
*
|
||||
|
|
|
@ -19,6 +19,7 @@ use Composer\Downloader\TransportException;
|
|||
/**
|
||||
* @author François Pluchino <francois.pluchino@opendisplay.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
*/
|
||||
class RemoteFilesystem
|
||||
{
|
||||
|
@ -76,6 +77,16 @@ class RemoteFilesystem
|
|||
return $this->get($originUrl, $fileUrl, $options, null, $progress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the options set in the constructor
|
||||
*
|
||||
* @return array Options
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file content or copy action.
|
||||
*
|
||||
|
|
|
@ -72,7 +72,7 @@ class AutoloadGeneratorTest extends TestCase
|
|||
}));
|
||||
$this->repository = $this->getMock('Composer\Repository\InstalledRepositoryInterface');
|
||||
|
||||
$this->eventDispatcher = $this->getMockBuilder('Composer\Script\EventDispatcher')
|
||||
$this->eventDispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
|
@ -626,12 +626,12 @@ EOF;
|
|||
{
|
||||
$this->eventDispatcher
|
||||
->expects($this->at(0))
|
||||
->method('dispatch')
|
||||
->method('dispatchScript')
|
||||
->with(ScriptEvents::PRE_AUTOLOAD_DUMP, false);
|
||||
|
||||
$this->eventDispatcher
|
||||
->expects($this->at(1))
|
||||
->method('dispatch')
|
||||
->method('dispatchScript')
|
||||
->with(ScriptEvents::POST_AUTOLOAD_DUMP, false);
|
||||
|
||||
$package = new Package('a', '1.0', '1.0');
|
||||
|
|
|
@ -23,7 +23,7 @@ class FileDownloaderTest extends \PHPUnit_Framework_TestCase
|
|||
$config = $config ?: $this->getMock('Composer\Config');
|
||||
$rfs = $rfs ?: $this->getMockBuilder('Composer\Util\RemoteFilesystem')->disableOriginalConstructor()->getMock();
|
||||
|
||||
return new FileDownloader($io, $config, null, $rfs, $filesystem);
|
||||
return new FileDownloader($io, $config, null, null, $rfs, $filesystem);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,11 +10,12 @@
|
|||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Test\Script;
|
||||
namespace Composer\Test\EventDispatcher;
|
||||
|
||||
use Composer\EventDispatcher\Event;
|
||||
use Composer\EventDispatcher\EventDispatcher;
|
||||
use Composer\Test\TestCase;
|
||||
use Composer\Script\Event;
|
||||
use Composer\Script\EventDispatcher;
|
||||
use Composer\Script;
|
||||
use Composer\Util\ProcessExecutor;
|
||||
|
||||
class EventDispatcherTest extends TestCase
|
||||
|
@ -26,12 +27,12 @@ class EventDispatcherTest extends TestCase
|
|||
{
|
||||
$io = $this->getMock('Composer\IO\IOInterface');
|
||||
$dispatcher = $this->getDispatcherStubForListenersTest(array(
|
||||
"Composer\Test\Script\EventDispatcherTest::call"
|
||||
"Composer\Test\EventDispatcher\EventDispatcherTest::call"
|
||||
), $io);
|
||||
|
||||
$io->expects($this->once())
|
||||
->method('write')
|
||||
->with('<error>Script Composer\Test\Script\EventDispatcherTest::call handling the post-install-cmd event terminated with an exception</error>');
|
||||
->with('<error>Script Composer\Test\EventDispatcher\EventDispatcherTest::call handling the post-install-cmd event terminated with an exception</error>');
|
||||
|
||||
$dispatcher->dispatchCommandEvent("post-install-cmd", false);
|
||||
}
|
||||
|
@ -43,7 +44,7 @@ class EventDispatcherTest extends TestCase
|
|||
public function testDispatcherCanExecuteSingleCommandLineScript($command)
|
||||
{
|
||||
$process = $this->getMock('Composer\Util\ProcessExecutor');
|
||||
$dispatcher = $this->getMockBuilder('Composer\Script\EventDispatcher')
|
||||
$dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')
|
||||
->setConstructorArgs(array(
|
||||
$this->getMock('Composer\Composer'),
|
||||
$this->getMock('Composer\IO\IOInterface'),
|
||||
|
@ -68,7 +69,7 @@ class EventDispatcherTest extends TestCase
|
|||
public function testDispatcherCanExecuteCliAndPhpInSameEventScriptStack()
|
||||
{
|
||||
$process = $this->getMock('Composer\Util\ProcessExecutor');
|
||||
$dispatcher = $this->getMockBuilder('Composer\Script\EventDispatcher')
|
||||
$dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')
|
||||
->setConstructorArgs(array(
|
||||
$this->getMock('Composer\Composer'),
|
||||
$this->getMock('Composer\IO\IOInterface'),
|
||||
|
@ -86,7 +87,7 @@ class EventDispatcherTest extends TestCase
|
|||
|
||||
$listeners = array(
|
||||
'echo -n foo',
|
||||
'Composer\\Test\\Script\\EventDispatcherTest::someMethod',
|
||||
'Composer\\Test\\EventDispatcher\\EventDispatcherTest::someMethod',
|
||||
'echo -n bar',
|
||||
);
|
||||
$dispatcher->expects($this->atLeastOnce())
|
||||
|
@ -95,7 +96,7 @@ class EventDispatcherTest extends TestCase
|
|||
|
||||
$dispatcher->expects($this->once())
|
||||
->method('executeEventPhpScript')
|
||||
->with('Composer\Test\Script\EventDispatcherTest', 'someMethod')
|
||||
->with('Composer\Test\EventDispatcher\EventDispatcherTest', 'someMethod')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$dispatcher->dispatchCommandEvent("post-install-cmd", false);
|
||||
|
@ -103,7 +104,7 @@ class EventDispatcherTest extends TestCase
|
|||
|
||||
private function getDispatcherStubForListenersTest($listeners, $io)
|
||||
{
|
||||
$dispatcher = $this->getMockBuilder('Composer\Script\EventDispatcher')
|
||||
$dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')
|
||||
->setConstructorArgs(array(
|
||||
$this->getMock('Composer\Composer'),
|
||||
$io,
|
||||
|
@ -129,7 +130,7 @@ class EventDispatcherTest extends TestCase
|
|||
|
||||
public function testDispatcherOutputsCommands()
|
||||
{
|
||||
$dispatcher = $this->getMockBuilder('Composer\Script\EventDispatcher')
|
||||
$dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')
|
||||
->setConstructorArgs(array(
|
||||
$this->getMock('Composer\Composer'),
|
||||
$this->getMock('Composer\IO\IOInterface'),
|
||||
|
@ -150,7 +151,7 @@ class EventDispatcherTest extends TestCase
|
|||
|
||||
public function testDispatcherOutputsErrorOnFailedCommand()
|
||||
{
|
||||
$dispatcher = $this->getMockBuilder('Composer\Script\EventDispatcher')
|
||||
$dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')
|
||||
->setConstructorArgs(array(
|
||||
$this->getMock('Composer\Composer'),
|
||||
$io = $this->getMock('Composer\IO\IOInterface'),
|
|
@ -8,8 +8,8 @@ Composer installers are installed first if they have no requirements
|
|||
"package": [
|
||||
{ "name": "pkg", "version": "1.0.0" },
|
||||
{ "name": "pkg2", "version": "1.0.0" },
|
||||
{ "name": "inst", "version": "1.0.0", "type": "composer-installer" },
|
||||
{ "name": "inst2", "version": "1.0.0", "type": "composer-installer", "require": { "pkg2": "*" } }
|
||||
{ "name": "inst", "version": "1.0.0", "type": "composer-plugin" },
|
||||
{ "name": "inst2", "version": "1.0.0", "type": "composer-plugin", "require": { "pkg2": "*" } }
|
||||
]
|
||||
}
|
||||
],
|
|
@ -1,19 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Installer;
|
||||
|
||||
use Composer\Installer\InstallerInterface;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Repository\InstalledRepositoryInterface;
|
||||
|
||||
class Custom implements InstallerInterface
|
||||
{
|
||||
public $version = 'installer-v1';
|
||||
|
||||
public function supports($packageType) {}
|
||||
public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package) {}
|
||||
public function install(InstalledRepositoryInterface $repo, PackageInterface $package) {}
|
||||
public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target) {}
|
||||
public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package) {}
|
||||
public function getInstallPath(PackageInterface $package) {}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Installer;
|
||||
|
||||
class Exception extends \Exception
|
||||
{
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"name": "",
|
||||
"version": "1.0.0",
|
||||
"type": "composer-installer",
|
||||
"autoload": { "psr-0": { "Installer": "" } },
|
||||
"extra": {
|
||||
"class": "Installer\\Custom"
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Installer;
|
||||
|
||||
use Composer\Installer\InstallerInterface;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Repository\InstalledRepositoryInterface;
|
||||
|
||||
class Custom2 implements InstallerInterface
|
||||
{
|
||||
public $version = 'installer-v2';
|
||||
|
||||
public function supports($packageType) {}
|
||||
public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package) {}
|
||||
public function install(InstalledRepositoryInterface $repo, PackageInterface $package) {}
|
||||
public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target) {}
|
||||
public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package) {}
|
||||
public function getInstallPath(PackageInterface $package) {}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Installer;
|
||||
|
||||
class Exception extends \Exception
|
||||
{
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"name": "",
|
||||
"version": "2.0.0",
|
||||
"type": "composer-installer",
|
||||
"autoload": { "psr-0": { "Installer": "" } },
|
||||
"extra": {
|
||||
"class": "Installer\\Custom2"
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Installer;
|
||||
|
||||
use Composer\Installer\InstallerInterface;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Repository\InstalledRepositoryInterface;
|
||||
|
||||
class Custom2 implements InstallerInterface
|
||||
{
|
||||
public $version = 'installer-v3';
|
||||
|
||||
public function supports($packageType) {}
|
||||
public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package) {}
|
||||
public function install(InstalledRepositoryInterface $repo, PackageInterface $package) {}
|
||||
public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target) {}
|
||||
public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package) {}
|
||||
public function getInstallPath(PackageInterface $package) {}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Installer;
|
||||
|
||||
class Exception extends \Exception
|
||||
{
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"name": "",
|
||||
"version": "3.0.0",
|
||||
"type": "composer-installer",
|
||||
"autoload": { "psr-0": { "Installer": "" } },
|
||||
"extra": {
|
||||
"class": "Installer\\Custom2"
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Installer;
|
||||
|
||||
use Composer\Installer\InstallerInterface;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Repository\InstalledRepositoryInterface;
|
||||
|
||||
class Custom1 implements InstallerInterface
|
||||
{
|
||||
public $name = 'custom1';
|
||||
public $version = 'installer-v4';
|
||||
|
||||
public function supports($packageType) {}
|
||||
public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package) {}
|
||||
public function install(InstalledRepositoryInterface $repo, PackageInterface $package) {}
|
||||
public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target) {}
|
||||
public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package) {}
|
||||
public function getInstallPath(PackageInterface $package) {}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Installer;
|
||||
|
||||
use Composer\Installer\InstallerInterface;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Repository\InstalledRepositoryInterface;
|
||||
|
||||
class Custom2 implements InstallerInterface
|
||||
{
|
||||
public $name = 'custom2';
|
||||
public $version = 'installer-v4';
|
||||
|
||||
public function supports($packageType) {}
|
||||
public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package) {}
|
||||
public function install(InstalledRepositoryInterface $repo, PackageInterface $package) {}
|
||||
public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target) {}
|
||||
public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package) {}
|
||||
public function getInstallPath(PackageInterface $package) {}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"name": "",
|
||||
"version": "4.0.0",
|
||||
"type": "composer-installer",
|
||||
"autoload": { "psr-0": { "Installer": "" } },
|
||||
"extra": {
|
||||
"class": [
|
||||
"Installer\\Custom1",
|
||||
"Installer\\Custom2"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -66,7 +66,7 @@ class InstallerTest extends TestCase
|
|||
$locker = $this->getMockBuilder('Composer\Package\Locker')->disableOriginalConstructor()->getMock();
|
||||
$installationManager = new InstallationManagerMock();
|
||||
|
||||
$eventDispatcher = $this->getMockBuilder('Composer\Script\EventDispatcher')->disableOriginalConstructor()->getMock();
|
||||
$eventDispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')->disableOriginalConstructor()->getMock();
|
||||
$autoloadGenerator = $this->getMockBuilder('Composer\Autoload\AutoloadGenerator')->disableOriginalConstructor()->getMock();
|
||||
|
||||
$installer = new Installer($io, $config, clone $rootPackage, $downloadManager, $repositoryManager, $locker, $installationManager, $eventDispatcher, $autoloadGenerator);
|
||||
|
@ -189,7 +189,7 @@ class InstallerTest extends TestCase
|
|||
$locker = new Locker($io, $lockJsonMock, $repositoryManager, $composer->getInstallationManager(), md5(json_encode($composerConfig)));
|
||||
$composer->setLocker($locker);
|
||||
|
||||
$eventDispatcher = $this->getMockBuilder('Composer\Script\EventDispatcher')->disableOriginalConstructor()->getMock();
|
||||
$eventDispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')->disableOriginalConstructor()->getMock();
|
||||
$autoloadGenerator = $this->getMock('Composer\Autoload\AutoloadGenerator', array(), array($eventDispatcher));
|
||||
$composer->setAutoloadGenerator($autoloadGenerator);
|
||||
$composer->setEventDispatcher($eventDispatcher);
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace Installer;
|
||||
|
||||
use Composer\Composer;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Plugin\PluginInterface;
|
||||
|
||||
class Plugin implements PluginInterface
|
||||
{
|
||||
public $version = 'installer-v1';
|
||||
|
||||
public function activate(Composer $composer, IOInterface $io)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"name": "plugin-v1",
|
||||
"version": "1.0.0",
|
||||
"type": "composer-plugin",
|
||||
"autoload": { "psr-0": { "Installer": "" } },
|
||||
"extra": {
|
||||
"class": "Installer\\Plugin"
|
||||
},
|
||||
"require": {
|
||||
"composer-plugin-api": "1.0.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace Installer;
|
||||
|
||||
use Composer\Composer;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Plugin\PluginInterface;
|
||||
|
||||
class Plugin2 implements PluginInterface
|
||||
{
|
||||
public $version = 'installer-v2';
|
||||
|
||||
public function activate(Composer $composer, IOInterface $io)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"name": "plugin-v2",
|
||||
"version": "2.0.0",
|
||||
"type": "composer-plugin",
|
||||
"autoload": { "psr-0": { "Installer": "" } },
|
||||
"extra": {
|
||||
"class": "Installer\\Plugin2"
|
||||
},
|
||||
"require": {
|
||||
"composer-plugin-api": "1.0.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace Installer;
|
||||
|
||||
use Composer\Composer;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Plugin\PluginInterface;
|
||||
|
||||
class Plugin2 implements PluginInterface
|
||||
{
|
||||
public $version = 'installer-v3';
|
||||
|
||||
public function activate(Composer $composer, IOInterface $io)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"name": "plugin-v3",
|
||||
"version": "3.0.0",
|
||||
"type": "composer-plugin",
|
||||
"autoload": { "psr-0": { "Installer": "" } },
|
||||
"extra": {
|
||||
"class": "Installer\\Plugin2"
|
||||
},
|
||||
"require": {
|
||||
"composer-plugin-api": "1.0.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Installer;
|
||||
|
||||
use Composer\Composer;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Plugin\PluginInterface;
|
||||
|
||||
class Plugin1 implements PluginInterface
|
||||
{
|
||||
public $name = 'plugin1';
|
||||
public $version = 'installer-v4';
|
||||
|
||||
public function activate(Composer $composer, IOInterface $io)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Installer;
|
||||
|
||||
use Composer\Composer;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Plugin\PluginInterface;
|
||||
|
||||
class Plugin2 implements PluginInterface
|
||||
{
|
||||
public $name = 'plugin2';
|
||||
public $version = 'installer-v4';
|
||||
|
||||
public function activate(Composer $composer, IOInterface $io)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "plugin-v4",
|
||||
"version": "4.0.0",
|
||||
"type": "composer-plugin",
|
||||
"autoload": { "psr-0": { "Installer": "" } },
|
||||
"extra": {
|
||||
"class": [
|
||||
"Installer\\Plugin1",
|
||||
"Installer\\Plugin2"
|
||||
]
|
||||
},
|
||||
"require": {
|
||||
"composer-plugin-api": "1.0.0"
|
||||
}
|
||||
}
|
|
@ -14,17 +14,19 @@ namespace Composer\Test\Installer;
|
|||
|
||||
use Composer\Composer;
|
||||
use Composer\Config;
|
||||
use Composer\Installer\InstallerInstaller;
|
||||
use Composer\Installer\PluginInstaller;
|
||||
use Composer\Package\Loader\JsonLoader;
|
||||
use Composer\Package\Loader\ArrayLoader;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Plugin\PluginManager;
|
||||
use Composer\Autoload\AutoloadGenerator;
|
||||
|
||||
class InstallerInstallerTest extends \PHPUnit_Framework_TestCase
|
||||
class PluginInstallerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected $composer;
|
||||
protected $packages;
|
||||
protected $im;
|
||||
protected $pm;
|
||||
protected $repository;
|
||||
protected $io;
|
||||
protected $autoloadGenerator;
|
||||
|
@ -34,17 +36,13 @@ class InstallerInstallerTest extends \PHPUnit_Framework_TestCase
|
|||
$loader = new JsonLoader(new ArrayLoader());
|
||||
$this->packages = array();
|
||||
for ($i = 1; $i <= 4; $i++) {
|
||||
$this->packages[] = $loader->load(__DIR__.'/Fixtures/installer-v'.$i.'/composer.json');
|
||||
$this->packages[] = $loader->load(__DIR__.'/Fixtures/plugin-v'.$i.'/composer.json');
|
||||
}
|
||||
|
||||
$dm = $this->getMockBuilder('Composer\Downloader\DownloadManager')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->im = $this->getMockBuilder('Composer\Installer\InstallationManager')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->repository = $this->getMock('Composer\Repository\InstalledRepositoryInterface');
|
||||
|
||||
$rm = $this->getMockBuilder('Composer\Repository\RepositoryManager')
|
||||
|
@ -56,127 +54,97 @@ class InstallerInstallerTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
$this->io = $this->getMock('Composer\IO\IOInterface');
|
||||
|
||||
$dispatcher = $this->getMockBuilder('Composer\Script\EventDispatcher')->disableOriginalConstructor()->getMock();
|
||||
$dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')->disableOriginalConstructor()->getMock();
|
||||
$this->autoloadGenerator = new AutoloadGenerator($dispatcher);
|
||||
|
||||
$this->composer = new Composer();
|
||||
$config = new Config();
|
||||
$this->composer->setConfig($config);
|
||||
$this->composer->setDownloadManager($dm);
|
||||
$this->composer->setInstallationManager($this->im);
|
||||
$this->composer->setRepositoryManager($rm);
|
||||
$this->composer->setAutoloadGenerator($this->autoloadGenerator);
|
||||
|
||||
$this->pm = new PluginManager($this->composer, $this->io);
|
||||
$this->composer->setPluginManager($this->pm);
|
||||
|
||||
$config->merge(array(
|
||||
'config' => array(
|
||||
'vendor-dir' => __DIR__.'/Fixtures/',
|
||||
'home' => __DIR__.'/Fixtures',
|
||||
'bin-dir' => __DIR__.'/Fixtures/bin',
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
public function testInstallNewInstaller()
|
||||
public function testInstallNewPlugin()
|
||||
{
|
||||
$this->repository
|
||||
->expects($this->once())
|
||||
->expects($this->exactly(2))
|
||||
->method('getPackages')
|
||||
->will($this->returnValue(array()));
|
||||
$installer = new InstallerInstallerMock($this->io, $this->composer);
|
||||
|
||||
$test = $this;
|
||||
$this->im
|
||||
->expects($this->once())
|
||||
->method('addInstaller')
|
||||
->will($this->returnCallback(function ($installer) use ($test) {
|
||||
$test->assertEquals('installer-v1', $installer->version);
|
||||
}));
|
||||
$installer = new PluginInstaller($this->io, $this->composer);
|
||||
$this->pm->loadInstalledPlugins();
|
||||
|
||||
$installer->install($this->repository, $this->packages[0]);
|
||||
|
||||
$plugins = $this->pm->getPlugins();
|
||||
$this->assertEquals('installer-v1', $plugins[0]->version);
|
||||
}
|
||||
|
||||
public function testInstallMultipleInstallers()
|
||||
public function testInstallMultiplePlugins()
|
||||
{
|
||||
$this->repository
|
||||
->expects($this->once())
|
||||
->expects($this->exactly(2))
|
||||
->method('getPackages')
|
||||
->will($this->returnValue(array()));
|
||||
|
||||
$installer = new InstallerInstallerMock($this->io, $this->composer);
|
||||
|
||||
$test = $this;
|
||||
|
||||
$this->im
|
||||
->expects($this->at(0))
|
||||
->method('addInstaller')
|
||||
->will($this->returnCallback(function ($installer) use ($test) {
|
||||
$test->assertEquals('custom1', $installer->name);
|
||||
$test->assertEquals('installer-v4', $installer->version);
|
||||
}));
|
||||
|
||||
$this->im
|
||||
->expects($this->at(1))
|
||||
->method('addInstaller')
|
||||
->will($this->returnCallback(function ($installer) use ($test) {
|
||||
$test->assertEquals('custom2', $installer->name);
|
||||
$test->assertEquals('installer-v4', $installer->version);
|
||||
}));
|
||||
$installer = new PluginInstaller($this->io, $this->composer);
|
||||
$this->pm->loadInstalledPlugins();
|
||||
|
||||
$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()
|
||||
{
|
||||
$this->repository
|
||||
->expects($this->once())
|
||||
->expects($this->exactly(3))
|
||||
->method('getPackages')
|
||||
->will($this->returnValue(array($this->packages[0])));
|
||||
$this->repository
|
||||
->expects($this->exactly(2))
|
||||
->method('hasPackage')
|
||||
->will($this->onConsecutiveCalls(true, false));
|
||||
$installer = new InstallerInstallerMock($this->io, $this->composer);
|
||||
|
||||
$test = $this;
|
||||
$this->im
|
||||
->expects($this->once())
|
||||
->method('addInstaller')
|
||||
->will($this->returnCallback(function ($installer) use ($test) {
|
||||
$test->assertEquals('installer-v2', $installer->version);
|
||||
}));
|
||||
$installer = new PluginInstaller($this->io, $this->composer);
|
||||
$this->pm->loadInstalledPlugins();
|
||||
|
||||
$installer->update($this->repository, $this->packages[0], $this->packages[1]);
|
||||
|
||||
$plugins = $this->pm->getPlugins();
|
||||
$this->assertEquals('installer-v2', $plugins[1]->version);
|
||||
}
|
||||
|
||||
public function testUpgradeWithSameClassName()
|
||||
{
|
||||
$this->repository
|
||||
->expects($this->once())
|
||||
->expects($this->exactly(3))
|
||||
->method('getPackages')
|
||||
->will($this->returnValue(array($this->packages[1])));
|
||||
$this->repository
|
||||
->expects($this->exactly(2))
|
||||
->method('hasPackage')
|
||||
->will($this->onConsecutiveCalls(true, false));
|
||||
$installer = new InstallerInstallerMock($this->io, $this->composer);
|
||||
|
||||
$test = $this;
|
||||
$this->im
|
||||
->expects($this->once())
|
||||
->method('addInstaller')
|
||||
->will($this->returnCallback(function ($installer) use ($test) {
|
||||
$test->assertEquals('installer-v3', $installer->version);
|
||||
}));
|
||||
$installer = new PluginInstaller($this->io, $this->composer);
|
||||
$this->pm->loadInstalledPlugins();
|
||||
|
||||
$installer->update($this->repository, $this->packages[1], $this->packages[2]);
|
||||
|
||||
$plugins = $this->pm->getPlugins();
|
||||
$this->assertEquals('installer-v3', $plugins[1]->version);
|
||||
}
|
||||
}
|
||||
|
||||
class InstallerInstallerMock extends InstallerInstaller
|
||||
{
|
||||
public function getInstallPath(PackageInterface $package)
|
||||
{
|
||||
$version = $package->getVersion();
|
||||
|
||||
return __DIR__.'/Fixtures/installer-v'.$version[0].'/';
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue