1
0
Fork 0

Backport bash completion suggestion definition from symfony/console 6.1

pull/10320/head
Jérôme Tamarelle 2022-04-14 22:24:33 +02:00 committed by Jordi Boggiano
parent fe6be142b1
commit ed7d8219ad
No known key found for this signature in database
GPG Key ID: 7BBD42C429EC80BC
30 changed files with 376 additions and 329 deletions

View File

@ -27,11 +27,9 @@ use Composer\Util\Filesystem;
use Composer\Util\Loop;
use Composer\Util\Platform;
use Composer\Util\ProcessExecutor;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Input\InputArgument;
use Composer\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Composer\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
@ -41,16 +39,9 @@ use Symfony\Component\Console\Output\OutputInterface;
*/
class ArchiveCommand extends BaseCommand
{
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
if ($this->completeAvailablePackage($input, $suggestions)) {
return;
}
use CompletionTrait;
if ($input->mustSuggestOptionValuesFor('format')) {
$suggestions->suggestValues(['tar', 'tar.gz', 'tar.bz2', 'zip']);
}
}
private const FORMATS = ['tar', 'tar.gz', 'tar.bz2', 'zip'];
/**
* @return void
@ -61,9 +52,9 @@ class ArchiveCommand extends BaseCommand
->setName('archive')
->setDescription('Creates an archive of this composer package.')
->setDefinition(array(
new InputArgument('package', InputArgument::OPTIONAL, 'The package to archive instead of the current project'),
new InputArgument('package', InputArgument::OPTIONAL, 'The package to archive instead of the current project', null, $this->suggestAvailablePackage()),
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, tar.gz, tar.bz2 or zip (default tar)'),
new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the resulting archive: tar, tar.gz, tar.bz2 or zip (default tar)', null, self::FORMATS),
new InputOption('dir', null, InputOption::VALUE_REQUIRED, 'Write the archive to this directory'),
new InputOption('file', null, InputOption::VALUE_REQUIRED, 'Write the archive with the given file name.'
.' Note that the format will be appended.'),

View File

@ -15,21 +15,16 @@ namespace Composer\Command;
use Composer\Composer;
use Composer\Config;
use Composer\Console\Application;
use Composer\Console\Input\InputArgument;
use Composer\Console\Input\InputOption;
use Composer\Factory;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterInterface;
use Composer\IO\IOInterface;
use Composer\IO\NullIO;
use Composer\Package\Package;
use Composer\Package\PackageInterface;
use Composer\Plugin\PreCommandRunEvent;
use Composer\Package\Version\VersionParser;
use Composer\Plugin\PluginEvents;
use Composer\Repository\CompositeRepository;
use Composer\Repository\InstalledRepository;
use Composer\Repository\PlatformRepository;
use Composer\Repository\RepositoryInterface;
use Composer\Repository\RootPackageRepository;
use Composer\Util\Platform;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
@ -191,6 +186,30 @@ abstract class BaseCommand extends Command
$this->io = $io;
}
/**
* @inheritdoc
*
* Backport suggested values definition from symfony/console 6.1+
*/
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
$definition = $this->getDefinition();
$name = (string) $input->getCompletionName();
if (CompletionInput::TYPE_OPTION_VALUE === $input->getCompletionType()
&& $definition->hasOption($name)
&& ($option = $definition->getOption($name)) instanceof InputOption
) {
$option->complete($input, $suggestions);
} elseif (CompletionInput::TYPE_ARGUMENT_VALUE === $input->getCompletionType()
&& $definition->hasArgument($name)
&& ($argument = $definition->getArgument($name)) instanceof InputArgument
) {
$argument->complete($input, $suggestions);
} else {
parent::complete($input, $suggestions);
}
}
/**
* @inheritDoc
*
@ -326,96 +345,7 @@ abstract class BaseCommand extends Command
}
/**
* Suggestion values for "prefer-install" option
*/
protected function completePreferInstall(CompletionInput $input, CompletionSuggestions $suggestions): bool
{
if ($input->mustSuggestOptionValuesFor('prefer-install')) {
$suggestions->suggestValues(['dist', 'source', 'auto']);
return true;
}
return false;
}
/**
* Suggest package names from installed ones.
*/
protected function completeInstalledPackage(CompletionInput $input, CompletionSuggestions $suggestions): bool
{
if (!$input->mustSuggestArgumentValuesFor('packages') &&
!$input->mustSuggestArgumentValuesFor('package') &&
!$input->mustSuggestOptionValuesFor('ignore')
) {
return false;
}
$composer = $this->getComposer();
$installedRepos = [new RootPackageRepository(clone $composer->getPackage())];
$locker = $composer->getLocker();
if ($locker->isLocked()) {
$installedRepos[] = $locker->getLockedRepository(true);
} else {
$installedRepos[] = $composer->getRepositoryManager()->getLocalRepository();
}
$installedRepo = new InstalledRepository($installedRepos);
$suggestions->suggestValues(array_map(function (PackageInterface $package) {
return $package->getName();
}, $installedRepo->getPackages()));
return true;
}
/**
* Suggest package names available on all configured repositories.
*/
protected function completeAvailablePackage(CompletionInput $input, CompletionSuggestions $suggestions): bool
{
if (!$input->mustSuggestArgumentValuesFor('packages') &&
!$input->mustSuggestArgumentValuesFor('package') &&
!$input->mustSuggestOptionValuesFor('require') &&
!$input->mustSuggestOptionValuesFor('require-dev')
) {
return false;
}
$composer = $this->getComposer();
$repos = new CompositeRepository($composer->getRepositoryManager()->getRepositories());
$packages = $repos->search('^'.preg_quote($input->getCompletionValue()), RepositoryInterface::SEARCH_NAME);
foreach (array_slice($packages, 0, 150) as $package) {
$suggestions->suggestValue($package['name']);
}
return true;
}
/**
* Suggests ext- packages from the ones available on the currently-running PHP
*/
protected function completePlatformPackage(CompletionInput $input, CompletionSuggestions $suggestions): bool
{
if (!$input->mustSuggestOptionValuesFor('require') &&
!$input->mustSuggestOptionValuesFor('require-dev') &&
!str_starts_with($input->getCompletionValue(), 'ext-')
) {
return false;
}
$repos = new PlatformRepository([], $this->getComposer()->getConfig()->get('platform') ?? []);
$suggestions->suggestValues(array_map(function (PackageInterface $package) {
return $package->getName();
}, $repos->getPackages()));
return true;
}
/**
* @param array<string, string> $requirements
* @param array<string> $requirements
*
* @return array<string, string>
*/

