1
0
Fork 0

PHPStan Level 5 (#10070)

* Bump PHPStan to level 5

* Update seld/phar-utils to latest

* Add phpstan-setup / phpstan scripts
pull/10076/head
Jordi Boggiano 2021-08-21 17:41:52 +02:00 committed by GitHub
parent 4b8585d767
commit d3c176ec69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
74 changed files with 395 additions and 547 deletions

View File

@ -78,11 +78,20 @@
], ],
"scripts": { "scripts": {
"compile": "@php -dphar.readonly=0 bin/compile", "compile": "@php -dphar.readonly=0 bin/compile",
"test": "simple-phpunit" "test": "simple-phpunit",
"phpstan-setup": [
"@composer config platform --unset",
"@php composer.phar update",
"@composer require --dev phpstan/phpstan:^0.12.93 phpstan/phpstan-phpunit:^0.12.17 phpunit/phpunit:^7.5.20 --with-all-dependencies",
"git checkout composer.json composer.lock"
],
"phpstan": "@php vendor/bin/phpstan analyse --configuration=phpstan/config.neon"
}, },
"scripts-descriptions": { "scripts-descriptions": {
"compile": "Compile composer.phar", "compile": "Compile composer.phar",
"test": "Run all tests" "test": "Run all tests",
"phpstan-setup": "Prepare environment to run PHPStan locally (must be run with PHP7.4)",
"phpstan": "Runs PHPStan (after phpstan-setup was executed, must be run with PHP7.4)"
}, },
"support": { "support": {
"issues": "https://github.com/composer/composer/issues", "issues": "https://github.com/composer/composer/issues",

12
composer.lock generated
View File

@ -608,16 +608,16 @@
}, },
{ {
"name": "seld/phar-utils", "name": "seld/phar-utils",
"version": "1.1.1", "version": "1.1.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Seldaek/phar-utils.git", "url": "https://github.com/Seldaek/phar-utils.git",
"reference": "8674b1d84ffb47cc59a101f5d5a3b61e87d23796" "reference": "749042a2315705d2dfbbc59234dd9ceb22bf3ff0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/8674b1d84ffb47cc59a101f5d5a3b61e87d23796", "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/749042a2315705d2dfbbc59234dd9ceb22bf3ff0",
"reference": "8674b1d84ffb47cc59a101f5d5a3b61e87d23796", "reference": "749042a2315705d2dfbbc59234dd9ceb22bf3ff0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -650,9 +650,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/Seldaek/phar-utils/issues", "issues": "https://github.com/Seldaek/phar-utils/issues",
"source": "https://github.com/Seldaek/phar-utils/tree/master" "source": "https://github.com/Seldaek/phar-utils/tree/1.1.2"
}, },
"time": "2020-07-07T18:42:57+00:00" "time": "2021-08-19T21:01:38+00:00"
}, },
{ {
"name": "symfony/console", "name": "symfony/console",

View File

@ -1,277 +1,11 @@
parameters: parameters:
ignoreErrors: ignoreErrors:
- -
message: "#^Else branch is unreachable because ternary operator condition is always true\\.$#" message: "#^Parameter \\#1 \\$autoload_function of function spl_autoload_register expects callable\\(string\\)\\: void, array\\(\\$this\\(Composer\\\\Autoload\\\\ClassLoader\\), 'loadClass'\\) given\\.$#"
count: 1 count: 1
path: ../src/Composer/Autoload/AutoloadGenerator.php path: ../src/Composer/Autoload/ClassLoader.php
- -
message: "#^Left side of && is always true\\.$#" message: "#^Parameter \\#2 \\$capabilityClassName of method Composer\\\\Plugin\\\\PluginManager\\:\\:getPluginCapability\\(\\) expects class\\-string\\<Composer\\\\Plugin\\\\Capability\\\\Capability\\>, string given\\.$#"
count: 1
path: ../src/Composer/Autoload/AutoloadGenerator.php
-
message: "#^If condition is always true\\.$#"
count: 1
path: ../src/Composer/Autoload/ClassMapGenerator.php
-
message: "#^Else branch is unreachable because previous condition is always true\\.$#"
count: 1
path: ../src/Composer/Command/BaseCommand.php
-
message: "#^Elseif branch is unreachable because previous condition is always true\\.$#"
count: 1
path: ../src/Composer/Command/BaseCommand.php
-
message: "#^Result of && is always false\\.$#"
count: 1
path: ../src/Composer/Command/DiagnoseCommand.php
-
message: "#^Strict comparison using \\!\\=\\= between '@package_version@' and '@package_version@' will always evaluate to false\\.$#"
count: 1
path: ../src/Composer/Command/DiagnoseCommand.php
-
message: "#^Ternary operator condition is always true\\.$#"
count: 1
path: ../src/Composer/Command/DiagnoseCommand.php
-
message: "#^Negated boolean expression is always false\\.$#"
count: 1
path: ../src/Composer/Command/InitCommand.php
-
message: "#^Negated boolean expression is always false\\.$#"
count: 1
path: ../src/Composer/Command/InstallCommand.php
-
message: "#^Call to function is_array\\(\\) with string will always evaluate to false\\.$#"
count: 1
path: ../src/Composer/Command/ShowCommand.php
-
message: "#^Elseif branch is unreachable because previous condition is always true\\.$#"
count: 1
path: ../src/Composer/Command/ShowCommand.php
-
message: "#^Negated boolean expression is always false\\.$#"
count: 1
path: ../src/Composer/Command/ShowCommand.php
-
message: "#^Unreachable statement \\- code above always terminates\\.$#"
count: 1
path: ../src/Composer/Composer.php
-
message: "#^If condition is always true\\.$#"
count: 1
path: ../src/Composer/Console/Application.php
-
message: "#^Left side of && is always true\\.$#"
count: 2 count: 2
path: ../src/Composer/Console/Application.php path: ../tests/Composer/Test/Plugin/PluginInstallerTest.php
-
message: "#^Strict comparison using \\!\\=\\= between '@package_branch…' and '@package_branch…' will always evaluate to false\\.$#"
count: 1
path: ../src/Composer/Console/Application.php
-
message: "#^Strict comparison using \\=\\=\\= between null and Composer\\\\Composer will always evaluate to false\\.$#"
count: 1
path: ../src/Composer/Console/Application.php
-
message: "#^Instanceof between mixed and Composer\\\\Package\\\\RootAliasPackage will always evaluate to false\\.$#"
count: 1
path: ../src/Composer/DependencyResolver/LockTransaction.php
-
message: "#^If condition is always true\\.$#"
count: 1
path: ../src/Composer/DependencyResolver/PoolBuilder.php
-
message: "#^Ternary operator condition is always true\\.$#"
count: 1
path: ../src/Composer/DependencyResolver/Problem.php
-
message: "#^If condition is always true\\.$#"
count: 2
path: ../src/Composer/Downloader/FileDownloader.php
-
message: "#^Left side of && is always true\\.$#"
count: 3
path: ../src/Composer/Downloader/FileDownloader.php
-
message: "#^Comparison operation \"\\>\" between 0 and 6 is always false\\.$#"
count: 1
path: ../src/Composer/Downloader/PathDownloader.php
-
message: "#^Comparison operation \"\\>\\=\" between 0 and 1 is always false\\.$#"
count: 1
path: ../src/Composer/Downloader/PathDownloader.php
-
message: "#^Result of && is always false\\.$#"
count: 2
path: ../src/Composer/Downloader/PathDownloader.php
-
message: "#^Result of \\|\\| is always false\\.$#"
count: 1
path: ../src/Composer/Downloader/PathDownloader.php
-
message: "#^Strict comparison using \\=\\=\\= between 0 and 6 will always evaluate to false\\.$#"
count: 1
path: ../src/Composer/Downloader/PathDownloader.php
-
message: "#^If condition is always true\\.$#"
count: 1
path: ../src/Composer/Factory.php
-
message: "#^Left side of && is always true\\.$#"
count: 3
path: ../src/Composer/Factory.php
-
message: "#^Strict comparison using \\=\\=\\= between 16 and 0 will always evaluate to false\\.$#"
count: 1
path: ../src/Composer/IO/ConsoleIO.php
-
message: "#^Result of && is always false\\.$#"
count: 1
path: ../src/Composer/InstalledVersions.php
-
message: "#^If condition is always true\\.$#"
count: 2
path: ../src/Composer/Installer.php
-
message: "#^Negated boolean expression is always false\\.$#"
count: 1
path: ../src/Composer/Installer.php
-
message: "#^Empty array passed to foreach\\.$#"
count: 1
path: ../src/Composer/Installer/InstallationManager.php
-
message: "#^Right side of && is always true\\.$#"
count: 2
path: ../src/Composer/Installer/InstallationManager.php
-
message: "#^Strict comparison using \\=\\=\\= between null and string will always evaluate to false\\.$#"
count: 1
path: ../src/Composer/Json/JsonFile.php
-
message: "#^If condition is always true\\.$#"
count: 1
path: ../src/Composer/Package/Dumper/ArrayDumper.php
-
message: "#^Ternary operator condition is always true\\.$#"
count: 1
path: ../src/Composer/Package/Link.php
-
message: "#^Unreachable statement \\- code above always terminates\\.$#"
count: 1
path: ../src/Composer/Package/Loader/ArrayLoader.php
-
message: "#^Else branch is unreachable because previous condition is always true\\.$#"
count: 1
path: ../src/Composer/Package/Locker.php
-
message: "#^If condition is always true\\.$#"
count: 3
path: ../src/Composer/Plugin/PluginManager.php
-
message: "#^Left side of && is always true\\.$#"
count: 1
path: ../src/Composer/Plugin/PluginManager.php
-
message: "#^Ternary operator condition is always true\\.$#"
count: 2
path: ../src/Composer/Plugin/PluginManager.php
-
message: "#^Instanceof between string and Composer\\\\Package\\\\PackageInterface will always evaluate to false\\.$#"
count: 1
path: ../src/Composer/Plugin/PostFileDownloadEvent.php
-
message: "#^Result of && is always false\\.$#"
count: 1
path: ../src/Composer/Plugin/PostFileDownloadEvent.php
-
message: "#^Negated boolean expression is always false\\.$#"
count: 1
path: ../src/Composer/Repository/ArrayRepository.php
-
message: "#^Strict comparison using \\=\\=\\= between null and Composer\\\\Repository\\\\RepositoryInterface will always evaluate to false\\.$#"
count: 1
path: ../src/Composer/Repository/ArrayRepository.php
-
message: "#^If condition is always false\\.$#"
count: 1
path: ../src/Composer/Repository/ComposerRepository.php
-
message: "#^Negated boolean expression is always false\\.$#"
count: 1
path: ../src/Composer/Repository/ComposerRepository.php
-
message: "#^Negated boolean expression is always true\\.$#"
count: 1
path: ../src/Composer/Repository/InstalledRepository.php
-
message: "#^Negated boolean expression is always true\\.$#"
count: 1
path: ../src/Composer/Repository/Vcs/GitBitbucketDriver.php
-
message: "#^Unreachable statement \\- code above always terminates\\.$#"
count: 1
path: ../src/Composer/Repository/Vcs/GitBitbucketDriver.php
-
message: "#^Negated boolean expression is always false\\.$#"
count: 1
path: ../src/Composer/Repository/Vcs/GitLabDriver.php
-
message: "#^Right side of && is always true\\.$#"
count: 1
path: ../src/Composer/Repository/Vcs/GitLabDriver.php

View File

@ -3,7 +3,7 @@ includes:
- ./baseline.neon - ./baseline.neon
parameters: parameters:
level: 4 level: 5
excludes_analyse: excludes_analyse:
- '../tests/Composer/Test/Fixtures/*' - '../tests/Composer/Test/Fixtures/*'
- '../tests/Composer/Test/Autoload/Fixtures/*' - '../tests/Composer/Test/Autoload/Fixtures/*'
@ -42,5 +42,11 @@ parameters:
- ../src - ../src
- ../tests - ../tests
dynamicConstantNames:
- Composer\Composer::BRANCH_ALIAS_VERSION
- Composer\Composer::VERSION
- Composer\Composer::RELEASE_DATE
- Composer\Composer::SOURCE_VERSION
rules: rules:
- Composer\PHPStanRules\AnonymousFunctionWithThisRule - Composer\PHPStanRules\AnonymousFunctionWithThisRule

View File

@ -41,7 +41,7 @@ class AutoloadGenerator
private $eventDispatcher; private $eventDispatcher;
/** /**
* @var IOInterface * @var ?IOInterface
*/ */
private $io; private $io;
@ -667,7 +667,7 @@ EOF;
$baseDir = "'phar://' . " . $baseDir; $baseDir = "'phar://' . " . $baseDir;
} }
return $baseDir . (($path !== false) ? var_export($path, true) : ""); return $baseDir . var_export($path, true);
} }
protected function getPlatformCheck(array $packageMap, array $ignorePlatformReqs, $checkPlatform, array $devPackageNames) protected function getPlatformCheck(array $packageMap, array $ignorePlatformReqs, $checkPlatform, array $devPackageNames)

View File

@ -33,7 +33,7 @@ class ClassMapGenerator
/** /**
* Generate a class map file * Generate a class map file
* *
* @param \Traversable $dirs Directories or a single path to search in * @param \Traversable|array $dirs Directories or a single path to search in
* @param string $file The name of the class map file * @param string $file The name of the class map file
*/ */
public static function dump($dirs, $file) public static function dump($dirs, $file)
@ -50,11 +50,11 @@ class ClassMapGenerator
/** /**
* Iterate over all files in the given directory searching for classes * Iterate over all files in the given directory searching for classes
* *
* @param \Iterator|string $path The path to search in or an iterator * @param \Traversable|string $path The path to search in or an iterator
* @param string $excluded Regex that matches file paths to be excluded from the classmap * @param string $excluded Regex that matches file paths to be excluded from the classmap
* @param IOInterface $io IO object * @param ?IOInterface $io IO object
* @param string $namespace Optional namespace prefix to filter by * @param ?string $namespace Optional namespace prefix to filter by
* @param string $autoloadType psr-0|psr-4 Optional autoload standard to use mapping rules * @param ?string $autoloadType psr-0|psr-4 Optional autoload standard to use mapping rules
* *
* @throws \RuntimeException When the path is neither an existing file nor directory * @throws \RuntimeException When the path is neither an existing file nor directory
* @return array A class map array * @return array A class map array
@ -152,7 +152,7 @@ class ClassMapGenerator
* @param string $baseNamespace prefix of given autoload mapping * @param string $baseNamespace prefix of given autoload mapping
* @param string $namespaceType psr-0|psr-4 * @param string $namespaceType psr-0|psr-4
* @param string $basePath root directory of given autoload mapping * @param string $basePath root directory of given autoload mapping
* @param IOInterface $io IO object * @param ?IOInterface $io IO object
* @return array valid classes * @return array valid classes
*/ */
private static function filterByNamespace($classes, $filePath, $baseNamespace, $namespaceType, $basePath, $io) private static function filterByNamespace($classes, $filePath, $baseNamespace, $namespaceType, $basePath, $io)

View File

