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

main
Jordi Boggiano 8 years ago
commit f681dbc51e

@ -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
php composer.phar depends doctrine/lexer
doctrine/annotations v1.2.7 requires doctrine/lexer (1.*)
doctrine/common v2.6.1 requires doctrine/lexer (1.*)
```
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 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
* **--recursive (-r):** Recursively resolves up to the root package.
* **--tree (-t):** Prints the results as a nested tree, implies -r.
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)
## 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.*)
```
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:
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 depends symfony/symfony --with-replaces -im ^3.0
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
* **--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.
## validate

@ -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()
{

@ -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()
{

@ -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

@ -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 ? ' ' : '| '));
}
}
}

@ -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()
{

@ -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

@ -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()
{

@ -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);
}
}

@ -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;

@ -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()
{

@ -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()
{

@ -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}

@ -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;

@ -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()
{

@ -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()
{

@ -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);
}
}

@ -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()
{

@ -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

@ -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;

@ -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();

@ -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';

@ -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;

@ -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()
{

@ -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()
{

@ -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()
{

@ -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

@ -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();

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

@ -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;

@ -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;
}
}

@ -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

Loading…
Cancel
Save