View File

@ -0,0 +1,102 @@
<?php declare(strict_types=1);
/*
* 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\Package\PackageInterface;
use Composer\Repository\CompositeRepository;
use Composer\Repository\InstalledRepository;
use Composer\Repository\PlatformRepository;
use Composer\Repository\RepositoryInterface;
use Composer\Repository\RootPackageRepository;
use Symfony\Component\Console\Completion\CompletionInput;
/**
* Adds completion to arguments and options.
*
* @internal
*/
trait CompletionTrait
{
/**
* @see BaseCommand::requireComposer()
*/
abstract public function requireComposer(bool $disablePlugins = null, bool $disableScripts = null): Composer;
/**
* Suggestion values for "prefer-install" option
*/
private function suggestPreferInstall(): array
{
return ['dist', 'source', 'auto'];
}
/**
* Suggest package names from installed.
*/
private function suggestInstalledPackage(): \Closure
{
return function (): array {
$composer = $this->requireComposer();
$installedRepos = [new RootPackageRepository(clone $composer->getPackage())];
$locker = $composer->getLocker();
if ($locker->isLocked()) {
$installedRepos[] = $locker->getLockedRepository(true);
} else {
$installedRepos[] = $composer->getRepositoryManager()->getLocalRepository();
}
$installedRepo = new InstalledRepository($installedRepos);
return array_map(function (PackageInterface $package) {
return $package->getName();
}, $installedRepo->getPackages());
};
}
/**
* Suggest package names available on all configured repositories.
* @todo rework to list packages from cache
*/
private function suggestAvailablePackage(): \Closure
{
return function (CompletionInput $input) {
$composer = $this->requireComposer();
$repos = new CompositeRepository($composer->getRepositoryManager()->getRepositories());
$packages = $repos->search('^' . preg_quote($input->getCompletionValue()), RepositoryInterface::SEARCH_NAME);
return array_column(array_slice($packages, 0, 150), 'name');
};
}
/**
* Suggest package names available on all configured repositories or
* ext- packages from the ones available on the currently-running PHP
*/
private function suggestAvailablePackageOrExtension(): \Closure
{
return function (CompletionInput $input) {
if (!str_starts_with($input->getCompletionValue(), 'ext-')) {
return $this->suggestAvailablePackage()($input);
}
$repos = new PlatformRepository([], $this->requireComposer()->getConfig()->get('platform') ?? []);
return array_map(function (PackageInterface $package) {
return $package->getName();
}, $repos->getPackages());
};
}
}

View File