@ -49,7 +49,7 @@ class ArchiveCommand extends BaseCommand
new InputOption('dir', null, InputOption::VALUE_REQUIRED, 'Write the archive to this directory'), new InputOption('dir', null, InputOption::VALUE_REQUIRED, 'Write the archive to this directory'),
new InputOption('file', null, InputOption::VALUE_REQUIRED, 'Write the archive with the given file name.' new InputOption('file', null, InputOption::VALUE_REQUIRED, 'Write the archive with the given file name.'
.' Note that the format will be appended.'), .' Note that the format will be appended.'),
new InputOption('ignore-filters', false, InputOption::VALUE_NONE, 'Ignore filters when saving package'), new InputOption('ignore-filters', null, InputOption::VALUE_NONE, 'Ignore filters when saving package'),
)) ))
->setHelp( ->setHelp(
<<<EOT <<<EOT

View File

@ -61,6 +61,7 @@ abstract class BaseCommand extends Command
if ($application instanceof Application) { if ($application instanceof Application) {
/* @var $application Application */ /* @var $application Application */
$this->composer = $application->getComposer($required, $disablePlugins); $this->composer = $application->getComposer($required, $disablePlugins);
/** @phpstan-ignore-next-line */
} elseif ($required) { } elseif ($required) {
throw new \RuntimeException( throw new \RuntimeException(
'Could not create a Composer\Composer instance, you must inject '. 'Could not create a Composer\Composer instance, you must inject '.
@ -109,8 +110,8 @@ abstract class BaseCommand extends Command
if (null === $this->io) { if (null === $this->io) {
$application = $this->getApplication(); $application = $this->getApplication();
if ($application instanceof Application) { if ($application instanceof Application) {
/* @var $application Application */
$this->io = $application->getIO(); $this->io = $application->getIO();
/** @phpstan-ignore-next-line */
} else { } else {
$this->io = new NullIO(); $this->io = new NullIO();
} }

View File

@ -304,9 +304,11 @@ EOT
try { try {
$url = $domain === 'github.com' ? 'https://api.'.$domain.'/' : 'https://'.$domain.'/api/v3/'; $url = $domain === 'github.com' ? 'https://api.'.$domain.'/' : 'https://'.$domain.'/api/v3/';
return $this->httpDownloader->get($url, array( $this->httpDownloader->get($url, array(
'retry-auth-failure' => false, 'retry-auth-failure' => false,
)) ? true : 'Unexpected error'; ));
return true;
} catch (\Exception $e) { } catch (\Exception $e) {
if ($e instanceof TransportException && $e->getCode() === 401) { if ($e instanceof TransportException && $e->getCode() === 401) {
return '<comment>The oauth token for '.$domain.' seems invalid, run "composer config --global --unset github-oauth.'.$domain.'" to remove it</comment>'; return '<comment>The oauth token for '.$domain.' seems invalid, run "composer config --global --unset github-oauth.'.$domain.'" to remove it</comment>';

View File

@ -43,7 +43,7 @@ use Symfony\Component\Console\Helper\FormatterHelper;
*/ */
class InitCommand extends BaseCommand class InitCommand extends BaseCommand
{ {
/** @var CompositeRepository */ /** @var ?CompositeRepository */
protected $repos; protected $repos;
/** @var array */ /** @var array */
@ -705,10 +705,11 @@ EOT
$finder = new ExecutableFinder(); $finder = new ExecutableFinder();
$gitBin = $finder->find('git'); $gitBin = $finder->find('git');
// TODO in v3 always call with an array // TODO in v2.3 always call with an array
if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandline')) { if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandline')) {
$cmd = new Process(array($gitBin, 'config', '-l')); $cmd = new Process(array($gitBin, 'config', '-l'));
} else { } else {
// @phpstan-ignore-next-line
$cmd = new Process(sprintf('%s config -l', ProcessExecutor::escape($gitBin))); $cmd = new Process(sprintf('%s config -l', ProcessExecutor::escape($gitBin)));
} }
$cmd->run(); $cmd->run();

View File

@ -320,7 +320,7 @@ EOT
'require-dev' => $rootPackage->getDevRequires(), 'require-dev' => $rootPackage->getDevRequires(),
); );
$loader = new ArrayLoader(); $loader = new ArrayLoader();
$newLinks = $loader->parseLinks($rootPackage->getName(), $rootPackage->getPrettyVersion(), BasePackage::$supportedLinkTypes[$requireKey]['description'], $requirements); $newLinks = $loader->parseLinks($rootPackage->getName(), $rootPackage->getPrettyVersion(), BasePackage::$supportedLinkTypes[$requireKey]['method'], $requirements);
$links[$requireKey] = array_merge($links[$requireKey], $newLinks); $links[$requireKey] = array_merge($links[$requireKey], $newLinks);
foreach ($requirements as $package => $constraint) { foreach ($requirements as $package => $constraint) {
unset($links[$removeKey][$package]); unset($links[$removeKey][$package]);

View File

@ -54,7 +54,7 @@ class ShowCommand extends BaseCommand
protected $versionParser; protected $versionParser;
protected $colors; protected $colors;
/** @var RepositorySet */ /** @var ?RepositorySet */
private $repositorySet; private $repositorySet;
protected function configure() protected function configure()
@ -311,12 +311,6 @@ EOT
return 0; return 0;
} }
if ($repos instanceof CompositeRepository) {
$repos = $repos->getRepositories();
} elseif (!is_array($repos)) {
$repos = array($repos);
}
// list packages // list packages
$packages = array(); $packages = array();
$packageFilterRegex = null; $packageFilterRegex = null;
@ -334,7 +328,7 @@ EOT
$input->setOption('path', false); $input->setOption('path', false);
} }
foreach ($repos as $repo) { foreach ($repos->getRepositories() as $repo) {
if ($repo === $platformRepo) { if ($repo === $platformRepo) {
$type = 'platform'; $type = 'platform';
} elseif ($lockedRepo !== null && $repo === $lockedRepo) { } elseif ($lockedRepo !== null && $repo === $lockedRepo) {
@ -1245,6 +1239,9 @@ EOT
return $candidate; return $candidate;
} }
/**
* @return RepositorySet
*/
private function getRepositorySet(Composer $composer) private function getRepositorySet(Composer $composer)
{ {
if (!$this->repositorySet) { if (!$this->repositorySet) {

View File

@ -315,6 +315,7 @@ EOT
$link->getSource(), $link->getSource(),
$link->getTarget(), $link->getTarget(),
$newConstraint, $newConstraint,
/** @phpstan-ignore-next-line */
$link->getDescription(), $link->getDescription(),
$link->getPrettyConstraint() . ', ' . $constraint $link->getPrettyConstraint() . ', ' . $constraint
); );

View File

@ -43,13 +43,25 @@ class Compiler
unlink($pharFile); unlink($pharFile);
} }
// TODO in v2.3 always call with an array
if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandline')) {
$process = new Process(array('git', 'log', '--pretty="%H"', '-n1', 'HEAD'), __DIR__);
} else {
// @phpstan-ignore-next-line
$process = new Process('git log --pretty="%H" -n1 HEAD', __DIR__); $process = new Process('git log --pretty="%H" -n1 HEAD', __DIR__);
}
if ($process->run() != 0) { if ($process->run() != 0) {
throw new \RuntimeException('Can\'t run git log. You must ensure to run compile from composer git repository clone and that git binary is available.'); throw new \RuntimeException('Can\'t run git log. You must ensure to run compile from composer git repository clone and that git binary is available.');
} }
$this->version = trim($process->getOutput()); $this->version = trim($process->getOutput());
// TODO in v2.3 always call with an array
if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandline')) {
$process = new Process(array('git', 'log', '-n1', '--pretty=%ci', 'HEAD'), __DIR__);
} else {
// @phpstan-ignore-next-line
$process = new Process('git log -n1 --pretty=%ci HEAD', __DIR__); $process = new Process('git log -n1 --pretty=%ci HEAD', __DIR__);
}
if ($process->run() != 0) { if ($process->run() != 0) {
throw new \RuntimeException('Can\'t run git log. You must ensure to run compile from composer git repository clone and that git binary is available.'); throw new \RuntimeException('Can\'t run git log. You must ensure to run compile from composer git repository clone and that git binary is available.');
} }
@ -57,7 +69,13 @@ class Compiler
$this->versionDate = new \DateTime(trim($process->getOutput())); $this->versionDate = new \DateTime(trim($process->getOutput()));
$this->versionDate->setTimezone(new \DateTimeZone('UTC')); $this->versionDate->setTimezone(new \DateTimeZone('UTC'));
// TODO in v2.3 always call with an array
if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandline')) {
$process = new Process(array('git', 'describe', '--tags', '--exact-match', 'HEAD'), __DIR__);
} else {
// @phpstan-ignore-next-line
$process = new Process('git describe --tags --exact-match HEAD'); $process = new Process('git describe --tags --exact-match HEAD');
}
if ($process->run() == 0) { if ($process->run() == 0) {
$this->version = trim($process->getOutput()); $this->version = trim($process->getOutput());
} else { } else {

View File

@ -88,9 +88,9 @@ class Composer
private $package; private $package;
/** /**
* @var Locker * @var ?Locker
*/ */
private $locker; private $locker = null;
/** /**
* @var Loop * @var Loop
@ -179,7 +179,7 @@ class Composer
} }
/** /**
* @return Locker * @return ?Locker
*/ */
public function getLocker() public function getLocker()
{ {

View File

@ -77,8 +77,8 @@ class Application extends BaseApplication
static $shutdownRegistered = false; static $shutdownRegistered = false;
if (function_exists('ini_set') && extension_loaded('xdebug')) { if (function_exists('ini_set') && extension_loaded('xdebug')) {
ini_set('xdebug.show_exception_trace', false); ini_set('xdebug.show_exception_trace', '0');
ini_set('xdebug.scream', false); ini_set('xdebug.scream', '0');
} }
if (function_exists('date_default_timezone_set') && function_exists('date_default_timezone_get')) { if (function_exists('date_default_timezone_set') && function_exists('date_default_timezone_get')) {
@ -408,7 +408,8 @@ class Application extends BaseApplication
* @param bool $required * @param bool $required
* @param bool|null $disablePlugins * @param bool|null $disablePlugins
* @throws JsonValidationException * @throws JsonValidationException
* @return \Composer\Composer * @throws \InvalidArgumentException
* @return ?\Composer\Composer If $required is true then the return value is guaranteed
*/ */
public function getComposer($required = true, $disablePlugins = null) public function getComposer($required = true, $disablePlugins = null)
{ {
@ -444,7 +445,7 @@ class Application extends BaseApplication
public function resetComposer() public function resetComposer()
{ {
$this->composer = null; $this->composer = null;
if ($this->getIO() && method_exists($this->getIO(), 'resetAuthentications')) { if (method_exists($this->getIO(), 'resetAuthentications')) {
$this->getIO()->resetAuthentications(); $this->getIO()->resetAuthentications();
} }
} }

View File

@ -14,6 +14,7 @@ namespace Composer\DependencyResolver;
use Composer\Package\BasePackage; use Composer\Package\BasePackage;
use Composer\Package\Link; use Composer\Package\Link;
use Composer\Semver\Constraint\ConstraintInterface;
/** /**
* @author Nils Adermann <naderman@naderman.de> * @author Nils Adermann <naderman@naderman.de>
@ -25,7 +26,9 @@ class GenericRule extends Rule
/** /**
* @param array $literals * @param array $literals
* @param int|null $reason A RULE_* constant describing the reason for generating this rule * @param int|null $reason A RULE_* constant describing the reason for generating this rule
* @param Link|BasePackage|int|null $reasonData * @param Link|BasePackage|int|null|array $reasonData
*
* @phpstan-param Link|BasePackage|int|null|array{packageName: string, constraint: ConstraintInterface} $reasonData
*/ */
public function __construct(array $literals, $reason, $reasonData) public function __construct(array $literals, $reason, $reasonData)
{ {

View File

@ -13,7 +13,8 @@
namespace Composer\DependencyResolver; namespace Composer\DependencyResolver;
use Composer\Package\AliasPackage; use Composer\Package\AliasPackage;
use Composer\Package\RootAliasPackage; use Composer\Package\BasePackage;
use Composer\Package\Package;
/** /**
* @author Nils Adermann <naderman@naderman.de> * @author Nils Adermann <naderman@naderman.de>
@ -23,22 +24,32 @@ class LockTransaction extends Transaction
{ {
/** /**
* packages in current lock file, platform repo or otherwise present * packages in current lock file, platform repo or otherwise present
* @var array *
* Indexed by spl_object_hash
*
* @var array<string, BasePackage>
*/ */
protected $presentMap; protected $presentMap;
/** /**
* Packages which cannot be mapped, platform repo, root package, other fixed repos * Packages which cannot be mapped, platform repo, root package, other fixed repos
* @var array *
* Indexed by package id
*
* @var array<int, BasePackage>
*/ */
protected $unlockableMap; protected $unlockableMap;
/** /**
* @var array * @var array{dev: BasePackage[], non-dev: BasePackage[], all: BasePackage[]}
*/ */
protected $resultPackages; protected $resultPackages;
public function __construct(Pool $pool, $presentMap, $unlockableMap, $decisions) /**
* @param array<string, BasePackage> $presentMap
* @param array<int, BasePackage> $unlockableMap
*/
public function __construct(Pool $pool, array $presentMap, array $unlockableMap, Decisions $decisions)
{ {
$this->presentMap = $presentMap; $this->presentMap = $presentMap;
$this->unlockableMap = $unlockableMap; $this->unlockableMap = $unlockableMap;
@ -88,7 +99,7 @@ class LockTransaction extends Transaction
{ {
$packages = array(); $packages = array();
foreach ($this->resultPackages[$devMode ? 'dev' : 'non-dev'] as $package) { foreach ($this->resultPackages[$devMode ? 'dev' : 'non-dev'] as $package) {
if (!($package instanceof AliasPackage) && !($package instanceof RootAliasPackage)) { if (!$package instanceof AliasPackage) {
// if we're just updating mirrors we need to reset references to the same as currently "present" packages' references to keep the lock file as-is // if we're just updating mirrors we need to reset references to the same as currently "present" packages' references to keep the lock file as-is
// we do not reset references if the currently present package didn't have any, or if the type of VCS has changed // we do not reset references if the currently present package didn't have any, or if the type of VCS has changed
if ($updateMirrors && !isset($this->presentMap[spl_object_hash($package)])) { if ($updateMirrors && !isset($this->presentMap[spl_object_hash($package)])) {
@ -97,7 +108,7 @@ class LockTransaction extends Transaction
if ($presentPackage->getSourceReference() && $presentPackage->getSourceType() === $package->getSourceType()) { if ($presentPackage->getSourceReference() && $presentPackage->getSourceType() === $package->getSourceType()) {
$package->setSourceDistReferences($presentPackage->getSourceReference()); $package->setSourceDistReferences($presentPackage->getSourceReference());
} }
if ($presentPackage->getReleaseDate()) { if ($presentPackage->getReleaseDate() && $package instanceof Package) {
$package->setReleaseDate($presentPackage->getReleaseDate()); $package->setReleaseDate($presentPackage->getReleaseDate());
} }
} }

View File

@ -202,7 +202,7 @@ class Pool implements \Countable
$str = "Pool:\n"; $str = "Pool:\n";
foreach ($this->packages as $package) { foreach ($this->packages as $package) {
$str .= '- '.str_pad($package->id, 6, ' ', STR_PAD_LEFT).': '.$package->getName()."\n"; $str .= '- '.str_pad((string) $package->id, 6, ' ', STR_PAD_LEFT).': '.$package->getName()."\n";
} }
return $str; return $str;

View File

@ -17,6 +17,7 @@ use Composer\IO\IOInterface;
use Composer\Package\AliasPackage; use Composer\Package\AliasPackage;
use Composer\Package\BasePackage; use Composer\Package\BasePackage;
use Composer\Package\CompleteAliasPackage; use Composer\Package\CompleteAliasPackage;
use Composer\Package\CompletePackage;
use Composer\Package\CompletePackageInterface; use Composer\Package\CompletePackageInterface;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Package\Version\StabilityFilter; use Composer\Package\Version\StabilityFilter;
@ -38,10 +39,12 @@ class PoolBuilder
{ {
/** /**
* @var int[] * @var int[]
* @phpstan-var array<string, BasePackage::STABILITY_*>
*/ */
private $acceptableStabilities; private $acceptableStabilities;
/** /**
* @var int[] * @var int[]
* @phpstan-var array<string, BasePackage::STABILITY_*>
*/ */
private $stabilityFlags; private $stabilityFlags;
/** /**
@ -55,7 +58,7 @@ class PoolBuilder
*/ */
private $rootReferences; private $rootReferences;
/** /**
* @var EventDispatcher * @var ?EventDispatcher
*/ */
private $eventDispatcher; private $eventDispatcher;
/** /**
@ -340,7 +343,7 @@ class PoolBuilder
} }
} }
private function loadPackage(Request $request, PackageInterface $package, $propagateUpdate = true) private function loadPackage(Request $request, BasePackage $package, $propagateUpdate = true)
{ {
$index = $this->indexCounter++; $index = $this->indexCounter++;
$this->packages[$index] = $package; $this->packages[$index] = $package;
@ -370,7 +373,7 @@ class PoolBuilder
} else { } else {
$basePackage = $package; $basePackage = $package;
} }
if ($basePackage instanceof CompletePackageInterface) { if ($basePackage instanceof CompletePackage) {
$aliasPackage = new CompleteAliasPackage($basePackage, $alias['alias_normalized'], $alias['alias']); $aliasPackage = new CompleteAliasPackage($basePackage, $alias['alias_normalized'], $alias['alias']);
} else { } else {
$aliasPackage = new AliasPackage($basePackage, $alias['alias_normalized'], $alias['alias']); $aliasPackage = new AliasPackage($basePackage, $alias['alias_normalized'], $alias['alias']);

View File

@ -18,6 +18,7 @@ use Composer\Package\RootPackageInterface;
use Composer\Repository\RepositorySet; use Composer\Repository\RepositorySet;
use Composer\Repository\LockArrayRepository; use Composer\Repository\LockArrayRepository;
use Composer\Semver\Constraint\Constraint; use Composer\Semver\Constraint\Constraint;
use Composer\Semver\Constraint\ConstraintInterface;
use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionParser;
/** /**
@ -459,7 +460,7 @@ class Problem
/** /**
* Turns a constraint into text usable in a sentence describing a request * Turns a constraint into text usable in a sentence describing a request
* *
* @param \Composer\Semver\Constraint\ConstraintInterface $constraint * @param ?ConstraintInterface $constraint
* @return string * @return string
*/ */
protected static function constraintToText($constraint) protected static function constraintToText($constraint)

View File

@ -401,7 +401,7 @@ class DownloadManager
} }
/** /**
* @return string[] * @return array<'dist'|'source'>&non-empty-array
*/ */
private function getAvailableSources(PackageInterface $package, PackageInterface $prevPackage = null) private function getAvailableSources(PackageInterface $package, PackageInterface $prevPackage = null)
{ {

View File

@ -51,9 +51,9 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
protected $httpDownloader; protected $httpDownloader;
/** @var Filesystem */ /** @var Filesystem */
protected $filesystem; protected $filesystem;
/** @var Cache */ /** @var ?Cache */
protected $cache; protected $cache;
/** @var EventDispatcher */ /** @var ?EventDispatcher */
protected $eventDispatcher; protected $eventDispatcher;
/** @var ProcessExecutor */ /** @var ProcessExecutor */
protected $process; protected $process;

View File

@ -38,6 +38,7 @@ use Composer\Autoload\AutoloadGenerator;
use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionParser;
use Composer\Downloader\TransportException; use Composer\Downloader\TransportException;
use Composer\Json\JsonValidationException; use Composer\Json\JsonValidationException;
use Composer\Repository\InstalledRepositoryInterface;
use Seld\JsonLint\JsonParser; use Seld\JsonLint\JsonParser;
/** /**
@ -434,10 +435,8 @@ class Factory
// once everything is initialized we can // once everything is initialized we can
// purge packages from local repos if they have been deleted on the filesystem // purge packages from local repos if they have been deleted on the filesystem
if ($rm->getLocalRepository()) {
$this->purgePackages($rm->getLocalRepository(), $im); $this->purgePackages($rm->getLocalRepository(), $im);
} }
}
return $composer; return $composer;
} }
@ -585,10 +584,10 @@ class Factory
} }
/** /**
* @param WritableRepositoryInterface $repo repository to purge packages from * @param InstalledRepositoryInterface $repo repository to purge packages from
* @param Installer\InstallationManager $im manager to check whether packages are still installed * @param Installer\InstallationManager $im manager to check whether packages are still installed
*/ */
protected function purgePackages(WritableRepositoryInterface $repo, Installer\InstallationManager $im) protected function purgePackages(InstalledRepositoryInterface $repo, Installer\InstallationManager $im)
{ {
foreach ($repo->getPackages() as $package) { foreach ($repo->getPackages() as $package) {
if (!$im->isPackageInstalled($repo, $package)) { if (!$im->isPackageInstalled($repo, $package)) {
@ -632,7 +631,7 @@ class Factory
if (isset($_SERVER['argv']) && in_array('disable-tls', $_SERVER['argv']) && (in_array('conf', $_SERVER['argv']) || in_array('config', $_SERVER['argv']))) { if (isset($_SERVER['argv']) && in_array('disable-tls', $_SERVER['argv']) && (in_array('conf', $_SERVER['argv']) || in_array('config', $_SERVER['argv']))) {
$warned = true; $warned = true;
$disableTls = !extension_loaded('openssl'); $disableTls = !extension_loaded('openssl');
} elseif ($config && $config->get('disable-tls') === true) { } elseif ($config->get('disable-tls') === true) {
if (!$warned) { if (!$warned) {
$io->writeError('<warning>You are running Composer with SSL/TLS protection disabled.</warning>'); $io->writeError('<warning>You are running Composer with SSL/TLS protection disabled.</warning>');
} }
@ -644,10 +643,10 @@ class Factory
} }
$httpDownloaderOptions = array(); $httpDownloaderOptions = array();
if ($disableTls === false) { if ($disableTls === false) {
if ($config && $config->get('cafile')) { if ($config->get('cafile')) {
$httpDownloaderOptions['ssl']['cafile'] = $config->get('cafile'); $httpDownloaderOptions['ssl']['cafile'] = $config->get('cafile');
} }
if ($config && $config->get('capath')) { if ($config->get('capath')) {
$httpDownloaderOptions['ssl']['capath'] = $config->get('capath'); $httpDownloaderOptions['ssl']['capath'] = $config->get('capath');
} }
$httpDownloaderOptions = array_replace_recursive($httpDownloaderOptions, $options); $httpDownloaderOptions = array_replace_recursive($httpDownloaderOptions, $options);

View File

@ -159,13 +159,6 @@ class ConsoleIO extends BaseIO
return; return;
} }
// hack to keep our usage BC with symfony<2.8 versions
// this removes the quiet output but there is no way around it
// see https://github.com/composer/composer/pull/4913
if (OutputInterface::VERBOSITY_QUIET === 0) {
$sfVerbosity = OutputInterface::OUTPUT_NORMAL;
}
if ($raw) { if ($raw) {
if ($sfVerbosity === OutputInterface::OUTPUT_NORMAL) { if ($sfVerbosity === OutputInterface::OUTPUT_NORMAL) {
$sfVerbosity = OutputInterface::OUTPUT_RAW; $sfVerbosity = OutputInterface::OUTPUT_RAW;

View File

@ -228,7 +228,7 @@ class InstalledVersions
/** /**
* @return array * @return array
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string} * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
*/ */
public static function getRootPackage() public static function getRootPackage()
{ {
@ -242,7 +242,7 @@ class InstalledVersions
* *
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[] * @return array[]
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>} * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
*/ */
public static function getRawData() public static function getRawData()
{ {
@ -265,7 +265,7 @@ class InstalledVersions
* Returns the raw data of all installed.php which are currently loaded for custom implementations * Returns the raw data of all installed.php which are currently loaded for custom implementations
* *
* @return array[] * @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}> * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
*/ */
public static function getAllRawData() public static function getAllRawData()
{ {
@ -288,7 +288,7 @@ class InstalledVersions
* @param array[] $data A vendor/composer/installed.php data set * @param array[] $data A vendor/composer/installed.php data set
* @return void * @return void
* *
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>} $data * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
*/ */
public static function reload($data) public static function reload($data)
{ {
@ -298,7 +298,7 @@ class InstalledVersions
/** /**
* @return array[] * @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}> * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
*/ */
private static function getInstalled() private static function getInstalled()
{ {

View File

@ -152,7 +152,7 @@ class Installer
protected $suggestedPackagesReporter; protected $suggestedPackagesReporter;
/** /**
* @var RepositoryInterface * @var ?RepositoryInterface
*/ */
protected $additionalFixedRepository; protected $additionalFixedRepository;
@ -180,6 +180,7 @@ class Installer
$this->installationManager = $installationManager; $this->installationManager = $installationManager;
$this->eventDispatcher = $eventDispatcher; $this->eventDispatcher = $eventDispatcher;
$this->autoloadGenerator = $autoloadGenerator; $this->autoloadGenerator = $autoloadGenerator;
$this->suggestedPackagesReporter = new SuggestedPackagesReporter($this->io);
$this->writeLock = $config->get('lock'); $this->writeLock = $config->get('lock');
} }
@ -238,10 +239,6 @@ class Installer
$localRepo = $this->repositoryManager->getLocalRepository(); $localRepo = $this->repositoryManager->getLocalRepository();
if (!$this->suggestedPackagesReporter) {
$this->suggestedPackagesReporter = new SuggestedPackagesReporter($this->io);
}
try { try {
if ($this->update) { if ($this->update) {
$res = $this->doUpdate($localRepo, $this->install); $res = $this->doUpdate($localRepo, $this->install);

View File

@ -47,7 +47,7 @@ class InstallationManager
private $loop; private $loop;
/** @var IOInterface */ /** @var IOInterface */
private $io; private $io;
/** @var EventDispatcher */ /** @var ?EventDispatcher */
private $eventDispatcher; private $eventDispatcher;
/** @var bool */ /** @var bool */
private $outputProgress; private $outputProgress;
@ -179,6 +179,7 @@ class InstallationManager
*/ */
public function execute(InstalledRepositoryInterface $repo, array $operations, $devMode = true, $runScripts = true) public function execute(InstalledRepositoryInterface $repo, array $operations, $devMode = true, $runScripts = true)
{ {
/** @var PromiseInterface[] */
$cleanupPromises = array(); $cleanupPromises = array();
$loop = $this->loop; $loop = $this->loop;

View File

@ -291,7 +291,7 @@ class JsonFile
/** /**
* Parses json string and returns hash. * Parses json string and returns hash.
* *
* @param string $json json string * @param ?string $json json string
* @param string $file the json file * @param string $file the json file
* *
* @throws ParsingException * @throws ParsingException
@ -300,7 +300,7 @@ class JsonFile
public static function parseJson($json, $file = null) public static function parseJson($json, $file = null)
{ {
if (null === $json) { if (null === $json) {
return; return null;
} }
$data = json_decode($json, true); $data = json_decode($json, true);
if (null === $data && JSON_ERROR_NONE !== json_last_error()) { if (null === $data && JSON_ERROR_NONE !== json_last_error()) {

View File

@ -113,6 +113,7 @@ class AliasPackage extends BasePackage
/** /**
* {@inheritDoc} * {@inheritDoc}
* @return array<string|int, Link>
*/ */
public function getConflicts() public function getConflicts()
{ {
@ -121,6 +122,7 @@ class AliasPackage extends BasePackage
/** /**
* {@inheritDoc} * {@inheritDoc}
* @return array<string|int, Link>
*/ */
public function getProvides() public function getProvides()
{ {
@ -129,6 +131,7 @@ class AliasPackage extends BasePackage
/** /**
* {@inheritDoc} * {@inheritDoc}
* @return array<string|int, Link>
*/ */
public function getReplaces() public function getReplaces()
{ {
@ -168,7 +171,7 @@ class AliasPackage extends BasePackage
/** /**
* @param Link[] $links * @param Link[] $links
* @param string $linkType * @param Link::TYPE_* $linkType
* *
* @return Link[] * @return Link[]
*/ */

View File

@ -24,6 +24,7 @@ abstract class BasePackage implements PackageInterface
{ {
/** /**
* @phpstan-var array<string, array{description: string, method: Link::TYPE_*}> * @phpstan-var array<string, array{description: string, method: Link::TYPE_*}>
* @internal
*/ */
public static $supportedLinkTypes = array( public static $supportedLinkTypes = array(
'require' => array('description' => 'requires', 'method' => Link::TYPE_REQUIRE), 'require' => array('description' => 'requires', 'method' => Link::TYPE_REQUIRE),

View File

@ -26,6 +26,12 @@ class Link
const TYPE_PROVIDE = 'provides'; const TYPE_PROVIDE = 'provides';
const TYPE_CONFLICT = 'conflicts'; const TYPE_CONFLICT = 'conflicts';
const TYPE_REPLACE = 'replaces'; const TYPE_REPLACE = 'replaces';
/**
* Special type
* @internal
*/
const TYPE_DOES_NOT_REQUIRE = 'does not require';
/** /**
* TODO should be marked private once 5.3 is dropped * TODO should be marked private once 5.3 is dropped
* @private * @private
@ -37,6 +43,7 @@ class Link
* *
* @internal * @internal
* @var string[] * @var string[]
* @phpstan-var array<self::TYPE_REQUIRE|self::TYPE_DEV_REQUIRE|self::TYPE_PROVIDE|self::TYPE_CONFLICT|self::TYPE_REPLACE>
*/ */
public static $TYPES = array( public static $TYPES = array(
self::TYPE_REQUIRE, self::TYPE_REQUIRE,
@ -63,12 +70,12 @@ class Link
/** /**
* @var string * @var string
* @phpstan-var self::TYPE_* $description * @phpstan-var string $description
*/ */
protected $description; protected $description;
/** /**
* @var string|null * @var ?string
*/ */
protected $prettyConstraint; protected $prettyConstraint;
@ -91,7 +98,7 @@ class Link
$this->source = strtolower($source); $this->source = strtolower($source);
$this->target = strtolower($target); $this->target = strtolower($target);
$this->constraint = $constraint; $this->constraint = $constraint;
$this->description = $description; $this->description = self::TYPE_DEV_REQUIRE === $description ? 'requires (for development)' : $description;
$this->prettyConstraint = $prettyConstraint; $this->prettyConstraint = $prettyConstraint;
} }
@ -154,6 +161,6 @@ class Link
*/ */
public function getPrettyString(PackageInterface $sourcePackage) public function getPrettyString(PackageInterface $sourcePackage)
{ {
return $sourcePackage->getPrettyString().' '.$this->description.' '.$this->target.($this->constraint ? ' '.$this->constraint->getPrettyString() : ''); return $sourcePackage->getPrettyString().' '.$this->description.' '.$this->target.' '.$this->constraint->getPrettyString();
} }
} }

View File

@ -45,9 +45,12 @@ class ArrayLoader implements LoaderInterface
/** /**
* @template PackageClass of CompletePackageInterface * @template PackageClass of CompletePackageInterface
*
* @param array $config package data * @param array $config package data
* @param string $class FQCN to be instantiated * @param string $class FQCN to be instantiated
* @return CompletePackage|CompleteAliasPackage *
* @return CompletePackage|CompleteAliasPackage|RootPackage|RootAliasPackage
*
* @phpstan-param class-string<PackageClass> $class * @phpstan-param class-string<PackageClass> $class
*/ */
public function load(array $config, $class = 'Composer\Package\CompletePackage') public function load(array $config, $class = 'Composer\Package\CompletePackage')
@ -65,7 +68,7 @@ class ArrayLoader implements LoaderInterface
$this->parseLinks( $this->parseLinks(
$package->getName(), $package->getName(),
$package->getPrettyVersion(), $package->getPrettyVersion(),
$opts['description'], $opts['method'],
$config[$type] $config[$type]
) )
); );
@ -78,23 +81,16 @@ class ArrayLoader implements LoaderInterface
} }
/** /**
* @template PackageClass of CompletePackageInterface
* @param array $versions * @param array $versions
* @param string $class FQCN to be instantiated
* @return list<CompletePackage|CompleteAliasPackage> * @return list<CompletePackage|CompleteAliasPackage>
* @phpstan-param class-string<PackageClass> $class
*/ */
public function loadPackages(array $versions, $class = 'Composer\Package\CompletePackage') public function loadPackages(array $versions)
{ {
if ($class !== 'Composer\Package\CompletePackage') {
trigger_error('The $class arg is deprecated, please reach out to Composer maintainers ASAP if you still need this.', E_USER_DEPRECATED);
}
$packages = array(); $packages = array();
$linkCache = array(); $linkCache = array();
foreach ($versions as $version) { foreach ($versions as $version) {
$package = $this->createObject($version, $class); $package = $this->createObject($version, 'Composer\Package\CompletePackage');
$this->configureCachedLinks($linkCache, $package, $version); $this->configureCachedLinks($linkCache, $package, $version);
$package = $this->configureObject($package, $version); $package = $this->configureObject($package, $version);
@ -137,14 +133,14 @@ class ArrayLoader implements LoaderInterface
} }
/** /**
* @param CompletePackageInterface $package * @param CompletePackage $package
* @param array $config package data * @param array $config package data
* @return RootPackage|RootAliasPackage|CompletePackage|CompleteAliasPackage * @return RootPackage|RootAliasPackage|CompletePackage|CompleteAliasPackage
*/ */
private function configureObject(PackageInterface $package, array $config) private function configureObject(PackageInterface $package, array $config)
{ {
if (!$package instanceof Package) { if (!$package instanceof CompletePackage) {
throw new \LogicException('ArrayLoader expects instances of the Composer\Package\Package class to function correctly'); throw new \LogicException('ArrayLoader expects instances of the Composer\Package\CompletePackage class to function correctly');
} }
$package->setType(isset($config['type']) ? strtolower($config['type']) : 'library'); $package->setType(isset($config['type']) ? strtolower($config['type']) : 'library');
@ -302,17 +298,13 @@ class ArrayLoader implements LoaderInterface
if ($aliasNormalized = $this->getBranchAlias($config)) { if ($aliasNormalized = $this->getBranchAlias($config)) {
$prettyAlias = preg_replace('{(\.9{7})+}', '.x', $aliasNormalized); $prettyAlias = preg_replace('{(\.9{7})+}', '.x', $aliasNormalized);
if ($package instanceof RootPackageInterface) { if ($package instanceof RootPackage) {
return new RootAliasPackage($package, $aliasNormalized, $prettyAlias); return new RootAliasPackage($package, $aliasNormalized, $prettyAlias);
} }
if ($package instanceof CompletePackageInterface) {
return new CompleteAliasPackage($package, $aliasNormalized, $prettyAlias); return new CompleteAliasPackage($package, $aliasNormalized, $prettyAlias);
} }
return new AliasPackage($package, $aliasNormalized, $prettyAlias);
}
return $package; return $package;
} }
@ -335,10 +327,10 @@ class ArrayLoader implements LoaderInterface
foreach ($config[$type] as $prettyTarget => $constraint) { foreach ($config[$type] as $prettyTarget => $constraint) {
$target = strtolower($prettyTarget); $target = strtolower($prettyTarget);
if ($constraint === 'self.version') { if ($constraint === 'self.version') {
$links[$target] = $this->createLink($name, $prettyVersion, $opts['description'], $target, $constraint); $links[$target] = $this->createLink($name, $prettyVersion, $opts['method'], $target, $constraint);
} else { } else {
if (!isset($linkCache[$name][$type][$target][$constraint])) { if (!isset($linkCache[$name][$type][$target][$constraint])) {
$linkCache[$name][$type][$target][$constraint] = array($target, $this->createLink($name, $prettyVersion, $opts['description'], $target, $constraint)); $linkCache[$name][$type][$target][$constraint] = array($target, $this->createLink($name, $prettyVersion, $opts['method'], $target, $constraint));
} }
list($target, $link) = $linkCache[$name][$type][$target][$constraint]; list($target, $link) = $linkCache[$name][$type][$target][$constraint];

View File

@ -186,11 +186,7 @@ class Locker
if (isset($lockData['aliases'])) { if (isset($lockData['aliases'])) {
foreach ($lockData['aliases'] as $alias) { foreach ($lockData['aliases'] as $alias) {
if (isset($packageByName[$alias['package']])) { if (isset($packageByName[$alias['package']])) {
if ($packageByName[$alias['package']] instanceof CompletePackageInterface) {
$aliasPkg = new CompleteAliasPackage($packageByName[$alias['package']], $alias['alias_normalized'], $alias['alias']); $aliasPkg = new CompleteAliasPackage($packageByName[$alias['package']], $alias['alias_normalized'], $alias['alias']);
} else {
$aliasPkg = new AliasPackage($packageByName[$alias['package']], $alias['alias_normalized'], $alias['alias']);
}
$aliasPkg->setRootPackageAlias(true); $aliasPkg->setRootPackageAlias(true);
$packages->addPackage($aliasPkg); $packages->addPackage($aliasPkg);
} }

View File

@ -22,46 +22,68 @@ use Composer\Util\ComposerMirror;
*/ */
class Package extends BasePackage class Package extends BasePackage
{ {
/** @var string */
protected $type; protected $type;
/** @var ?string */
protected $targetDir; protected $targetDir;
/** @var 'source'|'dist'|null */
protected $installationSource; protected $installationSource;
/** @var ?string */
protected $sourceType; protected $sourceType;
/** @var ?string */
protected $sourceUrl; protected $sourceUrl;
/** @var ?string */ /** @var ?string */
protected $sourceReference; protected $sourceReference;
/** @var ?array */
protected $sourceMirrors; protected $sourceMirrors;
/** @var ?string */
protected $distType; protected $distType;
/** @var ?string */
protected $distUrl; protected $distUrl;
/** @var ?string */ /** @var ?string */
protected $distReference; protected $distReference;
/** @var ?string */ /** @var ?string */
protected $distSha1Checksum; protected $distSha1Checksum;
/** @var ?array */
protected $distMirrors; protected $distMirrors;
/** @var string */
protected $version; protected $version;
/** @var string */
protected $prettyVersion; protected $prettyVersion;
/** @var ?\DateTime */
protected $releaseDate; protected $releaseDate;
/** @var mixed[] */
protected $extra = array(); protected $extra = array();
/** @var string[] */
protected $binaries = array(); protected $binaries = array();
/** @var bool */
protected $dev; protected $dev;
/** @var string */
protected $stability; protected $stability;
/** @var ?string */
protected $notificationUrl; protected $notificationUrl;
/** @var Link[] */ /** @var array<string, Link> */
protected $requires = array(); protected $requires = array();
/** @var Link[] */ /** @var array<string, Link> */
protected $conflicts = array(); protected $conflicts = array();
/** @var Link[] */ /** @var array<string, Link> */
protected $provides = array(); protected $provides = array();
/** @var Link[] */ /** @var array<string, Link> */
protected $replaces = array(); protected $replaces = array();
/** @var Link[] */ /** @var array<string, Link> */
protected $devRequires = array(); protected $devRequires = array();
/** @var array<string, string> */
protected $suggests = array(); protected $suggests = array();
/** @var array{psr-0?: array<string, string|string[]>, psr-4?: array<string, string|string[]>, classmap?: list<string>, files?: list<string>} */
protected $autoload = array(); protected $autoload = array();
/** @var array{psr-0?: array<string, string|string[]>, psr-4?: array<string, string|string[]>, classmap?: list<string>, files?: list<string>} */
protected $devAutoload = array(); protected $devAutoload = array();
/** @var string[] */
protected $includePaths = array(); protected $includePaths = array();
/** @var bool */
protected $isDefaultBranch = false; protected $isDefaultBranch = false;
/** @var array */ /** @var mixed[] */
protected $transportOptions = array(); protected $transportOptions = array();
/** /**
@ -395,7 +417,7 @@ class Package extends BasePackage
/** /**
* Set the required packages * Set the required packages
* *
* @param Link[] $requires A set of package links * @param array<string, Link> $requires A set of package links
*/ */
public function setRequires(array $requires) public function setRequires(array $requires)
{ {
@ -413,7 +435,7 @@ class Package extends BasePackage
/** /**
* Set the conflicting packages * Set the conflicting packages
* *
* @param Link[] $conflicts A set of package links * @param array<string, Link> $conflicts A set of package links
*/ */
public function setConflicts(array $conflicts) public function setConflicts(array $conflicts)
{ {
@ -422,6 +444,7 @@ class Package extends BasePackage
/** /**
* {@inheritDoc} * {@inheritDoc}
* @return array<string, Link>
*/ */
public function getConflicts() public function getConflicts()
{ {
@ -431,7 +454,7 @@ class Package extends BasePackage
/** /**
* Set the provided virtual packages * Set the provided virtual packages
* *
* @param Link[] $provides A set of package links * @param array<string, Link> $provides A set of package links
*/ */
public function setProvides(array $provides) public function setProvides(array $provides)
{ {
@ -440,6 +463,7 @@ class Package extends BasePackage
/** /**
* {@inheritDoc} * {@inheritDoc}
* @return array<string, Link>
*/ */
public function getProvides() public function getProvides()
{ {
@ -449,7 +473,7 @@ class Package extends BasePackage
/** /**
* Set the packages this one replaces * Set the packages this one replaces
* *
* @param Link[] $replaces A set of package links * @param array<string, Link> $replaces A set of package links
*/ */
public function setReplaces(array $replaces) public function setReplaces(array $replaces)
{ {
@ -458,6 +482,7 @@ class Package extends BasePackage
/** /**
* {@inheritDoc} * {@inheritDoc}
* @return array<string, Link>
*/ */
public function getReplaces() public function getReplaces()
{ {
@ -467,7 +492,7 @@ class Package extends BasePackage
/** /**
* Set the recommended packages * Set the recommended packages
* *
* @param Link[] $devRequires A set of package links * @param array<string, Link> $devRequires A set of package links
*/ */
public function setDevRequires(array $devRequires) public function setDevRequires(array $devRequires)
{ {
@ -485,7 +510,7 @@ class Package extends BasePackage
/** /**
* Set the suggested packages * Set the suggested packages
* *
* @param array $suggests A set of package names/comments * @param array<string, string> $suggests A set of package names/comments
*/ */
public function setSuggests(array $suggests) public function setSuggests(array $suggests)
{ {

View File

@ -82,14 +82,14 @@ interface PackageInterface
/** /**
* Returns the package targetDir property * Returns the package targetDir property
* *
* @return string|null The package targetDir * @return ?string The package targetDir
*/ */
public function getTargetDir(); public function getTargetDir();
/** /**
* Returns the package extra data * Returns the package extra data
* *
* @return array The package extra data * @return mixed[] The package extra data
*/ */
public function getExtra(); public function getExtra();
@ -97,27 +97,29 @@ interface PackageInterface
* Sets source from which this package was installed (source/dist). * Sets source from which this package was installed (source/dist).
* *
* @param string $type source/dist * @param string $type source/dist
* @phpstan-param 'source'|'dist'|null $type
*/ */
public function setInstallationSource($type); public function setInstallationSource($type);
/** /**
* Returns source from which this package was installed (source/dist). * Returns source from which this package was installed (source/dist).
* *
* @return string source/dist * @return ?string source/dist
* @phpstan-return 'source'|'dist'|null
*/ */
public function getInstallationSource(); public function getInstallationSource();
/** /**
* Returns the repository type of this package, e.g. git, svn * Returns the repository type of this package, e.g. git, svn
* *
* @return string The repository type * @return ?string The repository type
*/ */
public function getSourceType(); public function getSourceType();
/** /**
* Returns the repository url of this package, e.g. git://github.com/naderman/composer.git * Returns the repository url of this package, e.g. git://github.com/naderman/composer.git
* *
* @return string The repository url * @return ?string The repository url
*/ */
public function getSourceUrl(); public function getSourceUrl();
@ -138,12 +140,12 @@ interface PackageInterface
/** /**
* Returns the source mirrors of this package * Returns the source mirrors of this package
* *
* @return array|null * @return ?array
*/ */
public function getSourceMirrors(); public function getSourceMirrors();
/** /**
* @param array|null $mirrors * @param ?array $mirrors
* @return void * @return void
*/ */
public function setSourceMirrors($mirrors); public function setSourceMirrors($mirrors);
@ -151,14 +153,14 @@ interface PackageInterface
/** /**
* Returns the type of the distribution archive of this version, e.g. zip, tarball * Returns the type of the distribution archive of this version, e.g. zip, tarball
* *
* @return string The repository type * @return ?string The repository type
*/ */
public function getDistType(); public function getDistType();
/** /**
* Returns the url of the distribution archive of this version * Returns the url of the distribution archive of this version
* *
* @return string * @return ?string
*/ */
public function getDistUrl(); public function getDistUrl();
@ -186,12 +188,12 @@ interface PackageInterface
/** /**
* Returns the dist mirrors of this package * Returns the dist mirrors of this package
* *
* @return array|null * @return ?array
*/ */
public function getDistMirrors(); public function getDistMirrors();
/** /**
* @param array|null $mirrors * @param ?array $mirrors
* @return void * @return void
*/ */
public function setDistMirrors($mirrors); public function setDistMirrors($mirrors);
@ -226,7 +228,7 @@ interface PackageInterface
/** /**
* Returns the release date of the package * Returns the release date of the package
* *
* @return \DateTime * @return ?\DateTime
*/ */
public function getReleaseDate(); public function getReleaseDate();
@ -241,7 +243,7 @@ interface PackageInterface
* Returns a set of links to packages which need to be installed before * Returns a set of links to packages which need to be installed before
* this package can be installed * this package can be installed
* *
* @return Link[] An array of package links defining required packages * @return array<string, Link> An array of package links defining required packages
*/ */
public function getRequires(); public function getRequires();
@ -273,7 +275,7 @@ interface PackageInterface
* Returns a set of links to packages which are required to develop * Returns a set of links to packages which are required to develop
* this package. These are installed if in dev mode. * this package. These are installed if in dev mode.
* *
* @return Link[] An array of package links defining packages required for development * @return array<string, Link> An array of package links defining packages required for development
*/ */
public function getDevRequires(); public function getDevRequires();
@ -295,7 +297,7 @@ interface PackageInterface
* directories for autoloading using the type specified. * directories for autoloading using the type specified.
* *
* @return array Mapping of autoloading rules * @return array Mapping of autoloading rules
* @phpstan-return array{psr-0?: array<string, string>, psr-4?: array<string, string>, classmap?: list<string>, files?: list<string>} * @phpstan-return array{psr-0?: array<string, string|string[]>, psr-4?: array<string, string|string[]>, classmap?: list<string>, files?: list<string>}
*/ */
public function getAutoload(); public function getAutoload();
@ -308,7 +310,7 @@ interface PackageInterface
* directories for autoloading using the type specified. * directories for autoloading using the type specified.
* *
* @return array Mapping of dev autoloading rules * @return array Mapping of dev autoloading rules
* @phpstan-return array{psr-0?: array<string, string>, psr-4?: array<string, string>, classmap?: list<string>, files?: list<string>} * @phpstan-return array{psr-0?: array<string, string|string[]>, psr-4?: array<string, string|string[]>, classmap?: list<string>, files?: list<string>}
*/ */
public function getDevAutoload(); public function getDevAutoload();
@ -330,7 +332,7 @@ interface PackageInterface
/** /**
* Returns a reference to the repository that owns the package * Returns a reference to the repository that owns the package
* *
* @return RepositoryInterface * @return ?RepositoryInterface
*/ */
public function getRepository(); public function getRepository();
@ -351,7 +353,7 @@ interface PackageInterface
/** /**
* Returns the package notification url * Returns the package notification url
* *
* @return string * @return ?string
*/ */
public function getNotificationUrl(); public function getNotificationUrl();
@ -377,7 +379,7 @@ interface PackageInterface
/** /**
* Returns a list of options to download package dist files * Returns a list of options to download package dist files
* *
* @return array * @return mixed[]
*/ */
public function getTransportOptions(); public function getTransportOptions();

View File

@ -17,23 +17,23 @@ namespace Composer\Package;
*/ */
class RootAliasPackage extends CompleteAliasPackage implements RootPackageInterface class RootAliasPackage extends CompleteAliasPackage implements RootPackageInterface
{ {
/** @var RootPackageInterface */ /** @var RootPackage */
protected $aliasOf; protected $aliasOf;
/** /**
* All descendants' constructors should call this parent constructor * All descendants' constructors should call this parent constructor
* *
* @param RootPackageInterface $aliasOf The package this package is an alias of * @param RootPackage $aliasOf The package this package is an alias of
* @param string $version The version the alias must report * @param string $version The version the alias must report
* @param string $prettyVersion The alias's non-normalized version * @param string $prettyVersion The alias's non-normalized version
*/ */
public function __construct(RootPackageInterface $aliasOf, $version, $prettyVersion) public function __construct(RootPackage $aliasOf, $version, $prettyVersion)
{ {
parent::__construct($aliasOf, $version, $prettyVersion); parent::__construct($aliasOf, $version, $prettyVersion);
} }
/** /**
* @return RootPackageInterface * @return RootPackage
*/ */
public function getAliasOf() public function getAliasOf()
{ {

View File

@ -39,7 +39,7 @@ class PluginManager
protected $composer; protected $composer;
/** @var IOInterface */ /** @var IOInterface */
protected $io; protected $io;
/** @var Composer */ /** @var ?Composer */
protected $globalComposer; protected $globalComposer;
/** @var VersionParser */ /** @var VersionParser */
protected $versionParser; protected $versionParser;
@ -82,9 +82,7 @@ class PluginManager
$repo = $this->composer->getRepositoryManager()->getLocalRepository(); $repo = $this->composer->getRepositoryManager()->getLocalRepository();
$globalRepo = $this->globalComposer ? $this->globalComposer->getRepositoryManager()->getLocalRepository() : null; $globalRepo = $this->globalComposer ? $this->globalComposer->getRepositoryManager()->getLocalRepository() : null;
if ($repo) {
$this->loadRepository($repo, false); $this->loadRepository($repo, false);
}
if ($globalRepo) { if ($globalRepo) {
$this->loadRepository($globalRepo, true); $this->loadRepository($globalRepo, true);
} }
@ -259,6 +257,7 @@ class PluginManager
} }
if ($oldInstallerPlugin) { if ($oldInstallerPlugin) {
/** @var \Composer\Installer\InstallerInterface $installer */
$installer = $this->registeredPlugins[$package->getName()]; $installer = $this->registeredPlugins[$package->getName()];
unset($this->registeredPlugins[$package->getName()]); unset($this->registeredPlugins[$package->getName()]);
$this->composer->getInstallationManager()->removeInstaller($installer); $this->composer->getInstallationManager()->removeInstaller($installer);
@ -469,7 +468,7 @@ class PluginManager
array_key_exists($capability, $capabilities) array_key_exists($capability, $capabilities)
&& (empty($capabilities[$capability]) || !is_string($capabilities[$capability]) || !trim($capabilities[$capability])) && (empty($capabilities[$capability]) || !is_string($capabilities[$capability]) || !trim($capabilities[$capability]))
) { ) {
throw new \UnexpectedValueException('Plugin '.get_class($plugin).' provided invalid capability class name(s), got '.var_export($capabilities[$capability], 1)); throw new \UnexpectedValueException('Plugin '.get_class($plugin).' provided invalid capability class name(s), got '.var_export($capabilities[$capability], true));
} }
return null; return null;

View File

@ -59,6 +59,7 @@ class PostFileDownloadEvent extends Event
*/ */
public function __construct($name, $fileName, $checksum, $url, $type, $context = null) public function __construct($name, $fileName, $checksum, $url, $type, $context = null)
{ {
/** @phpstan-ignore-next-line */
if ($context === null && $type instanceof PackageInterface) { if ($context === null && $type instanceof PackageInterface) {
$context = $type; $context = $type;
$type = 'package'; $type = 'package';

View File

@ -13,7 +13,9 @@
namespace Composer\Repository; namespace Composer\Repository;
use Composer\Package\AliasPackage; use Composer\Package\AliasPackage;
use Composer\Package\BasePackage;
use Composer\Package\CompleteAliasPackage; use Composer\Package\CompleteAliasPackage;
use Composer\Package\CompletePackage;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Package\CompletePackageInterface; use Composer\Package\CompletePackageInterface;
use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionParser;
@ -28,11 +30,11 @@ use Composer\Semver\Constraint\Constraint;
*/ */
class ArrayRepository implements RepositoryInterface class ArrayRepository implements RepositoryInterface
{ {
/** @var ?PackageInterface[] */ /** @var ?array<PackageInterface&BasePackage> */
protected $packages = null; protected $packages = null;
/** /**
* @var ?PackageInterface[] indexed by package unique name and used to cache hasPackage calls * @var ?array<PackageInterface&BasePackage> indexed by package unique name and used to cache hasPackage calls
*/ */
protected $packageMap = null; protected $packageMap = null;
@ -232,13 +234,17 @@ class ArrayRepository implements RepositoryInterface
return $result; return $result;
} }
/**
* @phpstan-param PackageInterface&BasePackage $package
* @return AliasPackage|CompleteAliasPackage
*/
protected function createAliasPackage(PackageInterface $package, $alias, $prettyAlias) protected function createAliasPackage(PackageInterface $package, $alias, $prettyAlias)
{ {
while ($package instanceof AliasPackage) { while ($package instanceof AliasPackage) {
$package = $package->getAliasOf(); $package = $package->getAliasOf();
} }
if ($package instanceof CompletePackageInterface) { if ($package instanceof CompletePackage) {
return new CompleteAliasPackage($package, $alias, $prettyAlias); return new CompleteAliasPackage($package, $alias, $prettyAlias);
} }
@ -275,6 +281,10 @@ class ArrayRepository implements RepositoryInterface
$this->initialize(); $this->initialize();
} }
if (null === $this->packages) {
throw new \LogicException('initialize failed to initialize the packages array');
}
return $this->packages; return $this->packages;
} }

View File

@ -49,6 +49,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
private $url; private $url;
private $baseUrl; private $baseUrl;
private $io; private $io;
/** @var HttpDownloader */
private $httpDownloader; private $httpDownloader;
private $loop; private $loop;
protected $cache; protected $cache;

View File

@ -114,7 +114,7 @@ class InstalledRepository extends CompositeRepository
foreach ($package->getReplaces() as $link) { foreach ($package->getReplaces() as $link) {
foreach ($needles as $needle) { foreach ($needles as $needle) {
if ($link->getSource() === $needle) { if ($link->getSource() === $needle) {
if ($constraint === null || ($link->getConstraint()->matches($constraint) === !$invert)) { if ($constraint === null || ($link->getConstraint()->matches($constraint) === true)) {
// already displayed this node's dependencies, cutting short // already displayed this node's dependencies, cutting short
if (in_array($link->getTarget(), $packagesInTree)) { if (in_array($link->getTarget(), $packagesInTree)) {
$results[] = array($package, $link, false); $results[] = array($package, $link, false);
@ -221,7 +221,7 @@ class InstalledRepository extends CompositeRepository
} }
$results[] = array($package, $link, false); $results[] = array($package, $link, false);
$results[] = array($rootPackage, new Link($rootPackage->getName(), $link->getTarget(), new MatchAllConstraint, 'does not require', 'but ' . $pkg->getPrettyVersion() . ' is installed'), false); $results[] = array($rootPackage, new Link($rootPackage->getName(), $link->getTarget(), new MatchAllConstraint, Link::TYPE_DOES_NOT_REQUIRE, 'but ' . $pkg->getPrettyVersion() . ' is installed'), false);
} else { } else {
// no root so let's just print whatever we found // no root so let's just print whatever we found
$results[] = array($package, $link, false); $results[] = array($package, $link, false);

View File

@ -566,7 +566,7 @@ class PlatformRepository extends ArrayRepository
if ($name === 'uuid') { if ($name === 'uuid') {
$ext->setReplaces(array( $ext->setReplaces(array(
new Link('ext-uuid', 'lib-uuid', new Constraint('=', $version), Link::TYPE_REPLACE, $ext->getPrettyVersion()), 'lib-uuid' => new Link('ext-uuid', 'lib-uuid', new Constraint('=', $version), Link::TYPE_REPLACE, $ext->getPrettyVersion()),
)); ));
} }

View File

@ -44,6 +44,7 @@ interface RepositoryInterface extends \Countable
* @param string|ConstraintInterface $constraint package version or version constraint to match against * @param string|ConstraintInterface $constraint package version or version constraint to match against
* *
* @return PackageInterface|null * @return PackageInterface|null
* @phpstan-return (BasePackage&PackageInterface)|null
*/ */
public function findPackage($name, $constraint); public function findPackage($name, $constraint);
@ -54,6 +55,7 @@ interface RepositoryInterface extends \Countable
* @param string|ConstraintInterface $constraint package version or version constraint to match against * @param string|ConstraintInterface $constraint package version or version constraint to match against
* *
* @return PackageInterface[] * @return PackageInterface[]
* @phpstan-return array<BasePackage&PackageInterface>
*/ */
public function findPackages($name, $constraint = null); public function findPackages($name, $constraint = null);
@ -61,6 +63,7 @@ interface RepositoryInterface extends \Countable
* Returns list of registered packages. * Returns list of registered packages.
* *
* @return PackageInterface[] * @return PackageInterface[]
* @phpstan-return array<BasePackage&PackageInterface>
*/ */
public function getPackages(); public function getPackages();
@ -75,7 +78,10 @@ interface RepositoryInterface extends \Countable
* @param array<string, BasePackage::STABILITY_*> $stabilityFlags an array of package name => BasePackage::STABILITY_* value * @param array<string, BasePackage::STABILITY_*> $stabilityFlags an array of package name => BasePackage::STABILITY_* value
* @param array<string, array<string, PackageInterface>> $alreadyLoaded an array of package name => package version => package * @param array<string, array<string, PackageInterface>> $alreadyLoaded an array of package name => package version => package
* *
* @return array{namesFound: string[], packages: PackageInterface[]} * @return array
*
* @phpstan-param array<string, ConstraintInterface|null> $packageNameMap
* @phpstan-return array{namesFound: string[], packages: array<BasePackage&PackageInterface>}
*/ */
public function loadPackages(array $packageNameMap, array $acceptableStabilities, array $stabilityFlags, array $alreadyLoaded = array()); public function loadPackages(array $packageNameMap, array $acceptableStabilities, array $stabilityFlags, array $alreadyLoaded = array());

View File

@ -21,6 +21,7 @@ use Composer\IO\NullIO;
use Composer\Package\BasePackage; use Composer\Package\BasePackage;
use Composer\Package\AliasPackage; use Composer\Package\AliasPackage;
use Composer\Package\CompleteAliasPackage; use Composer\Package\CompleteAliasPackage;
use Composer\Package\CompletePackage;
use Composer\Package\CompletePackageInterface; use Composer\Package\CompletePackageInterface;
use Composer\Semver\Constraint\ConstraintInterface; use Composer\Semver\Constraint\ConstraintInterface;
use Composer\Package\Version\StabilityFilter; use Composer\Package\Version\StabilityFilter;
@ -56,13 +57,13 @@ class RepositorySet
/** /**
* @var int[] array of stability => BasePackage::STABILITY_* value * @var int[] array of stability => BasePackage::STABILITY_* value
* @phpstan-var array<string, int> * @phpstan-var array<string, BasePackage::STABILITY_*>
*/ */
private $acceptableStabilities; private $acceptableStabilities;
/** /**
* @var int[] array of package name => BasePackage::STABILITY_* value * @var int[] array of package name => BasePackage::STABILITY_* value
* @phpstan-var array<string, int> * @phpstan-var array<string, BasePackage::STABILITY_*>
*/ */
private $stabilityFlags; private $stabilityFlags;
@ -80,7 +81,7 @@ class RepositorySet
* *
* @param string $minimumStability * @param string $minimumStability
* @param int[] $stabilityFlags an array of package name => BasePackage::STABILITY_* value * @param int[] $stabilityFlags an array of package name => BasePackage::STABILITY_* value
* @phpstan-param array<string, int> $stabilityFlags * @phpstan-param array<string, BasePackage::STABILITY_*> $stabilityFlags
* @param array[] $rootAliases * @param array[] $rootAliases
* @phpstan-param list<array{package: string, version: string, alias: string, alias_normalized: string}> $rootAliases * @phpstan-param list<array{package: string, version: string, alias: string, alias_normalized: string}> $rootAliases
* @param string[] $rootReferences an array of package name => source reference * @param string[] $rootReferences an array of package name => source reference
@ -254,7 +255,7 @@ class RepositorySet
while ($package instanceof AliasPackage) { while ($package instanceof AliasPackage) {
$package = $package->getAliasOf(); $package = $package->getAliasOf();
} }
if ($package instanceof CompletePackageInterface) { if ($package instanceof CompletePackage) {
$aliasPackage = new CompleteAliasPackage($package, $alias['alias_normalized'], $alias['alias']); $aliasPackage = new CompleteAliasPackage($package, $alias['alias_normalized'], $alias['alias']);
} else { } else {
$aliasPackage = new AliasPackage($package, $alias['alias_normalized'], $alias['alias']); $aliasPackage = new AliasPackage($package, $alias['alias_normalized'], $alias['alias']);

View File

@ -77,6 +77,7 @@ abstract class BitbucketDriver extends VcsDriver
* sets some parameters which are used in other methods * sets some parameters which are used in other methods
* *
* @return bool * @return bool
* @phpstan-impure
*/ */
protected function getRepoData() protected function getRepoData()
{ {
@ -363,6 +364,8 @@ abstract class BitbucketDriver extends VcsDriver
* @param bool $fetchingRepoData * @param bool $fetchingRepoData
* *
* @return Response The result * @return Response The result
*
* @phpstan-impure
*/ */
protected function fetchWithOAuthCredentials($url, $fetchingRepoData = false) protected function fetchWithOAuthCredentials($url, $fetchingRepoData = false)
{ {
@ -396,6 +399,9 @@ abstract class BitbucketDriver extends VcsDriver
*/ */
abstract protected function generateSshUrl(); abstract protected function generateSshUrl();
/**
* @phpstan-impure
*/
protected function attemptCloneFallback() protected function attemptCloneFallback()
{ {
try { try {

View File

@ -31,12 +31,10 @@ class HgBitbucketDriver extends BitbucketDriver
if (null === $this->rootIdentifier) { if (null === $this->rootIdentifier) {
if (!$this->getRepoData()) { if (!$this->getRepoData()) {
// @phpstan-ignore-next-line
if (!$this->fallbackDriver) { if (!$this->fallbackDriver) {
throw new \LogicException('A fallback driver should be setup if getRepoData returns false'); throw new \LogicException('A fallback driver should be setup if getRepoData returns false');
} }
// @phpstan-ignore-next-line
return $this->fallbackDriver->getRootIdentifier(); return $this->fallbackDriver->getRootIdentifier();
} }

View File

@ -157,6 +157,7 @@ abstract class VcsDriver implements VcsDriverInterface
* @param string $url The URL of content * @param string $url The URL of content
* *
* @return Response * @return Response
* @throws TransportException
*/ */
protected function getContents($url) protected function getContents($url)
{ {

View File

@ -142,6 +142,7 @@ class CurlDownloader
if ($copyTo) { if ($copyTo) {
$errorMessage = ''; $errorMessage = '';
// @phpstan-ignore-next-line
set_error_handler(function ($code, $msg) use (&$errorMessage) { set_error_handler(function ($code, $msg) use (&$errorMessage) {
if ($errorMessage) { if ($errorMessage) {
$errorMessage .= "\n"; $errorMessage .= "\n";

View File

@ -481,6 +481,7 @@ class HttpDownloader
/** /**
* @internal * @internal
* @return bool
*/ */
public static function isCurlEnabled() public static function isCurlEnabled()
{ {

View File

@ -264,7 +264,7 @@ class NoProxyPattern
/** /**
* Returns the binary network mask mapped to IPv6 * Returns the binary network mask mapped to IPv6
* *
* @param string $prefix CIDR prefix-length * @param int $prefix CIDR prefix-length
* @param int $size Byte size of in_addr * @param int $size Byte size of in_addr
* *
* @return string * @return string
@ -274,7 +274,7 @@ class NoProxyPattern
$mask = ''; $mask = '';
if ($ones = floor($prefix / 8)) { if ($ones = floor($prefix / 8)) {
$mask = str_repeat(chr(255), $ones); $mask = str_repeat(chr(255), (int) $ones);
} }
if ($remainder = $prefix % 8) { if ($remainder = $prefix % 8) {
@ -291,7 +291,7 @@ class NoProxyPattern
* *
* @param string $rangeIp IP in_addr * @param string $rangeIp IP in_addr
* @param int $size Byte size of in_addr * @param int $size Byte size of in_addr
* @param string $prefix CIDR prefix-length * @param int $prefix CIDR prefix-length
* *
* @return string[] network in_addr, binary mask * @return string[] network in_addr, binary mask
*/ */

View File

@ -31,7 +31,7 @@ final class StreamContextFactory
* Creates a context supporting HTTP proxies * Creates a context supporting HTTP proxies
* *
* @param string $url URL the context is to be used for * @param string $url URL the context is to be used for
* @phpstan-param array{http?: array{follow_location?: int, max_redirects?: int, header?: string|array<string, string|int>}} $defaultOptions * @phpstan-param array{http?: array{follow_location?: int, max_redirects?: int, header?: string|array<string>}} $defaultOptions
* @param array $defaultOptions Options to merge with the default * @param array $defaultOptions Options to merge with the default
* @param array $defaultParams Parameters to specify on the context * @param array $defaultParams Parameters to specify on the context
* @throws \RuntimeException if https proxy required and OpenSSL uninstalled * @throws \RuntimeException if https proxy required and OpenSSL uninstalled

View File

@ -39,7 +39,7 @@ class SyncHelper
self::await($loop, $downloader->prepare($type, $package, $path, $prevPackage)); self::await($loop, $downloader->prepare($type, $package, $path, $prevPackage));
if ($type === 'update') { if ($type === 'update') {
self::await($loop, $downloader->update($package, $path, $prevPackage)); self::await($loop, $downloader->update($package, $prevPackage, $path));
} else { } else {
self::await($loop, $downloader->install($package, $path)); self::await($loop, $downloader->install($package, $path));
} }

View File

@ -78,7 +78,13 @@ class AllFunctionalTest extends TestCase
} }
} }
// TODO in v2.3 always call with an array
if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandline')) {
$proc = new Process(array((defined('PHP_BINARY') ? PHP_BINARY : 'php'), '-dphar.readonly=0', './bin/compile'), $target);
} else {
// @phpstan-ignore-next-line
$proc = new Process((defined('PHP_BINARY') ? escapeshellcmd(PHP_BINARY) : 'php').' -dphar.readonly=0 '.escapeshellarg('./bin/compile'), $target); $proc = new Process((defined('PHP_BINARY') ? escapeshellcmd(PHP_BINARY) : 'php').' -dphar.readonly=0 '.escapeshellarg('./bin/compile'), $target);
}
$exitcode = $proc->run(); $exitcode = $proc->run();
if ($exitcode !== 0 || trim($proc->getOutput())) { if ($exitcode !== 0 || trim($proc->getOutput())) {
@ -110,8 +116,15 @@ class AllFunctionalTest extends TestCase
'COMPOSER_CACHE_DIR' => $this->testDir.'cache', 'COMPOSER_CACHE_DIR' => $this->testDir.'cache',
); );
$cmd = (defined('PHP_BINARY') ? escapeshellcmd(PHP_BINARY) : 'php') .' '.escapeshellarg(self::$pharPath).' --no-ansi '.$testData['RUN']; // TODO in v2.3 always call with an array
if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandline')) {
$cmd = array((defined('PHP_BINARY') ? PHP_BINARY : 'php'), self::$pharPath, '--no-ansi', $testData['RUN']);
$proc = new Process($cmd, $this->testDir, $env, null, 300); $proc = new Process($cmd, $this->testDir, $env, null, 300);
} else {
$cmd = (defined('PHP_BINARY') ? escapeshellcmd(PHP_BINARY) : 'php') .' '.escapeshellarg(self::$pharPath).' --no-ansi '.$testData['RUN'];
// @phpstan-ignore-next-line
$proc = new Process($cmd, $this->testDir, $env, null, 300);
}
$output = ''; $output = '';
$exitcode = $proc->run(function ($type, $buffer) use (&$output) { $exitcode = $proc->run(function ($type, $buffer) use (&$output) {

View File

@ -371,8 +371,8 @@ class AutoloadGeneratorTest extends TestCase
{ {
$package = new RootPackage('root/a', '1.0', '1.0'); $package = new RootPackage('root/a', '1.0', '1.0');
$package->setRequires(array( $package->setRequires(array(
new Link('a', 'a/a', new MatchAllConstraint()), 'a/a' => new Link('a', 'a/a', new MatchAllConstraint()),
new Link('a', 'b/b', new MatchAllConstraint()), 'b/b' => new Link('a', 'b/b', new MatchAllConstraint()),
)); ));
$packages = array(); $packages = array();
@ -400,7 +400,7 @@ class AutoloadGeneratorTest extends TestCase
{ {
$package = new RootPackage('root/a', '1.0', '1.0'); $package = new RootPackage('root/a', '1.0', '1.0');
$package->setRequires(array( $package->setRequires(array(
new Link('a', 'a/a', new MatchAllConstraint()), 'a/a' => new Link('a', 'a/a', new MatchAllConstraint()),
)); ));
$packages = array(); $packages = array();
@ -408,11 +408,11 @@ class AutoloadGeneratorTest extends TestCase
$packages[] = $b = new Package('b/b', '1.0', '1.0'); $packages[] = $b = new Package('b/b', '1.0', '1.0');
$a->setAutoload(array('psr-0' => array('A' => 'src/', 'A\\B' => 'lib/'))); $a->setAutoload(array('psr-0' => array('A' => 'src/', 'A\\B' => 'lib/')));
$a->setRequires(array( $a->setRequires(array(
new Link('a/a', 'b/b', new MatchAllConstraint()), 'b/b' => new Link('a/a', 'b/b', new MatchAllConstraint()),
)); ));
$b->setAutoload(array('psr-0' => array('B\\Sub\\Name' => 'src/'))); $b->setAutoload(array('psr-0' => array('B\\Sub\\Name' => 'src/')));
$b->setRequires(array( $b->setRequires(array(
new Link('b/b', 'a/a', new MatchAllConstraint()), 'a/a' => new Link('b/b', 'a/a', new MatchAllConstraint()),
)); ));
$this->repository->expects($this->once()) $this->repository->expects($this->once())
@ -432,17 +432,17 @@ class AutoloadGeneratorTest extends TestCase
public function testNonDevAutoloadShouldIncludeReplacedPackages() public function testNonDevAutoloadShouldIncludeReplacedPackages()
{ {
$package = new RootPackage('root/a', '1.0', '1.0'); $package = new RootPackage('root/a', '1.0', '1.0');
$package->setRequires(array(new Link('a', 'a/a', new MatchAllConstraint()))); $package->setRequires(array('a/a' => new Link('a', 'a/a', new MatchAllConstraint())));
$packages = array(); $packages = array();
$packages[] = $a = new Package('a/a', '1.0', '1.0'); $packages[] = $a = new Package('a/a', '1.0', '1.0');
$packages[] = $b = new Package('b/b', '1.0', '1.0'); $packages[] = $b = new Package('b/b', '1.0', '1.0');
$a->setRequires(array(new Link('a/a', 'b/c', new MatchAllConstraint()))); $a->setRequires(array('b/c' => new Link('a/a', 'b/c', new MatchAllConstraint())));
$b->setAutoload(array('psr-4' => array('B\\' => 'src/'))); $b->setAutoload(array('psr-4' => array('B\\' => 'src/')));
$b->setReplaces( $b->setReplaces(
array(new Link('b/b', 'b/c', new Constraint('==', '1.0'), Link::TYPE_REPLACE)) array('b/c' => new Link('b/b', 'b/c', new Constraint('==', '1.0'), Link::TYPE_REPLACE))
); );
$this->repository->expects($this->once()) $this->repository->expects($this->once())
@ -467,7 +467,7 @@ class AutoloadGeneratorTest extends TestCase
{ {
$package = new RootPackage('root/a', '1.0', '1.0'); $package = new RootPackage('root/a', '1.0', '1.0');
$package->setRequires(array( $package->setRequires(array(
new Link('a', 'a/a', new MatchAllConstraint()), 'a/a' => new Link('a', 'a/a', new MatchAllConstraint()),
)); ));
$packages = array(); $packages = array();
@ -475,11 +475,11 @@ class AutoloadGeneratorTest extends TestCase
$packages[] = $b = new Package('b/b', '1.0', '1.0'); $packages[] = $b = new Package('b/b', '1.0', '1.0');
$a->setAutoload(array('psr-0' => array('A' => 'src/', 'A\\B' => 'lib/'))); $a->setAutoload(array('psr-0' => array('A' => 'src/', 'A\\B' => 'lib/')));
$a->setRequires(array( $a->setRequires(array(
new Link('a/a', 'c/c', new MatchAllConstraint()), 'c/c' => new Link('a/a', 'c/c', new MatchAllConstraint()),
)); ));
$b->setAutoload(array('psr-0' => array('B\\Sub\\Name' => 'src/'))); $b->setAutoload(array('psr-0' => array('B\\Sub\\Name' => 'src/')));
$b->setReplaces(array( $b->setReplaces(array(
new Link('b/b', 'c/c', new MatchAllConstraint()), 'c/c' => new Link('b/b', 'c/c', new MatchAllConstraint()),
)); ));
$this->repository->expects($this->once()) $this->repository->expects($this->once())
@ -500,7 +500,7 @@ class AutoloadGeneratorTest extends TestCase
{ {
$package = new RootPackage('root/a', '1.0', '1.0'); $package = new RootPackage('root/a', '1.0', '1.0');
$package->setRequires(array( $package->setRequires(array(
new Link('a', 'a/a', new MatchAllConstraint()), 'a/a' => new Link('a', 'a/a', new MatchAllConstraint()),
)); ));
$packages = array(); $packages = array();
@ -511,18 +511,18 @@ class AutoloadGeneratorTest extends TestCase
$packages[] = $e = new Package('e/e', '1.0', '1.0'); $packages[] = $e = new Package('e/e', '1.0', '1.0');
$a->setAutoload(array('classmap' => array('src/A.php'))); $a->setAutoload(array('classmap' => array('src/A.php')));
$a->setRequires(array( $a->setRequires(array(
new Link('a/a', 'b/b', new MatchAllConstraint()), 'b/b' => new Link('a/a', 'b/b', new MatchAllConstraint()),
)); ));
$b->setAutoload(array('classmap' => array('src/B.php'))); $b->setAutoload(array('classmap' => array('src/B.php')));
$b->setRequires(array( $b->setRequires(array(
new Link('b/b', 'e/e', new MatchAllConstraint()), 'e/e' => new Link('b/b', 'e/e', new MatchAllConstraint()),
)); ));
$c->setAutoload(array('classmap' => array('src/C.php'))); $c->setAutoload(array('classmap' => array('src/C.php')));
$c->setReplaces(array( $c->setReplaces(array(
new Link('c/c', 'b/b', new MatchAllConstraint()), 'b/b' => new Link('c/c', 'b/b', new MatchAllConstraint()),
)); ));
$c->setRequires(array( $c->setRequires(array(
new Link('c/c', 'd/d', new MatchAllConstraint()), 'd/d' => new Link('c/c', 'd/d', new MatchAllConstraint()),
)); ));
$d->setAutoload(array('classmap' => array('src/D.php'))); $d->setAutoload(array('classmap' => array('src/D.php')));
$e->setAutoload(array('classmap' => array('src/E.php'))); $e->setAutoload(array('classmap' => array('src/E.php')));
@ -552,7 +552,7 @@ class AutoloadGeneratorTest extends TestCase
{ {
$package = new RootPackage('root/a', '1.0', '1.0'); $package = new RootPackage('root/a', '1.0', '1.0');
$package->setRequires(array( $package->setRequires(array(
new Link('a', 'a/a', new MatchAllConstraint()), 'a/a' => new Link('a', 'a/a', new MatchAllConstraint()),
)); ));
$package->setAutoload(array( $package->setAutoload(array(
@ -657,8 +657,8 @@ EOF;
{ {
$package = new RootPackage('root/a', '1.0', '1.0'); $package = new RootPackage('root/a', '1.0', '1.0');
$package->setRequires(array( $package->setRequires(array(
new Link('a', 'a/a', new MatchAllConstraint()), 'a/a' => new Link('a', 'a/a', new MatchAllConstraint()),
new Link('a', 'b/b', new MatchAllConstraint()), 'b/b' => new Link('a', 'b/b', new MatchAllConstraint()),
)); ));
$packages = array(); $packages = array();
@ -697,8 +697,8 @@ EOF;
{ {
$package = new RootPackage('root/a', '1.0', '1.0'); $package = new RootPackage('root/a', '1.0', '1.0');
$package->setRequires(array( $package->setRequires(array(
new Link('a', 'a/a', new MatchAllConstraint()), 'a/a' => new Link('a', 'a/a', new MatchAllConstraint()),
new Link('a', 'b/b', new MatchAllConstraint()), 'b/b' => new Link('a', 'b/b', new MatchAllConstraint()),
)); ));
$packages = array(); $packages = array();
@ -737,9 +737,9 @@ EOF;
{ {
$package = new RootPackage('root/a', '1.0', '1.0'); $package = new RootPackage('root/a', '1.0', '1.0');
$package->setRequires(array( $package->setRequires(array(
new Link('a', 'a/a', new MatchAllConstraint()), 'a/a' => new Link('a', 'a/a', new MatchAllConstraint()),
new Link('a', 'b/b', new MatchAllConstraint()), 'b/b' => new Link('a', 'b/b', new MatchAllConstraint()),
new Link('a', 'c/c', new MatchAllConstraint()), 'c/c' => new Link('a', 'c/c', new MatchAllConstraint()),
)); ));
$packages = array(); $packages = array();
@ -782,9 +782,9 @@ EOF;
{ {
$package = new RootPackage('root/a', '1.0', '1.0'); $package = new RootPackage('root/a', '1.0', '1.0');
$package->setRequires(array( $package->setRequires(array(
new Link('a', 'a/a', new MatchAllConstraint()), 'a/a' => new Link('a', 'a/a', new MatchAllConstraint()),
new Link('a', 'b/b', new MatchAllConstraint()), 'b/b' => new Link('a', 'b/b', new MatchAllConstraint()),
new Link('a', 'c/c', new MatchAllConstraint()), 'c/c' => new Link('a', 'c/c', new MatchAllConstraint()),
)); ));
$packages = array(); $packages = array();
@ -831,9 +831,9 @@ EOF;
{ {
$package = new RootPackage('root/a', '1.0', '1.0'); $package = new RootPackage('root/a', '1.0', '1.0');
$package->setRequires(array( $package->setRequires(array(
new Link('a', 'a/a', new MatchAllConstraint()), 'a/a' => new Link('a', 'a/a', new MatchAllConstraint()),
new Link('a', 'b/b', new MatchAllConstraint()), 'b/b' => new Link('a', 'b/b', new MatchAllConstraint()),
new Link('a', 'c/c', new MatchAllConstraint()), 'c/c' => new Link('a', 'c/c', new MatchAllConstraint()),
)); ));
$packages = array(); $packages = array();
@ -881,9 +881,9 @@ EOF;
$package = new RootPackage('root/a', '1.0', '1.0'); $package = new RootPackage('root/a', '1.0', '1.0');
$package->setAutoload(array('files' => array('root.php'))); $package->setAutoload(array('files' => array('root.php')));
$package->setRequires(array( $package->setRequires(array(
new Link('a', 'a/a', new MatchAllConstraint()), 'a/a' => new Link('a', 'a/a', new MatchAllConstraint()),
new Link('a', 'b/b', new MatchAllConstraint()), 'b/b' => new Link('a', 'b/b', new MatchAllConstraint()),
new Link('a', 'c/c', new MatchAllConstraint()), 'c/c' => new Link('a', 'c/c', new MatchAllConstraint()),
)); ));
$packages = array(); $packages = array();
@ -932,9 +932,9 @@ EOF;
$notAutoloadPackage = new RootPackage('root/a', '1.0', '1.0'); $notAutoloadPackage = new RootPackage('root/a', '1.0', '1.0');
$requires = array( $requires = array(
new Link('a', 'a/a', new MatchAllConstraint()), 'a/a' => new Link('a', 'a/a', new MatchAllConstraint()),
new Link('a', 'b/b', new MatchAllConstraint()), 'b/b' => new Link('a', 'b/b', new MatchAllConstraint()),
new Link('a', 'c/c', new MatchAllConstraint()), 'c/c' => new Link('a', 'c/c', new MatchAllConstraint()),
); );
$autoloadPackage->setRequires($requires); $autoloadPackage->setRequires($requires);
$notAutoloadPackage->setRequires($requires); $notAutoloadPackage->setRequires($requires);
@ -1003,10 +1003,10 @@ EOF;
$package = new RootPackage('root/a', '1.0', '1.0'); $package = new RootPackage('root/a', '1.0', '1.0');
$package->setAutoload(array('files' => array('root2.php'))); $package->setAutoload(array('files' => array('root2.php')));
$package->setRequires(array( $package->setRequires(array(
new Link('a', 'z/foo', new MatchAllConstraint()), 'z/foo' => new Link('a', 'z/foo', new MatchAllConstraint()),
new Link('a', 'b/bar', new MatchAllConstraint()), 'b/bar' => new Link('a', 'b/bar', new MatchAllConstraint()),
new Link('a', 'd/d', new MatchAllConstraint()), 'd/d' => new Link('a', 'd/d', new MatchAllConstraint()),
new Link('a', 'e/e', new MatchAllConstraint()), 'e/e' => new Link('a', 'e/e', new MatchAllConstraint()),
)); ));
$packages = array(); $packages = array();
@ -1017,18 +1017,18 @@ EOF;
$packages[] = $e = new Package('e/e', '1.0', '1.0'); $packages[] = $e = new Package('e/e', '1.0', '1.0');
$z->setAutoload(array('files' => array('testA.php'))); $z->setAutoload(array('files' => array('testA.php')));
$z->setRequires(array(new Link('z/foo', 'c/lorem', new MatchAllConstraint()))); $z->setRequires(array('c/lorem' => new Link('z/foo', 'c/lorem', new MatchAllConstraint())));
$b->setAutoload(array('files' => array('testB.php'))); $b->setAutoload(array('files' => array('testB.php')));
$b->setRequires(array(new Link('b/bar', 'c/lorem', new MatchAllConstraint()), new Link('b/bar', 'd/d', new MatchAllConstraint()))); $b->setRequires(array('c/lorem' => new Link('b/bar', 'c/lorem', new MatchAllConstraint()), 'd/d' => new Link('b/bar', 'd/d', new MatchAllConstraint())));
$c->setAutoload(array('files' => array('testC.php'))); $c->setAutoload(array('files' => array('testC.php')));
$d->setAutoload(array('files' => array('testD.php'))); $d->setAutoload(array('files' => array('testD.php')));
$d->setRequires(array(new Link('d/d', 'c/lorem', new MatchAllConstraint()))); $d->setRequires(array('c/lorem' => new Link('d/d', 'c/lorem', new MatchAllConstraint())));
$e->setAutoload(array('files' => array('testE.php'))); $e->setAutoload(array('files' => array('testE.php')));
$e->setRequires(array(new Link('e/e', 'c/lorem', new MatchAllConstraint()))); $e->setRequires(array('c/lorem' => new Link('e/e', 'c/lorem', new MatchAllConstraint())));
$this->repository->expects($this->once()) $this->repository->expects($this->once())
->method('getCanonicalPackages') ->method('getCanonicalPackages')
@ -1076,8 +1076,8 @@ EOF;
'classmap' => array($this->workingDir.'/src'), 'classmap' => array($this->workingDir.'/src'),
)); ));
$rootPackage->setRequires(array( $rootPackage->setRequires(array(
new Link('z', 'a/a', new MatchAllConstraint()), 'a/a' => new Link('z', 'a/a', new MatchAllConstraint()),
new Link('z', 'b/b', new MatchAllConstraint()), 'b/b' => new Link('z', 'b/b', new MatchAllConstraint()),
)); ));
$packages = array(); $packages = array();
@ -1339,7 +1339,7 @@ EOF;
'files' => array('test.php'), 'files' => array('test.php'),
)); ));
$package->setRequires(array( $package->setRequires(array(
new Link('a', 'b/b', new MatchAllConstraint()), 'b/b' => new Link('a', 'b/b', new MatchAllConstraint()),
)); ));
$vendorPackage = new Package('b/b', '1.0', '1.0'); $vendorPackage = new Package('b/b', '1.0', '1.0');

View File

@ -110,7 +110,7 @@ class InitCommandTest extends TestCase
public function testNamespaceFromMissingPackageName() public function testNamespaceFromMissingPackageName()
{ {
$command = new InitCommand; $command = new InitCommand;
$namespace = $command->namespaceFromPackageName(null); $namespace = $command->namespaceFromPackageName('');
$this->assertNull($namespace); $this->assertNull($namespace);
} }
} }

View File

@ -16,6 +16,7 @@ use Composer\DependencyResolver\GenericRule;
use Composer\DependencyResolver\Rule; use Composer\DependencyResolver\Rule;
use Composer\DependencyResolver\RuleSet; use Composer\DependencyResolver\RuleSet;
use Composer\DependencyResolver\Pool; use Composer\DependencyResolver\Pool;
use Composer\Semver\Constraint\MatchNoneConstraint;
use Composer\Test\TestCase; use Composer\Test\TestCase;
class RuleSetTest extends TestCase class RuleSetTest extends TestCase
@ -144,7 +145,7 @@ class RuleSetTest extends TestCase
$ruleSet = new RuleSet; $ruleSet = new RuleSet;
$literal = $p->getId(); $literal = $p->getId();
$rule = new GenericRule(array($literal), Rule::RULE_ROOT_REQUIRE, array('packageName' => 'foo/bar', 'constraint' => null)); $rule = new GenericRule(array($literal), Rule::RULE_ROOT_REQUIRE, array('packageName' => 'foo/bar', 'constraint' => new MatchNoneConstraint));
$ruleSet->add($rule, RuleSet::TYPE_REQUEST); $ruleSet->add($rule, RuleSet::TYPE_REQUEST);

View File

@ -36,8 +36,8 @@ class BufferIOTest extends TestCase
'', '',
)); ));
$this->assertTrue($bufferIO->askConfirmation('Please say yes!', 'no')); $this->assertTrue($bufferIO->askConfirmation('Please say yes!', false));
$this->assertFalse($bufferIO->askConfirmation('Now please say no!', 'yes')); $this->assertFalse($bufferIO->askConfirmation('Now please say no!', true));
$this->assertSame('default', $bufferIO->ask('Empty string last', 'default')); $this->assertSame('default', $bufferIO->ask('Empty string last', 'default'));
} }
} }

View File

@ -191,7 +191,7 @@ class ConsoleIOTest extends TestCase
; ;
$consoleIO = new ConsoleIO($inputMock, $outputMock, $setMock); $consoleIO = new ConsoleIO($inputMock, $outputMock, $setMock);
$consoleIO->askConfirmation('Why?', 'default'); $consoleIO->askConfirmation('Why?', false);
} }
public function testAskAndValidate() public function testAskAndValidate()
@ -250,7 +250,7 @@ class ConsoleIOTest extends TestCase
; ;
$consoleIO = new ConsoleIO($inputMock, $outputMock, $setMock); $consoleIO = new ConsoleIO($inputMock, $outputMock, $setMock);
$result = $consoleIO->select('Select item', array("item1", "item2"), null, false, "Error message", true); $result = $consoleIO->select('Select item', array("item1", "item2"), 'item1', false, "Error message", true);
$this->assertEquals(array('1'), $result); $this->assertEquals(array('1'), $result);
} }

View File

@ -58,14 +58,14 @@ class NullIOTest extends TestCase
{ {
$io = new NullIO(); $io = new NullIO();
$this->assertEquals('foo', $io->askConfirmation('bar', 'foo')); $this->assertEquals(false, $io->askConfirmation('bar', false));
} }
public function testAskAndValidate() public function testAskAndValidate()
{ {
$io = new NullIO(); $io = new NullIO();
$this->assertEquals('foo', $io->askAndValidate('question', 'validator', false, 'foo')); $this->assertEquals('foo', $io->askAndValidate('question', function ($x) { return true; }, null, 'foo'));
} }
public function testSelect() public function testSelect()

View File

@ -288,7 +288,7 @@ class LibraryInstallerTest extends TestCase
protected function createPackageMock() protected function createPackageMock()
{ {
return $this->getMockBuilder('Composer\Package\Package') return $this->getMockBuilder('Composer\Package\Package')
->setConstructorArgs(array(md5(mt_rand()), '1.0.0.0', '1.0.0')) ->setConstructorArgs(array(md5((string) mt_rand()), '1.0.0.0', '1.0.0'))
->getMock(); ->getMock();
} }
} }

View File

@ -101,7 +101,7 @@ class MetapackageInstallerTest extends TestCase
private function createPackageMock() private function createPackageMock()
{ {
return $this->getMockBuilder('Composer\Package\Package') return $this->getMockBuilder('Composer\Package\Package')
->setConstructorArgs(array(md5(mt_rand()), '1.0.0.0', '1.0.0')) ->setConstructorArgs(array(md5((string) mt_rand()), '1.0.0.0', '1.0.0'))
->getMock(); ->getMock();
} }
} }

View File

@ -279,7 +279,7 @@ class SuggestedPackagesReporterTest extends TestCase
private function createPackageMock() private function createPackageMock()
{ {
return $this->getMockBuilder('Composer\Package\Package') return $this->getMockBuilder('Composer\Package\Package')
->setConstructorArgs(array(md5(mt_rand()), '1.0.0.0', '1.0.0')) ->setConstructorArgs(array(md5((string) mt_rand()), '1.0.0.0', '1.0.0'))
->getMock(); ->getMock();
} }
} }

View File

@ -16,13 +16,14 @@ use Composer\Composer;
use Composer\Config; use Composer\Config;
use Composer\Factory; use Composer\Factory;
use Composer\Repository\RepositoryManager; use Composer\Repository\RepositoryManager;
use Composer\Repository\WritableRepositoryInterface;
use Composer\Package\Version\VersionGuesser; use Composer\Package\Version\VersionGuesser;
use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionParser;
use Composer\Package\RootPackageInterface; use Composer\Package\RootPackageInterface;
use Composer\Installer; use Composer\Installer;
use Composer\EventDispatcher\EventDispatcher; use Composer\EventDispatcher\EventDispatcher;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Repository\InstalledArrayRepository;
use Composer\Repository\InstalledRepositoryInterface;
use Composer\Test\TestCase; use Composer\Test\TestCase;
use Composer\Util\Loop; use Composer\Util\Loop;
use Composer\Util\ProcessExecutor; use Composer\Util\ProcessExecutor;
@ -48,6 +49,7 @@ class FactoryMock extends Factory
protected function addLocalRepository(IOInterface $io, RepositoryManager $rm, $vendorDir, RootPackageInterface $rootPackage, ProcessExecutor $process = null) protected function addLocalRepository(IOInterface $io, RepositoryManager $rm, $vendorDir, RootPackageInterface $rootPackage, ProcessExecutor $process = null)
{ {
$rm->setLocalRepository(new InstalledArrayRepository);
} }
public function createInstallationManager(Loop $loop, IOInterface $io, EventDispatcher $dispatcher = null) public function createInstallationManager(Loop $loop, IOInterface $io, EventDispatcher $dispatcher = null)
@ -59,7 +61,7 @@ class FactoryMock extends Factory
{ {
} }
protected function purgePackages(WritableRepositoryInterface $repo, Installer\InstallationManager $im) protected function purgePackages(InstalledRepositoryInterface $repo, Installer\InstallationManager $im)
{ {
} }
} }

View File

@ -30,7 +30,7 @@ class ProcessExecutorMock extends ProcessExecutor
private $log = array(); private $log = array();
/** /**
* @param array<string|array{cmd: string, return: int, stdout?: string, stderr?: string, callback?: callable}> $expectations * @param array<string|array{cmd: string, return?: int, stdout?: string, stderr?: string, callback?: callable}> $expectations
* @param bool $strict set to true if you want to provide *all* expected commands, and not just a subset you are interested in testing * @param bool $strict set to true if you want to provide *all* expected commands, and not just a subset you are interested in testing
* @param array{return: int, stdout?: string, stderr?: string} $defaultHandler default command handler for undefined commands if not in strict mode * @param array{return: int, stdout?: string, stderr?: string} $defaultHandler default command handler for undefined commands if not in strict mode
*/ */

View File

@ -15,6 +15,7 @@ namespace Composer\Test\Package\Archiver;
use Composer\IO\NullIO; use Composer\IO\NullIO;
use Composer\Factory; use Composer\Factory;
use Composer\Package\Archiver\ArchiveManager; use Composer\Package\Archiver\ArchiveManager;
use Composer\Package\CompletePackage;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Util\Loop; use Composer\Util\Loop;
use Composer\Test\Mock\FactoryMock; use Composer\Test\Mock\FactoryMock;
@ -95,7 +96,7 @@ class ArchiveManagerTest extends ArchiverTest
unlink($target); unlink($target);
} }
protected function getTargetName(PackageInterface $package, $format, $fileName = null) protected function getTargetName(CompletePackage $package, $format, $fileName = null)
{ {
if (null === $fileName) { if (null === $fileName) {
$packageName = $this->manager->getPackageFilename($package); $packageName = $this->manager->getPackageFilename($package);

View File

@ -178,7 +178,7 @@ class ArrayDumperTest extends TestCase
), ),
array( array(
'require-dev', 'require-dev',
array(new Link('foo', 'foo/bar', new Constraint('=', '1.0.0.0'), 'requires (for development)', '1.0.0')), array(new Link('foo', 'foo/bar', new Constraint('=', '1.0.0.0'), Link::TYPE_DEV_REQUIRE, '1.0.0')),
'devRequires', 'devRequires',
array('foo/bar' => '1.0.0'), array('foo/bar' => '1.0.0'),
), ),

View File

@ -14,6 +14,7 @@ namespace Composer\Test\Package\Loader;
use Composer\Package\Loader\ArrayLoader; use Composer\Package\Loader\ArrayLoader;
use Composer\Package\Dumper\ArrayDumper; use Composer\Package\Dumper\ArrayDumper;
use Composer\Package\Link;
use Composer\Test\TestCase; use Composer\Test\TestCase;
class ArrayLoaderTest extends TestCase class ArrayLoaderTest extends TestCase
@ -287,7 +288,7 @@ class ArrayLoaderTest extends TestCase
*/ */
public function testPluginApiVersionAreKeptAsDeclared($apiVersion) public function testPluginApiVersionAreKeptAsDeclared($apiVersion)
{ {
$links = $this->loader->parseLinks('Plugin', '9.9.9', '', array('composer-plugin-api' => $apiVersion)); $links = $this->loader->parseLinks('Plugin', '9.9.9', Link::TYPE_REQUIRE, array('composer-plugin-api' => $apiVersion));
$this->assertArrayHasKey('composer-plugin-api', $links); $this->assertArrayHasKey('composer-plugin-api', $links);
$this->assertSame($apiVersion, $links['composer-plugin-api']->getConstraint()->getPrettyString()); $this->assertSame($apiVersion, $links['composer-plugin-api']->getConstraint()->getPrettyString());
@ -295,7 +296,7 @@ class ArrayLoaderTest extends TestCase
public function testPluginApiVersionDoesSupportSelfVersion() public function testPluginApiVersionDoesSupportSelfVersion()
{ {
$links = $this->loader->parseLinks('Plugin', '6.6.6', '', array('composer-plugin-api' => 'self.version')); $links = $this->loader->parseLinks('Plugin', '6.6.6', Link::TYPE_REQUIRE, array('composer-plugin-api' => 'self.version'));
$this->assertArrayHasKey('composer-plugin-api', $links); $this->assertArrayHasKey('composer-plugin-api', $links);
$this->assertSame('6.6.6', $links['composer-plugin-api']->getConstraint()->getPrettyString()); $this->assertSame('6.6.6', $links['composer-plugin-api']->getConstraint()->getPrettyString());

View File

@ -27,7 +27,7 @@ class RootAliasPackageTest extends TestCase
$alias = new RootAliasPackage($root->reveal(), '1.0', '1.0.0.0'); $alias = new RootAliasPackage($root->reveal(), '1.0', '1.0.0.0');
$this->assertEmpty($alias->getRequires()); $this->assertEmpty($alias->getRequires());
$links = array(new Link('a', 'b', new MatchAllConstraint(), 'foo', 'self.version')); $links = array(new Link('a', 'b', new MatchAllConstraint(), Link::TYPE_REQUIRE, 'self.version'));
$alias->setRequires($links); $alias->setRequires($links);
$this->assertNotEmpty($alias->getRequires()); $this->assertNotEmpty($alias->getRequires());
} }
@ -39,7 +39,7 @@ class RootAliasPackageTest extends TestCase
$alias = new RootAliasPackage($root->reveal(), '1.0', '1.0.0.0'); $alias = new RootAliasPackage($root->reveal(), '1.0', '1.0.0.0');
$this->assertEmpty($alias->getDevRequires()); $this->assertEmpty($alias->getDevRequires());
$links = array(new Link('a', 'b', new MatchAllConstraint(), 'foo', 'self.version')); $links = array(new Link('a', 'b', new MatchAllConstraint(), Link::TYPE_DEV_REQUIRE, 'self.version'));
$alias->setDevRequires($links); $alias->setDevRequires($links);
$this->assertNotEmpty($alias->getDevRequires()); $this->assertNotEmpty($alias->getDevRequires());
} }
@ -51,7 +51,7 @@ class RootAliasPackageTest extends TestCase
$alias = new RootAliasPackage($root->reveal(), '1.0', '1.0.0.0'); $alias = new RootAliasPackage($root->reveal(), '1.0', '1.0.0.0');
$this->assertEmpty($alias->getConflicts()); $this->assertEmpty($alias->getConflicts());
$links = array(new Link('a', 'b', new MatchAllConstraint(), 'foo', 'self.version')); $links = array(new Link('a', 'b', new MatchAllConstraint(), Link::TYPE_CONFLICT, 'self.version'));
$alias->setConflicts($links); $alias->setConflicts($links);
$this->assertNotEmpty($alias->getConflicts()); $this->assertNotEmpty($alias->getConflicts());
} }
@ -63,7 +63,7 @@ class RootAliasPackageTest extends TestCase
$alias = new RootAliasPackage($root->reveal(), '1.0', '1.0.0.0'); $alias = new RootAliasPackage($root->reveal(), '1.0', '1.0.0.0');
$this->assertEmpty($alias->getProvides()); $this->assertEmpty($alias->getProvides());
$links = array(new Link('a', 'b', new MatchAllConstraint(), 'foo', 'self.version')); $links = array(new Link('a', 'b', new MatchAllConstraint(), Link::TYPE_PROVIDE, 'self.version'));
$alias->setProvides($links); $alias->setProvides($links);
$this->assertNotEmpty($alias->getProvides()); $this->assertNotEmpty($alias->getProvides());
} }
@ -75,7 +75,7 @@ class RootAliasPackageTest extends TestCase
$alias = new RootAliasPackage($root->reveal(), '1.0', '1.0.0.0'); $alias = new RootAliasPackage($root->reveal(), '1.0', '1.0.0.0');
$this->assertEmpty($alias->getReplaces()); $this->assertEmpty($alias->getReplaces());
$links = array(new Link('a', 'b', new MatchAllConstraint(), 'foo', 'self.version')); $links = array(new Link('a', 'b', new MatchAllConstraint(), Link::TYPE_REPLACE, 'self.version'));
$alias->setReplaces($links); $alias->setReplaces($links);
$this->assertNotEmpty($alias->getReplaces()); $this->assertNotEmpty($alias->getReplaces());
} }

View File

@ -54,12 +54,12 @@ class PluginInstallerTest extends TestCase
protected $directory; protected $directory;
/** /**
* @var \PHPUnit\Framework\MockObject\MockObject * @var \PHPUnit\Framework\MockObject\MockObject&\Composer\Installer\InstallationManager
*/ */
protected $im; protected $im;
/** /**
* @var \PHPUnit\Framework\MockObject\MockObject * @var \PHPUnit\Framework\MockObject\MockObject&\Composer\Repository\InstalledRepositoryInterface
*/ */
protected $repository; protected $repository;

View File

@ -13,6 +13,7 @@
namespace Composer\Test\Repository; namespace Composer\Test\Repository;
use Composer\Package\Package; use Composer\Package\Package;
use Composer\Package\PackageInterface;
use Composer\Repository\PlatformRepository; use Composer\Repository\PlatformRepository;
use Composer\Test\TestCase; use Composer\Test\TestCase;
use PHPUnit\Framework\Assert; use PHPUnit\Framework\Assert;
@ -1189,7 +1190,7 @@ Linked Version => 1.2.11',
} }
} }
private function assertPackageLinks($context, array $expectedLinks, Package $sourcePackage, array $links) private function assertPackageLinks($context, array $expectedLinks, PackageInterface $sourcePackage, array $links)
{ {
self::assertCount(count($expectedLinks), $links, sprintf('%s: expected package count to match', $context)); self::assertCount(count($expectedLinks), $links, sprintf('%s: expected package count to match', $context));

View File

@ -94,7 +94,7 @@ abstract class TestCase extends PolyfillTestCase
$arrayLoader->parseLinks( $arrayLoader->parseLinks(
$package->getName(), $package->getName(),
$package->getPrettyVersion(), $package->getPrettyVersion(),
$opts['description'], $opts['method'],
$config[$type] $config[$type]
) )
); );

View File

@ -22,7 +22,7 @@ class MetadataMinifierTest extends TestCase
public function testMinifyExpand() public function testMinifyExpand()
{ {
$package1 = new CompletePackage('foo/bar', '2.0.0.0', '2.0.0'); $package1 = new CompletePackage('foo/bar', '2.0.0.0', '2.0.0');
$package1->setScripts(array('foo' => 'bar')); $package1->setScripts(array('foo' => array('bar')));
$package1->setLicense(array('MIT')); $package1->setLicense(array('MIT'));
$package2 = new CompletePackage('foo/bar', '1.2.0.0', '1.2.0'); $package2 = new CompletePackage('foo/bar', '1.2.0.0', '1.2.0');
$package2->setLicense(array('GPL')); $package2->setLicense(array('GPL'));
@ -32,7 +32,7 @@ class MetadataMinifierTest extends TestCase
$dumper = new ArrayDumper(); $dumper = new ArrayDumper();
$minified = array( $minified = array(
array('name' => 'foo/bar', 'version' => '2.0.0', 'version_normalized' => '2.0.0.0', 'type' => 'library', 'scripts' => array('foo' => 'bar'), 'license' => array('MIT')), array('name' => 'foo/bar', 'version' => '2.0.0', 'version_normalized' => '2.0.0.0', 'type' => 'library', 'scripts' => array('foo' => array('bar')), 'license' => array('MIT')),
array('version' => '1.2.0', 'version_normalized' => '1.2.0.0', 'license' => array('GPL'), 'homepage' => 'https://example.org', 'scripts' => '__unset'), array('version' => '1.2.0', 'version_normalized' => '1.2.0.0', 'license' => array('GPL'), 'homepage' => 'https://example.org', 'scripts' => '__unset'),
array('version' => '1.0.0', 'version_normalized' => '1.0.0.0', 'homepage' => '__unset'), array('version' => '1.0.0', 'version_normalized' => '1.0.0.0', 'homepage' => '__unset'),
); );

View File

@ -123,7 +123,7 @@ class PackageSorterTest extends TestCase
$links = array(); $links = array();
foreach ($requires as $requireName) { foreach ($requires as $requireName) {
$links[] = new Link($package->getName(), $requireName, new MatchAllConstraint); $links[$requireName] = new Link($package->getName(), $requireName, new MatchAllConstraint);
} }
$package->setRequires($links); $package->setRequires($links);