Add phpstan-symfony to get type info about console InputInterface, fix many errors (#10476)
Extract common init/require commands functionality into PackageDiscoveryTrait Extract some helper methods into BaseCommand for better typespull/10542/head
parent
48758c0207
commit
5c98a2cf8e
|
@ -37,14 +37,17 @@
|
|||
"symfony/finder": "^5.4 || ^6.0",
|
||||
"symfony/process": "^5.4 || ^6.0",
|
||||
"react/promise": "^2.8",
|
||||
"composer/pcre": "^1.0"
|
||||
"composer/pcre": "^1.0",
|
||||
"symfony/polyfill-php73": "^1.24",
|
||||
"symfony/polyfill-php80": "^1.24"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/phpunit-bridge": "^6.0",
|
||||
"phpstan/phpstan": "^1.4.1",
|
||||
"phpstan/phpstan-phpunit": "^1.0",
|
||||
"phpstan/phpstan-deprecation-rules": "^1",
|
||||
"phpstan/phpstan-strict-rules": "^1"
|
||||
"phpstan/phpstan-strict-rules": "^1",
|
||||
"phpstan/phpstan-symfony": "^1.1"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages",
|
||||
|
@ -83,7 +86,7 @@
|
|||
"scripts-descriptions": {
|
||||
"compile": "Compile composer.phar",
|
||||
"test": "Run all tests",
|
||||
"phpstan": "Runs PHPStan (after phpstan-setup was executed, must be run with PHP7.4)"
|
||||
"phpstan": "Runs PHPStan"
|
||||
},
|
||||
"support": {
|
||||
"issues": "https://github.com/composer/composer/issues",
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "36248b1f2f20c084208c57c0758261e8",
|
||||
"content-hash": "03b82664ef6f80651118f0c06a49280c",
|
||||
"packages": [
|
||||
{
|
||||
"name": "composer/ca-bundle",
|
||||
|
@ -2042,6 +2042,78 @@
|
|||
},
|
||||
"time": "2021-11-18T09:30:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-symfony",
|
||||
"version": "1.1.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan-symfony.git",
|
||||
"reference": "4e20d2e6b65a6eb2d0b8ff285c6c8c049faff03d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/4e20d2e6b65a6eb2d0b8ff285c6c8c049faff03d",
|
||||
"reference": "4e20d2e6b65a6eb2d0b8ff285c6c8c049faff03d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-simplexml": "*",
|
||||
"php": "^7.1 || ^8.0",
|
||||
"phpstan/phpstan": "^1.4"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/framework-bundle": "<3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"nikic/php-parser": "^4.13.0",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.2",
|
||||
"phpstan/phpstan-phpunit": "^1.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.0",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"symfony/config": "^4.2 || ^5.0",
|
||||
"symfony/console": "^4.0 || ^5.0",
|
||||
"symfony/form": "^4.0 || ^5.0",
|
||||
"symfony/framework-bundle": "^4.4 || ^5.0",
|
||||
"symfony/http-foundation": "^5.1",
|
||||
"symfony/messenger": "^4.2 || ^5.0",
|
||||
"symfony/polyfill-php80": "^1.24",
|
||||
"symfony/serializer": "^4.0 || ^5.0"
|
||||
},
|
||||
"type": "phpstan-extension",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0-dev"
|
||||
},
|
||||
"phpstan": {
|
||||
"includes": [
|
||||
"extension.neon",
|
||||
"rules.neon"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"PHPStan\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Lukáš Unger",
|
||||
"email": "looky.msc@gmail.com",
|
||||
"homepage": "https://lookyman.net"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Framework extensions and rules for PHPStan",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan-symfony/issues",
|
||||
"source": "https://github.com/phpstan/phpstan-symfony/tree/1.1.5"
|
||||
},
|
||||
"time": "2022-02-05T13:48:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/phpunit-bridge",
|
||||
"version": "v6.0.3",
|
||||
|
|
|
@ -263,12 +263,12 @@ class CommandProvider implements CommandProviderCapability
|
|||
|
||||
class Command extends BaseCommand
|
||||
{
|
||||
protected function configure()
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setName('custom-plugin-command');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$output->writeln('Executing');
|
||||
}
|
||||
|
|
|
@ -30,11 +30,6 @@ parameters:
|
|||
count: 1
|
||||
path: ../src/Composer/Command/ExecCommand.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#3 \\$length of function substr expects int\\|null, int\\<0, max\\>\\|false given\\.$#"
|
||||
count: 1
|
||||
path: ../src/Composer/Command/InitCommand.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$from of function rename expects string, string\\|false given\\.$#"
|
||||
count: 1
|
||||
|
@ -247,7 +242,7 @@ parameters:
|
|||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$string of function rawurlencode expects string, string\\|null given\\.$#"
|
||||
count: 17
|
||||
count: 15
|
||||
path: ../src/Composer/Util/Git.php
|
||||
|
||||
-
|
||||
|
@ -315,6 +310,11 @@ parameters:
|
|||
count: 1
|
||||
path: ../src/Composer/Util/Http/CurlDownloader.php
|
||||
|
||||
-
|
||||
message: "#^Property Composer\\\\Util\\\\Http\\\\CurlDownloader\\:\\:\\$jobs \\(array\\<array\\{url\\: string, origin\\: string, attributes\\: array\\{retryAuthFailure\\: bool, redirects\\: int, retries\\: int, storeAuth\\: bool\\}, options\\: array, progress\\: array, curlHandle\\: resource, filename\\: string\\|null, headerHandle\\: resource, \\.\\.\\.\\}\\>\\) does not accept non\\-empty\\-array\\<array\\{url\\: string, origin\\: string, attributes\\: array\\{retryAuthFailure\\: bool, redirects\\: int, retries\\: int, storeAuth\\: bool\\}, options\\: array, progress\\: array, curlHandle\\: CurlHandle\\|resource, filename\\: string\\|null, headerHandle\\: resource, \\.\\.\\.\\}\\>\\.$#"
|
||||
count: 1
|
||||
path: ../src/Composer/Util/Http/CurlDownloader.php
|
||||
|
||||
-
|
||||
message: "#^Property Composer\\\\Util\\\\Http\\\\CurlDownloader\\:\\:\\$multiHandle \\(resource\\|null\\) does not accept CurlMultiHandle\\.$#"
|
||||
count: 1
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,6 +2,8 @@ includes:
|
|||
- ../vendor/phpstan/phpstan-phpunit/extension.neon
|
||||
- ../vendor/phpstan/phpstan-deprecation-rules/rules.neon
|
||||
- ../vendor/phpstan/phpstan-strict-rules/rules.neon
|
||||
- ../vendor/phpstan/phpstan-symfony/extension.neon
|
||||
- ../vendor/phpstan/phpstan-symfony/rules.neon
|
||||
- ./baseline.neon
|
||||
- ./ignore-by-php-version.neon.php
|
||||
|
||||
|
@ -51,6 +53,9 @@ parameters:
|
|||
- ../src
|
||||
- ../tests
|
||||
|
||||
symfony:
|
||||
consoleApplicationLoader: ../tests/console-application.php
|
||||
|
||||
dynamicConstantNames:
|
||||
- Composer\Composer::BRANCH_ALIAS_VERSION
|
||||
- Composer\Composer::VERSION
|
||||
|
|
|
@ -37,7 +37,7 @@ EOT
|
|||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$composerVersion = Composer::getVersion();
|
||||
|
||||
|
|
|
@ -69,9 +69,9 @@ EOT
|
|||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$composer = $this->getComposer(false);
|
||||
$composer = $this->tryComposer();
|
||||
$config = null;
|
||||
|
||||
if ($composer) {
|
||||
|
@ -86,20 +86,16 @@ EOT
|
|||
$config = Factory::createConfig();
|
||||
}
|
||||
|
||||
if (null === $input->getOption('format')) {
|
||||
$input->setOption('format', $config->get('archive-format'));
|
||||
}
|
||||
if (null === $input->getOption('dir')) {
|
||||
$input->setOption('dir', $config->get('archive-dir'));
|
||||
}
|
||||
$format = $input->getOption('format') ?? $config->get('archive-format');
|
||||
$dir = $input->getOption('dir') ?? $config->get('archive-dir');
|
||||
|
||||
$returnCode = $this->archive(
|
||||
$this->getIO(),
|
||||
$config,
|
||||
$input->getArgument('package'),
|
||||
$input->getArgument('version'),
|
||||
$input->getOption('format'),
|
||||
$input->getOption('dir'),
|
||||
$format,
|
||||
$dir,
|
||||
$input->getOption('file'),
|
||||
$input->getOption('ignore-filters'),
|
||||
$composer
|
||||
|
@ -113,17 +109,9 @@ EOT
|
|||
}
|
||||
|
||||
/**
|
||||
* @param string|null $packageName
|
||||
* @param string|null $version
|
||||
* @param string $format
|
||||
* @param string $dest
|
||||
* @param string|null $fileName
|
||||
* @param bool $ignoreFilters
|
||||
*
|
||||
* @return int
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function archive(IOInterface $io, Config $config, $packageName = null, $version = null, $format = 'tar', $dest = '.', $fileName = null, $ignoreFilters = false, Composer $composer = null)
|
||||
protected function archive(IOInterface $io, Config $config, ?string $packageName, ?string $version, string $format, string $dest, ?string $fileName, bool $ignoreFilters, ?Composer $composer): int
|
||||
{
|
||||
if ($composer) {
|
||||
$archiveManager = $composer->getArchiveManager();
|
||||
|
@ -142,7 +130,7 @@ EOT
|
|||
return 1;
|
||||
}
|
||||
} else {
|
||||
$package = $this->getComposer()->getPackage();
|
||||
$package = $this->requireComposer()->getPackage();
|
||||
}
|
||||
|
||||
$io->writeError('<info>Creating the archive into "'.$dest.'".</info>');
|
||||
|
@ -166,7 +154,7 @@ EOT
|
|||
{
|
||||
$io->writeError('<info>Searching for the specified package.</info>');
|
||||
|
||||
if ($composer = $this->getComposer(false)) {
|
||||
if ($composer = $this->tryComposer()) {
|
||||
$localRepo = $composer->getRepositoryManager()->getLocalRepository();
|
||||
$repo = new CompositeRepository(array_merge(array($localRepo), $composer->getRepositoryManager()->getRepositories()));
|
||||
} else {
|
||||
|
|
|
@ -16,11 +16,15 @@ use Composer\Composer;
|
|||
use Composer\Config;
|
||||
use Composer\Console\Application;
|
||||
use Composer\Factory;
|
||||
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
|
||||
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterInterface;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\IO\NullIO;
|
||||
use Composer\Pcre\Preg;
|
||||
use Composer\Plugin\PreCommandRunEvent;
|
||||
use Composer\Package\Version\VersionParser;
|
||||
use Composer\Plugin\PluginEvents;
|
||||
use Composer\Repository\PlatformRepository;
|
||||
use Composer\Util\Platform;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Helper\TableSeparator;
|
||||
|
@ -32,8 +36,6 @@ use Symfony\Component\Console\Terminal;
|
|||
/**
|
||||
* Base class for Composer commands
|
||||
*
|
||||
* @method Application getApplication()
|
||||
*
|
||||
* @author Ryan Weaver <ryan@knplabs.com>
|
||||
* @author Konstantin Kudryashov <ever.zet@gmail.com>
|
||||
*/
|
||||
|
@ -50,21 +52,52 @@ abstract class BaseCommand extends Command
|
|||
private $io;
|
||||
|
||||
/**
|
||||
* @param bool $required
|
||||
* @param bool|null $disablePlugins
|
||||
* @param bool|null $disableScripts
|
||||
* Gets the application instance for this command.
|
||||
*/
|
||||
public function getApplication(): Application
|
||||
{
|
||||
$application = parent::getApplication();
|
||||
if (!$application instanceof Application) {
|
||||
throw new \RuntimeException('Composer commands can only work with an '.Application::class.' instance set');
|
||||
}
|
||||
|
||||
return $application;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $required Should be set to false, or use `requireComposer` instead
|
||||
* @param bool|null $disablePlugins If null, reads --no-plugins as default
|
||||
* @param bool|null $disableScripts If null, reads --no-scripts as default
|
||||
* @throws \RuntimeException
|
||||
* @return Composer|null
|
||||
* @deprecated since Composer 2.3.0 use requireComposer or tryComposer depending on whether you have $required set to true or false
|
||||
*/
|
||||
public function getComposer($required = true, $disablePlugins = null, $disableScripts = null)
|
||||
{
|
||||
if ($required) {
|
||||
return $this->requireComposer($disablePlugins, $disableScripts);
|
||||
}
|
||||
|
||||
return $this->tryComposer($disablePlugins, $disableScripts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the default Composer\Composer instance or throws
|
||||
*
|
||||
* Use this instead of getComposer if you absolutely need an instance
|
||||
*
|
||||
* @param bool|null $disablePlugins If null, reads --no-plugins as default
|
||||
* @param bool|null $disableScripts If null, reads --no-scripts as default
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function requireComposer(bool $disablePlugins = null, bool $disableScripts = null): Composer
|
||||
{
|
||||
if (null === $this->composer) {
|
||||
$application = $this->getApplication();
|
||||
$application = parent::getApplication();
|
||||
if ($application instanceof Application) {
|
||||
/* @var $application Application */
|
||||
$this->composer = $application->getComposer($required, $disablePlugins, $disableScripts);
|
||||
/** @phpstan-ignore-next-line */
|
||||
} elseif ($required) {
|
||||
$this->composer = $application->getComposer(true, $disablePlugins, $disableScripts);
|
||||
assert($this->composer instanceof Composer);
|
||||
} else {
|
||||
throw new \RuntimeException(
|
||||
'Could not create a Composer\Composer instance, you must inject '.
|
||||
'one if this command is not used with a Composer\Console\Application instance'
|
||||
|
@ -75,6 +108,26 @@ abstract class BaseCommand extends Command
|
|||
return $this->composer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the default Composer\Composer instance or null
|
||||
*
|
||||
* Use this instead of getComposer(false)
|
||||
*
|
||||
* @param bool|null $disablePlugins If null, reads --no-plugins as default
|
||||
* @param bool|null $disableScripts If null, reads --no-scripts as default
|
||||
*/
|
||||
public function tryComposer(bool $disablePlugins = null, bool $disableScripts = null): ?Composer
|
||||
{
|
||||
if (null === $this->composer) {
|
||||
$application = parent::getApplication();
|
||||
if ($application instanceof Application) {
|
||||
$this->composer = $application->getComposer(false, $disablePlugins, $disableScripts);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->composer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
|
@ -112,10 +165,9 @@ abstract class BaseCommand extends Command
|
|||
public function getIO()
|
||||
{
|
||||
if (null === $this->io) {
|
||||
$application = $this->getApplication();
|
||||
$application = parent::getApplication();
|
||||
if ($application instanceof Application) {
|
||||
$this->io = $application->getIO();
|
||||
/** @phpstan-ignore-next-line */
|
||||
} else {
|
||||
$this->io = new NullIO();
|
||||
}
|
||||
|
@ -147,7 +199,7 @@ abstract class BaseCommand extends Command
|
|||
$disableScripts = true;
|
||||
}
|
||||
|
||||
$composer = $this->getComposer(false, $disablePlugins, $disableScripts);
|
||||
$composer = $this->tryComposer($disablePlugins, $disableScripts);
|
||||
if (null === $composer) {
|
||||
$composer = Factory::createGlobal($this->getIO(), $disablePlugins, $disableScripts);
|
||||
}
|
||||
|
@ -194,7 +246,11 @@ abstract class BaseCommand extends Command
|
|||
break;
|
||||
}
|
||||
|
||||
if ($input->hasOption('prefer-install') && $input->getOption('prefer-install')) {
|
||||
if (!$input->hasOption('prefer-dist') || !$input->hasOption('prefer-source')) {
|
||||
return [$preferSource, $preferDist];
|
||||
}
|
||||
|
||||
if ($input->hasOption('prefer-install') && is_string($input->getOption('prefer-install'))) {
|
||||
if ($input->getOption('prefer-source')) {
|
||||
throw new \InvalidArgumentException('--prefer-source can not be used together with --prefer-install');
|
||||
}
|
||||
|
@ -219,14 +275,32 @@ abstract class BaseCommand extends Command
|
|||
|
||||
if ($input->getOption('prefer-source') || $input->getOption('prefer-dist') || ($keepVcsRequiresPreferSource && $input->hasOption('keep-vcs') && $input->getOption('keep-vcs'))) {
|
||||
$preferSource = $input->getOption('prefer-source') || ($keepVcsRequiresPreferSource && $input->hasOption('keep-vcs') && $input->getOption('keep-vcs'));
|
||||
$preferDist = (bool) $input->getOption('prefer-dist');
|
||||
$preferDist = $input->getOption('prefer-dist');
|
||||
}
|
||||
|
||||
return array($preferSource, $preferDist);
|
||||
}
|
||||
|
||||
protected function getPlatformRequirementFilter(InputInterface $input): PlatformRequirementFilterInterface
|
||||
{
|
||||
if (!$input->hasOption('ignore-platform-reqs') || !$input->hasOption('ignore-platform-req')) {
|
||||
throw new \LogicException('Calling getPlatformRequirementFilter from a command which does not define the --ignore-platform-req[s] flags is not permitted.');
|
||||
}
|
||||
|
||||
if (true === $input->getOption('ignore-platform-reqs')) {
|
||||
return PlatformRequirementFilterFactory::ignoreAll();
|
||||
}
|
||||
|
||||
$ignores = $input->getOption('ignore-platform-req');
|
||||
if (count($ignores) > 0) {
|
||||
return PlatformRequirementFilterFactory::fromBoolOrList($ignores);
|
||||
}
|
||||
|
||||
return PlatformRequirementFilterFactory::ignoreNothing();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $requirements
|
||||
* @param array<string> $requirements
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
|
|
|
@ -53,7 +53,7 @@ class BaseDependencyCommand extends BaseCommand
|
|||
protected function doExecute(InputInterface $input, OutputInterface $output, $inverted = false)
|
||||
{
|
||||
// Emit command event on startup
|
||||
$composer = $this->getComposer();
|
||||
$composer = $this->requireComposer();
|
||||
$commandEvent = new CommandEvent(PluginEvents::COMMAND, $this->getName(), $input, $output);
|
||||
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
|
||||
|
||||
|
|
|
@ -46,12 +46,9 @@ EOT
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$composer = $this->getComposer();
|
||||
$composer = $this->requireComposer();
|
||||
|
||||
$requires = array();
|
||||
$removePackages = array();
|
||||
|
|
|
@ -42,10 +42,7 @@ EOT
|
|||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$config = Factory::createConfig();
|
||||
$io = $this->getIO();
|
||||
|
|
|
@ -208,10 +208,9 @@ EOT
|
|||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
* @throws \Seld\JsonLint\ParsingException
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
// Open file in editor
|
||||
if (true === $input->getOption('editor')) {
|
||||
|
@ -242,7 +241,7 @@ EOT
|
|||
|
||||
// List the configuration of the file settings
|
||||
if (true === $input->getOption('list')) {
|
||||
$this->listConfiguration($this->config->all(), $this->config->raw(), $output, null, (bool) $input->getOption('source'));
|
||||
$this->listConfiguration($this->config->all(), $this->config->raw(), $output, null, $input->getOption('source'));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -122,10 +122,7 @@ EOT
|
|||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$config = Factory::createConfig();
|
||||
$io = $this->getIO();
|
||||
|
@ -141,12 +138,14 @@ EOT
|
|||
}
|
||||
|
||||
if ($input->isInteractive() && $input->getOption('ask')) {
|
||||
$parts = explode("/", strtolower($input->getArgument('package')), 2);
|
||||
$package = $input->getArgument('package');
|
||||
if (null === $package) {
|
||||
throw new \RuntimeException('Not enough arguments (missing: "package").');
|
||||
}
|
||||
$parts = explode("/", strtolower($package), 2);
|
||||
$input->setArgument('directory', $io->ask('New project directory [<comment>'.array_pop($parts).'</comment>]: '));
|
||||
}
|
||||
|
||||
$ignorePlatformReqs = $input->getOption('ignore-platform-reqs') ?: ($input->getOption('ignore-platform-req') ?: false);
|
||||
|
||||
return $this->installProject(
|
||||
$io,
|
||||
$config,
|
||||
|
@ -163,7 +162,7 @@ EOT
|
|||
$input->getOption('no-scripts'),
|
||||
$input->getOption('no-progress'),
|
||||
$input->getOption('no-install'),
|
||||
PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs),
|
||||
$this->getPlatformRequirementFilter($input),
|
||||
!$input->getOption('no-secure-http'),
|
||||
$input->getOption('add-repository')
|
||||
);
|
||||
|
@ -173,7 +172,7 @@ EOT
|
|||
* @param string|null $packageName
|
||||
* @param string|null $directory
|
||||
* @param string|null $packageVersion
|
||||
* @param string $stability
|
||||
* @param string|null $stability
|
||||
* @param bool $preferSource
|
||||
* @param bool $preferDist
|
||||
* @param bool $installDevPackages
|
||||
|
|
|
@ -50,12 +50,7 @@ EOT
|
|||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the function.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
return parent::doExecute($input, $output);
|
||||
}
|
||||
|
|
|
@ -69,12 +69,9 @@ EOT
|
|||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$composer = $this->getComposer(false);
|
||||
$composer = $this->tryComposer();
|
||||
$io = $this->getIO();
|
||||
|
||||
if ($composer) {
|
||||
|
|
|
@ -53,12 +53,9 @@ EOT
|
|||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$composer = $this->getComposer();
|
||||
$composer = $this->requireComposer();
|
||||
|
||||
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'dump-autoload', $input, $output);
|
||||
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
|
||||
|
@ -81,8 +78,6 @@ EOT
|
|||
$this->getIO()->write('<info>Generating autoload files</info>');
|
||||
}
|
||||
|
||||
$ignorePlatformReqs = $input->getOption('ignore-platform-reqs') ?: ($input->getOption('ignore-platform-req') ?: false);
|
||||
|
||||
$generator = $composer->getAutoloadGenerator();
|
||||
if ($input->getOption('no-dev')) {
|
||||
$generator->setDevMode(false);
|
||||
|
@ -96,7 +91,7 @@ EOT
|
|||
$generator->setClassMapAuthoritative($authoritative);
|
||||
$generator->setRunScripts(true);
|
||||
$generator->setApcu($apcu, $apcuPrefix);
|
||||
$generator->setPlatformRequirementFilter(PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs));
|
||||
$generator->setPlatformRequirementFilter($this->getPlatformRequirementFilter($input));
|
||||
$numberOfClasses = $generator->dump($config, $localRepo, $package, $installationManager, 'composer', $optimize);
|
||||
|
||||
if ($authoritative) {
|
||||
|
|
|
@ -49,14 +49,11 @@ EOT
|
|||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$composer = $this->getComposer();
|
||||
$composer = $this->requireComposer();
|
||||
$binDir = $composer->getConfig()->get('bin-dir');
|
||||
if ($input->getOption('list') || !$input->getArgument('binary')) {
|
||||
if ($input->getOption('list') || null === $input->getArgument('binary')) {
|
||||
$bins = glob($binDir . '/*');
|
||||
$bins = array_merge($bins, array_map(function ($e) {
|
||||
return "$e (local)";
|
||||
|
|
|
@ -43,12 +43,9 @@ class FundCommand extends BaseCommand
|
|||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$composer = $this->getComposer();
|
||||
$composer = $this->requireComposer();
|
||||
|
||||
$repo = $composer->getRepositoryManager()->getLocalRepository();
|
||||
$remoteRepos = new CompositeRepository($composer->getRepositoryManager()->getRepositories());
|
||||
|
|
|
@ -57,19 +57,16 @@ EOT
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$repos = $this->initializeRepos();
|
||||
$io = $this->getIO();
|
||||
$return = 0;
|
||||
|
||||
$packages = $input->getArgument('packages');
|
||||
if (!$packages) {
|
||||
if (count($packages) === 0) {
|
||||
$io->writeError('No package specified, opening homepage for the root package');
|
||||
$packages = array($this->getComposer()->getPackage()->getName());
|
||||
$packages = array($this->requireComposer()->getPackage()->getName());
|
||||
}
|
||||
|
||||
foreach ($packages as $packageName) {
|
||||
|
@ -163,7 +160,7 @@ EOT
|
|||
*/
|
||||
private function initializeRepos()
|
||||
{
|
||||
$composer = $this->getComposer(false);
|
||||
$composer = $this->tryComposer();
|
||||
|
||||
if ($composer) {
|
||||
return array_merge(
|
||||
|
|
|
@ -46,15 +46,17 @@ use Symfony\Component\Console\Helper\FormatterHelper;
|
|||
*/
|
||||
class InitCommand extends BaseCommand
|
||||
{
|
||||
use PackageDiscoveryTrait;
|
||||
|
||||
// Properties for PackageDiscoveryTrait
|
||||
/** @var ?CompositeRepository */
|
||||
protected $repos;
|
||||
/** @var RepositorySet[] */
|
||||
private $repositorySets;
|
||||
|
||||
/** @var array<string, string> */
|
||||
private $gitConfig;
|
||||
|
||||
/** @var RepositorySet[] */
|
||||
private $repositorySets;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
|
@ -93,9 +95,6 @@ EOT
|
|||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @return int
|
||||
* @throws \Seld\JsonLint\ParsingException
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
|
@ -117,7 +116,7 @@ EOT
|
|||
}
|
||||
|
||||
$repositories = $input->getOption('repository');
|
||||
if ($repositories) {
|
||||
if (count($repositories) > 0) {
|
||||
$config = Factory::createConfig($io);
|
||||
foreach ($repositories as $repo) {
|
||||
$options['repositories'][] = RepositoryFactory::configFromString($io, $config, $repo, true);
|
||||
|
@ -145,7 +144,7 @@ EOT
|
|||
$autoloadPath = null;
|
||||
if (isset($options['autoload'])) {
|
||||
$autoloadPath = $options['autoload'];
|
||||
$namespace = $this->namespaceFromPackageName($input->getOption('name'));
|
||||
$namespace = $this->namespaceFromPackageName((string) $input->getOption('name'));
|
||||
$options['autoload'] = (object) array(
|
||||
'psr-4' => array(
|
||||
$namespace . '\\' => $autoloadPath,
|
||||
|
@ -217,7 +216,7 @@ EOT
|
|||
|
||||
// --autoload - Show post-install configuration info
|
||||
if ($autoloadPath) {
|
||||
$namespace = $this->namespaceFromPackageName($input->getOption('name'));
|
||||
$namespace = $this->namespaceFromPackageName((string) $input->getOption('name'));
|
||||
|
||||
$io->writeError('PSR-4 autoloading configured. Use "<comment>namespace '.$namespace.';</comment>" in '.$autoloadPath);
|
||||
$io->writeError('Include the Composer autoloader with: <comment>require \'vendor/autoload.php\';</comment>');
|
||||
|
@ -240,7 +239,7 @@ EOT
|
|||
|
||||
// initialize repos if configured
|
||||
$repositories = $input->getOption('repository');
|
||||
if ($repositories) {
|
||||
if (count($repositories) > 0) {
|
||||
$config = Factory::createConfig($io);
|
||||
$repos = array(new PlatformRepository);
|
||||
$createDefaultPackagistRepo = true;
|
||||
|
@ -282,7 +281,8 @@ EOT
|
|||
|
||||
$cwd = realpath(".");
|
||||
|
||||
if (!$name = $input->getOption('name')) {
|
||||
$name = $input->getOption('name');
|
||||
if (null === $name) {
|
||||
$name = basename($cwd);
|
||||
$name = Preg::replace('{(?:([a-z])([A-Z])|([A-Z])([A-Z][a-z]))}', '\\1\\3-\\2\\4', $name);
|
||||
$name = strtolower($name);
|
||||
|
@ -323,7 +323,7 @@ EOT
|
|||
);
|
||||
$input->setOption('name', $name);
|
||||
|
||||
$description = $input->getOption('description') ?: false;
|
||||
$description = $input->getOption('description') ?: null;
|
||||
$description = $io->ask(
|
||||
'Description [<comment>'.$description.'</comment>]: ',
|
||||
$description
|
||||
|
@ -423,7 +423,7 @@ EOT
|
|||
$question = 'Would you like to define your dependencies (require) interactively [<comment>yes</comment>]? ';
|
||||
$require = $input->getOption('require');
|
||||
$requirements = array();
|
||||
if ($require || $io->askConfirmation($question)) {
|
||||
if (count($require) > 0 || $io->askConfirmation($question)) {
|
||||
$requirements = $this->determineRequirements($input, $output, $require, $platformRepo, $preferredStability);
|
||||
}
|
||||
$input->setOption('require', $requirements);
|
||||
|
@ -431,14 +431,14 @@ EOT
|
|||
$question = 'Would you like to define your dev dependencies (require-dev) interactively [<comment>yes</comment>]? ';
|
||||
$requireDev = $input->getOption('require-dev');
|
||||
$devRequirements = array();
|
||||
if ($requireDev || $io->askConfirmation($question)) {
|
||||
if (count($requireDev) > 0 || $io->askConfirmation($question)) {
|
||||
$devRequirements = $this->determineRequirements($input, $output, $requireDev, $platformRepo, $preferredStability);
|
||||
}
|
||||
$input->setOption('require-dev', $devRequirements);
|
||||
|
||||
// --autoload - input and validation
|
||||
$autoload = $input->getOption('autoload') ?: 'src/';
|
||||
$namespace = $this->namespaceFromPackageName($input->getOption('name'));
|
||||
$namespace = $this->namespaceFromPackageName((string) $input->getOption('name'));
|
||||
$autoload = $io->askAndValidate(
|
||||
'Add PSR-4 autoload mapping? Maps namespace "'.$namespace.'" to the entered relative path. [<comment>'.$autoload.'</comment>, n to skip]: ',
|
||||
function ($value) use ($autoload) {
|
||||
|
@ -489,197 +489,6 @@ EOT
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CompositeRepository
|
||||
*/
|
||||
protected function getRepos()
|
||||
{
|
||||
if (!$this->repos) {
|
||||
$this->repos = new CompositeRepository(array_merge(
|
||||
array(new PlatformRepository),
|
||||
RepositoryFactory::defaultRepos($this->getIO())
|
||||
));
|
||||
}
|
||||
|
||||
return $this->repos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string> $requires
|
||||
* @param PlatformRepository|null $platformRepo
|
||||
* @param string $preferredStability
|
||||
* @param bool $checkProvidedVersions
|
||||
* @param bool $fixed
|
||||
*
|
||||
* @return array<string>
|
||||
* @throws \Exception
|
||||
*/
|
||||
final protected function determineRequirements(InputInterface $input, OutputInterface $output, $requires = array(), PlatformRepository $platformRepo = null, $preferredStability = 'stable', $checkProvidedVersions = true, $fixed = false)
|
||||
{
|
||||
if ($requires) {
|
||||
$requires = $this->normalizeRequirements($requires);
|
||||
$result = array();
|
||||
$io = $this->getIO();
|
||||
|
||||
foreach ($requires as $requirement) {
|
||||
if (!isset($requirement['version'])) {
|
||||
// determine the best version automatically
|
||||
list($name, $version) = $this->findBestVersionAndNameForPackage($input, $requirement['name'], $platformRepo, $preferredStability, null, null, $fixed);
|
||||
$requirement['version'] = $version;
|
||||
|
||||
// replace package name from packagist.org
|
||||
$requirement['name'] = $name;
|
||||
|
||||
$io->writeError(sprintf(
|
||||
'Using version <info>%s</info> for <info>%s</info>',
|
||||
$requirement['version'],
|
||||
$requirement['name']
|
||||
));
|
||||
} else {
|
||||
// check that the specified version/constraint exists before we proceed
|
||||
list($name) = $this->findBestVersionAndNameForPackage($input, $requirement['name'], $platformRepo, $preferredStability, $checkProvidedVersions ? $requirement['version'] : null, 'dev', $fixed);
|
||||
|
||||
// replace package name from packagist.org
|
||||
$requirement['name'] = $name;
|
||||
}
|
||||
|
||||
$result[] = $requirement['name'] . ' ' . $requirement['version'];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
$versionParser = new VersionParser();
|
||||
|
||||
// Collect existing packages
|
||||
$composer = $this->getComposer(false);
|
||||
$installedRepo = $composer ? $composer->getRepositoryManager()->getLocalRepository() : null;
|
||||
$existingPackages = array();
|
||||
if ($installedRepo) {
|
||||
foreach ($installedRepo->getPackages() as $package) {
|
||||
$existingPackages[] = $package->getName();
|
||||
}
|
||||
}
|
||||
unset($composer, $installedRepo);
|
||||
|
||||
$io = $this->getIO();
|
||||
while (null !== $package = $io->ask('Search for a package: ')) {
|
||||
$matches = $this->getRepos()->search($package);
|
||||
|
||||
if (count($matches)) {
|
||||
// Remove existing packages from search results.
|
||||
foreach ($matches as $position => $foundPackage) {
|
||||
if (in_array($foundPackage['name'], $existingPackages, true)) {
|
||||
unset($matches[$position]);
|
||||
}
|
||||
}
|
||||
$matches = array_values($matches);
|
||||
|
||||
$exactMatch = null;
|
||||
$choices = array();
|
||||
foreach ($matches as $position => $foundPackage) {
|
||||
$abandoned = '';
|
||||
if (isset($foundPackage['abandoned'])) {
|
||||
if (is_string($foundPackage['abandoned'])) {
|
||||
$replacement = sprintf('Use %s instead', $foundPackage['abandoned']);
|
||||
} else {
|
||||
$replacement = 'No replacement was suggested';
|
||||
}
|
||||
$abandoned = sprintf('<warning>Abandoned. %s.</warning>', $replacement);
|
||||
}
|
||||
|
||||
$choices[] = sprintf(' <info>%5s</info> %s %s', "[$position]", $foundPackage['name'], $abandoned);
|
||||
if ($foundPackage['name'] === $package) {
|
||||
$exactMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// no match, prompt which to pick
|
||||
if (!$exactMatch) {
|
||||
$io->writeError(array(
|
||||
'',
|
||||
sprintf('Found <info>%s</info> packages matching <info>%s</info>', count($matches), $package),
|
||||
'',
|
||||
));
|
||||
|
||||
$io->writeError($choices);
|
||||
$io->writeError('');
|
||||
|
||||
$validator = function ($selection) use ($matches, $versionParser) {
|
||||
if ('' === $selection) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_numeric($selection) && isset($matches[(int) $selection])) {
|
||||
$package = $matches[(int) $selection];
|
||||
|
||||
return $package['name'];
|
||||
}
|
||||
|
||||
if (Preg::isMatch('{^\s*(?P<name>[\S/]+)(?:\s+(?P<version>\S+))?\s*$}', $selection, $packageMatches)) {
|
||||
if (isset($packageMatches['version'])) {
|
||||
// parsing `acme/example ~2.3`
|
||||
|
||||
// validate version constraint
|
||||
$versionParser->parseConstraints($packageMatches['version']);
|
||||
|
||||
return $packageMatches['name'].' '.$packageMatches['version'];
|
||||
}
|
||||
|
||||
// parsing `acme/example`
|
||||
return $packageMatches['name'];
|
||||
}
|
||||
|
||||
throw new \Exception('Not a valid selection');
|
||||
};
|
||||
|
||||
$package = $io->askAndValidate(
|
||||
'Enter package # to add, or the complete package name if it is not listed: ',
|
||||
$validator,
|
||||
3,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
// no constraint yet, determine the best version automatically
|
||||
if (false !== $package && false === strpos($package, ' ')) {
|
||||
$validator = function ($input) {
|
||||
$input = trim($input);
|
||||
|
||||
return $input ?: false;
|
||||
};
|
||||
|
||||
$constraint = $io->askAndValidate(
|
||||
'Enter the version constraint to require (or leave blank to use the latest version): ',
|
||||
$validator,
|
||||
3,
|
||||
false
|
||||
);
|
||||
|
||||
if (false === $constraint) {
|
||||
list(, $constraint) = $this->findBestVersionAndNameForPackage($input, $package, $platformRepo, $preferredStability);
|
||||
|
||||
$io->writeError(sprintf(
|
||||
'Using version <info>%s</info> for <info>%s</info>',
|
||||
$constraint,
|
||||
$package
|
||||
));
|
||||
}
|
||||
|
||||
$package .= ' '.$constraint;
|
||||
}
|
||||
|
||||
if (false !== $package) {
|
||||
$requires[] = $package;
|
||||
$existingPackages[] = substr($package, 0, strpos($package, ' '));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $requires;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $author
|
||||
*
|
||||
|
@ -815,229 +624,6 @@ EOT
|
|||
return false !== filter_var($email, FILTER_VALIDATE_EMAIL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $minimumStability
|
||||
*
|
||||
* @return RepositorySet
|
||||
*/
|
||||
private function getRepositorySet(InputInterface $input, $minimumStability = null)
|
||||
{
|
||||
$key = $minimumStability ?: 'default';
|
||||
|
||||
if (!isset($this->repositorySets[$key])) {
|
||||
$this->repositorySets[$key] = $repositorySet = new RepositorySet($minimumStability ?: $this->getMinimumStability($input));
|
||||
$repositorySet->addRepository($this->getRepos());
|
||||
}
|
||||
|
||||
return $this->repositorySets[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function getMinimumStability(InputInterface $input)
|
||||
{
|
||||
if ($input->hasOption('stability')) {
|
||||
return VersionParser::normalizeStability($input->getOption('stability') ?: 'stable');
|
||||
}
|
||||
|
||||
$file = Factory::getComposerFile();
|
||||
if (is_file($file) && Filesystem::isReadable($file) && is_array($composer = json_decode(file_get_contents($file), true))) {
|
||||
if (!empty($composer['minimum-stability'])) {
|
||||
return VersionParser::normalizeStability($composer['minimum-stability']);
|
||||
}
|
||||
}
|
||||
|
||||
return 'stable';
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a package name, this determines the best version to use in the require key.
|
||||
*
|
||||
* This returns a version with the ~ operator prefixed when possible.
|
||||
*
|
||||
* @param string $name
|
||||
* @param PlatformRepository|null $platformRepo
|
||||
* @param string $preferredStability
|
||||
* @param string|null $requiredVersion
|
||||
* @param string $minimumStability
|
||||
* @param bool $fixed
|
||||
* @throws \InvalidArgumentException
|
||||
* @return array{string, string} name version
|
||||
*/
|
||||
private function findBestVersionAndNameForPackage(InputInterface $input, $name, PlatformRepository $platformRepo = null, $preferredStability = 'stable', $requiredVersion = null, $minimumStability = null, $fixed = null)
|
||||
{
|
||||
// handle ignore-platform-reqs flag if present
|
||||
$ignorePlatformReqs = false;
|
||||
if ($input->hasOption('ignore-platform-reqs') && $input->hasOption('ignore-platform-req')) {
|
||||
$ignorePlatformReqs = $input->getOption('ignore-platform-reqs') ?: ($input->getOption('ignore-platform-req') ?: false);
|
||||
}
|
||||
$platformRequirementFilter = PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs);
|
||||
|
||||
// find the latest version allowed in this repo set
|
||||
$versionSelector = new VersionSelector($this->getRepositorySet($input, $minimumStability), $platformRepo);
|
||||
$effectiveMinimumStability = $minimumStability ?: $this->getMinimumStability($input);
|
||||
|
||||
$package = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, $platformRequirementFilter);
|
||||
|
||||
if (!$package) {
|
||||
// platform packages can not be found in the pool in versions other than the local platform's has
|
||||
// so if platform reqs are ignored we just take the user's word for it
|
||||
if ($platformRequirementFilter->isIgnored($name)) {
|
||||
return array($name, $requiredVersion ?: '*');
|
||||
}
|
||||
|
||||
// Check whether the package requirements were the problem
|
||||
if (!($platformRequirementFilter instanceof IgnoreAllPlatformRequirementFilter) && ($candidate = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, PlatformRequirementFilterFactory::ignoreAll()))) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Package %s%s has requirements incompatible with your PHP version, PHP extensions and Composer version' . $this->getPlatformExceptionDetails($candidate, $platformRepo),
|
||||
$name,
|
||||
$requiredVersion ? ' at version '.$requiredVersion : ''
|
||||
));
|
||||
}
|
||||
// Check whether the minimum stability was the problem but the package exists
|
||||
if ($package = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, $platformRequirementFilter, RepositorySet::ALLOW_UNACCEPTABLE_STABILITIES)) {
|
||||
// we must first verify if a valid package would be found in a lower priority repository
|
||||
if ($allReposPackage = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, $platformRequirementFilter, RepositorySet::ALLOW_SHADOWED_REPOSITORIES)) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Package '.$name.' exists in '.$allReposPackage->getRepository()->getRepoName().' and '.$package->getRepository()->getRepoName().' which has a higher repository priority. The packages from the higher priority repository do not match your minimum-stability and are therefore not installable. That repository is canonical so the lower priority repo\'s packages are not installable. See https://getcomposer.org/repoprio for details and assistance.'
|
||||
);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Could not find a version of package %s matching your minimum-stability (%s). Require it with an explicit version constraint allowing its desired stability.',
|
||||
$name,
|
||||
$effectiveMinimumStability
|
||||
));
|
||||
}
|
||||
// Check whether the required version was the problem
|
||||
if ($requiredVersion && $package = $versionSelector->findBestCandidate($name, null, $preferredStability, $platformRequirementFilter)) {
|
||||
// we must first verify if a valid package would be found in a lower priority repository
|
||||
if ($allReposPackage = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, PlatformRequirementFilterFactory::ignoreNothing(), RepositorySet::ALLOW_SHADOWED_REPOSITORIES)) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Package '.$name.' exists in '.$allReposPackage->getRepository()->getRepoName().' and '.$package->getRepository()->getRepoName().' which has a higher repository priority. The packages from the higher priority repository do not match your constraint and are therefore not installable. That repository is canonical so the lower priority repo\'s packages are not installable. See https://getcomposer.org/repoprio for details and assistance.'
|
||||
);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Could not find package %s in a version matching "%s" and a stability matching "'.$effectiveMinimumStability.'".',
|
||||
$name,
|
||||
$requiredVersion
|
||||
));
|
||||
}
|
||||
// Check whether the PHP version was the problem for all versions
|
||||
if (!($platformRequirementFilter instanceof IgnoreAllPlatformRequirementFilter) && ($candidate = $versionSelector->findBestCandidate($name, null, $preferredStability, PlatformRequirementFilterFactory::ignoreAll(), RepositorySet::ALLOW_UNACCEPTABLE_STABILITIES))) {
|
||||
$additional = '';
|
||||
if (false === $versionSelector->findBestCandidate($name, null, $preferredStability, PlatformRequirementFilterFactory::ignoreAll())) {
|
||||
$additional = PHP_EOL.PHP_EOL.'Additionally, the package was only found with a stability of "'.$candidate->getStability().'" while your minimum stability is "'.$effectiveMinimumStability.'".';
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Could not find package %s in any version matching your PHP version, PHP extensions and Composer version' . $this->getPlatformExceptionDetails($candidate, $platformRepo) . '%s',
|
||||
$name,
|
||||
$additional
|
||||
));
|
||||
}
|
||||
|
||||
// Check for similar names/typos
|
||||
$similar = $this->findSimilar($name);
|
||||
if ($similar) {
|
||||
if (in_array($name, $similar, true)) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
"Could not find package %s. It was however found via repository search, which indicates a consistency issue with the repository.",
|
||||
$name
|
||||
));
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
"Could not find package %s.\n\nDid you mean " . (count($similar) > 1 ? 'one of these' : 'this') . "?\n %s",
|
||||
$name,
|
||||
implode("\n ", $similar)
|
||||
));
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Could not find a matching version of package %s. Check the package spelling, your version constraint and that the package is available in a stability which matches your minimum-stability (%s).',
|
||||
$name,
|
||||
$effectiveMinimumStability
|
||||
));
|
||||
}
|
||||
|
||||
return array(
|
||||
$package->getPrettyName(),
|
||||
$fixed ? $package->getPrettyVersion() : $versionSelector->findRecommendedRequireVersion($package),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function getPlatformExceptionDetails(PackageInterface $candidate, PlatformRepository $platformRepo = null)
|
||||
{
|
||||
$details = array();
|
||||
if (!$platformRepo) {
|
||||
return '';
|
||||
}
|
||||
|
||||
foreach ($candidate->getRequires() as $link) {
|
||||
if (!PlatformRepository::isPlatformPackage($link->getTarget())) {
|
||||
continue;
|
||||
}
|
||||
$platformPkg = $platformRepo->findPackage($link->getTarget(), '*');
|
||||
if (!$platformPkg) {
|
||||
if ($platformRepo->isPlatformPackageDisabled($link->getTarget())) {
|
||||
$details[] = $candidate->getPrettyName().' '.$candidate->getPrettyVersion().' requires '.$link->getTarget().' '.$link->getPrettyConstraint().' but it is disabled by your platform config. Enable it again with "composer config platform.'.$link->getTarget().' --unset".';
|
||||
} else {
|
||||
$details[] = $candidate->getPrettyName().' '.$candidate->getPrettyVersion().' requires '.$link->getTarget().' '.$link->getPrettyConstraint().' but it is not present.';
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!$link->getConstraint()->matches(new Constraint('==', $platformPkg->getVersion()))) {
|
||||
$platformPkgVersion = $platformPkg->getPrettyVersion();
|
||||
$platformExtra = $platformPkg->getExtra();
|
||||
if (isset($platformExtra['config.platform']) && $platformPkg instanceof CompletePackageInterface) {
|
||||
$platformPkgVersion .= ' ('.$platformPkg->getDescription().')';
|
||||
}
|
||||
$details[] = $candidate->getPrettyName().' '.$candidate->getPrettyVersion().' requires '.$link->getTarget().' '.$link->getPrettyConstraint().' which does not match your installed version '.$platformPkgVersion.'.';
|
||||
}
|
||||
}
|
||||
|
||||
if (!$details) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return ':'.PHP_EOL.' - ' . implode(PHP_EOL.' - ', $details);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $package
|
||||
*
|
||||
* @return array<string>
|
||||
*/
|
||||
private function findSimilar($package)
|
||||
{
|
||||
try {
|
||||
$results = $this->repos->search($package);
|
||||
} catch (\Exception $e) {
|
||||
// ignore search errors
|
||||
return array();
|
||||
}
|
||||
$similarPackages = array();
|
||||
|
||||
$installedRepo = $this->getComposer()->getRepositoryManager()->getLocalRepository();
|
||||
|
||||
foreach ($results as $result) {
|
||||
if ($installedRepo->findPackage($result['name'], '*')) {
|
||||
// Ignore installed package
|
||||
continue;
|
||||
}
|
||||
$similarPackages[$result['name']] = levenshtein($package, $result['name']);
|
||||
}
|
||||
asort($similarPackages);
|
||||
|
||||
return array_keys(array_slice($similarPackages, 0, 5));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
|
|
|
@ -84,7 +84,8 @@ EOT
|
|||
$io->writeError('<warning>You are using the deprecated option "--no-suggest". It has no effect and will break in Composer 3.</warning>');
|
||||
}
|
||||
|
||||
if ($args = $input->getArgument('packages')) {
|
||||
$args = $input->getArgument('packages');
|
||||
if (count($args) > 0) {
|
||||
$io->writeError('<error>Invalid argument '.implode(' ', $args).'. Use "composer require '.implode(' ', $args).'" instead to add packages to your composer.json.</error>');
|
||||
|
||||
return 1;
|
||||
|
@ -96,7 +97,7 @@ EOT
|
|||
return 1;
|
||||
}
|
||||
|
||||
$composer = $this->getComposer(true, $input->getOption('no-plugins'), $input->getOption('no-scripts'));
|
||||
$composer = $this->requireComposer();
|
||||
|
||||
if ((!$composer->getLocker() || !$composer->getLocker()->isLocked()) && !HttpDownloader::isCurlEnabled()) {
|
||||
$io->writeError('<warning>Composer is operating significantly slower than normal because you do not have the PHP curl extension enabled.</warning>');
|
||||
|
@ -115,8 +116,6 @@ EOT
|
|||
$apcuPrefix = $input->getOption('apcu-autoloader-prefix');
|
||||
$apcu = $apcuPrefix !== null || $input->getOption('apcu-autoloader') || $config->get('apcu-autoloader');
|
||||
|
||||
$ignorePlatformReqs = $input->getOption('ignore-platform-reqs') ?: ($input->getOption('ignore-platform-req') ?: false);
|
||||
|
||||
$composer->getInstallationManager()->setOutputProgress(!$input->getOption('no-progress'));
|
||||
|
||||
$install
|
||||
|
@ -129,7 +128,7 @@ EOT
|
|||
->setOptimizeAutoloader($optimize)
|
||||
->setClassMapAuthoritative($authoritative)
|
||||
->setApcuAutoloader($apcu, $apcuPrefix)
|
||||
->setPlatformRequirementFilter(PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs))
|
||||
->setPlatformRequirementFilter($this->getPlatformRequirementFilter($input))
|
||||
;
|
||||
|
||||
if ($input->getOption('no-plugins')) {
|
||||
|
|
|
@ -54,12 +54,9 @@ EOT
|
|||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$composer = $this->getComposer();
|
||||
$composer = $this->requireComposer();
|
||||
|
||||
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'licenses', $input, $output);
|
||||
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
|
||||
|
|
|
@ -21,7 +21,7 @@ use Symfony\Component\Console\Output\OutputInterface;
|
|||
/**
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class OutdatedCommand extends ShowCommand
|
||||
class OutdatedCommand extends BaseCommand
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
|
@ -63,7 +63,7 @@ EOT
|
|||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$args = array(
|
||||
'command' => 'show',
|
||||
|
@ -75,7 +75,7 @@ EOT
|
|||
if ($input->getOption('direct')) {
|
||||
$args['--direct'] = true;
|
||||
}
|
||||
if ($input->getArgument('package')) {
|
||||
if (null !== $input->getArgument('package')) {
|
||||
$args['package'] = $input->getArgument('package');
|
||||
}
|
||||
if ($input->getOption('strict')) {
|
||||
|
@ -90,9 +90,7 @@ EOT
|
|||
if ($input->getOption('no-dev')) {
|
||||
$args['--no-dev'] = true;
|
||||
}
|
||||
if ($input->getOption('ignore-platform-req')) {
|
||||
$args['--ignore-platform-req'] = $input->getOption('ignore-platform-req');
|
||||
}
|
||||
$args['--ignore-platform-req'] = $input->getOption('ignore-platform-req');
|
||||
if ($input->getOption('ignore-platform-reqs')) {
|
||||
$args['--ignore-platform-reqs'] = true;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,424 @@
|
|||
<?php
|
||||
|
||||
namespace Composer\Command;
|
||||
|
||||
use Composer\Factory;
|
||||
use Composer\Filter\PlatformRequirementFilter\IgnoreAllPlatformRequirementFilter;
|
||||
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
|
||||
use Composer\Package\CompletePackageInterface;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Package\Version\VersionParser;
|
||||
use Composer\Package\Version\VersionSelector;
|
||||
use Composer\Pcre\Preg;
|
||||
use Composer\Repository\CompositeRepository;
|
||||
use Composer\Repository\PlatformRepository;
|
||||
use Composer\Repository\RepositoryFactory;
|
||||
use Composer\Repository\RepositorySet;
|
||||
use Composer\Semver\Constraint\Constraint;
|
||||
use Composer\Util\Filesystem;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
trait PackageDiscoveryTrait
|
||||
{
|
||||
/**
|
||||
* @return CompositeRepository
|
||||
*/
|
||||
protected function getRepos()
|
||||
{
|
||||
if (null === $this->repos) {
|
||||
$this->repos = new CompositeRepository(array_merge(
|
||||
array(new PlatformRepository),
|
||||
RepositoryFactory::defaultRepos($this->getIO())
|
||||
));
|
||||
}
|
||||
|
||||
return $this->repos;
|
||||
}
|
||||
|
||||
private function getRepositorySet(InputInterface $input, ?string $minimumStability = null): RepositorySet
|
||||
{
|
||||
$key = $minimumStability ?? 'default';
|
||||
|
||||
if (!isset($this->repositorySets[$key])) {
|
||||
$this->repositorySets[$key] = $repositorySet = new RepositorySet($minimumStability ?? $this->getMinimumStability($input));
|
||||
$repositorySet->addRepository($this->getRepos());
|
||||
}
|
||||
|
||||
return $this->repositorySets[$key];
|
||||
}
|
||||
|
||||
private function getMinimumStability(InputInterface $input): string
|
||||
{
|
||||
if ($input->hasOption('stability')) { // @phpstan-ignore-line as InitCommand does have this option but not all classes using this trait do
|
||||
return VersionParser::normalizeStability($input->getOption('stability') ?? 'stable');
|
||||
}
|
||||
|
||||
// @phpstan-ignore-next-line as RequireCommand does not have the option above so this code is reachable there
|
||||
$file = Factory::getComposerFile();
|
||||
if (is_file($file) && Filesystem::isReadable($file) && is_array($composer = json_decode((string) file_get_contents($file), true))) {
|
||||
if (!empty($composer['minimum-stability'])) {
|
||||
return VersionParser::normalizeStability($composer['minimum-stability']);
|
||||
}
|
||||
}
|
||||
|
||||
return 'stable';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string> $requires
|
||||
*
|
||||
* @return array<string>
|
||||
* @throws \Exception
|
||||
*/
|
||||
final protected function determineRequirements(InputInterface $input, OutputInterface $output, array $requires = array(), ?PlatformRepository $platformRepo = null, string $preferredStability = 'stable', bool $checkProvidedVersions = true, bool $fixed = false): array
|
||||
{
|
||||
if (count($requires) > 0) {
|
||||
$requires = $this->normalizeRequirements($requires);
|
||||
$result = array();
|
||||
$io = $this->getIO();
|
||||
|
||||
foreach ($requires as $requirement) {
|
||||
if (!isset($requirement['version'])) {
|
||||
// determine the best version automatically
|
||||
list($name, $version) = $this->findBestVersionAndNameForPackage($input, $requirement['name'], $platformRepo, $preferredStability, null, null, $fixed);
|
||||
$requirement['version'] = $version;
|
||||
|
||||
// replace package name from packagist.org
|
||||
$requirement['name'] = $name;
|
||||
|
||||
$io->writeError(sprintf(
|
||||
'Using version <info>%s</info> for <info>%s</info>',
|
||||
$requirement['version'],
|
||||
$requirement['name']
|
||||
));
|
||||
} else {
|
||||
// check that the specified version/constraint exists before we proceed
|
||||
list($name) = $this->findBestVersionAndNameForPackage($input, $requirement['name'], $platformRepo, $preferredStability, $checkProvidedVersions ? $requirement['version'] : null, 'dev', $fixed);
|
||||
|
||||
// replace package name from packagist.org
|
||||
$requirement['name'] = $name;
|
||||
}
|
||||
|
||||
$result[] = $requirement['name'] . ' ' . $requirement['version'];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
$versionParser = new VersionParser();
|
||||
|
||||
// Collect existing packages
|
||||
$composer = $this->tryComposer();
|
||||
$installedRepo = null;
|
||||
if (null !== $composer) {
|
||||
$installedRepo = $composer->getRepositoryManager()->getLocalRepository();
|
||||
}
|
||||
$existingPackages = array();
|
||||
if (null !== $installedRepo) {
|
||||
foreach ($installedRepo->getPackages() as $package) {
|
||||
$existingPackages[] = $package->getName();
|
||||
}
|
||||
}
|
||||
unset($composer, $installedRepo);
|
||||
|
||||
$io = $this->getIO();
|
||||
while (null !== $package = $io->ask('Search for a package: ')) {
|
||||
$matches = $this->getRepos()->search($package);
|
||||
|
||||
if (count($matches) > 0) {
|
||||
// Remove existing packages from search results.
|
||||
foreach ($matches as $position => $foundPackage) {
|
||||
if (in_array($foundPackage['name'], $existingPackages, true)) {
|
||||
unset($matches[$position]);
|
||||
}
|
||||
}
|
||||
$matches = array_values($matches);
|
||||
|
||||
$exactMatch = false;
|
||||
$choices = array();
|
||||
foreach ($matches as $position => $foundPackage) {
|
||||
$abandoned = '';
|
||||
if (isset($foundPackage['abandoned'])) {
|
||||
if (is_string($foundPackage['abandoned'])) {
|
||||
$replacement = sprintf('Use %s instead', $foundPackage['abandoned']);
|
||||
} else {
|
||||
$replacement = 'No replacement was suggested';
|
||||
}
|
||||
$abandoned = sprintf('<warning>Abandoned. %s.</warning>', $replacement);
|
||||
}
|
||||
|
||||
$choices[] = sprintf(' <info>%5s</info> %s %s', "[$position]", $foundPackage['name'], $abandoned);
|
||||
if ($foundPackage['name'] === $package) {
|
||||
$exactMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// no match, prompt which to pick
|
||||
if (!$exactMatch) {
|
||||
$io->writeError(array(
|
||||
'',
|
||||
sprintf('Found <info>%s</info> packages matching <info>%s</info>', count($matches), $package),
|
||||
'',
|
||||
));
|
||||
|
||||
$io->writeError($choices);
|
||||
$io->writeError('');
|
||||
|
||||
$validator = function ($selection) use ($matches, $versionParser) {
|
||||
if ('' === $selection) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_numeric($selection) && isset($matches[(int) $selection])) {
|
||||
$package = $matches[(int) $selection];
|
||||
|
||||
return $package['name'];
|
||||
}
|
||||
|
||||
if (Preg::isMatch('{^\s*(?P<name>[\S/]+)(?:\s+(?P<version>\S+))?\s*$}', $selection, $packageMatches)) {
|
||||
if (isset($packageMatches['version'])) {
|
||||
// parsing `acme/example ~2.3`
|
||||
|
||||
// validate version constraint
|
||||
$versionParser->parseConstraints($packageMatches['version']);
|
||||
|
||||
return $packageMatches['name'].' '.$packageMatches['version'];
|
||||
}
|
||||
|
||||
// parsing `acme/example`
|
||||
return $packageMatches['name'];
|
||||
}
|
||||
|
||||
throw new \Exception('Not a valid selection');
|
||||
};
|
||||
|
||||
$package = $io->askAndValidate(
|
||||
'Enter package # to add, or the complete package name if it is not listed: ',
|
||||
$validator,
|
||||
3,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
// no constraint yet, determine the best version automatically
|
||||
if (false !== $package && false === strpos($package, ' ')) {
|
||||
$validator = function ($input) {
|
||||
$input = trim($input);
|
||||
|
||||
return strlen($input) > 0 ? $input : false;
|
||||
};
|
||||
|
||||
$constraint = $io->askAndValidate(
|
||||
'Enter the version constraint to require (or leave blank to use the latest version): ',
|
||||
$validator,
|
||||
3,
|
||||
false
|
||||
);
|
||||
|
||||
if (false === $constraint) {
|
||||
list(, $constraint) = $this->findBestVersionAndNameForPackage($input, $package, $platformRepo, $preferredStability);
|
||||
|
||||
$io->writeError(sprintf(
|
||||
'Using version <info>%s</info> for <info>%s</info>',
|
||||
$constraint,
|
||||
$package
|
||||
));
|
||||
}
|
||||
|
||||
$package .= ' '.$constraint;
|
||||
}
|
||||
|
||||
if (false !== $package) {
|
||||
$requires[] = $package;
|
||||
$existingPackages[] = explode(' ', $package)[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $requires;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a package name, this determines the best version to use in the require key.
|
||||
*
|
||||
* This returns a version with the ~ operator prefixed when possible.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @return array{string, string} name version
|
||||
*/
|
||||
private function findBestVersionAndNameForPackage(InputInterface $input, string $name, ?PlatformRepository $platformRepo = null, string $preferredStability = 'stable', ?string $requiredVersion = null, ?string $minimumStability = null, bool $fixed = false): array
|
||||
{
|
||||
// handle ignore-platform-reqs flag if present
|
||||
$platformRequirementFilter = $this->getPlatformRequirementFilter($input);
|
||||
|
||||
// find the latest version allowed in this repo set
|
||||
$versionSelector = new VersionSelector($this->getRepositorySet($input, $minimumStability), $platformRepo);
|
||||
$effectiveMinimumStability = $minimumStability ?? $this->getMinimumStability($input);
|
||||
|
||||
$package = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, $platformRequirementFilter);
|
||||
|
||||
if (false === $package) {
|
||||
// platform packages can not be found in the pool in versions other than the local platform's has
|
||||
// so if platform reqs are ignored we just take the user's word for it
|
||||
if ($platformRequirementFilter->isIgnored($name)) {
|
||||
return array($name, $requiredVersion ?: '*');
|
||||
}
|
||||
|
||||
// Check whether the package requirements were the problem
|
||||
if (!($platformRequirementFilter instanceof IgnoreAllPlatformRequirementFilter) && false !== ($candidate = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, PlatformRequirementFilterFactory::ignoreAll()))) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Package %s%s has requirements incompatible with your PHP version, PHP extensions and Composer version' . $this->getPlatformExceptionDetails($candidate, $platformRepo),
|
||||
$name,
|
||||
is_string($requiredVersion) ? ' at version '.$requiredVersion : ''
|
||||
));
|
||||
}
|
||||
// Check whether the minimum stability was the problem but the package exists
|
||||
if (false !== ($package = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, $platformRequirementFilter, RepositorySet::ALLOW_UNACCEPTABLE_STABILITIES))) {
|
||||
// we must first verify if a valid package would be found in a lower priority repository
|
||||
if (false !== ($allReposPackage = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, $platformRequirementFilter, RepositorySet::ALLOW_SHADOWED_REPOSITORIES))) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Package '.$name.' exists in '.$allReposPackage->getRepository()->getRepoName().' and '.$package->getRepository()->getRepoName().' which has a higher repository priority. The packages from the higher priority repository do not match your minimum-stability and are therefore not installable. That repository is canonical so the lower priority repo\'s packages are not installable. See https://getcomposer.org/repoprio for details and assistance.'
|
||||
);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Could not find a version of package %s matching your minimum-stability (%s). Require it with an explicit version constraint allowing its desired stability.',
|
||||
$name,
|
||||
$effectiveMinimumStability
|
||||
));
|
||||
}
|
||||
// Check whether the required version was the problem
|
||||
if (is_string($requiredVersion) && false !== ($package = $versionSelector->findBestCandidate($name, null, $preferredStability, $platformRequirementFilter))) {
|
||||
// we must first verify if a valid package would be found in a lower priority repository
|
||||
if (false !== ($allReposPackage = $versionSelector->findBestCandidate($name, $requiredVersion, $preferredStability, PlatformRequirementFilterFactory::ignoreNothing(), RepositorySet::ALLOW_SHADOWED_REPOSITORIES))) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Package '.$name.' exists in '.$allReposPackage->getRepository()->getRepoName().' and '.$package->getRepository()->getRepoName().' which has a higher repository priority. The packages from the higher priority repository do not match your constraint and are therefore not installable. That repository is canonical so the lower priority repo\'s packages are not installable. See https://getcomposer.org/repoprio for details and assistance.'
|
||||
);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Could not find package %s in a version matching "%s" and a stability matching "'.$effectiveMinimumStability.'".',
|
||||
$name,
|
||||
$requiredVersion
|
||||
));
|
||||
}
|
||||
// Check whether the PHP version was the problem for all versions
|
||||
if (!$platformRequirementFilter instanceof IgnoreAllPlatformRequirementFilter && false !== ($candidate = $versionSelector->findBestCandidate($name, null, $preferredStability, PlatformRequirementFilterFactory::ignoreAll(), RepositorySet::ALLOW_UNACCEPTABLE_STABILITIES))) {
|
||||
$additional = '';
|
||||
if (false === $versionSelector->findBestCandidate($name, null, $preferredStability, PlatformRequirementFilterFactory::ignoreAll())) {
|
||||
$additional = PHP_EOL.PHP_EOL.'Additionally, the package was only found with a stability of "'.$candidate->getStability().'" while your minimum stability is "'.$effectiveMinimumStability.'".';
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Could not find package %s in any version matching your PHP version, PHP extensions and Composer version' . $this->getPlatformExceptionDetails($candidate, $platformRepo) . '%s',
|
||||
$name,
|
||||
$additional
|
||||
));
|
||||
}
|
||||
|
||||
// Check for similar names/typos
|
||||
$similar = $this->findSimilar($name);
|
||||
if (count($similar) > 0) {
|
||||
if (in_array($name, $similar, true)) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
"Could not find package %s. It was however found via repository search, which indicates a consistency issue with the repository.",
|
||||
$name
|
||||
));
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
"Could not find package %s.\n\nDid you mean " . (count($similar) > 1 ? 'one of these' : 'this') . "?\n %s",
|
||||
$name,
|
||||
implode("\n ", $similar)
|
||||
));
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Could not find a matching version of package %s. Check the package spelling, your version constraint and that the package is available in a stability which matches your minimum-stability (%s).',
|
||||
$name,
|
||||
$effectiveMinimumStability
|
||||
));
|
||||
}
|
||||
|
||||
return array(
|
||||
$package->getPrettyName(),
|
||||
$fixed ? $package->getPrettyVersion() : $versionSelector->findRecommendedRequireVersion($package),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string>
|
||||
*/
|
||||
private function findSimilar(string $package): array
|
||||
{
|
||||
try {
|
||||
if (null === $this->repos) {
|
||||
throw new \LogicException('findSimilar was called before $this->repos was initialized');
|
||||
}
|
||||
$results = $this->repos->search($package);
|
||||
} catch (\Throwable $e) {
|
||||
if ($e instanceof \LogicException) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
// ignore search errors
|
||||
return array();
|
||||
}
|
||||
$similarPackages = array();
|
||||
|
||||
$installedRepo = $this->requireComposer()->getRepositoryManager()->getLocalRepository();
|
||||
|
||||
foreach ($results as $result) {
|
||||
if (null !== $installedRepo->findPackage($result['name'], '*')) {
|
||||
// Ignore installed package
|
||||
continue;
|
||||
}
|
||||
$similarPackages[$result['name']] = levenshtein($package, $result['name']);
|
||||
}
|
||||
asort($similarPackages);
|
||||
|
||||
return array_keys(array_slice($similarPackages, 0, 5));
|
||||
}
|
||||
|
||||
private function getPlatformExceptionDetails(PackageInterface $candidate, ?PlatformRepository $platformRepo = null): string
|
||||
{
|
||||
$details = array();
|
||||
if (null === $platformRepo) {
|
||||
return '';
|
||||
}
|
||||
|
||||
foreach ($candidate->getRequires() as $link) {
|
||||
if (!PlatformRepository::isPlatformPackage($link->getTarget())) {
|
||||
continue;
|
||||
}
|
||||
$platformPkg = $platformRepo->findPackage($link->getTarget(), '*');
|
||||
if (null === $platformPkg) {
|
||||
if ($platformRepo->isPlatformPackageDisabled($link->getTarget())) {
|
||||
$details[] = $candidate->getPrettyName().' '.$candidate->getPrettyVersion().' requires '.$link->getTarget().' '.$link->getPrettyConstraint().' but it is disabled by your platform config. Enable it again with "composer config platform.'.$link->getTarget().' --unset".';
|
||||
} else {
|
||||
$details[] = $candidate->getPrettyName().' '.$candidate->getPrettyVersion().' requires '.$link->getTarget().' '.$link->getPrettyConstraint().' but it is not present.';
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!$link->getConstraint()->matches(new Constraint('==', $platformPkg->getVersion()))) {
|
||||
$platformPkgVersion = $platformPkg->getPrettyVersion();
|
||||
$platformExtra = $platformPkg->getExtra();
|
||||
if (isset($platformExtra['config.platform']) && $platformPkg instanceof CompletePackageInterface) {
|
||||
$platformPkgVersion .= ' ('.$platformPkg->getDescription().')';
|
||||
}
|
||||
$details[] = $candidate->getPrettyName().' '.$candidate->getPrettyVersion().' requires '.$link->getTarget().' '.$link->getPrettyConstraint().' which does not match your installed version '.$platformPkgVersion.'.';
|
||||
}
|
||||
}
|
||||
|
||||
if (count($details) === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return ':'.PHP_EOL.' - ' . implode(PHP_EOL.' - ', $details);
|
||||
}
|
||||
}
|
|
@ -51,12 +51,7 @@ EOT
|
|||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the function.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
return parent::doExecute($input, $output, true);
|
||||
}
|
||||
|
|
|
@ -70,11 +70,11 @@ EOT
|
|||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = $this->getIO();
|
||||
|
||||
$composer = $this->getComposer(true, $input->getOption('no-plugins'), $input->getOption('no-scripts'));
|
||||
$composer = $this->requireComposer();
|
||||
|
||||
$localRepo = $composer->getRepositoryManager()->getLocalRepository();
|
||||
$packagesToReinstall = array();
|
||||
|
@ -139,8 +139,6 @@ EOT
|
|||
$downloadManager = $composer->getDownloadManager();
|
||||
$package = $composer->getPackage();
|
||||
|
||||
$ignorePlatformReqs = $input->getOption('ignore-platform-reqs') ?: ($input->getOption('ignore-platform-req') ?: false);
|
||||
|
||||
$installationManager->setOutputProgress(!$input->getOption('no-progress'));
|
||||
if ($input->getOption('no-plugins')) {
|
||||
$installationManager->disablePlugins();
|
||||
|
@ -166,7 +164,7 @@ EOT
|
|||
$generator = $composer->getAutoloadGenerator();
|
||||
$generator->setClassMapAuthoritative($authoritative);
|
||||
$generator->setApcu($apcu, $apcuPrefix);
|
||||
$generator->setPlatformRequirementFilter(PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs));
|
||||
$generator->setPlatformRequirementFilter($this->getPlatformRequirementFilter($input));
|
||||
$generator->dump($config, $localRepo, $package, $installationManager, 'composer', $optimize);
|
||||
}
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ EOT
|
|||
protected function interact(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if ($input->getOption('unused')) {
|
||||
$composer = $this->getComposer();
|
||||
$composer = $this->requireComposer();
|
||||
$locker = $composer->getLocker();
|
||||
if (!$locker->isLocked()) {
|
||||
throw new \UnexpectedValueException('A valid composer.lock file is required to run this command with --unused');
|
||||
|
@ -115,7 +115,7 @@ EOT
|
|||
}
|
||||
$input->setArgument('packages', array_merge($input->getArgument('packages'), $unused));
|
||||
|
||||
if (!$input->getArgument('packages')) {
|
||||
if (count($input->getArgument('packages')) === 0) {
|
||||
$this->getIO()->writeError('<info>No unused packages to remove</info>');
|
||||
$this->setCode(function () {
|
||||
return 0;
|
||||
|
@ -125,7 +125,6 @@ EOT
|
|||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
* @throws \Seld\JsonLint\ParsingException
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
|
@ -210,13 +209,13 @@ EOT
|
|||
return 0;
|
||||
}
|
||||
|
||||
if ($composer = $this->getComposer(false)) {
|
||||
if ($composer = $this->tryComposer()) {
|
||||
$composer->getPluginManager()->deactivateInstalledPlugins();
|
||||
}
|
||||
|
||||
// Update packages
|
||||
$this->resetComposer();
|
||||
$composer = $this->getComposer(true, $input->getOption('no-plugins'), $input->getOption('no-scripts'));
|
||||
$composer = $this->requireComposer();
|
||||
|
||||
if ($dryRun) {
|
||||
$rootPackage = $composer->getPackage();
|
||||
|
@ -258,8 +257,6 @@ EOT
|
|||
|
||||
$io->writeError('<info>Running composer update '.implode(' ', $packages).$flags.'</info>');
|
||||
|
||||
$ignorePlatformReqs = $input->getOption('ignore-platform-reqs') ?: ($input->getOption('ignore-platform-req') ?: false);
|
||||
|
||||
$install
|
||||
->setVerbose($input->getOption('verbose'))
|
||||
->setDevMode($updateDevMode)
|
||||
|
@ -269,7 +266,7 @@ EOT
|
|||
->setUpdate(true)
|
||||
->setInstall(!$input->getOption('no-install'))
|
||||
->setUpdateAllowTransitiveDependencies($updateAllowTransitiveDependencies)
|
||||
->setPlatformRequirementFilter(PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs))
|
||||
->setPlatformRequirementFilter($this->getPlatformRequirementFilter($input))
|
||||
->setDryRun($dryRun)
|
||||
;
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ namespace Composer\Command;
|
|||
|
||||
use Composer\DependencyResolver\Request;
|
||||
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
|
||||
use Composer\Repository\RepositorySet;
|
||||
use Composer\Util\Filesystem;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
|
@ -38,8 +39,16 @@ use Composer\Util\Silencer;
|
|||
* @author Jérémy Romey <jeremy@free-agent.fr>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class RequireCommand extends InitCommand
|
||||
class RequireCommand extends BaseCommand
|
||||
{
|
||||
use PackageDiscoveryTrait;
|
||||
|
||||
// Properties for PackageDiscoveryTrait
|
||||
/** @var ?CompositeRepository */
|
||||
protected $repos;
|
||||
/** @var RepositorySet[] */
|
||||
private $repositorySets;
|
||||
|
||||
/** @var bool */
|
||||
private $newlyCreated;
|
||||
/** @var bool */
|
||||
|
@ -110,7 +119,6 @@ EOT
|
|||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
* @throws \Seld\JsonLint\ParsingException
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
|
@ -177,11 +185,11 @@ EOT
|
|||
}
|
||||
}
|
||||
|
||||
$composer = $this->getComposer(true, $input->getOption('no-plugins'));
|
||||
$composer = $this->requireComposer();
|
||||
$repos = $composer->getRepositoryManager()->getRepositories();
|
||||
|
||||
$platformOverrides = $composer->getConfig()->get('platform') ?: array();
|
||||
// initialize $this->repos as it is used by the parent InitCommand
|
||||
$platformOverrides = $composer->getConfig()->get('platform');
|
||||
// initialize $this->repos as it is used by the PackageDiscoveryTrait
|
||||
$this->repos = new CompositeRepository(array_merge(
|
||||
array($platformRepo = new PlatformRepository(array(), $platformOverrides)),
|
||||
$repos
|
||||
|
@ -256,7 +264,7 @@ EOT
|
|||
$this->firstRequire = $this->newlyCreated;
|
||||
if (!$this->firstRequire) {
|
||||
$composerDefinition = $this->json->read();
|
||||
if (empty($composerDefinition['require']) && empty($composerDefinition['require-dev'])) {
|
||||
if (count($composerDefinition['require'] ?? []) === 0 && count($composerDefinition['require-dev'] ?? []) === 0) {
|
||||
$this->firstRequire = true;
|
||||
}
|
||||
}
|
||||
|
@ -355,7 +363,7 @@ EOT
|
|||
{
|
||||
// Update packages
|
||||
$this->resetComposer();
|
||||
$composer = $this->getComposer(true, $input->getOption('no-plugins'), $input->getOption('no-scripts'));
|
||||
$composer = $this->requireComposer();
|
||||
|
||||
$this->dependencyResolutionCompleted = false;
|
||||
$composer->getEventDispatcher()->addListener(InstallerEvents::PRE_OPERATIONS_EXEC, array($this, 'markSolverComplete'), 10000);
|
||||
|
@ -401,7 +409,6 @@ EOT
|
|||
|
||||
$install = Installer::create($io, $composer);
|
||||
|
||||
$ignorePlatformReqs = $input->getOption('ignore-platform-reqs') ?: ($input->getOption('ignore-platform-req') ?: false);
|
||||
list($preferSource, $preferDist) = $this->getPreferredInstallOptions($composer->getConfig(), $input);
|
||||
|
||||
$install
|
||||
|
@ -416,7 +423,7 @@ EOT
|
|||
->setUpdate(true)
|
||||
->setInstall(!$input->getOption('no-install'))
|
||||
->setUpdateAllowTransitiveDependencies($updateAllowTransitiveDependencies)
|
||||
->setPlatformRequirementFilter(PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs))
|
||||
->setPlatformRequirementFilter($this->getPlatformRequirementFilter($input))
|
||||
->setPreferStable($input->getOption('prefer-stable'))
|
||||
->setPreferLowest($input->getOption('prefer-lowest'))
|
||||
;
|
||||
|
@ -472,7 +479,7 @@ EOT
|
|||
return true;
|
||||
}
|
||||
|
||||
protected function interact(InputInterface $input, OutputInterface $output)
|
||||
protected function interact(InputInterface $input, OutputInterface $output): void
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ 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::REQUIRED, 'Script name to run.'),
|
||||
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.'),
|
||||
|
@ -73,14 +73,11 @@ EOT
|
|||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
if ($input->getOption('list')) {
|
||||
return $this->listScripts($output);
|
||||
}
|
||||
if (!$input->getArgument('script')) {
|
||||
throw new \RuntimeException('Missing required argument "script"');
|
||||
}
|
||||
|
||||
$script = $input->getArgument('script');
|
||||
if (!in_array($script, $this->scriptEvents)) {
|
||||
|
@ -89,7 +86,7 @@ EOT
|
|||
}
|
||||
}
|
||||
|
||||
$composer = $this->getComposer();
|
||||
$composer = $this->requireComposer();
|
||||
$devMode = $input->getOption('dev') || !$input->getOption('no-dev');
|
||||
$event = new ScriptEvent($script, $composer, $this->getIO(), $devMode);
|
||||
$hasListeners = $composer->getEventDispatcher()->hasEventListeners($event);
|
||||
|
@ -117,7 +114,7 @@ EOT
|
|||
*/
|
||||
protected function listScripts(OutputInterface $output)
|
||||
{
|
||||
$scripts = $this->getComposer()->getPackage()->getScripts();
|
||||
$scripts = $this->requireComposer()->getPackage()->getScripts();
|
||||
|
||||
if (!count($scripts)) {
|
||||
return 0;
|
||||
|
|
|
@ -64,12 +64,9 @@ EOT
|
|||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$composer = $this->getComposer();
|
||||
$composer = $this->requireComposer();
|
||||
|
||||
$args = $input->getArguments();
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ EOT
|
|||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
// init repos
|
||||
$platformRepo = new PlatformRepository;
|
||||
|
@ -69,7 +69,7 @@ EOT
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (!($composer = $this->getComposer(false))) {
|
||||
if (!($composer = $this->tryComposer())) {
|
||||
$composer = Factory::create($this->getIO(), array(), $input->hasParameterOption('--no-plugins'));
|
||||
}
|
||||
$localRepo = $composer->getRepositoryManager()->getLocalRepository();
|
||||
|
|
|
@ -75,10 +75,9 @@ EOT
|
|||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
* @throws FilesystemException
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
// trigger autoloading of a few classes which may be needed when verifying/swapping the phar file
|
||||
// to ensure we do not try to load them from the new phar, see https://github.com/composer/composer/issues/10252
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace Composer\Command;
|
|||
use Composer\Composer;
|
||||
use Composer\DependencyResolver\DefaultPolicy;
|
||||
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
|
||||
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterInterface;
|
||||
use Composer\Json\JsonFile;
|
||||
use Composer\Package\BasePackage;
|
||||
use Composer\Package\CompletePackageInterface;
|
||||
|
@ -114,7 +115,7 @@ EOT
|
|||
$this->initStyles($output);
|
||||
}
|
||||
|
||||
$composer = $this->getComposer(false);
|
||||
$composer = $this->tryComposer();
|
||||
$io = $this->getIO();
|
||||
|
||||
if ($input->getOption('installed')) {
|
||||
|
@ -123,7 +124,7 @@ EOT
|
|||
|
||||
if ($input->getOption('outdated')) {
|
||||
$input->setOption('latest', true);
|
||||
} elseif ($input->getOption('ignore')) {
|
||||
} elseif (count($input->getOption('ignore')) > 0) {
|
||||
$io->writeError('<warning>You are using the option "ignore" for action other than "outdated", it will be ignored.</warning>');
|
||||
}
|
||||
|
||||
|
@ -158,7 +159,7 @@ EOT
|
|||
return 1;
|
||||
}
|
||||
|
||||
$ignorePlatformReqs = $input->getOption('ignore-platform-reqs') ?: ($input->getOption('ignore-platform-req') ?: false);
|
||||
$platformReqFilter = $this->getPlatformRequirementFilter($input);
|
||||
|
||||
// init repos
|
||||
$platformOverrides = array();
|
||||
|
@ -169,12 +170,15 @@ EOT
|
|||
$lockedRepo = null;
|
||||
|
||||
if ($input->getOption('self')) {
|
||||
$package = $this->getComposer()->getPackage();
|
||||
$package = $this->requireComposer()->getPackage();
|
||||
if ($input->getOption('name-only')) {
|
||||
$io->write($package->getName());
|
||||
|
||||
return 0;
|
||||
}
|
||||
if ($input->getArgument('package')) {
|
||||
throw new \InvalidArgumentException('You cannot use --self together with a package name');
|
||||
}
|
||||
$repos = $installedRepo = new InstalledRepository(array(new RootPackageRepository($package)));
|
||||
} elseif ($input->getOption('platform')) {
|
||||
$repos = $installedRepo = new InstalledRepository(array($platformRepo));
|
||||
|
@ -213,7 +217,7 @@ EOT
|
|||
} else {
|
||||
// --installed / default case
|
||||
if (!$composer) {
|
||||
$composer = $this->getComposer();
|
||||
$composer = $this->requireComposer();
|
||||
}
|
||||
$rootPkg = $composer->getPackage();
|
||||
$repos = $installedRepo = new InstalledRepository(array($composer->getRepositoryManager()->getLocalRepository()));
|
||||
|
@ -243,31 +247,33 @@ EOT
|
|||
$packageFilter = $input->getArgument('package');
|
||||
|
||||
// show single package or single version
|
||||
if (($packageFilter && false === strpos($packageFilter, '*')) || !empty($package)) {
|
||||
if (empty($package)) {
|
||||
list($package, $versions) = $this->getPackage($installedRepo, $repos, $input->getArgument('package'), $input->getArgument('version'));
|
||||
if (isset($package)) {
|
||||
$versions = array($package->getPrettyVersion() => $package->getVersion());
|
||||
} elseif (null !== $packageFilter && str_contains($packageFilter, '*')) {
|
||||
list($package, $versions) = $this->getPackage($installedRepo, $repos, $packageFilter, $input->getArgument('version'));
|
||||
|
||||
if (empty($package)) {
|
||||
$options = $input->getOptions();
|
||||
$hint = '';
|
||||
if ($input->getOption('locked')) {
|
||||
$hint .= ' in lock file';
|
||||
}
|
||||
if (isset($options['working-dir'])) {
|
||||
$hint .= ' in ' . $options['working-dir'] . '/composer.json';
|
||||
}
|
||||
if (PlatformRepository::isPlatformPackage($input->getArgument('package')) && !$input->getOption('platform')) {
|
||||
$hint .= ', try using --platform (-p) to show platform packages';
|
||||
}
|
||||
if (!$input->getOption('all')) {
|
||||
$hint .= ', try using --all (-a) to show all available packages';
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('Package "' . $packageFilter . '" not found'.$hint.'.');
|
||||
if (!isset($package)) {
|
||||
$options = $input->getOptions();
|
||||
$hint = '';
|
||||
if ($input->getOption('locked')) {
|
||||
$hint .= ' in lock file';
|
||||
}
|
||||
} else {
|
||||
$versions = array($package->getPrettyVersion() => $package->getVersion());
|
||||
if (isset($options['working-dir'])) {
|
||||
$hint .= ' in ' . $options['working-dir'] . '/composer.json';
|
||||
}
|
||||
if (PlatformRepository::isPlatformPackage($packageFilter) && !$input->getOption('platform')) {
|
||||
$hint .= ', try using --platform (-p) to show platform packages';
|
||||
}
|
||||
if (!$input->getOption('all')) {
|
||||
$hint .= ', try using --all (-a) to show all available packages';
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('Package "' . $packageFilter . '" not found'.$hint.'.');
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($package)) {
|
||||
assert(isset($versions));
|
||||
|
||||
$exitCode = 0;
|
||||
if ($input->getOption('tree')) {
|
||||
|
@ -278,32 +284,34 @@ EOT
|
|||
} else {
|
||||
$this->displayPackageTree(array($arrayTree));
|
||||
}
|
||||
|
||||
return $exitCode;
|
||||
}
|
||||
|
||||
$latestPackage = null;
|
||||
if ($input->getOption('latest')) {
|
||||
$latestPackage = $this->findLatestPackage($package, $composer, $platformRepo, $input->getOption('minor-only'), $platformReqFilter);
|
||||
}
|
||||
if (
|
||||
$input->getOption('outdated')
|
||||
&& $input->getOption('strict')
|
||||
&& $latestPackage
|
||||
&& $latestPackage->getFullPrettyVersion() !== $package->getFullPrettyVersion()
|
||||
&& (!$latestPackage instanceof CompletePackageInterface || !$latestPackage->isAbandoned())
|
||||
) {
|
||||
$exitCode = 1;
|
||||
}
|
||||
if ($input->getOption('path')) {
|
||||
$io->write($package->getName(), false);
|
||||
$io->write(' ' . strtok(realpath($composer->getInstallationManager()->getInstallPath($package)), "\r\n"));
|
||||
|
||||
return $exitCode;
|
||||
}
|
||||
|
||||
if ('json' === $format) {
|
||||
$this->printPackageInfoAsJson($package, $versions, $installedRepo, $latestPackage ?: null);
|
||||
} else {
|
||||
$latestPackage = null;
|
||||
if ($input->getOption('latest')) {
|
||||
$latestPackage = $this->findLatestPackage($package, $composer, $platformRepo, $input->getOption('minor-only'), $ignorePlatformReqs);
|
||||
}
|
||||
if (
|
||||
$input->getOption('outdated')
|
||||
&& $input->getOption('strict')
|
||||
&& $latestPackage
|
||||
&& $latestPackage->getFullPrettyVersion() !== $package->getFullPrettyVersion()
|
||||
&& (!$latestPackage instanceof CompletePackageInterface || !$latestPackage->isAbandoned())
|
||||
) {
|
||||
$exitCode = 1;
|
||||
}
|
||||
if ($input->getOption('path')) {
|
||||
$io->write($package->getName(), false);
|
||||
$io->write(' ' . strtok(realpath($composer->getInstallationManager()->getInstallPath($package)), "\r\n"));
|
||||
|
||||
return $exitCode;
|
||||
}
|
||||
|
||||
if ('json' === $format) {
|
||||
$this->printPackageInfoAsJson($package, $versions, $installedRepo, $latestPackage ?: null);
|
||||
} else {
|
||||
$this->printPackageInfo($package, $versions, $installedRepo, $latestPackage ?: null);
|
||||
}
|
||||
$this->printPackageInfo($package, $versions, $installedRepo, $latestPackage ?: null);
|
||||
}
|
||||
|
||||
return $exitCode;
|
||||
|
@ -407,7 +415,7 @@ EOT
|
|||
if ($showLatest && $showVersion) {
|
||||
foreach ($packages[$type] as $package) {
|
||||
if (is_object($package)) {
|
||||
$latestPackage = $this->findLatestPackage($package, $composer, $platformRepo, $showMinorOnly, $ignorePlatformReqs);
|
||||
$latestPackage = $this->findLatestPackage($package, $composer, $platformRepo, $showMinorOnly, $platformReqFilter);
|
||||
if ($latestPackage === false) {
|
||||
continue;
|
||||
}
|
||||
|
@ -597,7 +605,7 @@ EOT
|
|||
*/
|
||||
protected function getRootRequires()
|
||||
{
|
||||
$rootPackage = $this->getComposer()->getPackage();
|
||||
$rootPackage = $this->requireComposer()->getPackage();
|
||||
|
||||
return array_map(
|
||||
'strtolower',
|
||||
|
@ -717,7 +725,7 @@ EOT
|
|||
$io->write('<info>source</info> : ' . sprintf('[%s] <comment>%s</comment> %s', $package->getSourceType(), $package->getSourceUrl(), $package->getSourceReference()));
|
||||
$io->write('<info>dist</info> : ' . sprintf('[%s] <comment>%s</comment> %s', $package->getDistType(), $package->getDistUrl(), $package->getDistReference()));
|
||||
if ($installedRepo->hasPackage($package)) {
|
||||
$io->write('<info>path</info> : ' . sprintf('%s', realpath($this->getComposer()->getInstallationManager()->getInstallPath($package))));
|
||||
$io->write('<info>path</info> : ' . sprintf('%s', realpath($this->requireComposer()->getInstallationManager()->getInstallPath($package))));
|
||||
}
|
||||
$io->write('<info>names</info> : ' . implode(', ', $package->getNames()));
|
||||
|
||||
|
@ -865,7 +873,7 @@ EOT
|
|||
$latestPackage = $package;
|
||||
}
|
||||
|
||||
if ($package->getSourceType()) {
|
||||
if (null !== $package->getSourceType()) {
|
||||
$json['source'] = array(
|
||||
'type' => $package->getSourceType(),
|
||||
'url' => $package->getSourceUrl(),
|
||||
|
@ -873,7 +881,7 @@ EOT
|
|||
);
|
||||
}
|
||||
|
||||
if ($package->getDistType()) {
|
||||
if (null !== $package->getDistType()) {
|
||||
$json['dist'] = array(
|
||||
'type' => $package->getDistType(),
|
||||
'url' => $package->getDistUrl(),
|
||||
|
@ -882,7 +890,7 @@ EOT
|
|||
}
|
||||
|
||||
if ($installedRepo->hasPackage($package)) {
|
||||
$json['path'] = realpath($this->getComposer()->getInstallationManager()->getInstallPath($package));
|
||||
$json['path'] = realpath($this->requireComposer()->getInstallationManager()->getInstallPath($package));
|
||||
if ($json['path'] === false) {
|
||||
unset($json['path']);
|
||||
}
|
||||
|
@ -1281,12 +1289,9 @@ EOT
|
|||
/**
|
||||
* Given a package, this finds the latest package matching it
|
||||
*
|
||||
* @param bool $minorOnly
|
||||
* @param bool|string $ignorePlatformReqs
|
||||
*
|
||||
* @return PackageInterface|false
|
||||
*/
|
||||
private function findLatestPackage(PackageInterface $package, Composer $composer, PlatformRepository $platformRepo, $minorOnly = false, $ignorePlatformReqs = false)
|
||||
private function findLatestPackage(PackageInterface $package, Composer $composer, PlatformRepository $platformRepo, bool $minorOnly, PlatformRequirementFilterInterface $platformReqFilter)
|
||||
{
|
||||
// find the latest version allowed in this repo set
|
||||
$name = $package->getName();
|
||||
|
@ -1311,7 +1316,7 @@ EOT
|
|||
$targetVersion = '^' . $package->getVersion();
|
||||
}
|
||||
|
||||
$candidate = $versionSelector->findBestCandidate($name, $targetVersion, $bestStability, PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs));
|
||||
$candidate = $versionSelector->findBestCandidate($name, $targetVersion, $bestStability, $platformReqFilter);
|
||||
while ($candidate instanceof AliasPackage) {
|
||||
$candidate = $candidate->getAliasOf();
|
||||
}
|
||||
|
|
|
@ -59,12 +59,9 @@ EOT
|
|||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$composer = $this->getComposer();
|
||||
$composer = $this->requireComposer();
|
||||
|
||||
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'status', $input, $output);
|
||||
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
|
||||
|
@ -86,7 +83,7 @@ EOT
|
|||
private function doExecute(InputInterface $input)
|
||||
{
|
||||
// init repos
|
||||
$composer = $this->getComposer();
|
||||
$composer = $this->requireComposer();
|
||||
|
||||
$installedRepo = $composer->getRepositoryManager()->getLocalRepository();
|
||||
|
||||
|
|
|
@ -50,12 +50,9 @@ EOT
|
|||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$composer = $this->getComposer();
|
||||
$composer = $this->requireComposer();
|
||||
|
||||
$installedRepos = array(
|
||||
new RootPackageRepository(clone $composer->getPackage()),
|
||||
|
|
|
@ -109,10 +109,6 @@ EOT
|
|||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = $this->getIO();
|
||||
|
@ -123,7 +119,7 @@ EOT
|
|||
$io->writeError('<warning>You are using the deprecated option "--no-suggest". It has no effect and will break in Composer 3.</warning>');
|
||||
}
|
||||
|
||||
$composer = $this->getComposer(true, $input->getOption('no-plugins'), $input->getOption('no-scripts'));
|
||||
$composer = $this->requireComposer();
|
||||
|
||||
if (!HttpDownloader::isCurlEnabled()) {
|
||||
$io->writeError('<warning>Composer is operating significantly slower than normal because you do not have the PHP curl extension enabled.</warning>');
|
||||
|
@ -133,7 +129,7 @@ EOT
|
|||
$reqs = $this->formatRequirements($input->getOption('with'));
|
||||
|
||||
// extract --with shorthands from the allowlist
|
||||
if ($packages) {
|
||||
if (count($packages) > 0) {
|
||||
$allowlistPackagesWithRequirements = array_filter($packages, function ($pkg) {
|
||||
return Preg::isMatch('{\S+[ =:]\S+}', $pkg);
|
||||
});
|
||||
|
@ -219,8 +215,6 @@ EOT
|
|||
$updateAllowTransitiveDependencies = Request::UPDATE_LISTED_WITH_TRANSITIVE_DEPS_NO_ROOT_REQUIRE;
|
||||
}
|
||||
|
||||
$ignorePlatformReqs = $input->getOption('ignore-platform-reqs') ?: ($input->getOption('ignore-platform-req') ?: false);
|
||||
|
||||
$install
|
||||
->setDryRun($input->getOption('dry-run'))
|
||||
->setVerbose($input->getOption('verbose'))
|
||||
|
@ -236,7 +230,7 @@ EOT
|
|||
->setUpdateMirrors($updateMirrors)
|
||||
->setUpdateAllowList($packages)
|
||||
->setUpdateAllowTransitiveDependencies($updateAllowTransitiveDependencies)
|
||||
->setPlatformRequirementFilter(PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs))
|
||||
->setPlatformRequirementFilter($this->getPlatformRequirementFilter($input))
|
||||
->setPreferStable($input->getOption('prefer-stable'))
|
||||
->setPreferLowest($input->getOption('prefer-lowest'))
|
||||
;
|
||||
|
|
|
@ -66,10 +66,7 @@ EOT
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$file = $input->getArgument('file') ?: Factory::getComposerFile();
|
||||
$io = $this->getIO();
|
||||
|
|
|
@ -63,7 +63,7 @@ interface ConfigSourceInterface
|
|||
* Add a property
|
||||
*
|
||||
* @param string $name Name
|
||||
* @param string $value Value
|
||||
* @param string|string[] $value Value
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
|
|
@ -62,7 +62,7 @@ class JsonConfigSource implements ConfigSourceInterface
|
|||
*/
|
||||
public function addRepository($name, $config, $append = true)
|
||||
{
|
||||
$this->manipulateJson('addRepository', $name, $config, $append, function (&$config, $repo, $repoConfig) use ($append) {
|
||||
$this->manipulateJson('addRepository', function (&$config, $repo, $repoConfig) use ($append) {
|
||||
// if converting from an array format to hashmap format, and there is a {"packagist.org":false} repo, we have
|
||||
// to convert it to "packagist.org": false key on the hashmap otherwise it fails schema validation
|
||||
if (isset($config['repositories'])) {
|
||||
|
@ -83,7 +83,7 @@ class JsonConfigSource implements ConfigSourceInterface
|
|||
} else {
|
||||
$config['repositories'] = array($repo => $repoConfig) + $config['repositories'];
|
||||
}
|
||||
});
|
||||
}, $name, $config, $append);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -91,9 +91,9 @@ class JsonConfigSource implements ConfigSourceInterface
|
|||
*/
|
||||
public function removeRepository($name)
|
||||
{
|
||||
$this->manipulateJson('removeRepository', $name, function (&$config, $repo) {
|
||||
$this->manipulateJson('removeRepository', function (&$config, $repo) {
|
||||
unset($config['repositories'][$repo]);
|
||||
});
|
||||
}, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -102,7 +102,7 @@ class JsonConfigSource implements ConfigSourceInterface
|
|||
public function addConfigSetting($name, $value)
|
||||
{
|
||||
$authConfig = $this->authConfig;
|
||||
$this->manipulateJson('addConfigSetting', $name, $value, function (&$config, $key, $val) use ($authConfig) {
|
||||
$this->manipulateJson('addConfigSetting', function (&$config, $key, $val) use ($authConfig) {
|
||||
if (Preg::isMatch('{^(bitbucket-oauth|github-oauth|gitlab-oauth|gitlab-token|bearer|http-basic|platform)\.}', $key)) {
|
||||
list($key, $host) = explode('.', $key, 2);
|
||||
if ($authConfig) {
|
||||
|
@ -113,7 +113,7 @@ class JsonConfigSource implements ConfigSourceInterface
|
|||
} else {
|
||||
$config['config'][$key] = $val;
|
||||
}
|
||||
});
|
||||
}, $name, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -122,7 +122,7 @@ class JsonConfigSource implements ConfigSourceInterface
|
|||
public function removeConfigSetting($name)
|
||||
{
|
||||
$authConfig = $this->authConfig;
|
||||
$this->manipulateJson('removeConfigSetting', $name, function (&$config, $key) use ($authConfig) {
|
||||
$this->manipulateJson('removeConfigSetting', function (&$config, $key) use ($authConfig) {
|
||||
if (Preg::isMatch('{^(bitbucket-oauth|github-oauth|gitlab-oauth|gitlab-token|bearer|http-basic|platform)\.}', $key)) {
|
||||
list($key, $host) = explode('.', $key, 2);
|
||||
if ($authConfig) {
|
||||
|
@ -133,7 +133,7 @@ class JsonConfigSource implements ConfigSourceInterface
|
|||
} else {
|
||||
unset($config['config'][$key]);
|
||||
}
|
||||
});
|
||||
}, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -141,7 +141,7 @@ class JsonConfigSource implements ConfigSourceInterface
|
|||
*/
|
||||
public function addProperty($name, $value)
|
||||
{
|
||||
$this->manipulateJson('addProperty', $name, $value, function (&$config, $key, $val) {
|
||||
$this->manipulateJson('addProperty', function (&$config, $key, $val) {
|
||||
if (strpos($key, 'extra.') === 0 || strpos($key, 'scripts.') === 0) {
|
||||
$bits = explode('.', $key);
|
||||
$last = array_pop($bits);
|
||||
|
@ -156,7 +156,7 @@ class JsonConfigSource implements ConfigSourceInterface
|
|||
} else {
|
||||
$config[$key] = $val;
|
||||
}
|
||||
});
|
||||
}, $name, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -164,7 +164,7 @@ class JsonConfigSource implements ConfigSourceInterface
|
|||
*/
|
||||
public function removeProperty($name)
|
||||
{
|
||||
$this->manipulateJson('removeProperty', $name, function (&$config, $key) {
|
||||
$this->manipulateJson('removeProperty', function (&$config, $key) {
|
||||
if (strpos($key, 'extra.') === 0 || strpos($key, 'scripts.') === 0) {
|
||||
$bits = explode('.', $key);
|
||||
$last = array_pop($bits);
|
||||
|
@ -179,7 +179,7 @@ class JsonConfigSource implements ConfigSourceInterface
|
|||
} else {
|
||||
unset($config[$key]);
|
||||
}
|
||||
});
|
||||
}, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -187,9 +187,9 @@ class JsonConfigSource implements ConfigSourceInterface
|
|||
*/
|
||||
public function addLink($type, $name, $value)
|
||||
{
|
||||
$this->manipulateJson('addLink', $type, $name, $value, function (&$config, $type, $name, $value) {
|
||||
$this->manipulateJson('addLink', function (&$config, $type, $name, $value) {
|
||||
$config[$type][$name] = $value;
|
||||
});
|
||||
}, $type, $name, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -197,30 +197,25 @@ class JsonConfigSource implements ConfigSourceInterface
|
|||
*/
|
||||
public function removeLink($type, $name)
|
||||
{
|
||||
$this->manipulateJson('removeSubNode', $type, $name, function (&$config, $type, $name) {
|
||||
$this->manipulateJson('removeSubNode', function (&$config, $type, $name) {
|
||||
unset($config[$type][$name]);
|
||||
});
|
||||
$this->manipulateJson('removeMainKeyIfEmpty', $type, function (&$config, $type) {
|
||||
}, $type, $name);
|
||||
$this->manipulateJson('removeMainKeyIfEmpty', function (&$config, $type) {
|
||||
if (0 === count($config[$type])) {
|
||||
unset($config[$type]);
|
||||
}
|
||||
});
|
||||
}, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $method
|
||||
* @param mixed ...$args
|
||||
* @param callable $fallback
|
||||
* @param mixed ...$args
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function manipulateJson($method, $args, $fallback)
|
||||
private function manipulateJson($method, $fallback, ...$args)
|
||||
{
|
||||
$args = func_get_args();
|
||||
// remove method & fallback
|
||||
array_shift($args);
|
||||
$fallback = array_pop($args);
|
||||
|
||||
if ($this->file->exists()) {
|
||||
if (!is_writable($this->file->getPath())) {
|
||||
throw new \RuntimeException(sprintf('The file "%s" is not writable.', $this->file->getPath()));
|
||||
|
|
|
@ -33,7 +33,7 @@ use Symfony\Component\Process\ExecutableFinder;
|
|||
* The Event Dispatcher.
|
||||
*
|
||||
* Example in command:
|
||||
* $dispatcher = new EventDispatcher($this->getComposer(), $this->getApplication()->getIO());
|
||||
* $dispatcher = new EventDispatcher($this->requireComposer(), $this->getApplication()->getIO());
|
||||
* // ...
|
||||
* $dispatcher->dispatch(ScriptEvents::POST_INSTALL_CMD);
|
||||
* // ...
|
||||
|
|
|
@ -135,10 +135,10 @@ interface IOInterface extends LoggerInterface
|
|||
* Asks a question to the user.
|
||||
*
|
||||
* @param string $question The question to ask
|
||||
* @param string $default The default answer if none is given by the user
|
||||
* @param string|bool|int|float|null $default The default answer if none is given by the user
|
||||
*
|
||||
* @throws \RuntimeException If there is no data to read in the input stream
|
||||
* @return string|null The user answer
|
||||
* @return mixed The user answer
|
||||
*/
|
||||
public function ask($question, $default = null);
|
||||
|
||||
|
|
|
@ -237,7 +237,7 @@ class Git
|
|||
$storeAuth = $this->config->get('store-auths');
|
||||
}
|
||||
|
||||
if ($auth) {
|
||||
if (null !== $auth) {
|
||||
$authUrl = $match[1] . rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@' . $match[2] . $match[3];
|
||||
|
||||
$command = call_user_func($commandCallable, $authUrl);
|
||||
|
|
|
@ -28,7 +28,7 @@ use React\Promise\Promise;
|
|||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
* @phpstan-type Attributes array{retryAuthFailure: bool, redirects: int, retries: int, storeAuth: bool}
|
||||
* @phpstan-type Job array{url: string, origin: string, attributes: Attributes, options: mixed[], progress: mixed[], curlHandle: resource, filename: string|false, headerHandle: resource, bodyHandle: resource, resolve: callable, reject: callable}
|
||||
* @phpstan-type Job array{url: string, origin: string, attributes: Attributes, options: mixed[], progress: mixed[], curlHandle: resource, filename: string|null, headerHandle: resource, bodyHandle: resource, resolve: callable, reject: callable}
|
||||
*/
|
||||
class CurlDownloader
|
||||
{
|
||||
|
@ -158,12 +158,11 @@ class CurlDownloader
|
|||
*/
|
||||
private function initDownload($resolve, $reject, $origin, $url, $options, $copyTo = null, array $attributes = array())
|
||||
{
|
||||
$attributes = array_merge(array(
|
||||
'retryAuthFailure' => true,
|
||||
'redirects' => 0,
|
||||
'retries' => 0,
|
||||
'storeAuth' => false,
|
||||
), $attributes);
|
||||
// set defaults in a PHPStan-happy way (array_merge is not well supported)
|
||||
$attributes['retryAuthFailure'] = $attributes['retryAuthFailure'] ?? true;
|
||||
$attributes['redirects'] = $attributes['redirects'] ?? 0;
|
||||
$attributes['retries'] = $attributes['retries'] ?? 0;
|
||||
$attributes['storeAuth'] = $attributes['storeAuth'] ?? false;
|
||||
|
||||
$originalOptions = $options;
|
||||
|
||||
|
@ -300,7 +299,7 @@ class CurlDownloader
|
|||
if (is_resource($job['bodyHandle'])) {
|
||||
fclose($job['bodyHandle']);
|
||||
}
|
||||
if ($job['filename']) {
|
||||
if (null !== $job['filename']) {
|
||||
@unlink($job['filename'].'~');
|
||||
}
|
||||
unset($this->jobs[$id]);
|
||||
|
@ -314,7 +313,7 @@ class CurlDownloader
|
|||
{
|
||||
static $timeoutWarning = false;
|
||||
|
||||
if (!$this->jobs) {
|
||||
if (count($this->jobs) === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -382,7 +381,7 @@ class CurlDownloader
|
|||
}
|
||||
|
||||
// prepare response object
|
||||
if ($job['filename']) {
|
||||
if (null !== $job['filename']) {
|
||||
$contents = $job['filename'].'~';
|
||||
if ($statusCode >= 300) {
|
||||
rewind($job['bodyHandle']);
|
||||
|
@ -437,7 +436,7 @@ class CurlDownloader
|
|||
}
|
||||
|
||||
// resolve promise
|
||||
if ($job['filename']) {
|
||||
if (null !== $job['filename']) {
|
||||
rename($job['filename'].'~', $job['filename']);
|
||||
call_user_func($job['resolve'], $response);
|
||||
} else {
|
||||
|
@ -582,7 +581,7 @@ class CurlDownloader
|
|||
*/
|
||||
private function restartJob(array $job, $url, array $attributes = array())
|
||||
{
|
||||
if ($job['filename']) {
|
||||
if (null !== $job['filename']) {
|
||||
@unlink($job['filename'].'~');
|
||||
}
|
||||
|
||||
|
@ -599,7 +598,7 @@ class CurlDownloader
|
|||
*/
|
||||
private function failResponse(array $job, Response $response, $errorMessage)
|
||||
{
|
||||
if ($job['filename']) {
|
||||
if (null !== $job['filename']) {
|
||||
@unlink($job['filename'].'~');
|
||||
}
|
||||
|
||||
|
@ -623,7 +622,7 @@ class CurlDownloader
|
|||
if (is_resource($job['bodyHandle'])) {
|
||||
fclose($job['bodyHandle']);
|
||||
}
|
||||
if ($job['filename']) {
|
||||
if (null !== $job['filename']) {
|
||||
@unlink($job['filename'].'~');
|
||||
}
|
||||
call_user_func($job['reject'], $e);
|
||||
|
|
|
@ -61,7 +61,7 @@ class ApplicationTest extends TestCase
|
|||
|
||||
$inputMock->expects($this->any())
|
||||
->method('getFirstArgument')
|
||||
->will($this->returnValue('show'));
|
||||
->will($this->returnValue('about'));
|
||||
|
||||
$output = new BufferedOutput();
|
||||
$expectedOutput = '';
|
||||
|
@ -122,7 +122,7 @@ class ApplicationTest extends TestCase
|
|||
|
||||
$inputMock->expects($this->any())
|
||||
->method('getFirstArgument')
|
||||
->will($this->returnValue('show'));
|
||||
->will($this->returnValue('about'));
|
||||
|
||||
$outputMock->expects($this->never())
|
||||
->method("writeln");
|
||||
|
|
|
@ -53,9 +53,12 @@ class ArchiveCommandTest extends TestCase
|
|||
'mergeApplicationDefinition',
|
||||
'getSynopsis',
|
||||
'initialize',
|
||||
'getComposer',
|
||||
'tryComposer',
|
||||
'requireComposer',
|
||||
))->getMock();
|
||||
$command->expects($this->atLeastOnce())->method('getComposer')
|
||||
$command->expects($this->atLeastOnce())->method('tryComposer')
|
||||
->willReturn($composer);
|
||||
$command->expects($this->atLeastOnce())->method('requireComposer')
|
||||
->willReturn($composer);
|
||||
|
||||
$command->run($input, $output);
|
||||
|
@ -74,10 +77,10 @@ class ArchiveCommandTest extends TestCase
|
|||
'mergeApplicationDefinition',
|
||||
'getSynopsis',
|
||||
'initialize',
|
||||
'getComposer',
|
||||
'tryComposer',
|
||||
'archive',
|
||||
))->getMock();
|
||||
$command->expects($this->once())->method('getComposer')
|
||||
$command->expects($this->once())->method('tryComposer')
|
||||
->willReturn(null);
|
||||
$command->expects($this->once())->method('archive')
|
||||
->with(
|
||||
|
|
|
@ -80,10 +80,10 @@ class RunScriptCommandTest extends TestCase
|
|||
'mergeApplicationDefinition',
|
||||
'getSynopsis',
|
||||
'initialize',
|
||||
'getComposer',
|
||||
'requireComposer',
|
||||
))
|
||||
->getMock();
|
||||
$command->expects($this->any())->method('getComposer')->willReturn($composer);
|
||||
$command->expects($this->any())->method('requireComposer')->willReturn($composer);
|
||||
|
||||
$command->run($input, $output);
|
||||
}
|
||||
|
|
|
@ -64,10 +64,23 @@ class HttpDownloaderMock extends HttpDownloader
|
|||
throw new \UnexpectedValueException('Unexpected keys in process execution step: '.implode(', ', array_keys($diff)));
|
||||
}
|
||||
|
||||
return array_merge($default, $expect);
|
||||
// set defaults in a PHPStan-happy way (array_merge is not well supported)
|
||||
$expect['url'] = $expect['url'] ?? $default['url'];
|
||||
$expect['options'] = $expect['options'] ?? $default['options'];
|
||||
$expect['status'] = $expect['status'] ?? $default['status'];
|
||||
$expect['body'] = $expect['body'] ?? $default['body'];
|
||||
$expect['headers'] = $expect['headers'] ?? $default['headers'];
|
||||
|
||||
return $expect;
|
||||
}, $expectations);
|
||||
$this->strict = $strict;
|
||||
$this->defaultHandler = array_merge($this->defaultHandler, $defaultHandler);
|
||||
|
||||
// set defaults in a PHPStan-happy way (array_merge is not well supported)
|
||||
$defaultHandler['status'] = $defaultHandler['status'] ?? $this->defaultHandler['status'];
|
||||
$defaultHandler['body'] = $defaultHandler['body'] ?? $this->defaultHandler['body'];
|
||||
$defaultHandler['headers'] = $defaultHandler['headers'] ?? $this->defaultHandler['headers'];
|
||||
|
||||
$this->defaultHandler = $defaultHandler;
|
||||
}
|
||||
|
||||
public function assertComplete(): void
|
||||
|
|
|
@ -55,15 +55,30 @@ class ProcessExecutorMock extends ProcessExecutor
|
|||
$default = array('cmd' => '', 'return' => 0, 'stdout' => '', 'stderr' => '', 'callback' => null);
|
||||
$this->expectations = array_map(function ($expect) use ($default) {
|
||||
if (is_string($expect)) {
|
||||
$expect = array('cmd' => $expect);
|
||||
$command = $expect;
|
||||
$expect = $default;
|
||||
$expect['cmd'] = $command;
|
||||
} elseif (count($diff = array_diff_key(array_merge($default, $expect), $default)) > 0) {
|
||||
throw new \UnexpectedValueException('Unexpected keys in process execution step: '.implode(', ', array_keys($diff)));
|
||||
}
|
||||
|
||||
return array_merge($default, $expect);
|
||||
// set defaults in a PHPStan-happy way (array_merge is not well supported)
|
||||
$expect['cmd'] = $expect['cmd'] ?? $default['cmd'];
|
||||
$expect['return'] = $expect['return'] ?? $default['return'];
|
||||
$expect['stdout'] = $expect['stdout'] ?? $default['stdout'];
|
||||
$expect['stderr'] = $expect['stderr'] ?? $default['stderr'];
|
||||
$expect['callback'] = $expect['callback'] ?? $default['callback'];
|
||||
|
||||
return $expect;
|
||||
}, $expectations);
|
||||
$this->strict = $strict;
|
||||
$this->defaultHandler = array_merge($this->defaultHandler, $defaultHandler);
|
||||
|
||||
// set defaults in a PHPStan-happy way (array_merge is not well supported)
|
||||
$defaultHandler['return'] = $defaultHandler['return'] ?? $this->defaultHandler['return'];
|
||||
$defaultHandler['stdout'] = $defaultHandler['stdout'] ?? $this->defaultHandler['stdout'];
|
||||
$defaultHandler['stderr'] = $defaultHandler['stderr'] ?? $this->defaultHandler['stderr'];
|
||||
|
||||
$this->defaultHandler = $defaultHandler;
|
||||
}
|
||||
|
||||
public function assertComplete(): void
|
||||
|
|
|
@ -35,7 +35,7 @@ class Command extends BaseCommand
|
|||
$this->setName('custom-plugin-command');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$output->writeln('Executing');
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
return new \Composer\Console\Application();
|
Loading…
Reference in New Issue