@ -33,11 +33,9 @@ use Composer\Repository\InstalledArrayRepository;
use Composer\Repository\RepositorySet;
use Composer\Script\ScriptEvents;
use Composer\Util\Silencer;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Input\InputArgument;
use Composer\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Composer\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Finder\Finder;
use Composer\Json\JsonFile;
@ -57,10 +55,7 @@ use Composer\Package\Version\VersionParser;
*/
class CreateProjectCommand extends BaseCommand
{
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
$this->completeAvailablePackage($input, $suggestions) || $this->completePreferInstall($input, $suggestions);
}
use CompletionTrait;
/**
* @var SuggestedPackagesReporter
@ -76,13 +71,13 @@ class CreateProjectCommand extends BaseCommand
->setName('create-project')
->setDescription('Creates new project from a package into given directory.')
->setDefinition(array(
new InputArgument('package', InputArgument::OPTIONAL, 'Package name to be installed'),
new InputArgument('package', InputArgument::OPTIONAL, 'Package name to be installed', null, $this->suggestAvailablePackage()),
new InputArgument('directory', InputArgument::OPTIONAL, 'Directory where the files should be created'),
new InputArgument('version', InputArgument::OPTIONAL, 'Version, will default to latest'),
new InputOption('stability', 's', InputOption::VALUE_REQUIRED, 'Minimum-stability allowed (unless a version is specified).'),
new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'),
new InputOption('prefer-dist', null, InputOption::VALUE_NONE, 'Forces installation from package dist (default behavior).'),
new InputOption('prefer-install', null, InputOption::VALUE_REQUIRED, 'Forces installation from package dist|source|auto (auto chooses source for dev versions, dist for the rest).'),
new InputOption('prefer-install', null, InputOption::VALUE_REQUIRED, 'Forces installation from package dist|source|auto (auto chooses source for dev versions, dist for the rest).', null, $this->suggestPreferInstall()),
new InputOption('repository', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Add custom repositories to look the package up, either by URL or using JSON arrays'),
new InputOption('repository-url', null, InputOption::VALUE_REQUIRED, 'DEPRECATED: Use --repository instead.'),
new InputOption('add-repository', null, InputOption::VALUE_NONE, 'Add the custom repository in the composer.json. If a lock file is present it will be deleted and an update will be run instead of install.'),

View File

@ -12,22 +12,17 @@
namespace Composer\Command;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Composer\Console\Input\InputArgument;
use Composer\Console\Input\InputOption;
/**
* @author Niels Keurentjes <niels.keurentjes@omines.com>
*/
class DependsCommand extends BaseDependencyCommand
{
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
$this->completeInstalledPackage($input, $suggestions);
}
use CompletionTrait;
/**
* Configure command metadata.
@ -41,7 +36,7 @@ class DependsCommand extends BaseDependencyCommand
->setAliases(array('why'))
->setDescription('Shows which packages cause the given package to be installed.')
->setDefinition(array(
new InputArgument(self::ARGUMENT_PACKAGE, InputArgument::REQUIRED, 'Package to inspect'),
new InputArgument(self::ARGUMENT_PACKAGE, InputArgument::REQUIRED, 'Package to inspect', null, $this->suggestInstalledPackage()),
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'),
))

View File

@ -12,25 +12,16 @@
namespace Composer\Command;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Composer\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Composer\Console\Input\InputArgument;
/**
* @author Davey Shafik <me@daveyshafik.com>
*/
class ExecCommand extends BaseCommand
{
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
if ($input->mustSuggestArgumentValuesFor('binary')) {
$suggestions->suggestValues($this->getBinaries(false));
}
}
/**
* @return void
*/
@ -41,7 +32,9 @@ class ExecCommand extends BaseCommand
->setDescription('Executes a vendored binary/script.')
->setDefinition(array(
new InputOption('list', 'l', InputOption::VALUE_NONE),
new InputArgument('binary', InputArgument::OPTIONAL, 'The binary to run, e.g. phpunit'),
new InputArgument('binary', InputArgument::OPTIONAL, 'The binary to run, e.g. phpunit', null, function () {
return $this->getBinaries(false);
}),
new InputArgument(
'args',
InputArgument::IS_ARRAY | InputArgument::OPTIONAL,
@ -61,9 +54,9 @@ EOT
protected function execute(InputInterface $input, OutputInterface $output)
{
$composer = $this->requireComposer();
if ($input->getOption('list') || !$input->getArgument('binary')) {
if ($input->getOption('list') || null === $input->getArgument('binary')) {
$bins = $this->getBinaries(true);
if (count($bins) > 0) {
if ([] === $bins) {
$binDir = $composer->getConfig()->get('bin-dir');
throw new \RuntimeException("No binaries found in composer.json or in bin-dir ($binDir)");
@ -107,7 +100,7 @@ EOT
private function getBinaries(bool $forDisplay): array
{
$composer = $this->getComposer();
$composer = $this->requireComposer();
$binDir = $composer->getConfig()->get('bin-dir');
$bins = glob($binDir . '/*');
$localBins = $composer->getPackage()->getBinaries();

View File

@ -21,7 +21,7 @@ use Composer\Repository\CompositeRepository;
use Composer\Semver\Constraint\MatchAllConstraint;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Composer\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
@ -38,7 +38,7 @@ class FundCommand extends BaseCommand
$this->setName('fund')
->setDescription('Discover how to help fund the maintenance of your dependencies.')
->setDefinition(array(
new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the output: text or json', 'text'),
new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the output: text or json', 'text', ['text', 'json']),
))
;
}

View File

@ -20,7 +20,7 @@ use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Composer\Console\Input\InputArgument;
use Symfony\Component\Console\Input\StringInput;
use Symfony\Component\Console\Output\OutputInterface;

View File

@ -18,10 +18,8 @@ use Composer\Repository\RootPackageRepository;
use Composer\Repository\RepositoryFactory;
use Composer\Util\Platform;
use Composer\Util\ProcessExecutor;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Composer\Console\Input\InputArgument;
use Composer\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
@ -30,10 +28,7 @@ use Symfony\Component\Console\Output\OutputInterface;
*/
class HomeCommand extends BaseCommand
{
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
$this->completeInstalledPackage($input, $suggestions);
}
use CompletionTrait;
/**
* @inheritDoc
@ -47,7 +42,7 @@ class HomeCommand extends BaseCommand
->setAliases(array('home'))
->setDescription('Opens the package\'s repository URL or homepage in your browser.')
->setDefinition(array(
new InputArgument('packages', InputArgument::IS_ARRAY, 'Package(s) to browse to.'),
new InputArgument('packages', InputArgument::IS_ARRAY, 'Package(s) to browse to.', null, $this->suggestInstalledPackage()),
new InputOption('homepage', 'H', InputOption::VALUE_NONE, 'Open the homepage instead of the repository URL.'),
new InputOption('show', 's', InputOption::VALUE_NONE, 'Only show the homepage or repository URL.'),
))

View File

@ -23,11 +23,9 @@ use Composer\Repository\PlatformRepository;
use Composer\Repository\RepositoryFactory;
use Composer\Util\Filesystem;
use Composer\Util\Silencer;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Composer\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\ExecutableFinder;
use Symfony\Component\Process\Process;
@ -39,19 +37,12 @@ use Symfony\Component\Console\Helper\FormatterHelper;
*/
class InitCommand extends BaseCommand
{
use CompletionTrait;
use PackageDiscoveryTrait;
/** @var array<string, string> */
private $gitConfig;
/** @var RepositorySet[] */
private $repositorySets;
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
$this->completeAvailablePackage($input, $suggestions);
}
/**
* @inheritDoc
*
@ -68,8 +59,8 @@ class InitCommand extends BaseCommand
new InputOption('author', null, InputOption::VALUE_REQUIRED, 'Author name of package'),
new InputOption('type', null, InputOption::VALUE_OPTIONAL, 'Type of package (e.g. library, project, metapackage, composer-plugin)'),
new InputOption('homepage', null, InputOption::VALUE_REQUIRED, 'Homepage of package'),
new InputOption('require', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Package to require with a version constraint, e.g. foo/bar:1.0.0 or foo/bar=1.0.0 or "foo/bar 1.0.0"'),
new InputOption('require-dev', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Package to require for development with a version constraint, e.g. foo/bar:1.0.0 or foo/bar=1.0.0 or "foo/bar 1.0.0"'),
new InputOption('require', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Package to require with a version constraint, e.g. foo/bar:1.0.0 or foo/bar=1.0.0 or "foo/bar 1.0.0"', null, $this->suggestAvailablePackage()),
new InputOption('require-dev', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Package to require for development with a version constraint, e.g. foo/bar:1.0.0 or foo/bar=1.0.0 or "foo/bar 1.0.0"', null, $this->suggestAvailablePackage()),
new InputOption('stability', 's', InputOption::VALUE_REQUIRED, 'Minimum stability (empty or one of: '.implode(', ', array_keys(BasePackage::$stabilities)).')'),
new InputOption('license', 'l', InputOption::VALUE_REQUIRED, 'License of package'),
new InputOption('repository', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Add custom repositories, either by URL or using JSON arrays'),

View File

@ -16,11 +16,9 @@ use Composer\Installer;
use Composer\Plugin\CommandEvent;
use Composer\Plugin\PluginEvents;
use Composer\Util\HttpDownloader;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Composer\Console\Input\InputOption;
use Composer\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface;
/**
@ -31,10 +29,7 @@ use Symfony\Component\Console\Output\OutputInterface;
*/
class InstallCommand extends BaseCommand
{
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
$this->completePreferInstall($input, $suggestions) || $this->completeInstalledPackage($input, $suggestions);
}
use CompletionTrait;
/**
* @return void
@ -48,7 +43,7 @@ class InstallCommand extends BaseCommand
->setDefinition(array(
new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'),
new InputOption('prefer-dist', null, InputOption::VALUE_NONE, 'Forces installation from package dist (default behavior).'),
new InputOption('prefer-install', null, InputOption::VALUE_REQUIRED, 'Forces installation from package dist|source|auto (auto chooses source for dev versions, dist for the rest).'),
new InputOption('prefer-install', null, InputOption::VALUE_REQUIRED, 'Forces installation from package dist|source|auto (auto chooses source for dev versions, dist for the rest).', null, $this->suggestPreferInstall()),
new InputOption('dry-run', null, InputOption::VALUE_NONE, 'Outputs the operations but will not execute anything (implicitly enables --verbose).'),
new InputOption('dev', null, InputOption::VALUE_NONE, 'DEPRECATED: Enables installation of require-dev packages (enabled by default, only present for BC).'),
new InputOption('no-suggest', null, InputOption::VALUE_NONE, 'DEPRECATED: This flag does not exist anymore.'),
@ -63,7 +58,7 @@ class InstallCommand extends BaseCommand
new InputOption('apcu-autoloader-prefix', null, InputOption::VALUE_REQUIRED, 'Use a custom prefix for the APCu autoloader cache. Implicitly enables --apcu-autoloader'),
new InputOption('ignore-platform-req', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore a specific platform requirement (php & ext- packages).'),
new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore all platform requirements (php & ext- packages).'),
new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Should not be provided, use composer require instead to add a given package to composer.json.'),
new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Should not be provided, use composer require instead to add a given package to composer.json.', null, $this->suggestInstalledPackage()),
))
->setHelp(
<<<EOT

View File

@ -12,12 +12,10 @@
namespace Composer\Command;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Composer\Console\Input\InputArgument;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputOption;
use Composer\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
@ -25,10 +23,7 @@ use Symfony\Component\Console\Output\OutputInterface;
*/
class OutdatedCommand extends BaseCommand
{
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
$this->completeInstalledPackage($input, $suggestions);
}
use CompletionTrait;
/**
* @return void
@ -39,7 +34,7 @@ class OutdatedCommand extends BaseCommand
->setName('outdated')
->setDescription('Shows a list of installed packages that have updates available, including their latest version.')
->setDefinition(array(
new InputArgument('package', InputArgument::OPTIONAL, 'Package to inspect. Or a name including a wildcard (*) to filter lists of packages instead.'),
new InputArgument('package', InputArgument::OPTIONAL, 'Package to inspect. Or a name including a wildcard (*) to filter lists of packages instead.', null, $this->suggestInstalledPackage()),
new InputOption('outdated', 'o', InputOption::VALUE_NONE, 'Show only packages that are outdated (this is the default, but present here for compat with `show`'),
new InputOption('all', 'a', InputOption::VALUE_NONE, 'Show all installed packages with their latest versions'),
new InputOption('locked', null, InputOption::VALUE_NONE, 'Shows updates for packages from the lock file, regardless of what is currently in vendor dir'),
@ -48,7 +43,7 @@ class OutdatedCommand extends BaseCommand
new InputOption('minor-only', 'm', InputOption::VALUE_NONE, 'Show only packages that have minor SemVer-compatible updates. Use with the --outdated option.'),
new InputOption('patch-only', 'p', InputOption::VALUE_NONE, 'Show only packages that have patch SemVer-compatible updates. Use with the --outdated option.'),
new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the output: text or json', 'text'),
new InputOption('ignore', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore specified package(s). Use it with the --outdated option if you don\'t want to be informed about new versions of some packages.'),
new InputOption('ignore', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore specified package(s). Use it with the --outdated option if you don\'t want to be informed about new versions of some packages.', null, $this->suggestInstalledPackage()),
new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables search in require-dev packages.'),
new InputOption('ignore-platform-req', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore a specific platform requirement (php & ext- packages). Use with the --outdated option'),
new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore all platform requirements (php & ext- packages). Use with the --outdated option'),

View File

@ -12,22 +12,17 @@
namespace Composer\Command;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Composer\Console\Input\InputArgument;
use Composer\Console\Input\InputOption;
/**
* @author Niels Keurentjes <niels.keurentjes@omines.com>
*/
class ProhibitsCommand extends BaseDependencyCommand
{
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
$this->completeAvailablePackage($input, $suggestions);
}
use CompletionTrait;
/**
* Configure command metadata.
@ -41,7 +36,7 @@ class ProhibitsCommand extends BaseDependencyCommand
->setAliases(array('why-not'))
->setDescription('Shows which packages prevent the given package from being installed.')
->setDefinition(array(
new InputArgument(self::ARGUMENT_PACKAGE, InputArgument::REQUIRED, 'Package to inspect'),
new InputArgument(self::ARGUMENT_PACKAGE, InputArgument::REQUIRED, 'Package to inspect', null, $this->suggestAvailablePackage()),
new InputArgument(self::ARGUMENT_CONSTRAINT, InputArgument::REQUIRED, 'Version constraint, which version you expected to be installed'),
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'),

View File

@ -22,11 +22,9 @@ use Composer\Plugin\CommandEvent;
use Composer\Plugin\PluginEvents;
use Composer\Script\ScriptEvents;
use Composer\Util\Platform;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Composer\Console\Input\InputOption;
use Composer\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface;
/**
@ -34,10 +32,7 @@ use Symfony\Component\Console\Output\OutputInterface;
*/
class ReinstallCommand extends BaseCommand
{
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
$this->completeInstalledPackage($input, $suggestions) || $this->completePreferInstall($input, $suggestions);
}
use CompletionTrait;
/**
* @return void
@ -50,7 +45,7 @@ class ReinstallCommand extends BaseCommand
->setDefinition(array(
new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'),
new InputOption('prefer-dist', null, InputOption::VALUE_NONE, 'Forces installation from package dist (default behavior).'),
new InputOption('prefer-install', null, InputOption::VALUE_REQUIRED, 'Forces installation from package dist|source|auto (auto chooses source for dev versions, dist for the rest).'),
new InputOption('prefer-install', null, InputOption::VALUE_REQUIRED, 'Forces installation from package dist|source|auto (auto chooses source for dev versions, dist for the rest).', null, $this->suggestPreferInstall()),
new InputOption('no-autoloader', null, InputOption::VALUE_NONE, 'Skips autoloader generation'),
new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'),
new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump'),
@ -59,7 +54,7 @@ class ReinstallCommand extends BaseCommand
new InputOption('apcu-autoloader-prefix', null, InputOption::VALUE_REQUIRED, 'Use a custom prefix for the APCu autoloader cache. Implicitly enables --apcu-autoloader'),
new InputOption('ignore-platform-req', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore a specific platform requirement (php & ext- packages).'),
new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore all platform requirements (php & ext- packages).'),
new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::REQUIRED, 'List of package names to reinstall, can include a wildcard (*) to match any substring.'),
new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::REQUIRED, 'List of package names to reinstall, can include a wildcard (*) to match any substring.', null, $this->suggestInstalledPackage()),
))
->setHelp(
<<<EOT

View File

@ -20,11 +20,9 @@ use Composer\Plugin\CommandEvent;
use Composer\Plugin\PluginEvents;
use Composer\Json\JsonFile;
use Composer\Factory;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Composer\Console\Input\InputOption;
use Composer\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface;
use Composer\Package\BasePackage;
@ -34,10 +32,7 @@ use Composer\Package\BasePackage;
*/
class RemoveCommand extends BaseCommand
{
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
$this->completeInstalledPackage($input, $suggestions);
}
use CompletionTrait;
/**
* @return void
@ -48,7 +43,7 @@ class RemoveCommand extends BaseCommand
->setName('remove')
->setDescription('Removes a package from the require or require-dev.')
->setDefinition(array(
new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::REQUIRED, 'Packages that should be removed.'),
new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::REQUIRED, 'Packages that should be removed.', null, $this->suggestInstalledPackage()),
new InputOption('dev', null, InputOption::VALUE_NONE, 'Removes a package from the require-dev section.'),
new InputOption('dry-run', null, InputOption::VALUE_NONE, 'Outputs the operations but will not execute anything (implicitly enables --verbose).'),
new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'),

View File

@ -14,11 +14,9 @@ namespace Composer\Command;
use Composer\DependencyResolver\Request;
use Composer\Util\Filesystem;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Composer\Console\Input\InputArgument;
use Composer\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Composer\Factory;
use Composer\Installer;
@ -41,6 +39,7 @@ use Composer\Util\Silencer;
*/
class RequireCommand extends BaseCommand
{
use CompletionTrait;
use PackageDiscoveryTrait;
/** @var bool */
@ -60,11 +59,6 @@ class RequireCommand extends BaseCommand
/** @var bool */
private $dependencyResolutionCompleted = false;
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
$this->completePlatformPackage($input, $suggestions) || $this->completeAvailablePackage($input, $suggestions) || $this->completePreferInstall($input, $suggestions);
}
/**
* @return void
*/
@ -74,12 +68,12 @@ class RequireCommand extends BaseCommand
->setName('require')
->setDescription('Adds required packages to your composer.json and installs them.')
->setDefinition(array(
new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Optional package name can also include a version constraint, e.g. foo/bar or foo/bar:1.0.0 or foo/bar=1.0.0 or "foo/bar 1.0.0"'),
new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Optional package name can also include a version constraint, e.g. foo/bar or foo/bar:1.0.0 or foo/bar=1.0.0 or "foo/bar 1.0.0"', null, $this->suggestAvailablePackageOrExtension()),
new InputOption('dev', null, InputOption::VALUE_NONE, 'Add requirement to require-dev.'),
new InputOption('dry-run', null, InputOption::VALUE_NONE, 'Outputs the operations but will not execute anything (implicitly enables --verbose).'),
new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'),
new InputOption('prefer-dist', null, InputOption::VALUE_NONE, 'Forces installation from package dist (default behavior).'),
new InputOption('prefer-install', null, InputOption::VALUE_REQUIRED, 'Forces installation from package dist|source|auto (auto chooses source for dev versions, dist for the rest).'),
new InputOption('prefer-install', null, InputOption::VALUE_REQUIRED, 'Forces installation from package dist|source|auto (auto chooses source for dev versions, dist for the rest).', null, $this->suggestPreferInstall()),
new InputOption('fixed', null, InputOption::VALUE_NONE, 'Write fixed version to the composer.json.'),
new InputOption('no-suggest', null, InputOption::VALUE_NONE, 'DEPRECATED: This flag does not exist anymore.'),
new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'),

View File

@ -16,11 +16,9 @@ use Composer\Script\Event as ScriptEvent;
use Composer\Script\ScriptEvents;
use Composer\Util\ProcessExecutor;
use Composer\Util\Platform;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Composer\Console\Input\InputOption;
use Composer\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface;
/**
@ -46,13 +44,6 @@ class RunScriptCommand extends BaseCommand
ScriptEvents::POST_AUTOLOAD_DUMP,
);
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
if ($input->mustSuggestArgumentValuesFor('script')) {
$suggestions->suggestValues(array_keys($this->getComposer()->getPackage()->getScripts()));
}
}
/**
* @return void
*/
@ -63,7 +54,9 @@ class RunScriptCommand extends BaseCommand
->setAliases(array('run'))
->setDescription('Runs the scripts defined in composer.json.')
->setDefinition(array(
new InputArgument('script', InputArgument::OPTIONAL, 'Script name to run.'),
new InputArgument('script', InputArgument::OPTIONAL, 'Script name to run.', null, function () {
return array_keys($this->requireComposer()->getPackage()->getScripts());
}),
new InputArgument('args', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, ''),
new InputOption('timeout', null, InputOption::VALUE_REQUIRED, 'Sets script timeout in seconds, or 0 for never.'),
new InputOption('dev', null, InputOption::VALUE_NONE, 'Sets the dev mode.'),

View File

@ -13,8 +13,8 @@
namespace Composer\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Composer\Console\Input\InputOption;
use Composer\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface;
/**

View File

@ -14,12 +14,10 @@ namespace Composer\Command;
use Composer\Factory;
use Composer\Json\JsonFile;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Composer\Console\Input\InputArgument;
use Composer\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Composer\Repository\CompositeRepository;
use Composer\Repository\PlatformRepository;
@ -32,13 +30,6 @@ use Composer\Plugin\PluginEvents;
*/
class SearchCommand extends BaseCommand
{
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
if ($input->mustSuggestOptionValuesFor('format')) {
$suggestions->suggestValues(['json', 'text']);
}
}
/**
* @return void
*/
@ -51,7 +42,7 @@ class SearchCommand extends BaseCommand
new InputOption('only-name', 'N', InputOption::VALUE_NONE, 'Search only in package names'),
new InputOption('only-vendor', 'O', InputOption::VALUE_NONE, 'Search only for vendor / organization names, returns only "vendor" as result'),
new InputOption('type', 't', InputOption::VALUE_REQUIRED, 'Search for a specific package type'),
new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the output: text or json', 'text'),
new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the output: text or json', 'text', ['json', 'text']),
new InputArgument('tokens', InputArgument::IS_ARRAY | InputArgument::REQUIRED, 'tokens to search for'),
))
->setHelp(

View File

@ -24,8 +24,8 @@ use Composer\IO\IOInterface;
use Composer\Downloader\FilesystemException;
use Composer\Downloader\TransportException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Composer\Console\Input\InputOption;
use Composer\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Finder\Finder;

View File

@ -40,13 +40,11 @@ use Composer\Semver\Constraint\ConstraintInterface;
use Composer\Semver\Semver;
use Composer\Spdx\SpdxLicenses;
use Composer\Util\PackageInfo;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Console\Input\InputArgument;
use Composer\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Composer\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
@ -57,6 +55,8 @@ use Symfony\Component\Console\Output\OutputInterface;
*/
class ShowCommand extends BaseCommand
{
use CompletionTrait;
/** @var VersionParser */
protected $versionParser;
/** @var string[] */
@ -65,17 +65,6 @@ class ShowCommand extends BaseCommand
/** @var ?RepositorySet */
private $repositorySet;
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
if ($this->completeInstalledPackage($input, $suggestions)) {
return;
}
if ($input->mustSuggestOptionValuesFor('format')) {
$suggestions->suggestValues(['json', 'text']);
}
}
/**
* @return void
*/
@ -86,7 +75,7 @@ class ShowCommand extends BaseCommand
->setAliases(array('info'))
->setDescription('Shows information about packages.')
->setDefinition(array(
new InputArgument('package', InputArgument::OPTIONAL, 'Package to inspect. Or a name including a wildcard (*) to filter lists of packages instead.'),
new InputArgument('package', InputArgument::OPTIONAL, 'Package to inspect. Or a name including a wildcard (*) to filter lists of packages instead.', null, $this->suggestInstalledPackage()),
new InputArgument('version', InputArgument::OPTIONAL, 'Version or version constraint to inspect'),
new InputOption('all', null, InputOption::VALUE_NONE, 'List all packages'),
new InputOption('locked', null, InputOption::VALUE_NONE, 'List all locked packages'),
@ -99,12 +88,12 @@ class ShowCommand extends BaseCommand
new InputOption('tree', 't', InputOption::VALUE_NONE, 'List the dependencies as a tree'),
new InputOption('latest', 'l', InputOption::VALUE_NONE, 'Show the latest version'),
new InputOption('outdated', 'o', InputOption::VALUE_NONE, 'Show the latest version but only for packages that are outdated'),
new InputOption('ignore', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore specified package(s). Use it with the --outdated option if you don\'t want to be informed about new versions of some packages.'),
new InputOption('ignore', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore specified package(s). Use it with the --outdated option if you don\'t want to be informed about new versions of some packages.', null, $this->suggestInstalledPackage()),
new InputOption('minor-only', 'm', InputOption::VALUE_NONE, 'Show only packages that have minor SemVer-compatible updates. Use with the --outdated option.'),
new InputOption('patch-only', null, InputOption::VALUE_NONE, 'Show only packages that have patch SemVer-compatible updates. Use with the --outdated option.'),
new InputOption('direct', 'D', InputOption::VALUE_NONE, 'Shows only packages that are directly required by the root package'),
new InputOption('strict', null, InputOption::VALUE_NONE, 'Return a non-zero exit code when there are outdated packages'),
new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the output: text or json', 'text'),
new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the output: text or json', 'text', ['json', 'text']),
new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables search in require-dev packages.'),
new InputOption('ignore-platform-req', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore a specific platform requirement (php & ext- packages). Use with the --outdated option'),
new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore all platform requirements (php & ext- packages). Use with the --outdated option'),

View File

@ -13,7 +13,7 @@
namespace Composer\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Composer\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Composer\Downloader\ChangeReportInterface;
use Composer\Downloader\DvcsDownloaderInterface;

View File

@ -16,19 +16,14 @@ use Composer\Repository\PlatformRepository;
use Composer\Repository\RootPackageRepository;
use Composer\Repository\InstalledRepository;
use Composer\Installer\SuggestedPackagesReporter;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Input\InputArgument;
use Composer\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Composer\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class SuggestsCommand extends BaseCommand
{
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
$this->completeInstalledPackage($input, $suggestions);
}
use CompletionTrait;
/**
* @return void
@ -44,7 +39,7 @@ class SuggestsCommand extends BaseCommand
new InputOption('all', 'a', InputOption::VALUE_NONE, 'Show suggestions from all dependencies, including transitive ones'),
new InputOption('list', null, InputOption::VALUE_NONE, 'Show only list of suggested package names'),
new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Exclude suggestions from require-dev packages'),
new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Packages that you want to list suggestions from.'),
new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Packages that you want to list suggestions from.', null, $this->suggestInstalledPackage()),
))
->setHelp(
<<<EOT

View File

@ -24,12 +24,10 @@ use Composer\Package\Version\VersionParser;
use Composer\Util\HttpDownloader;
use Composer\Semver\Constraint\MultiConstraint;
use Composer\Package\Link;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Composer\Console\Input\InputOption;
use Composer\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\Question;
@ -39,10 +37,7 @@ use Symfony\Component\Console\Question\Question;
*/
class UpdateCommand extends BaseCommand
{
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
$this->completeInstalledPackage($input, $suggestions) || $this->completePreferInstall($input, $suggestions);
}
use CompletionTrait;
/**
* @return void
@ -54,11 +49,11 @@ class UpdateCommand extends BaseCommand
->setAliases(array('u', 'upgrade'))
->setDescription('Updates your dependencies to the latest version according to composer.json, and updates the composer.lock file.')
->setDefinition(array(
new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Packages that should be updated, if not provided all packages are.'),
new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Packages that should be updated, if not provided all packages are.', null, $this->suggestInstalledPackage()),
new InputOption('with', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Temporary version constraint to add, e.g. foo/bar:1.0.0 or foo/bar=1.0.0'),
new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'),
new InputOption('prefer-dist', null, InputOption::VALUE_NONE, 'Forces installation from package dist (default behavior).'),
new InputOption('prefer-install', null, InputOption::VALUE_REQUIRED, 'Forces installation from package dist|source|auto (auto chooses source for dev versions, dist for the rest).'),
new InputOption('prefer-install', null, InputOption::VALUE_REQUIRED, 'Forces installation from package dist|source|auto (auto chooses source for dev versions, dist for the rest).', null, $this->suggestPreferInstall()),
new InputOption('dry-run', null, InputOption::VALUE_NONE, 'Outputs the operations but will not execute anything (implicitly enables --verbose).'),
new InputOption('dev', null, InputOption::VALUE_NONE, 'DEPRECATED: Enables installation of require-dev packages (enabled by default, only present for BC).'),
new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables installation of require-dev packages.'),

View File

@ -0,0 +1,61 @@
<?php declare(strict_types=1);
/*
* 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\Console\Input;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Input\InputArgument as BaseInputArgument;
/**
* Backport suggested values definition from symfony/console 6.1+
*
* @author Jérôme Tamarelle <jerome@tamarelle.net>
*
* @internal
*/
class InputArgument extends BaseInputArgument
{
/**
* @var string[]|\Closure
*/
private $suggestedValues;
/**
* @inheritdoc
*
* @param string[]|\Closure(CompletionInput,CompletionSuggestions):list<string|Suggestion> $suggestedValues The values used for input completion
*/
public function __construct(string $name, int $mode = null, string $description = '', $default = null, $suggestedValues = [])
{
parent::__construct($name, $mode, $description, $default, $suggestedValues);
$this->suggestedValues = $suggestedValues;
}
/**
* Adds suggestions to $suggestions for the current completion input.
*
* @see Command::complete()
*/
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
$values = $this->suggestedValues;
if ($values instanceof \Closure && !\is_array($values = $values($input))) {
throw new LogicException(sprintf('Closure for option "%s" must return an array. Got "%s".', $this->getName(), get_debug_type($values)));
}
if ($values) {
$suggestions->suggestValues($values);
}
}
}

View File

@ -0,0 +1,65 @@
<?php declare(strict_types=1);
/*
* 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\Console\Input;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Input\InputOption as BaseInputOption;
/**
* Backport suggested values definition from symfony/console 6.1+
*
* @author Jérôme Tamarelle <jerome@tamarelle.net>
*
* @internal
*/
class InputOption extends BaseInputOption
{
/**
* @var string[]|\Closure
*/
private $suggestedValues;
/**
* @inheritdoc
*
* @param string[]|\Closure(CompletionInput,CompletionSuggestions):list<string|Suggestion> $suggestedValues The values used for input completion
*/
public function __construct(string $name, $shortcut = null, int $mode = null, string $description = '', $default = null, $suggestedValues = [])
{
parent::__construct($name, $shortcut, $mode, $description, $default, $suggestedValues);
$this->suggestedValues = $suggestedValues;
if ($suggestedValues && !$this->acceptValue()) {
throw new LogicException('Cannot set suggested values if the option does not accept a value.');
}
}
/**
* Adds suggestions to $suggestions for the current completion input.
*
* @see Command::complete()
*/
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
$values = $this->suggestedValues;
if ($values instanceof \Closure && !\is_array($values = $values($input))) {
throw new LogicException(sprintf('Closure for argument "%s" must return an array. Got "%s".', $this->getName(), get_debug_type($values)));
}
if ($values) {
$suggestions->suggestValues($values);
}
}
}

View File

@ -309,12 +309,14 @@ class Factory
throw new \InvalidArgumentException($message.PHP_EOL.$instructions);
}
try {
$file->validateSchema(JsonFile::LAX_SCHEMA);
} catch (JsonValidationException $e) {
$errors = ' - ' . implode(PHP_EOL . ' - ', $e->getErrors());
$message = $e->getMessage() . ':' . PHP_EOL . $errors;
throw new JsonValidationException($message);
if (!Platform::isInputCompletionProcess()) {
try {
$file->validateSchema(JsonFile::LAX_SCHEMA);
} catch (JsonValidationException $e) {
$errors = ' - ' . implode(PHP_EOL . ' - ', $e->getErrors());
$message = $e->getMessage() . ':' . PHP_EOL . $errors;
throw new JsonValidationException($message);
}
}
$localConfig = $file->read();

View File

@ -19,6 +19,7 @@ use Composer\IO\NullIO;
use Composer\Semver\VersionParser as SemverVersionParser;
use Composer\Util\Git as GitUtil;
use Composer\Util\HttpDownloader;
use Composer\Util\Platform;
use Composer\Util\ProcessExecutor;
use Composer\Util\Svn as SvnUtil;
use React\Promise\CancellablePromiseInterface;
@ -76,7 +77,7 @@ class VersionGuesser
// bypass version guessing in bash completions as it takes time to create
// new processes and the root version is usually not that important
if (isset($_SERVER['argv'][1]) && $_SERVER['argv'][1] === '_complete') {
if (Platform::isInputCompletionProcess()) {
return null;
}

View File

@ -44,12 +44,8 @@ class HttpDownloader
private $config;
/** @var array<Job> */
private $jobs = array();
/** @var bool */
private $disableTls;
/** @var mixed[] */
private $options = array();
/** @var mixed[]|null */
private $tlsDefaultOptions = null;
/** @var int */
private $runningJobs = 0;
/** @var int */
@ -77,19 +73,22 @@ class HttpDownloader
$this->disabled = (bool) Platform::getEnv('COMPOSER_DISABLE_NETWORK');
if ($disableTls === true) {
// make sure the tlsDefaultOptions are not loaded later
$this->tlsDefaultOptions = [];
// Setup TLS options
// The cafile option can be set via config.json
if ($disableTls === false) {
$this->options = StreamContextFactory::getTlsDefaults($options, $io);
}
$this->disableTls = $disableTls;
$this->options = $options;
// handle the other externally set options normally.
$this->options = array_replace_recursive($this->options, $options);
$this->config = $config;
if (self::isCurlEnabled()) {
$this->curl = new CurlDownloader($io, $config, $options, $disableTls);
}
$this->rfs = new RemoteFilesystem($io, $config, $options, $disableTls);
if (is_numeric($maxJobs = Platform::getEnv('COMPOSER_MAX_PARALLEL_HTTP'))) {
$this->maxJobs = max(1, min(50, (int) $maxJobs));
}
@ -172,13 +171,7 @@ class HttpDownloader
*/
public function getOptions()
{
if ($this->tlsDefaultOptions === null) {
// Setup TLS options
// The cafile option can be set via config.json
$this->tlsDefaultOptions = StreamContextFactory::getTlsDefaults($this->options, $this->io);
}
return array_replace_recursive($this->tlsDefaultOptions, $this->options);
return $this->options;
}
/**
@ -198,7 +191,7 @@ class HttpDownloader
*/
private function addJob(array $request, bool $sync = false): array
{
$request['options'] = array_replace_recursive($this->getOptions(), $request['options']);
$request['options'] = array_replace_recursive($this->options, $request['options']);
/** @var Job */
$job = array(
@ -218,6 +211,8 @@ class HttpDownloader
$this->io->setAuthentication($job['origin'], rawurldecode($match[1]), rawurldecode($match[2]));
}
$rfs = $this->rfs;
if ($this->canUseCurl($job)) {
$resolver = function ($resolve, $reject) use (&$job): void {
$job['status'] = HttpDownloader::STATUS_QUEUED;
@ -290,15 +285,6 @@ class HttpDownloader
return array($job, $promise);
}
private function getRFS(): RemoteFilesystem
{
if (null === $this->rfs) {
$this->rfs = new RemoteFilesystem($this->io, $this->config, $this->options, $this->disableTls);
}
return $this->rfs;
}
/**
* @param int $id
* @return void

View File

@ -225,6 +225,14 @@ class Platform
return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
}
/**
* @return bool Whether the current command is for bash completion
*/
public static function isInputCompletionProcess(): bool
{
return '_complete' === ($_SERVER['argv'][1] ?? null);
}
/**
* @return void
*/