Merge origin/master
Conflicts: doc/03-cli.md doc/04-schema.md src/Composer/Factory.phpmain
commit
e6560c0462
@ -1,11 +1,27 @@
|
||||
language: php
|
||||
|
||||
php:
|
||||
php:
|
||||
- 5.3.3
|
||||
- 5.3
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
- hhvm
|
||||
|
||||
before_script: composer install
|
||||
matrix:
|
||||
allow_failures:
|
||||
- php: hhvm
|
||||
|
||||
script: phpunit -c tests/complete.phpunit.xml
|
||||
before_script:
|
||||
- sudo apt-get install parallel
|
||||
- rm -f ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini
|
||||
- composer install --prefer-source
|
||||
- bin/composer install --prefer-source
|
||||
- git config --global user.name travis-ci
|
||||
- git config --global user.email travis@example.com
|
||||
|
||||
script:
|
||||
- ls -d tests/Composer/Test/* | parallel --gnu --keep-order 'echo "Running {} tests"; ./vendor/bin/phpunit -c tests/complete.phpunit.xml {};' || exit 1
|
||||
|
||||
git:
|
||||
depth: 5
|
@ -0,0 +1,160 @@
|
||||
<!--
|
||||
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
|
||||
|
||||
```json
|
||||
{
|
||||
"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:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
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.
|
||||
|
||||
> A plugin can also subscribe to [script events][7].
|
||||
|
||||
Example:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
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
|
||||
[7]: ./scripts.md#event-names
|
@ -0,0 +1,21 @@
|
||||
# Why are unbound version constraints a bad idea?
|
||||
|
||||
A version constraint without an upper bound such as `*`, `>=3.4` or
|
||||
`dev-master` will allow updates to any future version of the dependency.
|
||||
This includes major versions breaking backward compatibility.
|
||||
|
||||
Once a release of your package is tagged, you cannot tweak its dependencies
|
||||
anymore in case a dependency breaks BC - you have to do a new release but the
|
||||
previous one stays broken.
|
||||
|
||||
The only good alternative is to define an upper bound on your constraints,
|
||||
which you can increase in a new release after testing that your package is
|
||||
compatible with the new major version of your dependency.
|
||||
|
||||
For example instead of using `>=3.4` you should use `~3.4` which allows all
|
||||
versions up to `3.999` but does not include `4.0` and above. The `~` operator
|
||||
works very well with libraries follow [semantic versioning](http://semver.org).
|
||||
|
||||
**Note:** As a package maintainer, you can make the life of your users easier
|
||||
by providing an [alias version](../articles/aliases.md) for your development
|
||||
branch to allow it to match bound constraints.
|
@ -1,34 +1,44 @@
|
||||
[
|
||||
"AFL-1.1", "AFL-1.2", "AFL-2.0", "AFL-2.1", "AFL-3.0", "APL-1.0",
|
||||
"AFL-1.1", "AFL-1.2", "AFL-2.0", "AFL-2.1", "AFL-3.0", "APL-1.0", "Aladdin",
|
||||
"ANTLR-PD", "Apache-1.0", "Apache-1.1", "Apache-2.0", "APSL-1.0",
|
||||
"APSL-1.1", "APSL-1.2", "APSL-2.0", "Artistic-1.0", "Artistic-2.0", "AAL",
|
||||
"BSL-1.0", "BSD-2-Clause", "BSD-2-Clause-NetBSD", "BSD-2-Clause-FreeBSD",
|
||||
"BSD-3-Clause", "BSD-4-Clause", "BSD-4-Clause-UC", "CECILL-1.0",
|
||||
"CECILL-1.1", "CECILL-2.0", "CECILL-B", "CECILL-C", "ClArtistic",
|
||||
"CNRI-Python-GPL-Compatible", "CNRI-Python", "CDDL-1.0", "CDDL-1.1",
|
||||
"CPAL-1.0", "CPL-1.0", "CATOSL-1.1", "CC-BY-1.0", "CC-BY-2.0", "CC-BY-2.5",
|
||||
"CC-BY-3.0", "CC-BY-ND-1.0", "CC-BY-ND-2.0", "CC-BY-ND-2.5", "CC-BY-ND-3.0",
|
||||
"APSL-1.1", "APSL-1.2", "APSL-2.0", "Artistic-1.0", "Artistic-1.0-cl8",
|
||||
"Artistic-1.0-Perl", "Artistic-2.0", "AAL", "BitTorrent-1.0",
|
||||
"BitTorrent-1.1", "BSL-1.0", "BSD-2-Clause", "BSD-2-Clause-FreeBSD",
|
||||
"BSD-2-Clause-NetBSD", "BSD-3-Clause", "BSD-3-Clause-Clear", "BSD-4-Clause",
|
||||
"BSD-4-Clause-UC", "CECILL-1.0", "CECILL-1.1", "CECILL-2.0", "CECILL-B",
|
||||
"CECILL-C", "ClArtistic", "CNRI-Python", "CNRI-Python-GPL-Compatible",
|
||||
"CPOL-1.02", "CDDL-1.0", "CDDL-1.1", "CPAL-1.0", "CPL-1.0", "CATOSL-1.1",
|
||||
"Condor-1.1", "CC-BY-1.0", "CC-BY-2.0", "CC-BY-2.5", "CC-BY-3.0",
|
||||
"CC-BY-ND-1.0", "CC-BY-ND-2.0", "CC-BY-ND-2.5", "CC-BY-ND-3.0",
|
||||
"CC-BY-NC-1.0", "CC-BY-NC-2.0", "CC-BY-NC-2.5", "CC-BY-NC-3.0",
|
||||
"CC-BY-NC-ND-1.0", "CC-BY-NC-ND-2.0", "CC-BY-NC-ND-2.5", "CC-BY-NC-ND-3.0",
|
||||
"CC-BY-NC-SA-1.0", "CC-BY-NC-SA-2.0", "CC-BY-NC-SA-2.5", "CC-BY-NC-SA-3.0",
|
||||
"CC-BY-SA-1.0", "CC-BY-SA-2.0", "CC-BY-SA-2.5", "CC-BY-SA-3.0", "CC0-1.0",
|
||||
"CUA-OPL-1.0", "EPL-1.0", "eCos-2.0", "ECL-1.0", "ECL-2.0", "EFL-1.0",
|
||||
"EFL-2.0", "Entessa", "ErlPL-1.1", "EUDatagrid", "EUPL-1.0", "EUPL-1.1",
|
||||
"Fair", "Frameworx-1.0", "AGPL-3.0", "GFDL-1.1", "GFDL-1.2", "GFDL-1.3",
|
||||
"GPL-1.0", "GPL-1.0+", "GPL-2.0", "GPL-2.0+",
|
||||
"GPL-2.0-with-autoconf-exception", "GPL-2.0-with-bison-exception",
|
||||
"GPL-2.0-with-classpath-exception", "GPL-2.0-with-font-exception",
|
||||
"GPL-2.0-with-GCC-exception", "GPL-3.0", "GPL-3.0+",
|
||||
"GPL-3.0-with-autoconf-exception", "GPL-3.0-with-GCC-exception", "LGPL-2.1",
|
||||
"LGPL-2.1+", "LGPL-3.0", "LGPL-3.0+", "LGPL-2.0", "LGPL-2.0+", "gSOAP-1.3b",
|
||||
"HPND", "IPL-1.0", "IPA", "ISC", "LPPL-1.0", "LPPL-1.1", "LPPL-1.2",
|
||||
"LPPL-1.3c", "Libpng", "LPL-1.0", "LPL-1.02", "MS-PL", "MS-RL", "MirOS",
|
||||
"MIT", "Motosoto", "MPL-1.0", "MPL-1.1", "MPL-2.0", "Multics", "NASA-1.3",
|
||||
"Naumen", "NGPL", "Nokia", "NPOSL-3.0", "NTP", "OCLC-2.0", "ODbL-1.0",
|
||||
"PDDL-1.0", "OGTSL", "OSL-1.0", "OSL-2.0", "OSL-2.1", "OSL-3.0",
|
||||
"OLDAP-2.8", "OpenSSL", "PHP-3.0", "PHP-3.01", "PostgreSQL", "Python-2.0",
|
||||
"QPL-1.0", "RPSL-1.0", "RPL-1.5", "RHeCos-1.1", "RSCPL", "Ruby", "SAX-PD",
|
||||
"OFL-1.0", "OFL-1.1", "SimPL-2.0", "Sleepycat", "SugarCRM-1.1.3", "SPL-1.0",
|
||||
"Watcom-1.0", "NCSA", "VSL-1.0", "W3C", "WXwindows", "Xnet", "XFree86-1.1",
|
||||
"YPL-1.0", "YPL-1.1", "Zimbra-1.3", "Zlib", "ZPL-1.1", "ZPL-2.0", "ZPL-2.1"
|
||||
"CUA-OPL-1.0", "D-FSL-1.0", "WTFPL", "EPL-1.0", "eCos-2.0", "ECL-1.0",
|
||||
"ECL-2.0", "EFL-1.0", "EFL-2.0", "Entessa", "ErlPL-1.1", "EUDatagrid",
|
||||
"EUPL-1.0", "EUPL-1.1", "Fair", "Frameworx-1.0", "FTL", "AGPL-1.0",
|
||||
"AGPL-3.0", "GFDL-1.1", "GFDL-1.2", "GFDL-1.3", "GPL-1.0", "GPL-1.0+",
|
||||
"GPL-2.0", "GPL-2.0+", "GPL-2.0-with-autoconf-exception",
|
||||
"GPL-2.0-with-bison-exception", "GPL-2.0-with-classpath-exception",
|
||||
"GPL-2.0-with-font-exception", "GPL-2.0-with-GCC-exception", "GPL-3.0",
|
||||
"GPL-3.0+", "GPL-3.0-with-autoconf-exception", "GPL-3.0-with-GCC-exception",
|
||||
"LGPL-2.1", "LGPL-2.1+", "LGPL-3.0", "LGPL-3.0+", "LGPL-2.0", "LGPL-2.0+",
|
||||
"gSOAP-1.3b", "HPND", "IBM-pibs", "IPL-1.0", "Imlib2", "IJG", "Intel",
|
||||
"IPA", "ISC", "JSON", "LPPL-1.3a", "LPPL-1.0", "LPPL-1.1", "LPPL-1.2",
|
||||
"LPPL-1.3c", "Libpng", "LPL-1.02", "LPL-1.0", "MS-PL", "MS-RL", "MirOS",
|
||||
"MIT", "Motosoto", "MPL-1.0", "MPL-1.1", "MPL-2.0",
|
||||
"MPL-2.0-no-copyleft-exception", "Multics", "NASA-1.3", "Naumen",
|
||||
"NBPL-1.0", "NGPL", "NOSL", "NPL-1.0", "NPL-1.1", "Nokia", "NPOSL-3.0",
|
||||
"NTP", "OCLC-2.0", "ODbL-1.0", "PDDL-1.0", "OGTSL", "OLDAP-2.2.2",
|
||||
"OLDAP-1.1", "OLDAP-1.2", "OLDAP-1.3", "OLDAP-1.4", "OLDAP-2.0",
|
||||
"OLDAP-2.0.1", "OLDAP-2.1", "OLDAP-2.2", "OLDAP-2.2.1", "OLDAP-2.3",
|
||||
"OLDAP-2.4", "OLDAP-2.5", "OLDAP-2.6", "OLDAP-2.7", "OPL-1.0", "OSL-1.0",
|
||||
"OSL-2.0", "OSL-2.1", "OSL-3.0", "OLDAP-2.8", "OpenSSL", "PHP-3.0",
|
||||
"PHP-3.01", "PostgreSQL", "Python-2.0", "QPL-1.0", "RPSL-1.0", "RPL-1.1",
|
||||
"RPL-1.5", "RHeCos-1.1", "RSCPL", "Ruby", "SAX-PD", "SGI-B-1.0",
|
||||
"SGI-B-1.1", "SGI-B-2.0", "OFL-1.0", "OFL-1.1", "SimPL-2.0", "Sleepycat",
|
||||
"SMLNJ", "SugarCRM-1.1.3", "SISSL", "SISSL-1.2", "SPL-1.0", "Watcom-1.0",
|
||||
"NCSA", "VSL-1.0", "W3C", "WXwindows", "Xnet", "X11", "XFree86-1.1",
|
||||
"YPL-1.0", "YPL-1.1", "Zimbra-1.3", "Zlib", "ZPL-1.1", "ZPL-2.0", "ZPL-2.1",
|
||||
"Unlicense"
|
||||
]
|
@ -0,0 +1,143 @@
|
||||
<?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\Command;
|
||||
|
||||
use Composer\Factory;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\DependencyResolver\Pool;
|
||||
use Composer\Package\LinkConstraint\VersionConstraint;
|
||||
use Composer\Repository\CompositeRepository;
|
||||
use Composer\Script\ScriptEvents;
|
||||
use Composer\Plugin\CommandEvent;
|
||||
use Composer\Plugin\PluginEvents;
|
||||
use Composer\Package\Version\VersionParser;
|
||||
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Creates an archive of a package for distribution.
|
||||
*
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
*/
|
||||
class ArchiveCommand extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('archive')
|
||||
->setDescription('Create an archive of this composer package')
|
||||
->setDefinition(array(
|
||||
new InputArgument('package', InputArgument::OPTIONAL, 'The package to archive instead of the current project'),
|
||||
new InputArgument('version', InputArgument::OPTIONAL, 'A version constraint to find the package to archive'),
|
||||
new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the resulting archive: tar or zip', 'tar'),
|
||||
new InputOption('dir', false, InputOption::VALUE_REQUIRED, 'Write the archive to this directory', '.'),
|
||||
))
|
||||
->setHelp(<<<EOT
|
||||
The <info>archive</info> command creates an archive of the specified format
|
||||
containing the files and directories of the Composer project or the specified
|
||||
package in the specified version and writes it to the specified directory.
|
||||
|
||||
<info>php composer.phar archive [--format=zip] [--dir=/foo] [package [version]]</info>
|
||||
|
||||
EOT
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$composer = $this->getComposer(false);
|
||||
if ($composer) {
|
||||
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'archive', $input, $output);
|
||||
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
|
||||
$composer->getEventDispatcher()->dispatchScript(ScriptEvents::PRE_ARCHIVE_CMD);
|
||||
}
|
||||
|
||||
$returnCode = $this->archive(
|
||||
$this->getIO(),
|
||||
$input->getArgument('package'),
|
||||
$input->getArgument('version'),
|
||||
$input->getOption('format'),
|
||||
$input->getOption('dir')
|
||||
);
|
||||
|
||||
if (0 === $returnCode && $composer) {
|
||||
$composer->getEventDispatcher()->dispatchScript(ScriptEvents::POST_ARCHIVE_CMD);
|
||||
}
|
||||
|
||||
return $returnCode;
|
||||
}
|
||||
|
||||
protected function archive(IOInterface $io, $packageName = null, $version = null, $format = 'tar', $dest = '.')
|
||||
{
|
||||
$config = Factory::createConfig();
|
||||
$factory = new Factory;
|
||||
$downloadManager = $factory->createDownloadManager($io, $config);
|
||||
$archiveManager = $factory->createArchiveManager($config, $downloadManager);
|
||||
|
||||
if ($packageName) {
|
||||
$package = $this->selectPackage($io, $packageName, $version);
|
||||
|
||||
if (!$package) {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
$package = $this->getComposer()->getPackage();
|
||||
}
|
||||
|
||||
$io->write('<info>Creating the archive.</info>');
|
||||
$archiveManager->archive($package, $format, $dest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected function selectPackage(IOInterface $io, $packageName, $version = null)
|
||||
{
|
||||
$io->write('<info>Searching for the specified package.</info>');
|
||||
|
||||
if ($composer = $this->getComposer(false)) {
|
||||
$localRepo = $composer->getRepositoryManager()->getLocalRepository();
|
||||
$repos = new CompositeRepository(array_merge(array($localRepo), $composer->getRepositoryManager()->getRepositories()));
|
||||
} else {
|
||||
$defaultRepos = Factory::createDefaultRepositories($this->getIO());
|
||||
$io->write('No composer.json found in the current directory, searching packages from ' . implode(', ', array_keys($defaultRepos)));
|
||||
$repos = new CompositeRepository($defaultRepos);
|
||||
}
|
||||
|
||||
$pool = new Pool();
|
||||
$pool->addRepository($repos);
|
||||
|
||||
$parser = new VersionParser();
|
||||
$constraint = ($version) ? $parser->parseConstraints($version) : null;
|
||||
$packages = $pool->whatProvides($packageName, $constraint, true);
|
||||
|
||||
if (count($packages) > 1) {
|
||||
$package = reset($packages);
|
||||
$io->write('<info>Found multiple matches, selected '.$package->getPrettyString().'.</info>');
|
||||
$io->write('Alternatives were '.implode(', ', array_map(function ($p) { return $p->getPrettyString(); }, $packages)).'.');
|
||||
$io->write('<comment>Please use a more specific constraint to pick a different package.</comment>');
|
||||
} elseif ($packages) {
|
||||
$package = reset($packages);
|
||||
$io->write('<info>Found an exact match '.$package->getPrettyString().'.</info>');
|
||||
} else {
|
||||
$io->write('<error>Could not find a package matching '.$packageName.'.</error>');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return $package;
|
||||
}
|
||||
}
|
@ -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\Command;
|
||||
|
||||
use Composer\Cache;
|
||||
use Composer\Factory;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* @author David Neilsen <petah.p@gmail.com>
|
||||
*/
|
||||
class ClearCacheCommand extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('clear-cache')
|
||||
->setAliases(array('clearcache'))
|
||||
->setDescription('Clears composer\'s internal package cache.')
|
||||
->setHelp(<<<EOT
|
||||
The <info>clear-cache</info> deletes all cached packages from composer's
|
||||
cache directory.
|
||||
EOT
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$config = Factory::createConfig();
|
||||
$io = $this->getIO();
|
||||
|
||||
$cachePaths = array(
|
||||
'cache-dir' => $config->get('cache-dir'),
|
||||
'cache-files-dir' => $config->get('cache-files-dir'),
|
||||
'cache-repo-dir' => $config->get('cache-repo-dir'),
|
||||
'cache-vcs-dir' => $config->get('cache-vcs-dir'),
|
||||
);
|
||||
|
||||
foreach ($cachePaths as $key => $cachePath) {
|
||||
$cachePath = realpath($cachePath);
|
||||
if (!$cachePath) {
|
||||
$io->write("<info>Cache directory does not exist ($key): $cachePath</info>");
|
||||
return;
|
||||
}
|
||||
$cache = new Cache($io, $cachePath);
|
||||
if (!$cache->isEnabled()) {
|
||||
$io->write("<info>Cache is not enabled ($key): $cachePath</info>");
|
||||
return;
|
||||
}
|
||||
|
||||
$io->write("<info>Clearing cache ($key): $cachePath</info>");
|
||||
$cache->gc(0, 0);
|
||||
}
|
||||
|
||||
$io->write('<info>All caches cleared.</info>');
|
||||
}
|
||||
}
|
@ -0,0 +1,413 @@
|
||||
<?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\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\ProcessExecutor;
|
||||
use Composer\Util\RemoteFilesystem;
|
||||
use Composer\Util\StreamContextFactory;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class DiagnoseCommand extends Command
|
||||
{
|
||||
protected $rfs;
|
||||
protected $process;
|
||||
protected $failures = 0;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('diagnose')
|
||||
->setDescription('Diagnoses the system to identify common errors.')
|
||||
->setHelp(<<<EOT
|
||||
The <info>diagnose</info> command checks common errors to help debugging problems.
|
||||
|
||||
EOT
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$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());
|
||||
}
|
||||
|
||||
if ($composer) {
|
||||
$config = $composer->getConfig();
|
||||
} else {
|
||||
$config = Factory::createConfig();
|
||||
}
|
||||
|
||||
$this->rfs = new RemoteFilesystem($this->getIO(), $config);
|
||||
$this->process = new ProcessExecutor($this->getIO());
|
||||
|
||||
$output->write('Checking platform settings: ');
|
||||
$this->outputResult($output, $this->checkPlatform());
|
||||
|
||||
$output->write('Checking git settings: ');
|
||||
$this->outputResult($output, $this->checkGit());
|
||||
|
||||
$output->write('Checking http connectivity: ');
|
||||
$this->outputResult($output, $this->checkHttp());
|
||||
|
||||
$opts = stream_context_get_options(StreamContextFactory::getContext('http://example.org'));
|
||||
if (!empty($opts['http']['proxy'])) {
|
||||
$output->write('Checking HTTP proxy: ');
|
||||
$this->outputResult($output, $this->checkHttpProxy());
|
||||
$output->write('Checking HTTP proxy support for request_fulluri: ');
|
||||
$this->outputResult($output, $this->checkHttpProxyFullUriRequestParam());
|
||||
$output->write('Checking HTTPS proxy support for request_fulluri: ');
|
||||
$this->outputResult($output, $this->checkHttpsProxyFullUriRequestParam());
|
||||
}
|
||||
|
||||
if ($oauth = $config->get('github-oauth')) {
|
||||
foreach ($oauth as $domain => $token) {
|
||||
$output->write('Checking '.$domain.' oauth access: ');
|
||||
$this->outputResult($output, $this->checkGithubOauth($domain, $token));
|
||||
}
|
||||
}
|
||||
|
||||
$output->write('Checking disk free space: ');
|
||||
$this->outputResult($output, $this->checkDiskSpace($config));
|
||||
|
||||
$output->write('Checking composer version: ');
|
||||
$this->outputResult($output, $this->checkVersion());
|
||||
|
||||
return $this->failures;
|
||||
}
|
||||
|
||||
private function checkComposerSchema()
|
||||
{
|
||||
$validator = new ConfigValidator($this->getIO());
|
||||
list($errors, $publishErrors, $warnings) = $validator->validate(Factory::getComposerFile());
|
||||
|
||||
if ($errors || $publishErrors || $warnings) {
|
||||
$messages = array(
|
||||
'error' => array_merge($errors, $publishErrors),
|
||||
'warning' => $warnings,
|
||||
);
|
||||
|
||||
$output = '';
|
||||
foreach ($messages as $style => $msgs) {
|
||||
foreach ($msgs as $msg) {
|
||||
$output .= '<' . $style . '>' . $msg . '</' . $style . '>' . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
return rtrim($output);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function checkGit()
|
||||
{
|
||||
$this->process->execute('git config color.ui', $output);
|
||||
if (strtolower(trim($output)) === 'always') {
|
||||
return '<warning>Your git color.ui setting is set to always, this is known to create issues. Use "git config --global color.ui true" to set it correctly.</warning>';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function checkHttp()
|
||||
{
|
||||
$protocol = extension_loaded('openssl') ? 'https' : 'http';
|
||||
try {
|
||||
$json = $this->rfs->getContents('packagist.org', $protocol . '://packagist.org/packages.json', false);
|
||||
} catch (\Exception $e) {
|
||||
return $e;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function checkHttpProxy()
|
||||
{
|
||||
$protocol = extension_loaded('openssl') ? 'https' : 'http';
|
||||
try {
|
||||
$json = json_decode($this->rfs->getContents('packagist.org', $protocol . '://packagist.org/packages.json', false), true);
|
||||
$hash = reset($json['provider-includes']);
|
||||
$hash = $hash['sha256'];
|
||||
$path = str_replace('%hash%', $hash, key($json['provider-includes']));
|
||||
$provider = $this->rfs->getContents('packagist.org', $protocol . '://packagist.org/'.$path, false);
|
||||
|
||||
if (hash('sha256', $provider) !== $hash) {
|
||||
return 'It seems that your proxy is modifying http traffic on the fly';
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $e;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Due to various proxy servers configurations, some servers can't handle non-standard HTTP "http_proxy_request_fulluri" parameter,
|
||||
* and will return error 500/501 (as not implemented), see discussion @ https://github.com/composer/composer/pull/1825.
|
||||
* This method will test, if you need to disable this parameter via setting extra environment variable in your system.
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
private function checkHttpProxyFullUriRequestParam()
|
||||
{
|
||||
$url = 'http://packagist.org/packages.json';
|
||||
try {
|
||||
$this->rfs->getContents('packagist.org', $url, false);
|
||||
} catch (TransportException $e) {
|
||||
try {
|
||||
$this->rfs->getContents('packagist.org', $url, false, array('http' => array('request_fulluri' => false)));
|
||||
} catch (TransportException $e) {
|
||||
return 'Unable to assess the situation, maybe packagist.org is down ('.$e->getMessage().')';
|
||||
}
|
||||
|
||||
return 'It seems there is a problem with your proxy server, try setting the "HTTP_PROXY_REQUEST_FULLURI" and "HTTPS_PROXY_REQUEST_FULLURI" environment variables to "false"';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Due to various proxy servers configurations, some servers can't handle non-standard HTTP "http_proxy_request_fulluri" parameter,
|
||||
* and will return error 500/501 (as not implemented), see discussion @ https://github.com/composer/composer/pull/1825.
|
||||
* This method will test, if you need to disable this parameter via setting extra environment variable in your system.
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
private function checkHttpsProxyFullUriRequestParam()
|
||||
{
|
||||
if (!extension_loaded('openssl')) {
|
||||
return 'You need the openssl extension installed for this check';
|
||||
}
|
||||
|
||||
$url = 'https://api.github.com/repos/Seldaek/jsonlint/zipball/1.0.0';
|
||||
try {
|
||||
$rfcResult = $this->rfs->getContents('github.com', $url, false);
|
||||
} catch (TransportException $e) {
|
||||
try {
|
||||
$this->rfs->getContents('github.com', $url, false, array('http' => array('request_fulluri' => false)));
|
||||
} catch (TransportException $e) {
|
||||
return 'Unable to assess the situation, maybe github is down ('.$e->getMessage().')';
|
||||
}
|
||||
|
||||
return 'It seems there is a problem with your proxy server, try setting the "HTTPS_PROXY_REQUEST_FULLURI" environment variable to "false"';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function checkGithubOauth($domain, $token)
|
||||
{
|
||||
$this->getIO()->setAuthentication($domain, $token, 'x-oauth-basic');
|
||||
try {
|
||||
$url = $domain === 'github.com' ? 'https://api.'.$domain.'/user/repos' : 'https://'.$domain.'/api/v3/user/repos';
|
||||
|
||||
return $this->rfs->getContents($domain, $url, false) ? true : 'Unexpected error';
|
||||
} catch (\Exception $e) {
|
||||
if ($e instanceof TransportException && $e->getCode() === 401) {
|
||||
return '<warning>The oauth token for '.$domain.' seems invalid, run "composer config --global --unset github-oauth.'.$domain.'" to remove it</warning>';
|
||||
}
|
||||
|
||||
return $e;
|
||||
}
|
||||
}
|
||||
|
||||
private function checkDiskSpace($config)
|
||||
{
|
||||
$minSpaceFree = 1024*1024;
|
||||
if ((($df = @disk_free_space($dir = $config->get('home'))) !== false && $df < $minSpaceFree)
|
||||
|| (($df = @disk_free_space($dir = $config->get('vendor-dir'))) !== false && $df < $minSpaceFree)
|
||||
) {
|
||||
return '<error>The disk hosting '.$dir.' is full</error>';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function checkVersion()
|
||||
{
|
||||
$protocol = extension_loaded('openssl') ? 'https' : 'http';
|
||||
$latest = trim($this->rfs->getContents('getcomposer.org', $protocol . '://getcomposer.org/version', false));
|
||||
|
||||
if (Composer::VERSION !== $latest && Composer::VERSION !== '@package_version@') {
|
||||
return '<warning>Your are not running the latest version</warning>';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function outputResult(OutputInterface $output, $result)
|
||||
{
|
||||
if (true === $result) {
|
||||
$output->writeln('<info>OK</info>');
|
||||
} else {
|
||||
$this->failures++;
|
||||
$output->writeln('<error>FAIL</error>');
|
||||
if ($result instanceof \Exception) {
|
||||
$output->writeln('['.get_class($result).'] '.$result->getMessage());
|
||||
} elseif ($result) {
|
||||
$output->writeln($result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function checkPlatform()
|
||||
{
|
||||
$output = '';
|
||||
$out = function ($msg, $style) use (&$output) {
|
||||
$output .= '<'.$style.'>'.$msg.'</'.$style.'>';
|
||||
};
|
||||
|
||||
// code below taken from getcomposer.org/installer, any changes should be made there and replicated here
|
||||
$errors = array();
|
||||
$warnings = array();
|
||||
|
||||
$iniPath = php_ini_loaded_file();
|
||||
$displayIniMessage = false;
|
||||
if ($iniPath) {
|
||||
$iniMessage = PHP_EOL.PHP_EOL.'The php.ini used by your command-line PHP is: ' . $iniPath;
|
||||
} else {
|
||||
$iniMessage = PHP_EOL.PHP_EOL.'A php.ini file does not exist. You will have to create one.';
|
||||
}
|
||||
$iniMessage .= PHP_EOL.'If you can not modify the ini file, you can also run `php -d option=value` to modify ini values on the fly. You can use -d multiple times.';
|
||||
|
||||
if (!ini_get('allow_url_fopen')) {
|
||||
$errors['allow_url_fopen'] = true;
|
||||
}
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.3.2', '<')) {
|
||||
$errors['php'] = PHP_VERSION;
|
||||
}
|
||||
|
||||
if (!isset($errors['php']) && version_compare(PHP_VERSION, '5.3.4', '<')) {
|
||||
$warnings['php'] = PHP_VERSION;
|
||||
}
|
||||
|
||||
if (!extension_loaded('openssl')) {
|
||||
$warnings['openssl'] = true;
|
||||
}
|
||||
|
||||
if (!defined('HHVM_VERSION') && !extension_loaded('apcu') && ini_get('apc.enable_cli')) {
|
||||
$warnings['apc_cli'] = true;
|
||||
}
|
||||
|
||||
if (ini_get('xdebug.profiler_enabled')) {
|
||||
$warnings['xdebug_profile'] = true;
|
||||
} elseif (extension_loaded('xdebug')) {
|
||||
$warnings['xdebug_loaded'] = true;
|
||||
}
|
||||
|
||||
ob_start();
|
||||
phpinfo(INFO_GENERAL);
|
||||
$phpinfo = ob_get_clean();
|
||||
if (preg_match('{Configure Command(?: *</td><td class="v">| *=> *)(.*?)(?:</td>|$)}m', $phpinfo, $match)) {
|
||||
$configure = $match[1];
|
||||
|
||||
if (false !== strpos($configure, '--enable-sigchild')) {
|
||||
$warnings['sigchild'] = true;
|
||||
}
|
||||
|
||||
if (false !== strpos($configure, '--with-curlwrappers')) {
|
||||
$warnings['curlwrappers'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($errors)) {
|
||||
foreach ($errors as $error => $current) {
|
||||
switch ($error) {
|
||||
case 'php':
|
||||
$text = PHP_EOL."Your PHP ({$current}) is too old, you must upgrade to PHP 5.3.2 or higher.";
|
||||
break;
|
||||
|
||||
case 'allow_url_fopen':
|
||||
$text = PHP_EOL."The allow_url_fopen setting is incorrect.".PHP_EOL;
|
||||
$text .= "Add the following to the end of your `php.ini`:".PHP_EOL;
|
||||
$text .= " allow_url_fopen = On";
|
||||
$displayIniMessage = true;
|
||||
break;
|
||||
}
|
||||
$out($text, 'error');
|
||||
}
|
||||
|
||||
$output .= PHP_EOL;
|
||||
}
|
||||
|
||||
if (!empty($warnings)) {
|
||||
foreach ($warnings as $warning => $current) {
|
||||
switch ($warning) {
|
||||
case 'apc_cli':
|
||||
$text = PHP_EOL."The apc.enable_cli setting is incorrect.".PHP_EOL;
|
||||
$text .= "Add the following to the end of your `php.ini`:".PHP_EOL;
|
||||
$text .= " apc.enable_cli = Off";
|
||||
$displayIniMessage = true;
|
||||
break;
|
||||
|
||||
case 'sigchild':
|
||||
$text = PHP_EOL."PHP was compiled with --enable-sigchild which can cause issues on some platforms.".PHP_EOL;
|
||||
$text .= "Recompile it without this flag if possible, see also:".PHP_EOL;
|
||||
$text .= " https://bugs.php.net/bug.php?id=22999";
|
||||
break;
|
||||
|
||||
case 'curlwrappers':
|
||||
$text = PHP_EOL."PHP was compiled with --with-curlwrappers which will cause issues with HTTP authentication and GitHub.".PHP_EOL;
|
||||
$text .= "Recompile it without this flag if possible";
|
||||
break;
|
||||
|
||||
case 'openssl':
|
||||
$text = PHP_EOL."The openssl extension is missing, which will reduce the security and stability of Composer.".PHP_EOL;
|
||||
$text .= "If possible you should enable it or recompile php with --with-openssl";
|
||||
break;
|
||||
|
||||
case 'php':
|
||||
$text = PHP_EOL."Your PHP ({$current}) is quite old, upgrading to PHP 5.3.4 or higher is recommended.".PHP_EOL;
|
||||
$text .= "Composer works with 5.3.2+ for most people, but there might be edge case issues.";
|
||||
break;
|
||||
|
||||
case 'xdebug_loaded':
|
||||
$text = PHP_EOL."The xdebug extension is loaded, this can slow down Composer a little.".PHP_EOL;
|
||||
$text .= "Disabling it when using Composer is recommended, but should not cause issues beyond slowness.";
|
||||
break;
|
||||
|
||||
case 'xdebug_profile':
|
||||
$text = PHP_EOL."The xdebug.profiler_enabled setting is enabled, this can slow down Composer a lot.".PHP_EOL;
|
||||
$text .= "Add the following to the end of your `php.ini` to disable it:".PHP_EOL;
|
||||
$text .= " xdebug.profiler_enabled = 0";
|
||||
$displayIniMessage = true;
|
||||
break;
|
||||
}
|
||||
$out($text, 'warning');
|
||||
}
|
||||
}
|
||||
|
||||
if ($displayIniMessage) {
|
||||
$out($iniMessage, 'warning');
|
||||
}
|
||||
|
||||
return !$warnings && !$errors ? true : $output;
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
<?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\Command;
|
||||
|
||||
use Composer\Factory;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\StringInput;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class GlobalCommand extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('global')
|
||||
->setDescription('Allows running commands in the global composer dir ($COMPOSER_HOME).')
|
||||
->setDefinition(array(
|
||||
new InputArgument('command-name', InputArgument::REQUIRED, ''),
|
||||
new InputArgument('args', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, ''),
|
||||
))
|
||||
->setHelp(<<<EOT
|
||||
Use this command as a wrapper to run other Composer commands
|
||||
within the global context of COMPOSER_HOME.
|
||||
|
||||
You can use this to install CLI utilities globally, all you need
|
||||
is to add the COMPOSER_HOME/vendor/bin dir to your PATH env var.
|
||||
|
||||
COMPOSER_HOME is c:\Users\<user>\AppData\Roaming\Composer on Windows
|
||||
and /home/<user>/.composer on unix systems.
|
||||
|
||||
Note: This path may vary depending on customizations to bin-dir in
|
||||
composer.json or the environmental variable COMPOSER_BIN_DIR.
|
||||
|
||||
EOT
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
public function run(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
// extract real command name
|
||||
$tokens = preg_split('{\s+}', $input->__toString());
|
||||
$args = array();
|
||||
foreach ($tokens as $token) {
|
||||
if ($token && $token[0] !== '-') {
|
||||
$args[] = $token;
|
||||
if (count($args) >= 2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// show help for this command if no command was found
|
||||
if (count($args) < 2) {
|
||||
return parent::run($input, $output);
|
||||
}
|
||||
|
||||
// change to global dir
|
||||
$config = Factory::createConfig();
|
||||
chdir($config->get('home'));
|
||||
$output->writeln('<info>Changed current directory to '.$config->get('home').'</info>');
|
||||
|
||||
// create new input without "global" command prefix
|
||||
$input = new StringInput(preg_replace('{\bg(?:l(?:o(?:b(?:a(?:l)?)?)?)?)?\b}', '', $input->__toString(), 1));
|
||||
|
||||
return $this->getApplication()->run($input, $output);
|
||||
}
|
||||
}
|
@ -0,0 +1,163 @@
|
||||
<?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\Command;
|
||||
|
||||
use Composer\DependencyResolver\Pool;
|
||||
use Composer\Factory;
|
||||
use Composer\Package\CompletePackageInterface;
|
||||
use Composer\Package\Loader\InvalidPackageException;
|
||||
use Composer\Repository\CompositeRepository;
|
||||
use Composer\Repository\RepositoryInterface;
|
||||
use Composer\Util\ProcessExecutor;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Process\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* @author Robert Schönthal <seroscho@googlemail.com>
|
||||
*/
|
||||
class HomeCommand extends Command
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('browse')
|
||||
->setAliases(array('home'))
|
||||
->setDescription('Opens the package\'s repository URL or homepage in your browser.')
|
||||
->setDefinition(array(
|
||||
new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::REQUIRED, 'Package(s) to browse to.'),
|
||||
new InputOption('homepage', 'H', InputOption::VALUE_NONE, 'Open the homepage instead of the repository URL.'),
|
||||
))
|
||||
->setHelp(<<<EOT
|
||||
The home command opens a package's repository URL or
|
||||
homepage in your default browser.
|
||||
|
||||
To open the homepage by default, use -H or --homepage.
|
||||
EOT
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$repo = $this->initializeRepo($input, $output);
|
||||
$return = 0;
|
||||
|
||||
foreach ($input->getArgument('packages') as $packageName) {
|
||||
$package = $this->getPackage($repo, $packageName);
|
||||
|
||||
if (!$package instanceof CompletePackageInterface) {
|
||||
$return = 1;
|
||||
$output->writeln('<warning>Package '.$packageName.' not found</warning>');
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$support = $package->getSupport();
|
||||
$url = isset($support['source']) ? $support['source'] : $package->getSourceUrl();
|
||||
if (!$url || $input->getOption('homepage')) {
|
||||
$url = $package->getHomepage();
|
||||
}
|
||||
|
||||
if (!filter_var($url, FILTER_VALIDATE_URL)) {
|
||||
$return = 1;
|
||||
$output->writeln('<warning>'.($input->getOption('homepage') ? 'Invalid or missing homepage' : 'Invalid or missing repository URL').' for '.$packageName.'</warning>');
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->openBrowser($url);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* finds a package by name
|
||||
*
|
||||
* @param RepositoryInterface $repos
|
||||
* @param string $name
|
||||
* @return CompletePackageInterface
|
||||
*/
|
||||
protected function getPackage(RepositoryInterface $repos, $name)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
$pool = new Pool('dev');
|
||||
$pool->addRepository($repos);
|
||||
$matches = $pool->whatProvides($name);
|
||||
|
||||
foreach ($matches as $index => $package) {
|
||||
// skip providers/replacers
|
||||
if ($package->getName() !== $name) {
|
||||
unset($matches[$index]);
|
||||
continue;
|
||||
}
|
||||
|
||||
return $package;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* opens a url in your system default browser
|
||||
*
|
||||
* @param string $url
|
||||
*/
|
||||
private function openBrowser($url)
|
||||
{
|
||||
$url = ProcessExecutor::escape($url);
|
||||
|
||||
if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
|
||||
return passthru('start "web" explorer "' . $url . '"');
|
||||
}
|
||||
|
||||
passthru('which xdg-open', $linux);
|
||||
passthru('which open', $osx);
|
||||
|
||||
if (0 === $linux) {
|
||||
passthru('xdg-open ' . $url);
|
||||
} elseif (0 === $osx) {
|
||||
passthru('open ' . $url);
|
||||
} else {
|
||||
$this->getIO()->write('no suitable browser opening command found, open yourself: ' . $url);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* initializes the repo
|
||||
*
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return CompositeRepository
|
||||
*/
|
||||
private function initializeRepo(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$composer = $this->getComposer(false);
|
||||
|
||||
if ($composer) {
|
||||
$repo = new CompositeRepository($composer->getRepositoryManager()->getRepositories());
|
||||
} else {
|
||||
$defaultRepos = Factory::createDefaultRepositories($this->getIO());
|
||||
$repo = new CompositeRepository($defaultRepos);
|
||||
}
|
||||
|
||||
return $repo;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
<?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\Command;
|
||||
|
||||
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\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* @author Benoît Merlet <benoit.merlet@gmail.com>
|
||||
*/
|
||||
class LicensesCommand extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('licenses')
|
||||
->setDescription('Show information about licenses of dependencies')
|
||||
->setDefinition(array(
|
||||
new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the output: text or json', 'text'),
|
||||
))
|
||||
->setHelp(<<<EOT
|
||||
The license command displays detailed information about the licenses of
|
||||
the installed dependencies.
|
||||
|
||||
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();
|
||||
|
||||
$versionParser = new VersionParser;
|
||||
|
||||
$packages = array();
|
||||
foreach ($repo->getPackages() as $package) {
|
||||
$packages[$package->getName()] = $package;
|
||||
}
|
||||
|
||||
ksort($packages);
|
||||
|
||||
switch ($format = $input->getOption('format')) {
|
||||
case 'text':
|
||||
$output->writeln('Name: <comment>'.$root->getPrettyName().'</comment>');
|
||||
$output->writeln('Version: <comment>'.$versionParser->formatVersion($root).'</comment>');
|
||||
$output->writeln('Licenses: <comment>'.(implode(', ', $root->getLicense()) ?: 'none').'</comment>');
|
||||
$output->writeln('Dependencies:');
|
||||
|
||||
$table = $this->getHelperSet()->get('table');
|
||||
$table->setLayout(TableHelper::LAYOUT_BORDERLESS);
|
||||
$table->setHorizontalBorderChar('');
|
||||
foreach ($packages as $package) {
|
||||
$table->addRow(array(
|
||||
$package->getPrettyName(),
|
||||
$versionParser->formatVersion($package),
|
||||
implode(', ', $package->getLicense()) ?: 'none',
|
||||
));
|
||||
}
|
||||
$table->render($output);
|
||||
break;
|
||||
|
||||
case 'json':
|
||||
foreach ($packages as $package) {
|
||||
$dependencies[$package->getPrettyName()] = array(
|
||||
'version' => $versionParser->formatVersion($package),
|
||||
'license' => $package->getLicense(),
|
||||
);
|
||||
}
|
||||
|
||||
$output->writeln(JsonFile::encode(array(
|
||||
'name' => $root->getPrettyName(),
|
||||
'version' => $versionParser->formatVersion($root),
|
||||
'license' => $root->getLicense(),
|
||||
'dependencies' => $dependencies,
|
||||
)));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \RuntimeException(sprintf('Unsupported format "%s". See help for supported formats.', $format));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
<?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\Command;
|
||||
|
||||
use Composer\Config\JsonConfigSource;
|
||||
use Composer\Installer;
|
||||
use Composer\Plugin\CommandEvent;
|
||||
use Composer\Plugin\PluginEvents;
|
||||
use Composer\Json\JsonFile;
|
||||
use Composer\Factory;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* @author Pierre du Plessis <pdples@gmail.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class RemoveCommand extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('remove')
|
||||
->setDescription('Removes a package from the require or require-dev')
|
||||
->setDefinition(array(
|
||||
new InputArgument('packages', InputArgument::IS_ARRAY, 'Packages that should be removed.'),
|
||||
new InputOption('dev', null, InputOption::VALUE_NONE, 'Removes a package from the require-dev section.'),
|
||||
new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'),
|
||||
new InputOption('no-update', null, InputOption::VALUE_NONE, 'Disables the automatic update of the dependencies.'),
|
||||
new InputOption('update-no-dev', null, InputOption::VALUE_NONE, 'Run the dependency update with the --no-dev option.'),
|
||||
new InputOption('update-with-dependencies', null, InputOption::VALUE_NONE, 'Allows inherited dependencies to be updated with explicit dependencies.'),
|
||||
))
|
||||
->setHelp(<<<EOT
|
||||
The <info>remove</info> command removes a package from the current
|
||||
list of installed packages
|
||||
|
||||
<info>php composer.phar remove</info>
|
||||
|
||||
EOT
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$packages = $input->getArgument('packages');
|
||||
|
||||
$file = Factory::getComposerFile();
|
||||
|
||||
$jsonFile = new JsonFile($file);
|
||||
$composer = $jsonFile->read();
|
||||
$composerBackup = file_get_contents($jsonFile->getPath());
|
||||
|
||||
$json = new JsonConfigSource($jsonFile);
|
||||
|
||||
$type = $input->getOption('dev') ? 'require-dev' : 'require';
|
||||
$altType = !$input->getOption('dev') ? 'require-dev' : 'require';
|
||||
|
||||
foreach ($packages as $package) {
|
||||
if (isset($composer[$type][$package])) {
|
||||
$json->removeLink($type, $package);
|
||||
} elseif (isset($composer[$altType][$package])) {
|
||||
$output->writeln('<warning>'.$package.' could not be found in '.$type.' but it is present in '.$altType.'</warning>');
|
||||
$dialog = $this->getHelperSet()->get('dialog');
|
||||
if ($this->getIO()->isInteractive()) {
|
||||
if ($dialog->askConfirmation($output, $dialog->getQuestion('Do you want to remove it from '.$altType, 'yes', '?'), true)) {
|
||||
$json->removeLink($altType, $package);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$output->writeln('<warning>'.$package.' is not required in your composer.json and has not been removed</warning>');
|
||||
}
|
||||
}
|
||||
|
||||
if ($input->getOption('no-update')) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Update packages
|
||||
$composer = $this->getComposer();
|
||||
$composer->getDownloadManager()->setOutputProgress(!$input->getOption('no-progress'));
|
||||
$io = $this->getIO();
|
||||
|
||||
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'remove', $input, $output);
|
||||
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
|
||||
|
||||
$install = Installer::create($io, $composer);
|
||||
|
||||
$updateDevMode = !$input->getOption('update-no-dev');
|
||||
$install
|
||||
->setVerbose($input->getOption('verbose'))
|
||||
->setDevMode($updateDevMode)
|
||||
->setUpdate(true)
|
||||
->setUpdateWhitelist($packages)
|
||||
->setWhitelistDependencies($input->getOption('update-with-dependencies'));
|
||||
;
|
||||
|
||||
$status = $install->run();
|
||||
if ($status !== 0) {
|
||||
$output->writeln("\n".'<error>Removal failed, reverting '.$file.' to its original content.</error>');
|
||||
file_put_contents($jsonFile->getPath(), $composerBackup);
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
<?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\Command;
|
||||
|
||||
use Composer\Script\CommandEvent;
|
||||
use Composer\Script\ScriptEvents;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien.potencier@gmail.com>
|
||||
*/
|
||||
class RunScriptCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var array Array with command events
|
||||
*/
|
||||
protected $commandEvents = array(
|
||||
ScriptEvents::PRE_INSTALL_CMD,
|
||||
ScriptEvents::POST_INSTALL_CMD,
|
||||
ScriptEvents::PRE_UPDATE_CMD,
|
||||
ScriptEvents::POST_UPDATE_CMD,
|
||||
ScriptEvents::PRE_STATUS_CMD,
|
||||
ScriptEvents::POST_STATUS_CMD,
|
||||
ScriptEvents::POST_ROOT_PACKAGE_INSTALL,
|
||||
ScriptEvents::POST_CREATE_PROJECT_CMD
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array Array with script events
|
||||
*/
|
||||
protected $scriptEvents = array(
|
||||
ScriptEvents::PRE_ARCHIVE_CMD,
|
||||
ScriptEvents::POST_ARCHIVE_CMD,
|
||||
ScriptEvents::PRE_AUTOLOAD_DUMP,
|
||||
ScriptEvents::POST_AUTOLOAD_DUMP
|
||||
);
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('run-script')
|
||||
->setDescription('Run the scripts defined in composer.json.')
|
||||
->setDefinition(array(
|
||||
new InputArgument('script', InputArgument::REQUIRED, 'Script name to run.'),
|
||||
new InputArgument('args', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, ''),
|
||||
new InputOption('dev', null, InputOption::VALUE_NONE, 'Sets the dev mode.'),
|
||||
new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables the dev mode.'),
|
||||
))
|
||||
->setHelp(<<<EOT
|
||||
The <info>run-script</info> command runs scripts defined in composer.json:
|
||||
|
||||
<info>php composer.phar run-script post-update-cmd</info>
|
||||
EOT
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$script = $input->getArgument('script');
|
||||
if (!in_array($script, $this->commandEvents) && !in_array($script, $this->scriptEvents)) {
|
||||
if (defined('Composer\Script\ScriptEvents::'.str_replace('-', '_', strtoupper($script)))) {
|
||||
throw new \InvalidArgumentException(sprintf('Script "%s" cannot be run with this command', $script));
|
||||
}
|
||||
}
|
||||
|
||||
$composer = $this->getComposer();
|
||||
$hasListeners = $composer->getEventDispatcher()->hasEventListeners(new CommandEvent($script, $composer, $this->getIO()));
|
||||
if (!$hasListeners) {
|
||||
throw new \InvalidArgumentException(sprintf('Script "%s" is not defined in this package', $script));
|
||||
}
|
||||
|
||||
// add the bin dir to the PATH to make local binaries of deps usable in scripts
|
||||
$binDir = $composer->getConfig()->get('bin-dir');
|
||||
if (is_dir($binDir)) {
|
||||
putenv('PATH='.realpath($binDir).PATH_SEPARATOR.getenv('PATH'));
|
||||
}
|
||||
|
||||
$args = $input->getArgument('args');
|
||||
|
||||
if (in_array($script, $this->commandEvents)) {
|
||||
return $composer->getEventDispatcher()->dispatchCommandEvent($script, $input->getOption('dev') || !$input->getOption('no-dev'), $args);
|
||||
}
|
||||
|
||||
return $composer->getEventDispatcher()->dispatchScript($script, $input->getOption('dev') || !$input->getOption('no-dev'), $args);
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
<?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\Command;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class ScriptAliasCommand extends Command
|
||||
{
|
||||
private $script;
|
||||
|
||||
public function __construct($script)
|
||||
{
|
||||
$this->script = $script;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName($this->script)
|
||||
->setDescription('Run the '.$this->script.' script as defined in composer.json.')
|
||||
->setDefinition(array(
|
||||
new InputOption('dev', null, InputOption::VALUE_NONE, 'Sets the dev mode.'),
|
||||
new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables the dev mode.'),
|
||||
new InputArgument('args', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, ''),
|
||||
))
|
||||
->setHelp(<<<EOT
|
||||
The <info>run-script</info> command runs scripts defined in composer.json:
|
||||
|
||||
<info>php composer.phar run-script post-update-cmd</info>
|
||||
EOT
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$composer = $this->getComposer();
|
||||
|
||||
// add the bin dir to the PATH to make local binaries of deps usable in scripts
|
||||
$binDir = $composer->getConfig()->get('bin-dir');
|
||||
if (is_dir($binDir)) {
|
||||
putenv('PATH='.realpath($binDir).PATH_SEPARATOR.getenv('PATH'));
|
||||
}
|
||||
|
||||
$args = $input->getArguments();
|
||||
|
||||
return $composer->getEventDispatcher()->dispatchScript($this->script, $input->getOption('dev') || !$input->getOption('no-dev'), $args['args']);
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
<?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\Downloader;
|
||||
|
||||
use Composer\Package\PackageInterface;
|
||||
|
||||
/**
|
||||
* ChangeReport interface.
|
||||
*
|
||||
* @author Sascha Egerer <sascha.egerer@dkd.de>
|
||||
*/
|
||||
interface ChangeReportInterface
|
||||
{
|
||||
/**
|
||||
* Checks for changes to the local copy
|
||||
*
|
||||
* @param PackageInterface $package package instance
|
||||
* @param string $path package directory
|
||||
* @return string|null changes or null
|
||||
*/
|
||||
public function getLocalChanges(PackageInterface $package, $path);
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
<?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\Downloader;
|
||||
|
||||
/**
|
||||
* Exception thrown when issues exist on local filesystem
|
||||
*
|
||||
* @author Javier Spagnoletti <jspagnoletti@javierspagnoletti.com.ar>
|
||||
*/
|
||||
class FilesystemException extends \Exception
|
||||
{
|
||||
public function __construct($message = null, $code = null, \Exception $previous = null)
|
||||
{
|
||||
parent::__construct("Filesystem exception: \n".$message, $code, $previous);
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
<?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\Downloader;
|
||||
|
||||
use Composer\Config;
|
||||
use Composer\Cache;
|
||||
use Composer\EventDispatcher\EventDispatcher;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Util\ProcessExecutor;
|
||||
use Composer\IO\IOInterface;
|
||||
|
||||
/**
|
||||
* GZip archive downloader.
|
||||
*
|
||||
* @author Pavel Puchkin <i@neoascetic.me>
|
||||
*/
|
||||
class GzipDownloader extends ArchiveDownloader
|
||||
{
|
||||
protected $process;
|
||||
|
||||
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, $eventDispatcher, $cache);
|
||||
}
|
||||
|
||||
protected function extract($file, $path)
|
||||
{
|
||||
$targetFilepath = $path . DIRECTORY_SEPARATOR . basename(substr($file, 0, -3));
|
||||
|
||||
// Try to use gunzip on *nix
|
||||
if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
|
||||
$command = 'gzip -cd ' . ProcessExecutor::escape($file) . ' > ' . ProcessExecutor::escape($targetFilepath);
|
||||
|
||||
if (0 === $this->process->execute($command, $ignoredOutput)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput();
|
||||
throw new \RuntimeException($processError);
|
||||
}
|
||||
|
||||
// Windows version of PHP has built-in support of gzip functions
|
||||
$archiveFile = gzopen($file, 'rb');
|
||||
$targetFile = fopen($targetFilepath, 'wb');
|
||||
while ($string = gzread($archiveFile, 4096)) {
|
||||
fwrite($targetFile, $string, strlen($string));
|
||||
}
|
||||
gzclose($archiveFile);
|
||||
fclose($targetFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getFileName(PackageInterface $package, $path)
|
||||
{
|
||||
return $path.'/'.pathinfo(parse_url($package->getDistUrl(), PHP_URL_PATH), PATHINFO_BASENAME);
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
<?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\Downloader;
|
||||
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Repository\VcsRepository;
|
||||
use Composer\Util\Perforce;
|
||||
|
||||
/**
|
||||
* @author Matt Whittom <Matt.Whittom@veteransunited.com>
|
||||
*/
|
||||
class PerforceDownloader extends VcsDownloader
|
||||
{
|
||||
protected $perforce;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function doDownload(PackageInterface $package, $path, $url)
|
||||
{
|
||||
$ref = $package->getSourceReference();
|
||||
$label = $this->getLabelFromSourceReference($ref);
|
||||
|
||||
$this->io->write(' Cloning ' . $ref);
|
||||
$this->initPerforce($package, $path, $url);
|
||||
$this->perforce->setStream($ref);
|
||||
$this->perforce->p4Login($this->io);
|
||||
$this->perforce->writeP4ClientSpec();
|
||||
$this->perforce->connectClient();
|
||||
$this->perforce->syncCodeBase($label);
|
||||
$this->perforce->cleanupClientSpec();
|
||||
}
|
||||
|
||||
private function getLabelFromSourceReference($ref)
|
||||
{
|
||||
$pos = strpos($ref,'@');
|
||||
if (false !== $pos) {
|
||||
return substr($ref, $pos + 1);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function initPerforce($package, $path, $url)
|
||||
{
|
||||
if (!empty($this->perforce)) {
|
||||
$this->perforce->initializePath($path);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$repository = $package->getRepository();
|
||||
$repoConfig = null;
|
||||
if ($repository instanceof VcsRepository) {
|
||||
$repoConfig = $this->getRepoConfig($repository);
|
||||
}
|
||||
$this->perforce = Perforce::create($repoConfig, $url, $path, $this->process, $this->io);
|
||||
}
|
||||
|
||||
private function getRepoConfig(VcsRepository $repository)
|
||||
{
|
||||
return $repository->getRepoConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function doUpdate(PackageInterface $initial, PackageInterface $target, $path, $url)
|
||||
{
|
||||
$this->doDownload($target, $path, $url);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getLocalChanges(PackageInterface $package, $path)
|
||||
{
|
||||
$this->io->write('Perforce driver does not check for local changes before overriding', true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function getCommitLogs($fromReference, $toReference, $path)
|
||||
{
|
||||
$commitLogs = $this->perforce->getCommitLogs($fromReference, $toReference);
|
||||
|
||||
return $commitLogs;
|
||||
}
|
||||
|
||||
public function setPerforce($perforce)
|
||||
{
|
||||
$this->perforce = $perforce;
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
<?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\Downloader;
|
||||
|
||||
use Composer\Config;
|
||||
use Composer\Cache;
|
||||
use Composer\EventDispatcher\EventDispatcher;
|
||||
use Composer\Util\ProcessExecutor;
|
||||
use Composer\IO\IOInterface;
|
||||
use RarArchive;
|
||||
|
||||
/**
|
||||
* RAR archive downloader.
|
||||
*
|
||||
* Based on previous work by Jordi Boggiano ({@see ZipDownloader}).
|
||||
*
|
||||
* @author Derrick Nelson <drrcknlsn@gmail.com>
|
||||
*/
|
||||
class RarDownloader extends ArchiveDownloader
|
||||
{
|
||||
protected $process;
|
||||
|
||||
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, $eventDispatcher, $cache);
|
||||
}
|
||||
|
||||
protected function extract($file, $path)
|
||||
{
|
||||
$processError = null;
|
||||
|
||||
// Try to use unrar on *nix
|
||||
if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
|
||||
$command = 'unrar x ' . ProcessExecutor::escape($file) . ' ' . ProcessExecutor::escape($path) . ' && chmod -R u+w ' . ProcessExecutor::escape($path);
|
||||
|
||||
if (0 === $this->process->execute($command, $ignoredOutput)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput();
|
||||
}
|
||||
|
||||
if (!class_exists('RarArchive')) {
|
||||
// php.ini path is added to the error message to help users find the correct file
|
||||
$iniPath = php_ini_loaded_file();
|
||||
|
||||
if ($iniPath) {
|
||||
$iniMessage = 'The php.ini used by your command-line PHP is: ' . $iniPath;
|
||||
} else {
|
||||
$iniMessage = 'A php.ini file does not exist. You will have to create one.';
|
||||
}
|
||||
|
||||
$error = "Could not decompress the archive, enable the PHP rar extension or install unrar.\n"
|
||||
. $iniMessage . "\n" . $processError;
|
||||
|
||||
if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
|
||||
$error = "Could not decompress the archive, enable the PHP rar extension.\n" . $iniMessage;
|
||||
}
|
||||
|
||||
throw new \RuntimeException($error);
|
||||
}
|
||||
|
||||
$rarArchive = RarArchive::open($file);
|
||||
|
||||
if (false === $rarArchive) {
|
||||
throw new \UnexpectedValueException('Could not open RAR archive: ' . $file);
|
||||
}
|
||||
|
||||
$entries = $rarArchive->getEntries();
|
||||
|
||||
if (false === $entries) {
|
||||
throw new \RuntimeException('Could not retrieve RAR archive entries');
|
||||
}
|
||||
|
||||
foreach ($entries as $entry) {
|
||||
if (false === $entry->extract($path)) {
|
||||
throw new \RuntimeException('Could not extract entry');
|
||||
}
|
||||
}
|
||||
|
||||
$rarArchive->close();
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
<?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 array Arguments passed by the user, these will be forwarded to CLI script handlers
|
||||
*/
|
||||
protected $args;
|
||||
|
||||
/**
|
||||
* @var array Flags usable in PHP script handlers
|
||||
*/
|
||||
protected $flags;
|
||||
|
||||
/**
|
||||
* @var boolean Whether the event should not be passed to more listeners
|
||||
*/
|
||||
private $propagationStopped = false;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $name The event name
|
||||
* @param array $args Arguments passed by the user
|
||||
* @param array $flags Optional flags to pass data not as argument
|
||||
*/
|
||||
public function __construct($name, array $args = array(), array $flags = array())
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->args = $args;
|
||||
$this->flags = $flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the event's name.
|
||||
*
|
||||
* @return string The event name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the event's arguments.
|
||||
*
|
||||
* @return array The event arguments
|
||||
*/
|
||||
public function getArguments()
|
||||
{
|
||||
return $this->args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the event's flags.
|
||||
*
|
||||
* @return array The event flags
|
||||
*/
|
||||
public function getFlags()
|
||||
{
|
||||
return $this->flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
@ -0,0 +1,314 @@
|
||||
<?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;
|
||||
|
||||
use Composer\DependencyResolver\PolicyInterface;
|
||||
use Composer\DependencyResolver\Pool;
|
||||
use Composer\DependencyResolver\Request;
|
||||
use Composer\Installer\InstallerEvent;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Composer;
|
||||
use Composer\DependencyResolver\Operation\OperationInterface;
|
||||
use Composer\Repository\CompositeRepository;
|
||||
use Composer\Script;
|
||||
use Composer\Script\CommandEvent;
|
||||
use Composer\Script\PackageEvent;
|
||||
use Composer\Util\ProcessExecutor;
|
||||
|
||||
/**
|
||||
* The Event Dispatcher.
|
||||
*
|
||||
* Example in command:
|
||||
* $dispatcher = new EventDispatcher($this->getComposer(), $this->getApplication()->getIO());
|
||||
* // ...
|
||||
* $dispatcher->dispatch(ScriptEvents::POST_INSTALL_CMD);
|
||||
* // ...
|
||||
*
|
||||
* @author François Pluchino <francois.pluchino@opendisplay.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
*/
|
||||
class EventDispatcher
|
||||
{
|
||||
protected $composer;
|
||||
protected $io;
|
||||
protected $loader;
|
||||
protected $process;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Composer $composer The composer instance
|
||||
* @param IOInterface $io The IOInterface instance
|
||||
* @param ProcessExecutor $process
|
||||
*/
|
||||
public function __construct(Composer $composer, IOInterface $io, ProcessExecutor $process = null)
|
||||
{
|
||||
$this->composer = $composer;
|
||||
$this->io = $io;
|
||||
$this->process = $process ?: new ProcessExecutor($io);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch an event
|
||||
*
|
||||
* @param string $eventName An event name
|
||||
* @param Event $event
|
||||
* @return int return code of the executed script if any, for php scripts a false return
|
||||
* value is changed to 1, anything else to 0
|
||||
*/
|
||||
public function dispatch($eventName, Event $event = null)
|
||||
{
|
||||
if (null == $event) {
|
||||
$event = new Event($eventName);
|
||||
}
|
||||
|
||||
return $this->doDispatch($event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a script event.
|
||||
*
|
||||
* @param string $eventName The constant in ScriptEvents
|
||||
* @param bool $devMode
|
||||
* @param array $additionalArgs Arguments passed by the user
|
||||
* @param array $flags Optional flags to pass data not as argument
|
||||
* @return int return code of the executed script if any, for php scripts a false return
|
||||
* value is changed to 1, anything else to 0
|
||||
*/
|
||||
public function dispatchScript($eventName, $devMode = false, $additionalArgs = array(), $flags = array())
|
||||
{
|
||||
return $this->doDispatch(new Script\Event($eventName, $this->composer, $this->io, $devMode, $additionalArgs, $flags));
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a package event.
|
||||
*
|
||||
* @param string $eventName The constant in ScriptEvents
|
||||
* @param boolean $devMode Whether or not we are in dev mode
|
||||
* @param OperationInterface $operation The package being installed/updated/removed
|
||||
* @return int return code of the executed script if any, for php scripts a false return
|
||||
* value is changed to 1, anything else to 0
|
||||
*/
|
||||
public function dispatchPackageEvent($eventName, $devMode, OperationInterface $operation)
|
||||
{
|
||||
return $this->doDispatch(new PackageEvent($eventName, $this->composer, $this->io, $devMode, $operation));
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a command event.
|
||||
*
|
||||
* @param string $eventName The constant in ScriptEvents
|
||||
* @param boolean $devMode Whether or not we are in dev mode
|
||||
* @param array $additionalArgs Arguments passed by the user
|
||||
* @param array $flags Optional flags to pass data not as argument
|
||||
* @return int return code of the executed script if any, for php scripts a false return
|
||||
* value is changed to 1, anything else to 0
|
||||
*/
|
||||
public function dispatchCommandEvent($eventName, $devMode, $additionalArgs = array(), $flags = array())
|
||||
{
|
||||
return $this->doDispatch(new CommandEvent($eventName, $this->composer, $this->io, $devMode, $additionalArgs, $flags));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dispatch a installer event.
|
||||
*
|
||||
* @param string $eventName The constant in InstallerEvents
|
||||
* @param PolicyInterface $policy The policy
|
||||
* @param Pool $pool The pool
|
||||
* @param CompositeRepository $installedRepo The installed repository
|
||||
* @param Request $request The request
|
||||
* @param array $operations The list of operations
|
||||
*
|
||||
* @return int return code of the executed script if any, for php scripts a false return
|
||||
* value is changed to 1, anything else to 0
|
||||
*/
|
||||
public function dispatchInstallerEvent($eventName, PolicyInterface $policy, Pool $pool, CompositeRepository $installedRepo, Request $request, array $operations = array())
|
||||
{
|
||||
return $this->doDispatch(new InstallerEvent($eventName, $this->composer, $this->io, $policy, $pool, $installedRepo, $request, $operations));
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the listeners of an event.
|
||||
*
|
||||
* @param Event $event The event object to pass to the event handlers/listeners.
|
||||
* @param string $additionalArgs
|
||||
* @return int return code of the executed script if any, for php scripts a false return
|
||||
* value is changed to 1, anything else to 0
|
||||
* @throws \RuntimeException
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function doDispatch(Event $event)
|
||||
{
|
||||
$listeners = $this->getListeners($event);
|
||||
|
||||
$return = 0;
|
||||
foreach ($listeners as $callable) {
|
||||
if (!is_string($callable) && is_callable($callable)) {
|
||||
$return = false === call_user_func($callable, $event) ? 1 : 0;
|
||||
} elseif ($this->isPhpScript($callable)) {
|
||||
$className = substr($callable, 0, strpos($callable, '::'));
|
||||
$methodName = substr($callable, strpos($callable, '::') + 2);
|
||||
|
||||
if (!class_exists($className)) {
|
||||
$this->io->write('<warning>Class '.$className.' is not autoloadable, can not call '.$event->getName().' script</warning>');
|
||||
continue;
|
||||
}
|
||||
if (!is_callable($callable)) {
|
||||
$this->io->write('<warning>Method '.$callable.' is not callable, can not call '.$event->getName().' script</warning>');
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$return = false === $this->executeEventPhpScript($className, $methodName, $event) ? 1 : 0;
|
||||
} catch (\Exception $e) {
|
||||
$message = "Script %s handling the %s event terminated with an exception";
|
||||
$this->io->write('<error>'.sprintf($message, $callable, $event->getName()).'</error>');
|
||||
throw $e;
|
||||
}
|
||||
} else {
|
||||
$args = implode(' ', array_map(array('Composer\Util\ProcessExecutor','escape'), $event->getArguments()));
|
||||
if (0 !== ($exitCode = $this->process->execute($callable . ($args === '' ? '' : ' '.$args)))) {
|
||||
$event->getIO()->write(sprintf('<error>Script %s handling the %s event returned with an error</error>', $callable, $event->getName()));
|
||||
|
||||
throw new \RuntimeException('Error Output: '.$this->process->getErrorOutput(), $exitCode);
|
||||
}
|
||||
}
|
||||
|
||||
if ($event->isPropagationStopped()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $className
|
||||
* @param string $methodName
|
||||
* @param Event $event Event invoking the PHP callable
|
||||
*/
|
||||
protected function executeEventPhpScript($className, $methodName, Event $event)
|
||||
{
|
||||
return $className::$methodName($event);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an event has listeners registered
|
||||
*
|
||||
* @param Event $event
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasEventListeners(Event $event)
|
||||
{
|
||||
$listeners = $this->getListeners($event);
|
||||
|
||||
return count($listeners) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all listeners defined as scripts in the package
|
||||
*
|
||||
* @param Event $event Event object
|
||||
* @return array Listeners
|
||||
*/
|
||||
protected function getScriptListeners(Event $event)
|
||||
{
|
||||
$package = $this->composer->getPackage();
|
||||
$scripts = $package->getScripts();
|
||||
|
||||
if (empty($scripts[$event->getName()])) {
|
||||
return array();
|
||||
}
|
||||
|
||||
if ($this->loader) {
|
||||
$this->loader->unregister();
|
||||
}
|
||||
|
||||
$generator = $this->composer->getAutoloadGenerator();
|
||||
$packages = $this->composer->getRepositoryManager()->getLocalRepository()->getCanonicalPackages();
|
||||
$packageMap = $generator->buildPackageMap($this->composer->getInstallationManager(), $package, $packages);
|
||||
$map = $generator->parseAutoloads($packageMap, $package);
|
||||
$this->loader = $generator->createLoader($map);
|
||||
$this->loader->register();
|
||||
|
||||
return $scripts[$event->getName()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if string given references a class path and method
|
||||
*
|
||||
* @param string $callable
|
||||
* @return boolean
|
||||
*/
|
||||
protected function isPhpScript($callable)
|
||||
{
|
||||
return false === strpos($callable, ' ') && false !== strpos($callable, '::');
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
<?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\IO;
|
||||
|
||||
use Composer\Config;
|
||||
|
||||
abstract class BaseIO implements IOInterface
|
||||
{
|
||||
protected $authentications = array();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getAuthentications()
|
||||
{
|
||||
return $this->authentications;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function hasAuthentication($repositoryName)
|
||||
{
|
||||
return isset($this->authentications[$repositoryName]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getAuthentication($repositoryName)
|
||||
{
|
||||
if (isset($this->authentications[$repositoryName])) {
|
||||
return $this->authentications[$repositoryName];
|
||||
}
|
||||
|
||||
return array('username' => null, 'password' => null);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function setAuthentication($repositoryName, $username, $password = null)
|
||||
{
|
||||
$this->authentications[$repositoryName] = array('username' => $username, 'password' => $password);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadConfiguration(Config $config)
|
||||
{
|
||||
// reload oauth token from config if available
|
||||
if ($tokens = $config->get('github-oauth')) {
|
||||
foreach ($tokens as $domain => $token) {
|
||||
if (!preg_match('{^[a-z0-9]+$}', $token)) {
|
||||
throw new \UnexpectedValueException('Your github oauth token for '.$domain.' contains invalid characters: "'.$token.'"');
|
||||
}
|
||||
$this->setAuthentication($domain, $token, 'x-oauth-basic');
|
||||
}
|
||||
}
|
||||
|
||||
// reload http basic credentials from config if available
|
||||
if ($creds = $config->get('http-basic')) {
|
||||
foreach ($creds as $domain => $cred) {
|
||||
$this->setAuthentication($domain, $cred['username'], $cred['password']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue