1
0
Fork 0

Merge remote-tracking branch 'curry684/rewrite-depends'

pull/4958/head
Jordi Boggiano 2016-02-24 17:42:11 +00:00
commit f681dbc51e
32 changed files with 443 additions and 170 deletions

View File

@ -328,34 +328,67 @@ to limit output to suggestions made by those packages only.
## depends
The `depends` command tells you which other packages depend on a certain
package. You can specify which link types (`require`, `require-dev`)
should be included in the listing. By default both are used.
package. As with installation `require-dev` relationships are only considered
for the root package.
```sh
php composer.phar depends --link-type=require monolog/monolog
nrk/monolog-fluent requires monolog/monolog (~1.8)
poc/poc requires monolog/monolog (^1.6)
propel/propel requires monolog/monolog (1.*)
symfony/monolog-bridge requires monolog/monolog (>=1.2)
symfony/symfony requires monolog/monolog (~1)
php composer.phar depends doctrine/lexer
doctrine/annotations v1.2.7 requires doctrine/lexer (1.*)
doctrine/common v2.6.1 requires doctrine/lexer (1.*)
```
If you want, for example, find any installed package that is **not** allowing
Symfony version 3 or one of its components, you can run the following command:
You can optionally specify a version constraint after the package to limit the
search.
Add the `--tree` or `-t` flag to show a recursive tree of why the package is
depended upon, for example:
```sh
php composer.phar depends symfony/symfony --with-replaces -im ^3.0
php composer.phar depends psr/log -t
psr/log 1.0.0 Common interface for logging libraries
|- aboutyou/app-sdk 2.6.11 (requires psr/log 1.0.*)
| `- __root__ (requires aboutyou/app-sdk ^2.6)
|- monolog/monolog 1.17.2 (requires psr/log ~1.0)
| `- laravel/framework v5.2.16 (requires monolog/monolog ~1.11)
| `- __root__ (requires laravel/framework ^5.2)
`- symfony/symfony v3.0.2 (requires psr/log ~1.0)
`- __root__ (requires symfony/symfony ^3.0)
```
### Options
* **--link-type:** The link types to match on, can be specified multiple
times.
* **--match-constraint (-m):** Filters the dependencies shown using this constraint.
* **--invert-match-constraint (-i):** Turns --match-constraint around into a blacklist
instead of a whitelist.
* **--with-replaces:** Search for replaced packages as well.
* **--recursive (-r):** Recursively resolves up to the root package.
* **--tree (-t):** Prints the results as a nested tree, implies -r.
## prohibits
The `prohibits` command tells you which packages are blocking a given package
from being installed. Specify a version constraint to verify whether upgrades
can be performed in your project, and if not why not. See the following
example:
```sh
php composer.phar prohibits symfony/symfony 3.1
laravel/framework v5.2.16 requires symfony/var-dumper (2.8.*|3.0.*)
```
Note that you can also specify platform requirements, for example to check
whether you can upgrade your server to PHP 8.0:
```sh
php composer.phar prohibits php:8
doctrine/cache v1.6.0 requires php (~5.5|~7.0)
doctrine/common v2.6.1 requires php (~5.5|~7.0)
doctrine/instantiator 1.0.5 requires php (>=5.3,<8.0-DEV)
```
As with `depends` you can request a recursive lookup, which will list all
packages depending on the packages that cause the conflict.
### Options
* **--recursive (-r):** Recursively resolves up to the root package.
* **--tree (-t):** Prints the results as a nested tree, implies -r.
## validate

View File

@ -18,7 +18,7 @@ use Symfony\Component\Console\Output\OutputInterface;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class AboutCommand extends Command
class AboutCommand extends BaseCommand
{
protected function configure()
{

View File

@ -30,7 +30,7 @@ use Symfony\Component\Console\Output\OutputInterface;
*
* @author Nils Adermann <naderman@naderman.de>
*/
class ArchiveCommand extends Command
class ArchiveCommand extends BaseCommand
{
protected function configure()
{

View File

@ -18,7 +18,7 @@ use Composer\IO\IOInterface;
use Composer\IO\NullIO;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Command\Command as BaseCommand;
use Symfony\Component\Console\Command\Command;
/**
* Base class for Composer commands
@ -26,7 +26,7 @@ use Symfony\Component\Console\Command\Command as BaseCommand;
* @author Ryan Weaver <ryan@knplabs.com>
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
abstract class Command extends BaseCommand
abstract class BaseCommand extends Command
{
/**
* @var Composer

View File

@ -0,0 +1,190 @@
<?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\Package\Link;
use Composer\Package\PackageInterface;
use Composer\Repository\ArrayRepository;
use Composer\Repository\CompositeRepository;
use Composer\Repository\PlatformRepository;
use Composer\Plugin\CommandEvent;
use Composer\Plugin\PluginEvents;
use Composer\Package\Version\VersionParser;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Base implementation for commands mapping dependency relationships.
*
* @author Niels Keurentjes <niels.keurentjes@omines.com>
*/
class BaseDependencyCommand extends BaseCommand
{
const ARGUMENT_PACKAGE = 'package';
const ARGUMENT_CONSTRAINT = 'constraint';
const OPTION_RECURSIVE = 'recursive';
const OPTION_TREE = 'tree';
/**
* Set common options and arguments.
*/
protected function configure()
{
$this->setDefinition(array(
new InputArgument(self::ARGUMENT_PACKAGE, InputArgument::REQUIRED, 'Package to inspect'),
new InputArgument(self::ARGUMENT_CONSTRAINT, InputArgument::OPTIONAL, 'Optional version constraint', '*'),
new InputOption(self::OPTION_RECURSIVE, 'r', InputOption::VALUE_NONE, 'Recursively resolves up to the root package'),
new InputOption(self::OPTION_TREE, 't', InputOption::VALUE_NONE, 'Prints the results as a nested tree'),
));
}
/**
* Execute the command.
*
* @param InputInterface $input
* @param OutputInterface $output
* @param bool $inverted Whether to invert matching process (why-not vs why behaviour)
* @return int|null Exit code of the operation.
*/
protected function doExecute(InputInterface $input, OutputInterface $output, $inverted = false)
{
// Emit command event on startup
$composer = $this->getComposer();
$commandEvent = new CommandEvent(PluginEvents::COMMAND, $this->getName(), $input, $output);
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
// Prepare repositories and set up a pool
$platformOverrides = $composer->getConfig()->get('platform') ?: array();
$repository = new CompositeRepository(array(
new ArrayRepository(array($composer->getPackage())),
$composer->getRepositoryManager()->getLocalRepository(),
new PlatformRepository(array(), $platformOverrides),
));
$pool = new Pool();
$pool->addRepository($repository);
// Parse package name and constraint
list($needle, $textConstraint) = array_pad(explode(':', $input->getArgument(self::ARGUMENT_PACKAGE)),
2, $input->getArgument(self::ARGUMENT_CONSTRAINT));
// Find packages that are or provide the requested package first
$packages = $pool->whatProvides($needle);
if (empty($packages)) {
throw new \InvalidArgumentException(sprintf('Could not find package "%s" in your project', $needle));
}
// Include replaced packages for inverted lookups as they are then the actual starting point to consider
$needles = array($needle);
if ($inverted) {
foreach ($packages as $package) {
$needles = array_merge($needles, array_map(function (Link $link) {
return $link->getTarget();
}, $package->getReplaces()));
}
}
// Parse constraint if one was supplied
if ('*' !== $textConstraint) {
$versionParser = new VersionParser();
$constraint = $versionParser->parseConstraints($textConstraint);
} else {
$constraint = null;
}
// Parse rendering options
$renderTree = $input->getOption(self::OPTION_TREE);
$recursive = $renderTree || $input->getOption(self::OPTION_RECURSIVE);
// Resolve dependencies
$results = $repository->getDependents($needles, $constraint, $inverted, $recursive);
if (empty($results)) {
$extra = (null !== $constraint) ? sprintf(' in versions %smatching %s', $inverted ? 'not ' : '', $textConstraint) : '';
$this->getIO()->writeError(sprintf('<info>There is no installed package depending on "%s"%s</info>',
$needle, $extra));
} elseif ($renderTree) {
$root = $packages[0];
$this->getIO()->write(sprintf('<info>%s</info> %s %s', $root->getPrettyName(), $root->getPrettyVersion(), $root->getDescription()));
$this->printTree($output, $results);
} else {
$this->printTable($output, $results);
}
return 0;
}
/**
* Assembles and prints a bottom-up table of the dependencies.
*
* @param OutputInterface $output
* @param array $results
*/
protected function printTable(OutputInterface $output, $results)
{
$table = array();
$doubles = array();
do {
$queue = array();
$rows = array();
foreach($results as $result) {
/**
* @var PackageInterface $package
* @var Link $link
*/
list($package, $link, $children) = $result;
$unique = (string)$link;
if (isset($doubles[$unique])) {
continue;
}
$doubles[$unique] = true;
$version = (strpos($package->getPrettyVersion(), 'No version set') === 0) ? '-' : $package->getPrettyVersion();
$rows[] = array($package->getPrettyName(), $version, $link->getDescription(), sprintf('%s (%s)', $link->getTarget(), $link->getPrettyConstraint()));
$queue = array_merge($queue, $children);
}
$results = $queue;
$table = array_merge($rows, $table);
} while(!empty($results));
// Render table
$renderer = new Table($output);
$renderer->setStyle('compact')->setRows($table)->render();
}
/**
* Recursively prints a tree of the selected results.
*
* @param OutputInterface $output
* @param array $results
* @param string $prefix
*/
protected function printTree(OutputInterface $output, $results, $prefix = '')
{
$count = count($results);
$idx = 0;
foreach($results as $key => $result) {
/**
* @var PackageInterface $package
* @var Link $link
*/
list($package, $link, $children) = $result;
$isLast = (++$idx == $count);
$versionText = (strpos($package->getPrettyVersion(), 'No version set') === 0) ? '' : $package->getPrettyVersion();
$packageText = rtrim(sprintf('%s %s', $package->getPrettyName(), $versionText));
$linkText = implode(' ', array($link->getDescription(), $link->getTarget(), $link->getPrettyConstraint()));
$output->write(sprintf("%s%s %s (%s)\n", $prefix, $isLast ? '`-' : '|-', $packageText, $linkText));
$this->printTree($output, $children, $prefix . ($isLast ? ' ' : '| '));
}
}
}

View File

@ -20,7 +20,7 @@ use Symfony\Component\Console\Output\OutputInterface;
/**
* @author David Neilsen <petah.p@gmail.com>
*/
class ClearCacheCommand extends Command
class ClearCacheCommand extends BaseCommand
{
protected function configure()
{

View File

@ -27,7 +27,7 @@ use Composer\Json\JsonFile;
* @author Joshua Estes <Joshua.Estes@iostudio.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class ConfigCommand extends Command
class ConfigCommand extends BaseCommand
{
/**
* @var Config

View File

@ -46,7 +46,7 @@ use Composer\Package\Version\VersionParser;
* @author Tobias Munk <schmunk@usrbin.de>
* @author Nils Adermann <naderman@naderman.de>
*/
class CreateProjectCommand extends Command
class CreateProjectCommand extends BaseCommand
{
protected function configure()
{

View File

@ -12,43 +12,25 @@
namespace Composer\Command;
use Composer\DependencyResolver\Pool;
use Composer\Package\Link;
use Composer\Package\PackageInterface;
use Composer\Repository\ArrayRepository;
use Composer\Repository\CompositeRepository;
use Composer\Repository\PlatformRepository;
use Composer\Plugin\CommandEvent;
use Composer\Plugin\PluginEvents;
use Composer\Package\Version\VersionParser;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
* @author Justin Rainbow <justin.rainbow@gmail.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @author Niels Keurentjes <niels.keurentjes@omines.com>
*/
class DependsCommand extends Command
class DependsCommand extends BaseDependencyCommand
{
protected $linkTypes = array(
'require' => array('requires', 'requires'),
'require-dev' => array('devRequires', 'requires (dev)'),
);
/**
* Configure command metadata.
*/
protected function configure()
{
parent::configure();
$this
->setName('depends')
->setDescription('Shows which packages depend on the given package')
->setDefinition(array(
new InputArgument('package', InputArgument::REQUIRED, 'Package to inspect'),
new InputOption('link-type', '', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Link types to show (require, require-dev)', array_keys($this->linkTypes)),
new InputOption('match-constraint', 'm', InputOption::VALUE_REQUIRED, 'Filters the dependencies shown using this constraint', '*'),
new InputOption('invert-match-constraint', 'i', InputOption::VALUE_NONE, 'Turns --match-constraint around into a blacklist instead of whitelist'),
new InputOption('with-replaces', '', InputOption::VALUE_NONE, 'Search for replaced packages as well'),
))
->setAliases(array('why'))
->setDescription('Shows which packages cause the given package to be installed')
->setHelp(<<<EOT
Displays detailed information about where a package is referenced.
@ -59,82 +41,15 @@ EOT
;
}
/**
* Execute the function.
*
* @param InputInterface $input
* @param OutputInterface $output
* @return int|null
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$composer = $this->getComposer();
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'depends', $input, $output);
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
$platformOverrides = $composer->getConfig()->get('platform') ?: array();
$repo = new CompositeRepository(array(
new ArrayRepository(array($composer->getPackage())),
$composer->getRepositoryManager()->getLocalRepository(),
new PlatformRepository(array(), $platformOverrides),
));
$needle = $input->getArgument('package');
$pool = new Pool();
$pool->addRepository($repo);
$packages = $pool->whatProvides($needle);
if (empty($packages)) {
throw new \InvalidArgumentException('Could not find package "'.$needle.'" in your project.');
}
$linkTypes = $this->linkTypes;
$types = array_map(function ($type) use ($linkTypes) {
$type = rtrim($type, 's');
if (!isset($linkTypes[$type])) {
throw new \InvalidArgumentException('Unexpected link type: '.$type.', valid types: '.implode(', ', array_keys($linkTypes)));
}
return $type;
}, $input->getOption('link-type'));
$versionParser = new VersionParser();
$constraint = $versionParser->parseConstraints($input->getOption('match-constraint'));
$matchInvert = $input->getOption('invert-match-constraint');
$needles = array($needle);
if (true === $input->getOption('with-replaces')) {
foreach ($packages as $package) {
$needles = array_merge($needles, array_map(function (Link $link) {
return $link->getTarget();
}, $package->getReplaces()));
}
}
$messages = array();
$outputPackages = array();
$io = $this->getIO();
/** @var PackageInterface $package */
foreach ($repo->getPackages() as $package) {
foreach ($types as $type) {
/** @var Link $link */
foreach ($package->{'get'.$linkTypes[$type][0]}() as $link) {
foreach ($needles as $needle) {
if ($link->getTarget() === $needle && ($link->getConstraint()->matches($constraint) ? !$matchInvert : $matchInvert)) {
if (!isset($outputPackages[$package->getName()])) {
$messages[] = '<info>'.$package->getPrettyName() . '</info> ' . $linkTypes[$type][1] . ' ' . $needle .' (<info>' . $link->getPrettyConstraint() . '</info>)';
$outputPackages[$package->getName()] = true;
}
}
}
}
}
}
if ($messages) {
sort($messages);
$io->write($messages);
} else {
$matchText = '';
if ($input->getOption('match-constraint') !== '*') {
$matchText = ' in versions '.($matchInvert ? 'not ' : '').'matching ' . $input->getOption('match-constraint');
}
$io->writeError('<info>There is no installed package depending on "'.$needle.'"'.$matchText.'.</info>');
}
return parent::doExecute($input, $output, false);
}
}

View File

@ -29,7 +29,7 @@ use Symfony\Component\Console\Output\OutputInterface;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class DiagnoseCommand extends Command
class DiagnoseCommand extends BaseCommand
{
/** @var RemoteFileSystem */
protected $rfs;

View File

@ -21,7 +21,7 @@ use Symfony\Component\Console\Output\OutputInterface;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class DumpAutoloadCommand extends Command
class DumpAutoloadCommand extends BaseCommand
{
protected function configure()
{

View File

@ -21,7 +21,7 @@ use Symfony\Component\Console\Output\OutputInterface;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class GlobalCommand extends Command
class GlobalCommand extends BaseCommand
{
protected function configure()
{

View File

@ -26,7 +26,7 @@ use Symfony\Component\Console\Output\OutputInterface;
/**
* @author Robert Schönthal <seroscho@googlemail.com>
*/
class HomeCommand extends Command
class HomeCommand extends BaseCommand
{
/**
* {@inheritDoc}

View File

@ -31,7 +31,7 @@ use Symfony\Component\Process\ExecutableFinder;
* @author Justin Rainbow <justin.rainbow@gmail.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class InitCommand extends Command
class InitCommand extends BaseCommand
{
/** @var CompositeRepository */
protected $repos;

View File

@ -26,7 +26,7 @@ use Symfony\Component\Console\Output\OutputInterface;
* @author Konstantin Kudryashov <ever.zet@gmail.com>
* @author Nils Adermann <naderman@naderman.de>
*/
class InstallCommand extends Command
class InstallCommand extends BaseCommand
{
protected function configure()
{

View File

@ -25,7 +25,7 @@ use Symfony\Component\Console\Output\OutputInterface;
/**
* @author Benoît Merlet <benoit.merlet@gmail.com>
*/
class LicensesCommand extends Command
class LicensesCommand extends BaseCommand
{
protected function configure()
{

View File

@ -0,0 +1,55 @@
<?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\Output\OutputInterface;
/**
* @author Niels Keurentjes <niels.keurentjes@omines.com>
*/
class ProhibitsCommand extends BaseDependencyCommand
{
/**
* Configure command metadata.
*/
protected function configure()
{
parent::configure();
$this
->setName('prohibits')
->setAliases(array('why-not'))
->setDescription('Shows which packages prevent the given package from being installed')
->setHelp(<<<EOT
Displays detailed information about why a package cannot be installed.
<info>php composer.phar prohibits composer/composer</info>
EOT
)
;
}
/**
* Execute the function.
*
* @param InputInterface $input
* @param OutputInterface $output
* @return int|null
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
return parent::doExecute($input, $output, true);
}
}

View File

@ -27,7 +27,7 @@ use Symfony\Component\Console\Output\OutputInterface;
* @author Pierre du Plessis <pdples@gmail.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class RemoveCommand extends Command
class RemoveCommand extends BaseCommand
{
protected function configure()
{

View File

@ -23,7 +23,7 @@ use Symfony\Component\Console\Output\OutputInterface;
/**
* @author Fabien Potencier <fabien.potencier@gmail.com>
*/
class RunScriptCommand extends Command
class RunScriptCommand extends BaseCommand
{
/**
* @var array Array with command events

View File

@ -20,7 +20,7 @@ use Symfony\Component\Console\Output\OutputInterface;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class ScriptAliasCommand extends Command
class ScriptAliasCommand extends BaseCommand
{
private $script;

View File

@ -26,7 +26,7 @@ use Composer\Plugin\PluginEvents;
/**
* @author Robert Schönthal <seroscho@googlemail.com>
*/
class SearchCommand extends Command
class SearchCommand extends BaseCommand
{
protected $matches;
protected $lowMatches = array();

View File

@ -30,7 +30,7 @@ use Symfony\Component\Finder\Finder;
* @author Kevin Ran <kran@adobe.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class SelfUpdateCommand extends Command
class SelfUpdateCommand extends BaseCommand
{
const HOMEPAGE = 'getcomposer.org';
const OLD_INSTALL_EXT = '-old.phar';

View File

@ -38,7 +38,7 @@ use Composer\Spdx\SpdxLicenses;
* @author Jordi Boggiano <j.boggiano@seld.be>
* @author Jérémy Romey <jeremyFreeAgent>
*/
class ShowCommand extends Command
class ShowCommand extends BaseCommand
{
protected $versionParser;
protected $colors;

View File

@ -24,7 +24,7 @@ use Composer\Script\ScriptEvents;
* @author Tiago Ribeiro <tiago.ribeiro@seegno.com>
* @author Rui Marinho <rui.marinho@seegno.com>
*/
class StatusCommand extends Command
class StatusCommand extends BaseCommand
{
protected function configure()
{

View File

@ -17,7 +17,7 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class SuggestsCommand extends Command
class SuggestsCommand extends BaseCommand
{
protected function configure()
{

View File

@ -28,7 +28,7 @@ use Symfony\Component\Console\Question\Question;
* @author Jordi Boggiano <j.boggiano@seld.be>
* @author Nils Adermann <naderman@naderman.de>
*/
class UpdateCommand extends Command
class UpdateCommand extends BaseCommand
{
protected function configure()
{

View File

@ -29,7 +29,7 @@ use Symfony\Component\Console\Output\OutputInterface;
* @author Robert Schönthal <seroscho@googlemail.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class ValidateCommand extends Command
class ValidateCommand extends BaseCommand
{
/**
* configure

View File

@ -279,33 +279,35 @@ class Application extends BaseApplication
}
/**
* Initializes all the composer commands
* Initializes all the composer commands.
*/
protected function getDefaultCommands()
{
$commands = parent::getDefaultCommands();
$commands[] = new Command\AboutCommand();
$commands[] = new Command\ConfigCommand();
$commands[] = new Command\DependsCommand();
$commands[] = new Command\InitCommand();
$commands[] = new Command\InstallCommand();
$commands[] = new Command\CreateProjectCommand();
$commands[] = new Command\UpdateCommand();
$commands[] = new Command\SearchCommand();
$commands[] = new Command\ValidateCommand();
$commands[] = new Command\ShowCommand();
$commands[] = new Command\SuggestsCommand();
$commands[] = new Command\RequireCommand();
$commands[] = new Command\DumpAutoloadCommand();
$commands[] = new Command\StatusCommand();
$commands[] = new Command\ArchiveCommand();
$commands[] = new Command\DiagnoseCommand();
$commands[] = new Command\RunScriptCommand();
$commands[] = new Command\LicensesCommand();
$commands[] = new Command\GlobalCommand();
$commands[] = new Command\ClearCacheCommand();
$commands[] = new Command\RemoveCommand();
$commands[] = new Command\HomeCommand();
$commands = array_merge(parent::getDefaultCommands(), array(
new Command\AboutCommand(),
new Command\ConfigCommand(),
new Command\DependsCommand(),
new Command\ProhibitsCommand(),
new Command\InitCommand(),
new Command\InstallCommand(),
new Command\CreateProjectCommand(),
new Command\UpdateCommand(),
new Command\SearchCommand(),
new Command\ValidateCommand(),
new Command\ShowCommand(),
new Command\SuggestsCommand(),
new Command\RequireCommand(),
new Command\DumpAutoloadCommand(),
new Command\StatusCommand(),
new Command\ArchiveCommand(),
new Command\DiagnoseCommand(),
new Command\RunScriptCommand(),
new Command\LicensesCommand(),
new Command\GlobalCommand(),
new Command\ClearCacheCommand(),
new Command\RemoveCommand(),
new Command\HomeCommand(),
));
if ('phar:' === substr(__FILE__, 0, 5)) {
$commands[] = new Command\SelfUpdateCommand();

View File

@ -64,6 +64,14 @@ class Link
$this->prettyConstraint = $prettyConstraint;
}
/**
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* @return string
*/

View File

@ -24,7 +24,7 @@ use Composer\Semver\Constraint\Constraint;
*
* @author Nils Adermann <naderman@naderman.de>
*/
class ArrayRepository implements RepositoryInterface
class ArrayRepository extends BaseRepository
{
/** @var PackageInterface[] */
protected $packages;

View File

@ -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\Repository;
use Composer\Package\RootPackageInterface;
use Composer\Semver\Constraint\ConstraintInterface;
/**
* Common ancestor class for generic repository functionality.
*
* @author Niels Keurentjes <niels.keurentjes@omines.com>
*/
abstract class BaseRepository implements RepositoryInterface
{
/**
* Returns a list of links causing the requested needle packages to be installed, as an associative array with the
* dependent's name as key, and an array containing in order the PackageInterface and Link describing the relationship
* as values. If recursive lookup was requested a third value is returned containing an identically formed array up
* to the root package.
*
* @param string|string[] $needle The package name(s) to inspect.
* @param ConstraintInterface|null $constraint Optional constraint to filter by.
* @param bool $invert Whether to invert matches to discover reasons for the package *NOT* to be installed.
* @param bool $recurse Whether to recursively expand the requirement tree up to the root package.
* @return array An associative array of arrays as described above.
*/
public function getDependents($needle, $constraint = null, $invert = false, $recurse = true)
{
$needles = is_array($needle) ? $needle : array($needle);
$results = array();
// Loop over all currently installed packages.
foreach ($this->getPackages() as $package) {
$links = $package->getRequires();
// Replacements are considered valid reasons for a package to be installed during forward resolution
if (!$invert) {
$links += $package->getReplaces();
}
// Require-dev is only relevant for the root package
if ($package instanceof RootPackageInterface) {
$links += $package->getDevRequires();
}
// Cross-reference all discovered links to the needles
foreach ($links as $link) {
foreach ($needles as $needle) {
if ($link->getTarget() === $needle) {
if (is_null($constraint) || (($link->getConstraint()->matches($constraint) === !$invert))) {
$results[$link->getSource()] = array($package, $link, $recurse ? $this->getDependents($link->getSource(), null, false, true) : array());
}
}
}
}
}
ksort($results);
return $results;
}
}

View File

@ -19,7 +19,7 @@ use Composer\Package\PackageInterface;
*
* @author Beau Simensen <beau@dflydev.com>
*/
class CompositeRepository implements RepositoryInterface
class CompositeRepository extends BaseRepository
{
/**
* List of repositories