1
0
Fork 0

Bump phpstan to level 3 (#9734)

Clean up PackageInterface/CompletePackageInterface, add missing methods, type things in solver as BasePackage, added CompleteAliasPackage, ..
pull/9765/head
Jordi Boggiano 2021-03-09 15:49:40 +01:00 committed by GitHub
parent 8392508e23
commit 4940009f83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
98 changed files with 1007 additions and 572 deletions

View File

@ -52,5 +52,5 @@ jobs:
- name: Run PHPStan - name: Run PHPStan
# Locked to phpunit 7.5 here as newer ones have void return types which break inheritance # Locked to phpunit 7.5 here as newer ones have void return types which break inheritance
run: | run: |
bin/composer require --dev phpstan/phpstan:^0.12.69 phpunit/phpunit:^7.5.20 --with-all-dependencies ${{ env.COMPOSER_FLAGS }} bin/composer require --dev phpstan/phpstan:^0.12.69 phpstan/phpstan-phpunit:^0.12.17 phpunit/phpunit:^7.5.20 --with-all-dependencies ${{ env.COMPOSER_FLAGS }}
vendor/bin/phpstan analyse --configuration=phpstan/config.neon vendor/bin/phpstan analyse --configuration=phpstan/config.neon

View File

@ -1,6 +1,8 @@
includes:
- ../vendor/phpstan/phpstan-phpunit/extension.neon
parameters: parameters:
level: 1 level: 3
checkClassCaseSensitivity: true # Level 2 rule
excludes_analyse: excludes_analyse:
- '../tests/Composer/Test/Fixtures/*' - '../tests/Composer/Test/Fixtures/*'
- '../tests/Composer/Test/Autoload/Fixtures/*' - '../tests/Composer/Test/Autoload/Fixtures/*'
@ -29,6 +31,9 @@ parameters:
- '~^Call to an undefined static method Composer\\Test\\PolyfillTestCase::setExpectedException\(\)\.$~' - '~^Call to an undefined static method Composer\\Test\\PolyfillTestCase::setExpectedException\(\)\.$~'
- '~^Call to an undefined method Composer\\Test\\[a-zA-Z0-9\\]+::(assertFileDoesNotExist|assertMatchesRegularExpression)\(\)\.$~' - '~^Call to an undefined method Composer\\Test\\[a-zA-Z0-9\\]+::(assertFileDoesNotExist|assertMatchesRegularExpression)\(\)\.$~'
# Mock errors
- '~^Call to an undefined method (PHPUnit\\Framework\\MockObject\\MockObject|Prophecy\\Prophecy\\ObjectProphecy)::.*$~'
bootstrapFiles: bootstrapFiles:
- ../tests/bootstrap.php - ../tests/bootstrap.php
@ -38,25 +43,3 @@ parameters:
rules: rules:
- Composer\PHPStanRules\AnonymousFunctionWithThisRule - Composer\PHPStanRules\AnonymousFunctionWithThisRule
# Level 2 rules
- PHPStan\Rules\Cast\EchoRule
- PHPStan\Rules\Cast\InvalidCastRule
- PHPStan\Rules\Cast\InvalidPartOfEncapsedStringRule
- PHPStan\Rules\Cast\PrintRule
- PHPStan\Rules\Functions\IncompatibleDefaultParameterTypeRule
- PHPStan\Rules\Generics\ClassAncestorsRule
- PHPStan\Rules\Generics\ClassTemplateTypeRule
- PHPStan\Rules\Generics\FunctionTemplateTypeRule
- PHPStan\Rules\Generics\FunctionSignatureVarianceRule
- PHPStan\Rules\Generics\InterfaceAncestorsRule
- PHPStan\Rules\Generics\InterfaceTemplateTypeRule
- PHPStan\Rules\Generics\MethodTemplateTypeRule
- PHPStan\Rules\Generics\MethodSignatureVarianceRule
- PHPStan\Rules\Generics\TraitTemplateTypeRule
- PHPStan\Rules\Operators\InvalidBinaryOperationRule
- PHPStan\Rules\Operators\InvalidUnaryOperationRule
- PHPStan\Rules\Operators\InvalidComparisonOperationRule
- PHPStan\Rules\PhpDoc\IncompatiblePhpDocTypeRule
- PHPStan\Rules\PhpDoc\IncompatiblePropertyPhpDocTypeRule
- PHPStan\Rules\PhpDoc\InvalidPhpDocTagValueRule
- PHPStan\Rules\PhpDoc\InvalidPHPStanDocTagRule

View File

@ -338,7 +338,7 @@ class ClassLoader
* Loads the given class or interface. * Loads the given class or interface.
* *
* @param string $class The name of the class * @param string $class The name of the class
* @return bool|null True if loaded, null otherwise * @return true|null True if loaded, null otherwise
*/ */
public function loadClass($class) public function loadClass($class)
{ {
@ -347,6 +347,8 @@ class ClassLoader
return true; return true;
} }
return null;
} }
/** /**

View File

@ -16,6 +16,7 @@ use Composer\Factory;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Config; use Composer\Config;
use Composer\Composer; use Composer\Composer;
use Composer\Package\CompletePackageInterface;
use Composer\Repository\CompositeRepository; use Composer\Repository\CompositeRepository;
use Composer\Repository\RepositoryFactory; use Composer\Repository\RepositoryFactory;
use Composer\Script\ScriptEvents; use Composer\Script\ScriptEvents;
@ -140,6 +141,9 @@ EOT
return 0; return 0;
} }
/**
* @return CompletePackageInterface|false
*/
protected function selectPackage(IOInterface $io, $packageName, $version = null) protected function selectPackage(IOInterface $io, $packageName, $version = null)
{ {
$io->writeError('<info>Searching for the specified package.</info>'); $io->writeError('<info>Searching for the specified package.</info>');
@ -171,6 +175,10 @@ EOT
return false; return false;
} }
if (!$package instanceof CompletePackageInterface) {
throw new \LogicException('Expected a CompletePackageInterface instance but found '.get_class($package));
}
return $package; return $package;
} }
} }

View File

@ -212,6 +212,8 @@ abstract class BaseCommand extends Command
if (method_exists($rendererStyle, 'setVerticalBorderChars')) { if (method_exists($rendererStyle, 'setVerticalBorderChars')) {
$rendererStyle->setVerticalBorderChars(''); $rendererStyle->setVerticalBorderChars('');
} else { } else {
// TODO remove in composer 2.2
// @phpstan-ignore-next-line
$rendererStyle->setVerticalBorderChar(''); $rendererStyle->setVerticalBorderChar('');
} }
$rendererStyle->setCellRowContentFormat('%s '); $rendererStyle->setCellRowContentFormat('%s ');

View File

@ -27,6 +27,7 @@ use Composer\Util\StreamContextFactory;
use Composer\SelfUpdate\Keys; use Composer\SelfUpdate\Keys;
use Composer\SelfUpdate\Versions; use Composer\SelfUpdate\Versions;
use Composer\IO\NullIO; use Composer\IO\NullIO;
use Composer\Package\CompletePackageInterface;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\ExecutableFinder; use Symfony\Component\Process\ExecutableFinder;
@ -159,7 +160,7 @@ EOT
$platformRepo = new PlatformRepository(array(), $platformOverrides); $platformRepo = new PlatformRepository(array(), $platformOverrides);
$phpPkg = $platformRepo->findPackage('php', '*'); $phpPkg = $platformRepo->findPackage('php', '*');
$phpVersion = $phpPkg->getPrettyVersion(); $phpVersion = $phpPkg->getPrettyVersion();
if (false !== strpos($phpPkg->getDescription(), 'overridden')) { if ($phpPkg instanceof CompletePackageInterface && false !== strpos($phpPkg->getDescription(), 'overridden')) {
$phpVersion .= ' - ' . $phpPkg->getDescription(); $phpVersion .= ' - ' . $phpPkg->getDescription();
} }

View File

@ -58,6 +58,10 @@ EOT
public function run(InputInterface $input, OutputInterface $output) public function run(InputInterface $input, OutputInterface $output)
{ {
if (!method_exists($input, '__toString')) {
throw new \LogicException('Expected an Input instance that is stringable, got '.get_class($input));
}
// extract real command name // extract real command name
$tokens = preg_split('{\s+}', $input->__toString()); $tokens = preg_split('{\s+}', $input->__toString());
$args = array(); $args = array();

View File

@ -15,6 +15,7 @@ namespace Composer\Command;
use Composer\Factory; use Composer\Factory;
use Composer\Json\JsonFile; use Composer\Json\JsonFile;
use Composer\Package\BasePackage; use Composer\Package\BasePackage;
use Composer\Package\CompletePackageInterface;
use Composer\Package\Package; use Composer\Package\Package;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionParser;
@ -31,6 +32,7 @@ use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\ExecutableFinder; use Symfony\Component\Process\ExecutableFinder;
use Symfony\Component\Process\Process; use Symfony\Component\Process\Process;
use Symfony\Component\Console\Helper\FormatterHelper;
/** /**
* @author Justin Rainbow <justin.rainbow@gmail.com> * @author Justin Rainbow <justin.rainbow@gmail.com>
@ -172,6 +174,7 @@ EOT
{ {
$git = $this->getGitConfig(); $git = $this->getGitConfig();
$io = $this->getIO(); $io = $this->getIO();
/** @var FormatterHelper $formatter */
$formatter = $this->getHelperSet()->get('formatter'); $formatter = $this->getHelperSet()->get('formatter');
// initialize repos if configured // initialize repos if configured
@ -831,7 +834,7 @@ EOT
if (!$link->getConstraint()->matches(new Constraint('==', $platformPkg->getVersion()))) { if (!$link->getConstraint()->matches(new Constraint('==', $platformPkg->getVersion()))) {
$platformPkgVersion = $platformPkg->getPrettyVersion(); $platformPkgVersion = $platformPkg->getPrettyVersion();
$platformExtra = $platformPkg->getExtra(); $platformExtra = $platformPkg->getExtra();
if (isset($platformExtra['config.platform'])) { if (isset($platformExtra['config.platform']) && $platformPkg instanceof CompletePackageInterface) {
$platformPkgVersion .= ' ('.$platformPkg->getDescription().')'; $platformPkgVersion .= ' ('.$platformPkg->getDescription().')';
} }
$details[] = $candidate->getName().' requires '.$link->getTarget().' '.$link->getPrettyConstraint().' which does not match your installed version '.$platformPkgVersion.'.'; $details[] = $candidate->getName().' requires '.$link->getTarget().' '.$link->getPrettyConstraint().' which does not match your installed version '.$platformPkgVersion.'.';

View File

@ -81,6 +81,8 @@ EOT
if (method_exists($tableStyle, 'setVerticalBorderChars')) { if (method_exists($tableStyle, 'setVerticalBorderChars')) {
$tableStyle->setVerticalBorderChars(''); $tableStyle->setVerticalBorderChars('');
} else { } else {
// TODO remove in composer 2.2
// @phpstan-ignore-next-line
$tableStyle->setVerticalBorderChar(''); $tableStyle->setVerticalBorderChar('');
} }
$tableStyle->setCellRowContentFormat('%s '); $tableStyle->setCellRowContentFormat('%s ');

View File

@ -266,7 +266,13 @@ EOT
if ($input->getOption('latest')) { if ($input->getOption('latest')) {
$latestPackage = $this->findLatestPackage($package, $composer, $platformRepo, $input->getOption('minor-only')); $latestPackage = $this->findLatestPackage($package, $composer, $platformRepo, $input->getOption('minor-only'));
} }
if ($input->getOption('outdated') && $input->getOption('strict') && $latestPackage && $latestPackage->getFullPrettyVersion() !== $package->getFullPrettyVersion() && !$latestPackage->isAbandoned()) { if (
$input->getOption('outdated')
&& $input->getOption('strict')
&& $latestPackage
&& $latestPackage->getFullPrettyVersion() !== $package->getFullPrettyVersion()
&& (!$latestPackage instanceof CompletePackageInterface || !$latestPackage->isAbandoned())
) {
$exitCode = 1; $exitCode = 1;
} }
if ($input->getOption('path')) { if ($input->getOption('path')) {
@ -330,6 +336,8 @@ EOT
$width = $terminal->getWidth(); $width = $terminal->getWidth();
} else { } else {
// For versions of Symfony console before 3.2 // For versions of Symfony console before 3.2
// TODO remove in composer 2.2
// @phpstan-ignore-next-line
list($width) = $this->getApplication()->getTerminalDimensions(); list($width) = $this->getApplication()->getTerminalDimensions();
} }
if (null === $width) { if (null === $width) {
@ -386,6 +394,7 @@ EOT
$showMinorOnly = $input->getOption('minor-only'); $showMinorOnly = $input->getOption('minor-only');
$ignoredPackages = array_map('strtolower', $input->getOption('ignore')); $ignoredPackages = array_map('strtolower', $input->getOption('ignore'));
$indent = $showAllTypes ? ' ' : ''; $indent = $showAllTypes ? ' ' : '';
/** @var PackageInterface[] $latestPackages */
$latestPackages = array(); $latestPackages = array();
$exitCode = 0; $exitCode = 0;
$viewData = array(); $viewData = array();
@ -426,7 +435,7 @@ EOT
} }
// Determine if Composer is checking outdated dependencies and if current package should trigger non-default exit code // Determine if Composer is checking outdated dependencies and if current package should trigger non-default exit code
$packageIsUpToDate = $latestPackage && $latestPackage->getFullPrettyVersion() === $package->getFullPrettyVersion() && !$latestPackage->isAbandoned(); $packageIsUpToDate = $latestPackage && $latestPackage->getFullPrettyVersion() === $package->getFullPrettyVersion() && (!$latestPackage instanceof CompletePackageInterface || !$latestPackage->isAbandoned());
$packageIsIgnored = \in_array($package->getPrettyName(), $ignoredPackages, true); $packageIsIgnored = \in_array($package->getPrettyName(), $ignoredPackages, true);
if ($input->getOption('outdated') && ($packageIsUpToDate || $packageIsIgnored)) { if ($input->getOption('outdated') && ($packageIsUpToDate || $packageIsIgnored)) {
continue; continue;
@ -454,7 +463,7 @@ EOT
$packageViewData['path'] = strtok(realpath($composer->getInstallationManager()->getInstallPath($package)), "\r\n"); $packageViewData['path'] = strtok(realpath($composer->getInstallationManager()->getInstallPath($package)), "\r\n");
} }
if ($latestPackage && $latestPackage->isAbandoned()) { if ($latestPackage instanceof CompletePackageInterface && $latestPackage->isAbandoned()) {
$replacement = is_string($latestPackage->getReplacementPackage()) $replacement = is_string($latestPackage->getReplacementPackage())
? 'Use ' . $latestPackage->getReplacementPackage() . ' instead' ? 'Use ' . $latestPackage->getReplacementPackage() . ' instead'
: 'No replacement was suggested'; : 'No replacement was suggested';
@ -670,7 +679,7 @@ EOT
} }
$io->write('<info>names</info> : ' . implode(', ', $package->getNames())); $io->write('<info>names</info> : ' . implode(', ', $package->getNames()));
if ($latestPackage->isAbandoned()) { if ($latestPackage instanceof CompletePackageInterface && $latestPackage->isAbandoned()) {
$replacement = ($latestPackage->getReplacementPackage() !== null) $replacement = ($latestPackage->getReplacementPackage() !== null)
? ' The author suggests using the ' . $latestPackage->getReplacementPackage(). ' package instead.' ? ' The author suggests using the ' . $latestPackage->getReplacementPackage(). ' package instead.'
: null; : null;
@ -836,7 +845,7 @@ EOT
} }
} }
if ($latestPackage->isAbandoned()) { if ($latestPackage instanceof CompletePackageInterface && $latestPackage->isAbandoned()) {
$json['replacement'] = $latestPackage->getReplacementPackage(); $json['replacement'] = $latestPackage->getReplacementPackage();
} }
@ -1045,7 +1054,7 @@ EOT
$tree = array( $tree = array(
'name' => $package->getPrettyName(), 'name' => $package->getPrettyName(),
'version' => $package->getPrettyVersion(), 'version' => $package->getPrettyVersion(),
'description' => $package->getDescription(), 'description' => $package instanceof CompletePackageInterface ? $package->getDescription() : '',
); );
if ($children) { if ($children) {
@ -1112,7 +1121,7 @@ EOT
* Display a package tree * Display a package tree
* *
* @param string $name * @param string $name
* @param PackageInterface|string $package * @param Link $link
* @param InstalledRepository $installedRepo * @param InstalledRepository $installedRepo
* @param RepositoryInterface $remoteRepos * @param RepositoryInterface $remoteRepos
* @param array $packagesInTree * @param array $packagesInTree
@ -1120,7 +1129,7 @@ EOT
*/ */
protected function addTree( protected function addTree(
$name, $name,
$package, Link $link,
InstalledRepository $installedRepo, InstalledRepository $installedRepo,
RepositoryInterface $remoteRepos, RepositoryInterface $remoteRepos,
array $packagesInTree array $packagesInTree
@ -1130,7 +1139,7 @@ EOT
$installedRepo, $installedRepo,
$remoteRepos, $remoteRepos,
$name, $name,
$package->getPrettyConstraint() === 'self.version' ? $package->getConstraint() : $package->getPrettyConstraint() $link->getPrettyConstraint() === 'self.version' ? $link->getConstraint() : $link->getPrettyConstraint()
); );
if (is_object($package)) { if (is_object($package)) {
$requires = $package->getRequires(); $requires = $package->getRequires();

View File

@ -44,7 +44,7 @@ use Composer\Exception\NoSslException;
class Application extends BaseApplication class Application extends BaseApplication
{ {
/** /**
* @var Composer * @var ?Composer
*/ */
protected $composer; protected $composer;

View File

@ -164,7 +164,7 @@ class Decisions implements \Iterator, \Countable
public function next() public function next()
{ {
return prev($this->decisionQueue); prev($this->decisionQueue);
} }
public function valid() public function valid()

View File

@ -12,9 +12,9 @@
namespace Composer\DependencyResolver; namespace Composer\DependencyResolver;
use Composer\Package\PackageInterface;
use Composer\Package\AliasPackage; use Composer\Package\AliasPackage;
use Composer\Package\BasePackage; use Composer\Package\BasePackage;
use Composer\Package\PackageInterface;
use Composer\Semver\Constraint\Constraint; use Composer\Semver\Constraint\Constraint;
/** /**
@ -88,7 +88,7 @@ class DefaultPolicy implements PolicyInterface
/** /**
* @protected * @protected
*/ */
public function compareByPriority(Pool $pool, PackageInterface $a, PackageInterface $b, $requiredPackage = null, $ignoreReplace = false) public function compareByPriority(Pool $pool, BasePackage $a, BasePackage $b, $requiredPackage = null, $ignoreReplace = false)
{ {
// prefer aliases to the original package // prefer aliases to the original package
if ($a->getName() === $b->getName()) { if ($a->getName() === $b->getName()) {
@ -139,11 +139,11 @@ class DefaultPolicy implements PolicyInterface
* Replace constraints are ignored. This method should only be used for * Replace constraints are ignored. This method should only be used for
* prioritisation, not for actual constraint verification. * prioritisation, not for actual constraint verification.
* *
* @param PackageInterface $source * @param BasePackage $source
* @param PackageInterface $target * @param BasePackage $target
* @return bool * @return bool
*/ */
protected function replaces(PackageInterface $source, PackageInterface $target) protected function replaces(BasePackage $source, BasePackage $target)
{ {
foreach ($source->getReplaces() as $link) { foreach ($source->getReplaces() as $link) {
if ($link->getTarget() === $target->getName() if ($link->getTarget() === $target->getName()

View File

@ -12,7 +12,7 @@
namespace Composer\DependencyResolver; namespace Composer\DependencyResolver;
use Composer\Package\PackageInterface; use Composer\Package\BasePackage;
use Composer\Package\Link; use Composer\Package\Link;
/** /**
@ -25,7 +25,7 @@ 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|PackageInterface|int|null $reasonData * @param Link|BasePackage|int|null $reasonData
*/ */
public function __construct(array $literals, $reason, $reasonData) public function __construct(array $literals, $reason, $reasonData)
{ {

View File

@ -12,7 +12,7 @@
namespace Composer\DependencyResolver; namespace Composer\DependencyResolver;
use Composer\Package\PackageInterface; use Composer\Package\BasePackage;
use Composer\Package\Link; use Composer\Package\Link;
/** /**
@ -27,7 +27,7 @@ class MultiConflictRule extends Rule
/** /**
* @param array $literals * @param array $literals
* @param int $reason A RULE_* constant describing the reason for generating this rule * @param int $reason A RULE_* constant describing the reason for generating this rule
* @param Link|PackageInterface $reasonData * @param Link|BasePackage $reasonData
*/ */
public function __construct(array $literals, $reason, $reasonData) public function __construct(array $literals, $reason, $reasonData)
{ {

View File

@ -16,7 +16,7 @@ use Composer\Package\Version\VersionParser;
use Composer\Semver\CompilingMatcher; use Composer\Semver\CompilingMatcher;
use Composer\Semver\Constraint\ConstraintInterface; use Composer\Semver\Constraint\ConstraintInterface;
use Composer\Semver\Constraint\Constraint; use Composer\Semver\Constraint\Constraint;
use Composer\Package\PackageInterface; use Composer\Package\BasePackage;
/** /**
* A package pool contains all packages for dependency resolution * A package pool contains all packages for dependency resolution
@ -26,10 +26,13 @@ use Composer\Package\PackageInterface;
*/ */
class Pool implements \Countable class Pool implements \Countable
{ {
/** @var BasePackage[] */
protected $packages = array(); protected $packages = array();
/** @var array<string, BasePackage[]> */
protected $packageByName = array(); protected $packageByName = array();
protected $versionParser; protected $versionParser;
protected $providerCache = array(); protected $providerCache = array();
/** @var BasePackage[] */
protected $unacceptableFixedOrLockedPackages; protected $unacceptableFixedOrLockedPackages;
public function __construct(array $packages = array(), array $unacceptableFixedOrLockedPackages = array()) public function __construct(array $packages = array(), array $unacceptableFixedOrLockedPackages = array())
@ -54,6 +57,9 @@ class Pool implements \Countable
} }
} }
/**
* @return BasePackage[]
*/
public function getPackages() public function getPackages()
{ {
return $this->packages; return $this->packages;
@ -63,7 +69,7 @@ class Pool implements \Countable
* Retrieves the package object for a given package id. * Retrieves the package object for a given package id.
* *
* @param int $id * @param int $id
* @return PackageInterface * @return BasePackage
*/ */
public function packageById($id) public function packageById($id)
{ {
@ -84,7 +90,7 @@ class Pool implements \Countable
* @param string $name The package name to be searched for * @param string $name The package name to be searched for
* @param ConstraintInterface $constraint A constraint that all returned * @param ConstraintInterface $constraint A constraint that all returned
* packages must match or null to return all * packages must match or null to return all
* @return PackageInterface[] A set of packages * @return BasePackage[] A set of packages
*/ */
public function whatProvides($name, ConstraintInterface $constraint = null) public function whatProvides($name, ConstraintInterface $constraint = null)
{ {
@ -140,12 +146,12 @@ class Pool implements \Countable
* Checks if the package matches the given constraint directly or through * Checks if the package matches the given constraint directly or through
* provided or replaced packages * provided or replaced packages
* *
* @param PackageInterface $candidate * @param BasePackage $candidate
* @param string $name Name of the package to be matched * @param string $name Name of the package to be matched
* @param ConstraintInterface $constraint The constraint to verify * @param ConstraintInterface $constraint The constraint to verify
* @return bool * @return bool
*/ */
public function match($candidate, $name, ConstraintInterface $constraint = null) public function match(BasePackage $candidate, $name, ConstraintInterface $constraint = null)
{ {
$candidateName = $candidate->getName(); $candidateName = $candidate->getName();
$candidateVersion = $candidate->getVersion(); $candidateVersion = $candidate->getVersion();
@ -185,7 +191,7 @@ class Pool implements \Countable
return false; return false;
} }
public function isUnacceptableFixedOrLockedPackage(PackageInterface $package) public function isUnacceptableFixedOrLockedPackage(BasePackage $package)
{ {
return \in_array($package, $this->unacceptableFixedOrLockedPackages, true); return \in_array($package, $this->unacceptableFixedOrLockedPackages, true);
} }

View File

@ -16,6 +16,8 @@ use Composer\EventDispatcher\EventDispatcher;
use Composer\IO\IOInterface; 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\CompletePackageInterface;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Package\Version\StabilityFilter; use Composer\Package\Version\StabilityFilter;
use Composer\Plugin\PluginEvents; use Composer\Plugin\PluginEvents;
@ -43,10 +45,12 @@ class PoolBuilder
*/ */
private $stabilityFlags; private $stabilityFlags;
/** /**
* @var array[]
* @psalm-var array<string, array<string, array{alias: string, alias_normalized: string}>> * @psalm-var array<string, array<string, array{alias: string, alias_normalized: string}>>
*/ */
private $rootAliases; private $rootAliases;
/** /**
* @var string[]
* @psalm-var array<string, string> * @psalm-var array<string, string>
*/ */
private $rootReferences; private $rootReferences;
@ -59,27 +63,32 @@ class PoolBuilder
*/ */
private $io; private $io;
/** /**
* @psalm-var array<string, AliasPackage> * @var array[]
* @psalm-var array<string, AliasPackage[]>
*/ */
private $aliasMap = array(); private $aliasMap = array();
/** /**
* @var ConstraintInterface[]
* @psalm-var array<string, ConstraintInterface> * @psalm-var array<string, ConstraintInterface>
*/ */
private $packagesToLoad = array(); private $packagesToLoad = array();
/** /**
* @var ConstraintInterface[]
* @psalm-var array<string, ConstraintInterface> * @psalm-var array<string, ConstraintInterface>
*/ */
private $loadedPackages = array(); private $loadedPackages = array();
/** /**
* @var array[]
* @psalm-var array<int, array<string, array<string, PackageInterface>>> * @psalm-var array<int, array<string, array<string, PackageInterface>>>
*/ */
private $loadedPerRepo = array(); private $loadedPerRepo = array();
/** /**
* @psalm-var Package[] * @var PackageInterface[]
*/ */
private $packages = array(); private $packages = array();
/** /**
* @psalm-var list<Package> * @var PackageInterface[]
* @psalm-var list<PackageInterface>
*/ */
private $unacceptableFixedOrLockedPackages = array(); private $unacceptableFixedOrLockedPackages = array();
private $updateAllowList = array(); private $updateAllowList = array();
@ -95,6 +104,7 @@ class PoolBuilder
*/ */
private $maxExtendedReqs = array(); private $maxExtendedReqs = array();
/** /**
* @var array
* @psalm-var array<string, bool> * @psalm-var array<string, bool>
*/ */
private $updateAllowWarned = array(); private $updateAllowWarned = array();
@ -360,7 +370,11 @@ class PoolBuilder
} else { } else {
$basePackage = $package; $basePackage = $package;
} }
if ($basePackage instanceof CompletePackageInterface) {
$aliasPackage = new CompleteAliasPackage($basePackage, $alias['alias_normalized'], $alias['alias']);
} else {
$aliasPackage = new AliasPackage($basePackage, $alias['alias_normalized'], $alias['alias']); $aliasPackage = new AliasPackage($basePackage, $alias['alias_normalized'], $alias['alias']);
}
$aliasPackage->setRootPackageAlias(true); $aliasPackage->setRootPackageAlias(true);
$newIndex = $this->indexCounter++; $newIndex = $this->indexCounter++;

View File

@ -13,7 +13,7 @@
namespace Composer\DependencyResolver; namespace Composer\DependencyResolver;
use Composer\Package\Link; use Composer\Package\Link;
use Composer\Package\PackageInterface; use Composer\Package\BasePackage;
use Composer\Package\AliasPackage; use Composer\Package\AliasPackage;
use Composer\Repository\RepositorySet; use Composer\Repository\RepositorySet;
use Composer\Repository\PlatformRepository; use Composer\Repository\PlatformRepository;
@ -47,7 +47,7 @@ abstract class Rule
/** /**
* @param int $reason A RULE_* constant describing the reason for generating this rule * @param int $reason A RULE_* constant describing the reason for generating this rule
* @param Link|PackageInterface $reasonData * @param Link|BasePackage $reasonData
*/ */
public function __construct($reason, $reasonData) public function __construct($reason, $reasonData)
{ {
@ -62,6 +62,8 @@ abstract class Rule
abstract public function getHash(); abstract public function getHash();
abstract public function __toString();
abstract public function equals(Rule $rule); abstract public function equals(Rule $rule);
public function getReason() public function getReason()
@ -361,7 +363,7 @@ abstract class Rule
return Problem::getPackageList($packages, $isVerbose); return Problem::getPackageList($packages, $isVerbose);
} }
private function deduplicateDefaultBranchAlias(PackageInterface $package) private function deduplicateDefaultBranchAlias(BasePackage $package)
{ {
if ($package instanceof AliasPackage && $package->getPrettyVersion() === VersionParser::DEFAULT_BRANCH_ALIAS) { if ($package instanceof AliasPackage && $package->getPrettyVersion() === VersionParser::DEFAULT_BRANCH_ALIAS) {
$package = $package->getAliasOf(); $package = $package->getAliasOf();

View File

@ -12,7 +12,7 @@
namespace Composer\DependencyResolver; namespace Composer\DependencyResolver;
use Composer\Package\PackageInterface; use Composer\Package\BasePackage;
use Composer\Package\Link; use Composer\Package\Link;
/** /**
@ -27,7 +27,7 @@ class Rule2Literals extends Rule
* @param int $literal1 * @param int $literal1
* @param int $literal2 * @param int $literal2
* @param int $reason A RULE_* constant describing the reason for generating this rule * @param int $reason A RULE_* constant describing the reason for generating this rule
* @param Link|PackageInterface $reasonData * @param Link|BasePackage $reasonData
*/ */
public function __construct($literal1, $literal2, $reason, $reasonData) public function __construct($literal1, $literal2, $reason, $reasonData)
{ {

View File

@ -113,6 +113,9 @@ class RuleSet implements \IteratorAggregate, \Countable
return $this->rules; return $this->rules;
} }
/**
* @return RuleSetIterator
*/
public function getIterator() public function getIterator()
{ {
return new RuleSetIterator($this->getRules()); return new RuleSetIterator($this->getRules());

View File

@ -12,7 +12,7 @@
namespace Composer\DependencyResolver; namespace Composer\DependencyResolver;
use Composer\Package\PackageInterface; use Composer\Package\BasePackage;
use Composer\Package\AliasPackage; use Composer\Package\AliasPackage;
use Composer\Repository\PlatformRepository; use Composer\Repository\PlatformRepository;
@ -41,7 +41,7 @@ class RuleSetGenerator
* This rule is of the form (-A|B|C), where B and C are the providers of * This rule is of the form (-A|B|C), where B and C are the providers of
* one requirement of the package A. * one requirement of the package A.
* *
* @param PackageInterface $package The package with a requirement * @param BasePackage $package The package with a requirement
* @param array $providers The providers of the requirement * @param array $providers The providers of the requirement
* @param int $reason A RULE_* constant describing the * @param int $reason A RULE_* constant describing the
* reason for generating this rule * reason for generating this rule
@ -49,7 +49,7 @@ class RuleSetGenerator
* that goes with the reason * that goes with the reason
* @return Rule|null The generated rule or null if tautological * @return Rule|null The generated rule or null if tautological
*/ */
protected function createRequireRule(PackageInterface $package, array $providers, $reason, $reasonData = null) protected function createRequireRule(BasePackage $package, array $providers, $reason, $reasonData = null)
{ {
$literals = array(-$package->id); $literals = array(-$package->id);
@ -70,7 +70,7 @@ class RuleSetGenerator
* The rule is (A|B|C) with A, B and C different packages. If the given * The rule is (A|B|C) with A, B and C different packages. If the given
* set of packages is empty an impossible rule is generated. * set of packages is empty an impossible rule is generated.
* *
* @param array $packages The set of packages to choose from * @param BasePackage[] $packages The set of packages to choose from
* @param int $reason A RULE_* constant describing the reason for * @param int $reason A RULE_* constant describing the reason for
* generating this rule * generating this rule
* @param array $reasonData Additional data like the root require or fix request info * @param array $reasonData Additional data like the root require or fix request info
@ -92,15 +92,15 @@ class RuleSetGenerator
* The rule for conflicting packages A and B is (-A|-B). A is called the issuer * The rule for conflicting packages A and B is (-A|-B). A is called the issuer
* and B the provider. * and B the provider.
* *
* @param PackageInterface $issuer The package declaring the conflict * @param BasePackage $issuer The package declaring the conflict
* @param PackageInterface $provider The package causing the conflict * @param BasePackage $provider The package causing the conflict
* @param int $reason A RULE_* constant describing the * @param int $reason A RULE_* constant describing the
* reason for generating this rule * reason for generating this rule
* @param mixed $reasonData Any data, e.g. the package name, that * @param mixed $reasonData Any data, e.g. the package name, that
* goes with the reason * goes with the reason
* @return Rule|null The generated rule * @return Rule|null The generated rule
*/ */
protected function createRule2Literals(PackageInterface $issuer, PackageInterface $provider, $reason, $reasonData = null) protected function createRule2Literals(BasePackage $issuer, BasePackage $provider, $reason, $reasonData = null)
{ {
// ignore self conflict // ignore self conflict
if ($issuer === $provider) { if ($issuer === $provider) {
@ -142,13 +142,13 @@ class RuleSetGenerator
$this->rules->add($newRule, $type); $this->rules->add($newRule, $type);
} }
protected function addRulesForPackage(PackageInterface $package, $ignorePlatformReqs) protected function addRulesForPackage(BasePackage $package, $ignorePlatformReqs)
{ {
$workQueue = new \SplQueue; $workQueue = new \SplQueue;
$workQueue->enqueue($package); $workQueue->enqueue($package);
while (!$workQueue->isEmpty()) { while (!$workQueue->isEmpty()) {
/** @var PackageInterface $package */ /** @var BasePackage $package */
$package = $workQueue->dequeue(); $package = $workQueue->dequeue();
if (isset($this->addedMap[$package->id])) { if (isset($this->addedMap[$package->id])) {
continue; continue;
@ -192,7 +192,7 @@ class RuleSetGenerator
protected function addConflictRules($ignorePlatformReqs = false) protected function addConflictRules($ignorePlatformReqs = false)
{ {
/** @var PackageInterface $package */ /** @var BasePackage $package */
foreach ($this->addedMap as $package) { foreach ($this->addedMap as $package) {
foreach ($package->getConflicts() as $link) { foreach ($package->getConflicts() as $link) {
// even if conlict ends up being with an alias, there would be at least one actual package by this name // even if conlict ends up being with an alias, there would be at least one actual package by this name

View File

@ -137,7 +137,7 @@ class DownloadManager
$installationSource = $package->getInstallationSource(); $installationSource = $package->getInstallationSource();
if ('metapackage' === $package->getType()) { if ('metapackage' === $package->getType()) {
return; return null;
} }
if ('dist' === $installationSource) { if ('dist' === $installationSource) {
@ -256,6 +256,8 @@ class DownloadManager
if ($downloader) { if ($downloader) {
return $downloader->prepare($type, $package, $targetDir, $prevPackage); return $downloader->prepare($type, $package, $targetDir, $prevPackage);
} }
return \React\Promise\resolve();
} }
/** /**
@ -275,6 +277,8 @@ class DownloadManager
if ($downloader) { if ($downloader) {
return $downloader->install($package, $targetDir); return $downloader->install($package, $targetDir);
} }
return \React\Promise\resolve();
} }
/** /**
@ -295,7 +299,7 @@ class DownloadManager
// no downloaders present means update from metapackage to metapackage, nothing to do // no downloaders present means update from metapackage to metapackage, nothing to do
if (!$initialDownloader && !$downloader) { if (!$initialDownloader && !$downloader) {
return; return \React\Promise\resolve();
} }
// if we have a downloader present before, but not after, the package became a metapackage and its files should be removed // if we have a downloader present before, but not after, the package became a metapackage and its files should be removed
@ -348,6 +352,8 @@ class DownloadManager
if ($downloader) { if ($downloader) {
return $downloader->remove($package, $targetDir); return $downloader->remove($package, $targetDir);
} }
return \React\Promise\resolve();
} }
/** /**
@ -367,6 +373,8 @@ class DownloadManager
if ($downloader) { if ($downloader) {
return $downloader->cleanup($type, $package, $targetDir, $prevPackage); return $downloader->cleanup($type, $package, $targetDir, $prevPackage);
} }
return \React\Promise\resolve();
} }
/** /**

View File

@ -112,8 +112,10 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
}; };
$retries = 3; $retries = 3;
$urls = $package->getDistUrls(); $distUrls = $package->getDistUrls();
foreach ($urls as $index => $url) { /** @var array<array{base: string, processed: string, cacheKey: string}> $urls */
$urls = array();
foreach ($distUrls as $index => $url) {
$processedUrl = $this->processUrl($package, $url); $processedUrl = $this->processUrl($package, $url);
$urls[$index] = array( $urls[$index] = array(
'base' => $url, 'base' => $url,
@ -140,6 +142,7 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
$accept = null; $accept = null;
$reject = null; $reject = null;
$download = function () use ($io, $output, $httpDownloader, $cache, $cacheKeyGenerator, $eventDispatcher, $package, $fileName, &$urls, &$accept, &$reject) { $download = function () use ($io, $output, $httpDownloader, $cache, $cacheKeyGenerator, $eventDispatcher, $package, $fileName, &$urls, &$accept, &$reject) {
/** @var array{base: string, processed: string, cacheKey: string} $url */
$url = reset($urls); $url = reset($urls);
$index = key($urls); $index = key($urls);
@ -271,6 +274,7 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
*/ */
public function prepare($type, PackageInterface $package, $path, PackageInterface $prevPackage = null) public function prepare($type, PackageInterface $package, $path, PackageInterface $prevPackage = null)
{ {
return \React\Promise\resolve();
} }
/** /**
@ -300,6 +304,8 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
$this->filesystem->removeDirectory($dir); $this->filesystem->removeDirectory($dir);
} }
} }
return \React\Promise\resolve();
} }
/** /**
@ -324,6 +330,8 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
} }
} }
} }
return \React\Promise\resolve();
} }
/** /**

View File

@ -25,6 +25,7 @@ class FossilDownloader extends VcsDownloader
*/ */
protected function doDownload(PackageInterface $package, $path, $url, PackageInterface $prevPackage = null) protected function doDownload(PackageInterface $package, $path, $url, PackageInterface $prevPackage = null)
{ {
return \React\Promise\resolve();
} }
/** /**
@ -51,6 +52,8 @@ class FossilDownloader extends VcsDownloader
if (0 !== $this->process->execute($command, $ignoredOutput, realpath($path))) { if (0 !== $this->process->execute($command, $ignoredOutput, realpath($path))) {
throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
} }
return \React\Promise\resolve();
} }
/** /**
@ -72,6 +75,8 @@ class FossilDownloader extends VcsDownloader
if (0 !== $this->process->execute($command, $ignoredOutput, realpath($path))) { if (0 !== $this->process->execute($command, $ignoredOutput, realpath($path))) {
throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
} }
return \React\Promise\resolve();
} }
/** /**

View File

@ -74,6 +74,8 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
} elseif (null === $gitVersion) { } elseif (null === $gitVersion) {
throw new \RuntimeException('git was not found in your PATH, skipping source download'); throw new \RuntimeException('git was not found in your PATH, skipping source download');
} }
return \React\Promise\resolve();
} }
/** /**
@ -129,6 +131,8 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
} }
$package->setSourceReference($newRef); $package->setSourceReference($newRef);
} }
return \React\Promise\resolve();
} }
/** /**
@ -192,6 +196,8 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
if ($updateOriginUrl) { if ($updateOriginUrl) {
$this->updateOriginUrl($path, $target->getSourceUrl()); $this->updateOriginUrl($path, $target->getSourceUrl());
} }
return \React\Promise\resolve();
} }
/** /**
@ -201,7 +207,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
{ {
GitUtil::cleanEnv(); GitUtil::cleanEnv();
if (!$this->hasMetadataRepository($path)) { if (!$this->hasMetadataRepository($path)) {
return; return null;
} }
$command = 'git status --porcelain --untracked-files=no'; $command = 'git status --porcelain --untracked-files=no';
@ -217,7 +223,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
GitUtil::cleanEnv(); GitUtil::cleanEnv();
$path = $this->normalizePath($path); $path = $this->normalizePath($path);
if (!$this->hasMetadataRepository($path)) { if (!$this->hasMetadataRepository($path)) {
return; return null;
} }
$command = 'git show-ref --head -d'; $command = 'git show-ref --head -d';
@ -228,13 +234,13 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
$refs = trim($output); $refs = trim($output);
if (!preg_match('{^([a-f0-9]+) HEAD$}mi', $refs, $match)) { if (!preg_match('{^([a-f0-9]+) HEAD$}mi', $refs, $match)) {
// could not match the HEAD for some reason // could not match the HEAD for some reason
return; return null;
} }
$headRef = $match[1]; $headRef = $match[1];
if (!preg_match_all('{^'.$headRef.' refs/heads/(.+)$}mi', $refs, $matches)) { if (!preg_match_all('{^'.$headRef.' refs/heads/(.+)$}mi', $refs, $matches)) {
// not on a branch, we are either on a not-modified tag or some sort of detached head, so skip this // not on a branch, we are either on a not-modified tag or some sort of detached head, so skip this
return; return null;
} }
$candidateBranches = $matches[1]; $candidateBranches = $matches[1];

View File

@ -33,14 +33,14 @@ class GzipDownloader extends ArchiveDownloader
$command = 'gzip -cd ' . ProcessExecutor::escape($file) . ' > ' . ProcessExecutor::escape($targetFilepath); $command = 'gzip -cd ' . ProcessExecutor::escape($file) . ' > ' . ProcessExecutor::escape($targetFilepath);
if (0 === $this->process->execute($command, $ignoredOutput)) { if (0 === $this->process->execute($command, $ignoredOutput)) {
return; return \React\Promise\resolve();
} }
if (extension_loaded('zlib')) { if (extension_loaded('zlib')) {
// Fallback to using the PHP extension. // Fallback to using the PHP extension.
$this->extractUsingExt($file, $targetFilepath); $this->extractUsingExt($file, $targetFilepath);
return; return \React\Promise\resolve();
} }
$processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput(); $processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput();
@ -49,6 +49,8 @@ class GzipDownloader extends ArchiveDownloader
// Windows version of PHP has built-in support of gzip functions // Windows version of PHP has built-in support of gzip functions
$this->extractUsingExt($file, $targetFilepath); $this->extractUsingExt($file, $targetFilepath);
return \React\Promise\resolve();
} }
private function extractUsingExt($file, $targetFilepath) private function extractUsingExt($file, $targetFilepath)

View File

@ -29,6 +29,8 @@ class HgDownloader extends VcsDownloader
if (null === HgUtils::getVersion($this->process)) { if (null === HgUtils::getVersion($this->process)) {
throw new \RuntimeException('hg was not found in your PATH, skipping source download'); throw new \RuntimeException('hg was not found in your PATH, skipping source download');
} }
return \React\Promise\resolve();
} }
/** /**
@ -49,6 +51,8 @@ class HgDownloader extends VcsDownloader
if (0 !== $this->process->execute($command, $ignoredOutput, realpath($path))) { if (0 !== $this->process->execute($command, $ignoredOutput, realpath($path))) {
throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
} }
return \React\Promise\resolve();
} }
/** /**
@ -70,6 +74,8 @@ class HgDownloader extends VcsDownloader
}; };
$hgUtils->runCommand($command, $url, $path); $hgUtils->runCommand($command, $url, $path);
return \React\Promise\resolve();
} }
/** /**

View File

@ -52,7 +52,7 @@ class PathDownloader extends FileDownloader implements VcsCapableDownloaderInter
} }
if (realpath($path) === $realUrl) { if (realpath($path) === $realUrl) {
return; return \React\Promise\resolve();
} }
if (strpos(realpath($path) . DIRECTORY_SEPARATOR, $realUrl . DIRECTORY_SEPARATOR) === 0) { if (strpos(realpath($path) . DIRECTORY_SEPARATOR, $realUrl . DIRECTORY_SEPARATOR) === 0) {
@ -67,6 +67,8 @@ class PathDownloader extends FileDownloader implements VcsCapableDownloaderInter
$realUrl $realUrl
)); ));
} }
return \React\Promise\resolve();
} }
/** /**
@ -83,7 +85,7 @@ class PathDownloader extends FileDownloader implements VcsCapableDownloaderInter
$this->io->writeError(" - " . InstallOperation::format($package) . $this->getInstallOperationAppendix($package, $path)); $this->io->writeError(" - " . InstallOperation::format($package) . $this->getInstallOperationAppendix($package, $path));
} }
return; return \React\Promise\resolve();
} }
// Get the transport options with default values // Get the transport options with default values
@ -151,6 +153,8 @@ class PathDownloader extends FileDownloader implements VcsCapableDownloaderInter
if ($output) { if ($output) {
$this->io->writeError(''); $this->io->writeError('');
} }
return \React\Promise\resolve();
} }
/** /**
@ -176,13 +180,19 @@ class PathDownloader extends FileDownloader implements VcsCapableDownloaderInter
$this->io->writeError(" <warning>Could not remove junction at " . $path . " - is another process locking it?</warning>"); $this->io->writeError(" <warning>Could not remove junction at " . $path . " - is another process locking it?</warning>");
throw new \RuntimeException('Could not reliably remove junction for package ' . $package->getName()); throw new \RuntimeException('Could not reliably remove junction for package ' . $package->getName());
} }
} elseif (realpath($path) === realpath($package->getDistUrl())) {
return \React\Promise\resolve();
}
if (realpath($path) === realpath($package->getDistUrl())) {
if ($output) { if ($output) {
$this->io->writeError(" - " . UninstallOperation::format($package).", source is still present in $path"); $this->io->writeError(" - " . UninstallOperation::format($package).", source is still present in $path");
} }
} else {
return parent::remove($package, $path, $output); return \React\Promise\resolve();
} }
return parent::remove($package, $path, $output);
} }
/** /**
@ -199,6 +209,8 @@ class PathDownloader extends FileDownloader implements VcsCapableDownloaderInter
if ($packageVersion = $guesser->guessVersion($packageConfig, $path)) { if ($packageVersion = $guesser->guessVersion($packageConfig, $path)) {
return $packageVersion['commit']; return $packageVersion['commit'];
} }
return null;
} }
/** /**

View File

@ -29,6 +29,7 @@ class PerforceDownloader extends VcsDownloader
*/ */
protected function doDownload(PackageInterface $package, $path, $url, PackageInterface $prevPackage = null) protected function doDownload(PackageInterface $package, $path, $url, PackageInterface $prevPackage = null)
{ {
return \React\Promise\resolve();
} }
/** /**
@ -47,6 +48,8 @@ class PerforceDownloader extends VcsDownloader
$this->perforce->connectClient(); $this->perforce->connectClient();
$this->perforce->syncCodeBase($label); $this->perforce->syncCodeBase($label);
$this->perforce->cleanupClientSpec(); $this->perforce->cleanupClientSpec();
return \React\Promise\resolve();
} }
private function getLabelFromSourceReference($ref) private function getLabelFromSourceReference($ref)
@ -85,7 +88,7 @@ class PerforceDownloader extends VcsDownloader
*/ */
protected function doUpdate(PackageInterface $initial, PackageInterface $target, $path, $url) protected function doUpdate(PackageInterface $initial, PackageInterface $target, $path, $url)
{ {
$this->doInstall($target, $path, $url); return $this->doInstall($target, $path, $url);
} }
/** /**
@ -94,6 +97,8 @@ class PerforceDownloader extends VcsDownloader
public function getLocalChanges(PackageInterface $package, $path) public function getLocalChanges(PackageInterface $package, $path)
{ {
$this->io->writeError('Perforce driver does not check for local changes before overriding'); $this->io->writeError('Perforce driver does not check for local changes before overriding');
return null;
} }
/** /**

View File

@ -34,5 +34,7 @@ class PharDownloader extends ArchiveDownloader
* https://github.com/koto/phar-util * https://github.com/koto/phar-util
* http://blog.kotowicz.net/2010/08/hardening-php-how-to-securely-include.html * http://blog.kotowicz.net/2010/08/hardening-php-how-to-securely-include.html
*/ */
return \React\Promise\resolve();
} }
} }

View File

@ -36,7 +36,7 @@ class RarDownloader extends ArchiveDownloader
$command = 'unrar x ' . ProcessExecutor::escape($file) . ' ' . ProcessExecutor::escape($path) . ' >/dev/null && chmod -R u+w ' . ProcessExecutor::escape($path); $command = 'unrar x ' . ProcessExecutor::escape($file) . ' ' . ProcessExecutor::escape($path) . ' >/dev/null && chmod -R u+w ' . ProcessExecutor::escape($path);
if (0 === $this->process->execute($command, $ignoredOutput)) { if (0 === $this->process->execute($command, $ignoredOutput)) {
return; return \React\Promise\resolve();
} }
$processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput(); $processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput();
@ -75,5 +75,7 @@ class RarDownloader extends ArchiveDownloader
} }
$rarArchive->close(); $rarArchive->close();
return \React\Promise\resolve();
} }
} }

View File

@ -35,6 +35,8 @@ class SvnDownloader extends VcsDownloader
if (null === $util->binaryVersion()) { if (null === $util->binaryVersion()) {
throw new \RuntimeException('svn was not found in your PATH, skipping source download'); throw new \RuntimeException('svn was not found in your PATH, skipping source download');
} }
return \React\Promise\resolve();
} }
/** /**
@ -55,6 +57,8 @@ class SvnDownloader extends VcsDownloader
$this->io->writeError(" Checking out ".$package->getSourceReference()); $this->io->writeError(" Checking out ".$package->getSourceReference());
$this->execute($package, $url, "svn co", sprintf("%s/%s", $url, $ref), null, $path); $this->execute($package, $url, "svn co", sprintf("%s/%s", $url, $ref), null, $path);
return \React\Promise\resolve();
} }
/** /**
@ -77,6 +81,8 @@ class SvnDownloader extends VcsDownloader
$this->io->writeError(" Checking out " . $ref); $this->io->writeError(" Checking out " . $ref);
$this->execute($target, $url, "svn switch" . $flags, sprintf("%s/%s", $url, $ref), $path); $this->execute($target, $url, "svn switch" . $flags, sprintf("%s/%s", $url, $ref), $path);
return \React\Promise\resolve();
} }
/** /**

View File

@ -29,5 +29,7 @@ class TarDownloader extends ArchiveDownloader
// Can throw an UnexpectedValueException // Can throw an UnexpectedValueException
$archive = new \PharData($file); $archive = new \PharData($file);
$archive->extractTo($path, null, true); $archive->extractTo($path, null, true);
return \React\Promise\resolve();
} }
} }

View File

@ -86,6 +86,8 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa
} }
} }
} }
return \React\Promise\resolve();
} }
/** /**
@ -101,6 +103,8 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa
} elseif ($type === 'uninstall') { } elseif ($type === 'uninstall') {
$this->cleanChanges($package, $path, false); $this->cleanChanges($package, $path, false);
} }
return \React\Promise\resolve();
} }
/** /**
@ -112,6 +116,8 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa
$this->reapplyChanges($path); $this->reapplyChanges($path);
unset($this->hasCleanedChanges[$prevPackage->getUniqueName()]); unset($this->hasCleanedChanges[$prevPackage->getUniqueName()]);
} }
return \React\Promise\resolve();
} }
/** /**
@ -145,6 +151,8 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa
} }
} }
} }
return \React\Promise\resolve();
} }
/** /**
@ -207,6 +215,8 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa
if (!$urls && $exception) { if (!$urls && $exception) {
throw $exception; throw $exception;
} }
return \React\Promise\resolve();
} }
/** /**
@ -238,6 +248,8 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa
if ($packageVersion = $guesser->guessVersion($packageConfig, $path)) { if ($packageVersion = $guesser->guessVersion($packageConfig, $path)) {
return $packageVersion['commit']; return $packageVersion['commit'];
} }
return null;
} }
/** /**
@ -255,6 +267,8 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa
if (null !== $this->getLocalChanges($package, $path)) { if (null !== $this->getLocalChanges($package, $path)) {
throw new \RuntimeException('Source directory ' . $path . ' has uncommitted changes.'); throw new \RuntimeException('Source directory ' . $path . ' has uncommitted changes.');
} }
return \React\Promise\resolve();
} }
/** /**
@ -321,6 +335,9 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa
*/ */
abstract protected function hasMetadataRepository($path); abstract protected function hasMetadataRepository($path);
/**
* @return string[]
*/
private function prepareUrls(array $urls) private function prepareUrls(array $urls)
{ {
foreach ($urls as $index => $url) { foreach ($urls as $index => $url) {

View File

@ -28,7 +28,7 @@ class XzDownloader extends ArchiveDownloader
$command = 'tar -xJf ' . ProcessExecutor::escape($file) . ' -C ' . ProcessExecutor::escape($path); $command = 'tar -xJf ' . ProcessExecutor::escape($file) . ' -C ' . ProcessExecutor::escape($path);
if (0 === $this->process->execute($command, $ignoredOutput)) { if (0 === $this->process->execute($command, $ignoredOutput)) {
return; return \React\Promise\resolve();
} }
$processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput(); $processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput();

View File

@ -17,6 +17,7 @@ use Composer\Util\IniHelper;
use Composer\Util\Platform; use Composer\Util\Platform;
use Composer\Util\ProcessExecutor; use Composer\Util\ProcessExecutor;
use Symfony\Component\Process\ExecutableFinder; use Symfony\Component\Process\ExecutableFinder;
use React\Promise\PromiseInterface;
use ZipArchive; use ZipArchive;
/** /**
@ -72,6 +73,7 @@ class ZipDownloader extends ArchiveDownloader
* @param string $file File to extract * @param string $file File to extract
* @param string $path Path where to extract file * @param string $path Path where to extract file
* @param bool $isLastChance If true it is called as a fallback and should throw an exception * @param bool $isLastChance If true it is called as a fallback and should throw an exception
* @return PromiseInterface
*/ */
private function extractWithSystemUnzip(PackageInterface $package, $file, $path, $isLastChance, $async = false) private function extractWithSystemUnzip(PackageInterface $package, $file, $path, $isLastChance, $async = false)
{ {
@ -157,6 +159,7 @@ class ZipDownloader extends ArchiveDownloader
* @param string $file File to extract * @param string $file File to extract
* @param string $path Path where to extract file * @param string $path Path where to extract file
* @param bool $isLastChance If true it is called as a fallback and should throw an exception * @param bool $isLastChance If true it is called as a fallback and should throw an exception
* @return PromiseInterface
* *
* TODO v3 should make this private once we can drop PHP 5.3 support * TODO v3 should make this private once we can drop PHP 5.3 support
* @protected * @protected
@ -214,6 +217,7 @@ class ZipDownloader extends ArchiveDownloader
* *
* @param string $file File to extract * @param string $file File to extract
* @param string $path Path where to extract file * @param string $path Path where to extract file
* @return PromiseInterface|null
* *
* TODO v3 should make this private once we can drop PHP 5.3 support * TODO v3 should make this private once we can drop PHP 5.3 support
* @protected * @protected

View File

@ -24,7 +24,7 @@ use Composer\Installer\PackageEvent;
use Composer\Installer\BinaryInstaller; use Composer\Installer\BinaryInstaller;
use Composer\Util\ProcessExecutor; use Composer\Util\ProcessExecutor;
use Composer\Script\Event as ScriptEvent; use Composer\Script\Event as ScriptEvent;
use Composer\ClassLoader; use Composer\Autoload\ClassLoader;
use Symfony\Component\Process\PhpExecutableFinder; use Symfony\Component\Process\PhpExecutableFinder;
use Symfony\Component\Process\ExecutableFinder; use Symfony\Component\Process\ExecutableFinder;

View File

@ -154,119 +154,71 @@ abstract class BaseIO implements IOInterface
} }
/** /**
* System is unusable. * {@inheritDoc}
*
* @param string $message
* @param array $context
* @return null
*/ */
public function emergency($message, array $context = array()) public function emergency($message, array $context = array())
{ {
return $this->log(LogLevel::EMERGENCY, $message, $context); $this->log(LogLevel::EMERGENCY, $message, $context);
} }
/** /**
* Action must be taken immediately. * {@inheritDoc}
*
* Example: Entire website down, database unavailable, etc. This should
* trigger the SMS alerts and wake you up.
*
* @param string $message
* @param array $context
* @return null
*/ */
public function alert($message, array $context = array()) public function alert($message, array $context = array())
{ {
return $this->log(LogLevel::ALERT, $message, $context); $this->log(LogLevel::ALERT, $message, $context);
} }
/** /**
* Critical conditions. * {@inheritDoc}
*
* Example: Application component unavailable, unexpected exception.
*
* @param string $message
* @param array $context
* @return null
*/ */
public function critical($message, array $context = array()) public function critical($message, array $context = array())
{ {
return $this->log(LogLevel::CRITICAL, $message, $context); $this->log(LogLevel::CRITICAL, $message, $context);
} }
/** /**
* Runtime errors that do not require immediate action but should typically * {@inheritDoc}
* be logged and monitored.
*
* @param string $message
* @param array $context
* @return null
*/ */
public function error($message, array $context = array()) public function error($message, array $context = array())
{ {
return $this->log(LogLevel::ERROR, $message, $context); $this->log(LogLevel::ERROR, $message, $context);
} }
/** /**
* Exceptional occurrences that are not errors. * {@inheritDoc}
*
* Example: Use of deprecated APIs, poor use of an API, undesirable things
* that are not necessarily wrong.
*
* @param string $message
* @param array $context
* @return null
*/ */
public function warning($message, array $context = array()) public function warning($message, array $context = array())
{ {
return $this->log(LogLevel::WARNING, $message, $context); $this->log(LogLevel::WARNING, $message, $context);
} }
/** /**
* Normal but significant events. * {@inheritDoc}
*
* @param string $message
* @param array $context
* @return null
*/ */
public function notice($message, array $context = array()) public function notice($message, array $context = array())
{ {
return $this->log(LogLevel::NOTICE, $message, $context); $this->log(LogLevel::NOTICE, $message, $context);
} }
/** /**
* Interesting events. * {@inheritDoc}
*
* Example: User logs in, SQL logs.
*
* @param string $message
* @param array $context
* @return null
*/ */
public function info($message, array $context = array()) public function info($message, array $context = array())
{ {
return $this->log(LogLevel::INFO, $message, $context); $this->log(LogLevel::INFO, $message, $context);
} }
/** /**
* Detailed debug information. * {@inheritDoc}
*
* @param string $message
* @param array $context
* @return null
*/ */
public function debug($message, array $context = array()) public function debug($message, array $context = array())
{ {
return $this->log(LogLevel::DEBUG, $message, $context); $this->log(LogLevel::DEBUG, $message, $context);
} }
/** /**
* Logs with an arbitrary level. * {@inheritDoc}
*
* @param mixed $level
* @param string $message
* @param array $context
* @return null
*/ */
public function log($level, $message, array $context = array()) public function log($level, $message, array $context = array())
{ {

View File

@ -24,6 +24,11 @@ use Symfony\Component\Console\Helper\HelperSet;
*/ */
class BufferIO extends ConsoleIO class BufferIO extends ConsoleIO
{ {
/** @var StringInput */
protected $input;
/** @var StreamOutput */
protected $output;
/** /**
* @param string $input * @param string $input
* @param int $verbosity * @param int $verbosity

View File

@ -106,7 +106,7 @@ class NullIO extends BaseIO
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public function askAndValidate($question, $validator, $attempts = false, $default = null) public function askAndValidate($question, $validator, $attempts = null, $default = null)
{ {
return $default; return $default;
} }

View File

@ -135,13 +135,14 @@ class Installer
protected $writeLock; protected $writeLock;
protected $executeOperations = true; protected $executeOperations = true;
/** @var bool */
protected $updateMirrors = false;
/** /**
* Array of package names/globs flagged for update * Array of package names/globs flagged for update
* *
* @var array|null * @var array|null
*/ */
protected $updateMirrors = false; protected $updateAllowList = null;
protected $updateAllowList;
protected $updateAllowTransitiveDependencies = Request::UPDATE_ONLY_LISTED; protected $updateAllowTransitiveDependencies = Request::UPDATE_ONLY_LISTED;
/** /**
@ -918,7 +919,8 @@ class Installer
foreach ($packages as $key => $package) { foreach ($packages as $key => $package) {
if ($package instanceof AliasPackage) { if ($package instanceof AliasPackage) {
$alias = (string) $package->getAliasOf(); $alias = (string) $package->getAliasOf();
$packages[$key] = new AliasPackage($packages[$alias], $package->getVersion(), $package->getPrettyVersion()); $className = get_class($package);
$packages[$key] = new $className($packages[$alias], $package->getVersion(), $package->getPrettyVersion());
} }
} }
$rm->setLocalRepository( $rm->setLocalRepository(

View File

@ -172,12 +172,12 @@ class InstallationManager
/** /**
* Executes solver operation. * Executes solver operation.
* *
* @param RepositoryInterface $repo repository in which to add/remove/update packages * @param InstalledRepositoryInterface $repo repository in which to add/remove/update packages
* @param OperationInterface[] $operations operations to execute * @param OperationInterface[] $operations operations to execute
* @param bool $devMode whether the install is being run in dev mode * @param bool $devMode whether the install is being run in dev mode
* @param bool $runScripts whether to dispatch script events * @param bool $runScripts whether to dispatch script events
*/ */
public function execute(RepositoryInterface $repo, array $operations, $devMode = true, $runScripts = true) public function execute(InstalledRepositoryInterface $repo, array $operations, $devMode = true, $runScripts = true)
{ {
$cleanupPromises = array(); $cleanupPromises = array();
@ -243,8 +243,8 @@ class InstallationManager
$batches = array(); $batches = array();
$batch = array(); $batch = array();
foreach ($operations as $index => $operation) { foreach ($operations as $index => $operation) {
if (in_array($operation->getOperationType(), array('update', 'install'), true)) { if ($operation instanceof UpdateOperation || $operation instanceof InstallOperation) {
$package = $operation->getOperationType() === 'update' ? $operation->getTargetPackage() : $operation->getPackage(); $package = $operation instanceof UpdateOperation ? $operation->getTargetPackage() : $operation->getPackage();
if ($package->getType() === 'composer-plugin' && ($extra = $package->getExtra()) && isset($extra['plugin-modifies-downloads']) && $extra['plugin-modifies-downloads'] === true) { if ($package->getType() === 'composer-plugin' && ($extra = $package->getExtra()) && isset($extra['plugin-modifies-downloads']) && $extra['plugin-modifies-downloads'] === true) {
if ($batch) { if ($batch) {
$batches[] = $batch; $batches[] = $batch;
@ -272,7 +272,7 @@ class InstallationManager
pcntl_signal(SIGINT, $prevHandler); pcntl_signal(SIGINT, $prevHandler);
} }
if ($handleInterruptsWindows) { if ($handleInterruptsWindows) {
sapi_windows_set_ctrl_handler($prevHandler, false); sapi_windows_set_ctrl_handler($windowsHandler, false);
} }
throw $e; throw $e;
@ -282,7 +282,7 @@ class InstallationManager
pcntl_signal(SIGINT, $prevHandler); pcntl_signal(SIGINT, $prevHandler);
} }
if ($handleInterruptsWindows) { if ($handleInterruptsWindows) {
sapi_windows_set_ctrl_handler($prevHandler, false); sapi_windows_set_ctrl_handler($windowsHandler, false);
} }
// do a last write so that we write the repository even if nothing changed // do a last write so that we write the repository even if nothing changed
@ -295,7 +295,7 @@ class InstallationManager
* @param array $operations List of operations to execute in this batch * @param array $operations List of operations to execute in this batch
* @param array $allOperations Complete list of operations to be executed in the install job, used for event listeners * @param array $allOperations Complete list of operations to be executed in the install job, used for event listeners
*/ */
private function downloadAndExecuteBatch(RepositoryInterface $repo, array $operations, array &$cleanupPromises, $devMode, $runScripts, array $allOperations) private function downloadAndExecuteBatch(InstalledRepositoryInterface $repo, array $operations, array &$cleanupPromises, $devMode, $runScripts, array $allOperations)
{ {
$promises = array(); $promises = array();
@ -372,7 +372,7 @@ class InstallationManager
* @param array $operations List of operations to execute in this batch * @param array $operations List of operations to execute in this batch
* @param array $allOperations Complete list of operations to be executed in the install job, used for event listeners * @param array $allOperations Complete list of operations to be executed in the install job, used for event listeners
*/ */
private function executeBatch(RepositoryInterface $repo, array $operations, array $cleanupPromises, $devMode, $runScripts, array $allOperations) private function executeBatch(InstalledRepositoryInterface $repo, array $operations, array $cleanupPromises, $devMode, $runScripts, array $allOperations)
{ {
$promises = array(); $promises = array();
$postExecCallbacks = array(); $postExecCallbacks = array();
@ -460,10 +460,10 @@ class InstallationManager
/** /**
* Executes install operation. * Executes install operation.
* *
* @param RepositoryInterface $repo repository in which to check * @param InstalledRepositoryInterface $repo repository in which to check
* @param InstallOperation $operation operation instance * @param InstallOperation $operation operation instance
*/ */
public function install(RepositoryInterface $repo, InstallOperation $operation) public function install(InstalledRepositoryInterface $repo, InstallOperation $operation)
{ {
$package = $operation->getPackage(); $package = $operation->getPackage();
$installer = $this->getInstaller($package->getType()); $installer = $this->getInstaller($package->getType());
@ -476,10 +476,10 @@ class InstallationManager
/** /**
* Executes update operation. * Executes update operation.
* *
* @param RepositoryInterface $repo repository in which to check * @param InstalledRepositoryInterface $repo repository in which to check
* @param UpdateOperation $operation operation instance * @param UpdateOperation $operation operation instance
*/ */
public function update(RepositoryInterface $repo, UpdateOperation $operation) public function update(InstalledRepositoryInterface $repo, UpdateOperation $operation)
{ {
$initial = $operation->getInitialPackage(); $initial = $operation->getInitialPackage();
$target = $operation->getTargetPackage(); $target = $operation->getTargetPackage();
@ -509,10 +509,10 @@ class InstallationManager
/** /**
* Uninstalls package. * Uninstalls package.
* *
* @param RepositoryInterface $repo repository in which to check * @param InstalledRepositoryInterface $repo repository in which to check
* @param UninstallOperation $operation operation instance * @param UninstallOperation $operation operation instance
*/ */
public function uninstall(RepositoryInterface $repo, UninstallOperation $operation) public function uninstall(InstalledRepositoryInterface $repo, UninstallOperation $operation)
{ {
$package = $operation->getPackage(); $package = $operation->getPackage();
$installer = $this->getInstaller($package->getType()); $installer = $this->getInstaller($package->getType());
@ -523,10 +523,10 @@ class InstallationManager
/** /**
* Executes markAliasInstalled operation. * Executes markAliasInstalled operation.
* *
* @param RepositoryInterface $repo repository in which to check * @param InstalledRepositoryInterface $repo repository in which to check
* @param MarkAliasInstalledOperation $operation operation instance * @param MarkAliasInstalledOperation $operation operation instance
*/ */
public function markAliasInstalled(RepositoryInterface $repo, MarkAliasInstalledOperation $operation) public function markAliasInstalled(InstalledRepositoryInterface $repo, MarkAliasInstalledOperation $operation)
{ {
$package = $operation->getPackage(); $package = $operation->getPackage();
@ -538,10 +538,10 @@ class InstallationManager
/** /**
* Executes markAlias operation. * Executes markAlias operation.
* *
* @param RepositoryInterface $repo repository in which to check * @param InstalledRepositoryInterface $repo repository in which to check
* @param MarkAliasUninstalledOperation $operation operation instance * @param MarkAliasUninstalledOperation $operation operation instance
*/ */
public function markAliasUninstalled(RepositoryInterface $repo, MarkAliasUninstalledOperation $operation) public function markAliasUninstalled(InstalledRepositoryInterface $repo, MarkAliasUninstalledOperation $operation)
{ {
$package = $operation->getPackage(); $package = $operation->getPackage();

View File

@ -55,6 +55,7 @@ class MetapackageInstaller implements InstallerInterface
public function download(PackageInterface $package, PackageInterface $prevPackage = null) public function download(PackageInterface $package, PackageInterface $prevPackage = null)
{ {
// noop // noop
return \React\Promise\resolve();
} }
/** /**
@ -63,6 +64,7 @@ class MetapackageInstaller implements InstallerInterface
public function prepare($type, PackageInterface $package, PackageInterface $prevPackage = null) public function prepare($type, PackageInterface $package, PackageInterface $prevPackage = null)
{ {
// noop // noop
return \React\Promise\resolve();
} }
/** /**
@ -71,6 +73,7 @@ class MetapackageInstaller implements InstallerInterface
public function cleanup($type, PackageInterface $package, PackageInterface $prevPackage = null) public function cleanup($type, PackageInterface $package, PackageInterface $prevPackage = null)
{ {
// noop // noop
return \React\Promise\resolve();
} }
/** /**
@ -81,6 +84,8 @@ class MetapackageInstaller implements InstallerInterface
$this->io->writeError(" - " . InstallOperation::format($package)); $this->io->writeError(" - " . InstallOperation::format($package));
$repo->addPackage(clone $package); $repo->addPackage(clone $package);
return \React\Promise\resolve();
} }
/** /**
@ -96,6 +101,8 @@ class MetapackageInstaller implements InstallerInterface
$repo->removePackage($initial); $repo->removePackage($initial);
$repo->addPackage(clone $target); $repo->addPackage(clone $target);
return \React\Promise\resolve();
} }
/** /**
@ -110,6 +117,8 @@ class MetapackageInstaller implements InstallerInterface
$this->io->writeError(" - " . UninstallOperation::format($package)); $this->io->writeError(" - " . UninstallOperation::format($package));
$repo->removePackage($package); $repo->removePackage($package);
return \React\Promise\resolve();
} }
/** /**

View File

@ -45,6 +45,7 @@ class NoopInstaller implements InstallerInterface
*/ */
public function download(PackageInterface $package, PackageInterface $prevPackage = null) public function download(PackageInterface $package, PackageInterface $prevPackage = null)
{ {
return \React\Promise\resolve();
} }
/** /**
@ -52,6 +53,7 @@ class NoopInstaller implements InstallerInterface
*/ */
public function prepare($type, PackageInterface $package, PackageInterface $prevPackage = null) public function prepare($type, PackageInterface $package, PackageInterface $prevPackage = null)
{ {
return \React\Promise\resolve();
} }
/** /**
@ -59,6 +61,7 @@ class NoopInstaller implements InstallerInterface
*/ */
public function cleanup($type, PackageInterface $package, PackageInterface $prevPackage = null) public function cleanup($type, PackageInterface $package, PackageInterface $prevPackage = null)
{ {
return \React\Promise\resolve();
} }
/** /**
@ -69,6 +72,8 @@ class NoopInstaller implements InstallerInterface
if (!$repo->hasPackage($package)) { if (!$repo->hasPackage($package)) {
$repo->addPackage(clone $package); $repo->addPackage(clone $package);
} }
return \React\Promise\resolve();
} }
/** /**
@ -84,6 +89,8 @@ class NoopInstaller implements InstallerInterface
if (!$repo->hasPackage($target)) { if (!$repo->hasPackage($target)) {
$repo->addPackage(clone $target); $repo->addPackage(clone $target);
} }
return \React\Promise\resolve();
} }
/** /**
@ -95,6 +102,8 @@ class NoopInstaller implements InstallerInterface
throw new \InvalidArgumentException('Package is not installed: '.$package); throw new \InvalidArgumentException('Package is not installed: '.$package);
} }
$repo->removePackage($package); $repo->removePackage($package);
return \React\Promise\resolve();
} }
/** /**

View File

@ -101,7 +101,7 @@ class SuggestedPackagesReporter
* @param int $mode One of the MODE_* constants from this class * @param int $mode One of the MODE_* constants from this class
* @param InstalledRepository|null $installedRepo If passed in, suggested packages which are installed already will be skipped * @param InstalledRepository|null $installedRepo If passed in, suggested packages which are installed already will be skipped
* @param PackageInterface|null $onlyDependentsOf If passed in, only the suggestions from direct dependents of that package, or from the package itself, will be shown * @param PackageInterface|null $onlyDependentsOf If passed in, only the suggestions from direct dependents of that package, or from the package itself, will be shown
* @return SuggestedPackagesReporter * @return void
*/ */
public function output($mode, InstalledRepository $installedRepo = null, PackageInterface $onlyDependentsOf = null) public function output($mode, InstalledRepository $installedRepo = null, PackageInterface $onlyDependentsOf = null)
{ {
@ -122,7 +122,7 @@ class SuggestedPackagesReporter
$this->io->write(sprintf('<info>%s</info>', $name)); $this->io->write(sprintf('<info>%s</info>', $name));
} }
return 0; return;
} }
// Grouped by package // Grouped by package
@ -160,8 +160,6 @@ class SuggestedPackagesReporter
$this->io->write('<info>'.$diff.' additional suggestions</info> by transitive dependencies can be shown with <info>--all</info>'); $this->io->write('<info>'.$diff.' additional suggestions</info> by transitive dependencies can be shown with <info>--all</info>');
} }
} }
return $this;
} }
/** /**
@ -169,7 +167,7 @@ class SuggestedPackagesReporter
* *
* @param InstalledRepository|null $installedRepo If passed in, suggested packages which are installed already will be skipped * @param InstalledRepository|null $installedRepo If passed in, suggested packages which are installed already will be skipped
* @param PackageInterface|null $onlyDependentsOf If passed in, only the suggestions from direct dependents of that package, or from the package itself, will be shown * @param PackageInterface|null $onlyDependentsOf If passed in, only the suggestions from direct dependents of that package, or from the package itself, will be shown
* @return SuggestedPackagesReporter * @return void
*/ */
public function outputMinimalistic(InstalledRepository $installedRepo = null, PackageInterface $onlyDependentsOf = null) public function outputMinimalistic(InstalledRepository $installedRepo = null, PackageInterface $onlyDependentsOf = null)
{ {
@ -177,8 +175,6 @@ class SuggestedPackagesReporter
if ($suggestedPackages) { if ($suggestedPackages) {
$this->io->writeError('<info>'.count($suggestedPackages).' package suggestions were added by new dependencies, use `composer suggest` to see details.</info>'); $this->io->writeError('<info>'.count($suggestedPackages).' package suggestions were added by new dependencies, use `composer suggest` to see details.</info>');
} }
return $this;
} }
/** /**

View File

@ -18,7 +18,7 @@ use Composer\Package\Version\VersionParser;
/** /**
* @author Jordi Boggiano <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
*/ */
class AliasPackage extends BasePackage implements CompletePackageInterface class AliasPackage extends BasePackage
{ {
protected $version; protected $version;
protected $prettyVersion; protected $prettyVersion;
@ -27,7 +27,7 @@ class AliasPackage extends BasePackage implements CompletePackageInterface
protected $stability; protected $stability;
protected $hasSelfVersionRequires = false; protected $hasSelfVersionRequires = false;
/** @var PackageInterface */ /** @var BasePackage */
protected $aliasOf; protected $aliasOf;
/** @var Link[] */ /** @var Link[] */
protected $requires; protected $requires;
@ -43,11 +43,11 @@ class AliasPackage extends BasePackage implements CompletePackageInterface
/** /**
* All descendants' constructors should call this parent constructor * All descendants' constructors should call this parent constructor
* *
* @param PackageInterface $aliasOf The package this package is an alias of * @param BasePackage $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(PackageInterface $aliasOf, $version, $prettyVersion) public function __construct(BasePackage $aliasOf, $version, $prettyVersion)
{ {
parent::__construct($aliasOf->getName()); parent::__construct($aliasOf->getName());
@ -64,7 +64,7 @@ class AliasPackage extends BasePackage implements CompletePackageInterface
} }
/** /**
* @return PackageInterface * @return BasePackage
*/ */
public function getAliasOf() public function getAliasOf()
{ {
@ -210,6 +210,11 @@ class AliasPackage extends BasePackage implements CompletePackageInterface
return $this->hasSelfVersionRequires; return $this->hasSelfVersionRequires;
} }
public function __toString()
{
return parent::__toString().' ('.($this->rootPackageAlias ? 'root ' : ''). 'alias of '.$this->aliasOf->getVersion().')';
}
/*************************************** /***************************************
* Wrappers around the aliased package * * Wrappers around the aliased package *
***************************************/ ***************************************/
@ -261,12 +266,12 @@ class AliasPackage extends BasePackage implements CompletePackageInterface
public function setSourceReference($reference) public function setSourceReference($reference)
{ {
return $this->aliasOf->setSourceReference($reference); $this->aliasOf->setSourceReference($reference);
} }
public function setSourceMirrors($mirrors) public function setSourceMirrors($mirrors)
{ {
return $this->aliasOf->setSourceMirrors($mirrors); $this->aliasOf->setSourceMirrors($mirrors);
} }
public function getSourceMirrors() public function getSourceMirrors()
@ -296,7 +301,7 @@ class AliasPackage extends BasePackage implements CompletePackageInterface
public function setDistReference($reference) public function setDistReference($reference)
{ {
return $this->aliasOf->setDistReference($reference); $this->aliasOf->setDistReference($reference);
} }
public function getDistSha1Checksum() public function getDistSha1Checksum()
@ -306,7 +311,7 @@ class AliasPackage extends BasePackage implements CompletePackageInterface
public function setTransportOptions(array $options) public function setTransportOptions(array $options)
{ {
return $this->aliasOf->setTransportOptions($options); $this->aliasOf->setTransportOptions($options);
} }
public function getTransportOptions() public function getTransportOptions()
@ -316,7 +321,7 @@ class AliasPackage extends BasePackage implements CompletePackageInterface
public function setDistMirrors($mirrors) public function setDistMirrors($mirrors)
{ {
return $this->aliasOf->setDistMirrors($mirrors); $this->aliasOf->setDistMirrors($mirrors);
} }
public function getDistMirrors() public function getDistMirrors()
@ -324,16 +329,6 @@ class AliasPackage extends BasePackage implements CompletePackageInterface
return $this->aliasOf->getDistMirrors(); return $this->aliasOf->getDistMirrors();
} }
public function getScripts()
{
return $this->aliasOf->getScripts();
}
public function getLicense()
{
return $this->aliasOf->getLicense();
}
public function getAutoload() public function getAutoload()
{ {
return $this->aliasOf->getAutoload(); return $this->aliasOf->getAutoload();
@ -349,11 +344,6 @@ class AliasPackage extends BasePackage implements CompletePackageInterface
return $this->aliasOf->getIncludePaths(); return $this->aliasOf->getIncludePaths();
} }
public function getRepositories()
{
return $this->aliasOf->getRepositories();
}
public function getReleaseDate() public function getReleaseDate()
{ {
return $this->aliasOf->getReleaseDate(); return $this->aliasOf->getReleaseDate();
@ -364,88 +354,33 @@ class AliasPackage extends BasePackage implements CompletePackageInterface
return $this->aliasOf->getBinaries(); return $this->aliasOf->getBinaries();
} }
public function getKeywords()
{
return $this->aliasOf->getKeywords();
}
public function getDescription()
{
return $this->aliasOf->getDescription();
}
public function getHomepage()
{
return $this->aliasOf->getHomepage();
}
public function getSuggests() public function getSuggests()
{ {
return $this->aliasOf->getSuggests(); return $this->aliasOf->getSuggests();
} }
public function getAuthors()
{
return $this->aliasOf->getAuthors();
}
public function getSupport()
{
return $this->aliasOf->getSupport();
}
public function getFunding()
{
return $this->aliasOf->getFunding();
}
public function getNotificationUrl() public function getNotificationUrl()
{ {
return $this->aliasOf->getNotificationUrl(); return $this->aliasOf->getNotificationUrl();
} }
public function getArchiveName()
{
return $this->aliasOf->getArchiveName();
}
public function getArchiveExcludes()
{
return $this->aliasOf->getArchiveExcludes();
}
public function isDefaultBranch() public function isDefaultBranch()
{ {
return $this->aliasOf->isDefaultBranch(); return $this->aliasOf->isDefaultBranch();
} }
public function isAbandoned()
{
return $this->aliasOf->isAbandoned();
}
public function getReplacementPackage()
{
return $this->aliasOf->getReplacementPackage();
}
public function __toString()
{
return parent::__toString().' ('.($this->rootPackageAlias ? 'root ' : ''). 'alias of '.$this->aliasOf->getVersion().')';
}
public function setDistUrl($url) public function setDistUrl($url)
{ {
return $this->aliasOf->setDistUrl($url); $this->aliasOf->setDistUrl($url);
} }
public function setDistType($type) public function setDistType($type)
{ {
return $this->aliasOf->setDistType($type); $this->aliasOf->setDistType($type);
} }
public function setSourceDistReferences($reference) public function setSourceDistReferences($reference)
{ {
return $this->aliasOf->setSourceDistReferences($reference); $this->aliasOf->setSourceDistReferences($reference);
} }
} }

View File

@ -18,6 +18,7 @@ use Composer\Package\RootPackageInterface;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
use Composer\Util\Loop; use Composer\Util\Loop;
use Composer\Json\JsonFile; use Composer\Json\JsonFile;
use Composer\Package\CompletePackageInterface;
/** /**
* @author Matthieu Moquet <matthieu@moquet.net> * @author Matthieu Moquet <matthieu@moquet.net>
@ -74,11 +75,11 @@ class ArchiveManager
/** /**
* Generate a distinct filename for a particular version of a package. * Generate a distinct filename for a particular version of a package.
* *
* @param PackageInterface $package The package to get a name for * @param CompletePackageInterface $package The package to get a name for
* *
* @return string A filename without an extension * @return string A filename without an extension
*/ */
public function getPackageFilename(PackageInterface $package) public function getPackageFilename(CompletePackageInterface $package)
{ {
if ($package->getArchiveName()) { if ($package->getArchiveName()) {
$baseName = $package->getArchiveName(); $baseName = $package->getArchiveName();
@ -107,7 +108,7 @@ class ArchiveManager
/** /**
* Create an archive of the specified package. * Create an archive of the specified package.
* *
* @param PackageInterface $package The package to archive * @param CompletePackageInterface $package The package to archive
* @param string $format The format of the archive (zip, tar, ...) * @param string $format The format of the archive (zip, tar, ...)
* @param string $targetDir The directory where to build the archive * @param string $targetDir The directory where to build the archive
* @param string|null $fileName The relative file name to use for the archive, or null to generate * @param string|null $fileName The relative file name to use for the archive, or null to generate
@ -117,7 +118,7 @@ class ArchiveManager
* @throws \RuntimeException * @throws \RuntimeException
* @return string The path of the created archive * @return string The path of the created archive
*/ */
public function archive(PackageInterface $package, $format, $targetDir, $fileName = null, $ignoreFilters = false) public function archive(CompletePackageInterface $package, $format, $targetDir, $fileName = null, $ignoreFilters = false)
{ {
if (empty($format)) { if (empty($format)) {
throw new \InvalidArgumentException('Format must be specified'); throw new \InvalidArgumentException('Format must be specified');

View File

@ -23,7 +23,7 @@ use Composer\Repository\PlatformRepository;
abstract class BasePackage implements PackageInterface abstract class BasePackage implements PackageInterface
{ {
/** /**
* @phpstan-var array<string, array{description: string, method: Link::TYPE_*}> * @psalm-var array<string, array{description: string, method: Link::TYPE_*}>
*/ */
public static $supportedLinkTypes = array( public static $supportedLinkTypes = array(
'require' => array('description' => 'requires', 'method' => Link::TYPE_REQUIRE), 'require' => array('description' => 'requires', 'method' => Link::TYPE_REQUIRE),
@ -50,16 +50,16 @@ abstract class BasePackage implements PackageInterface
/** /**
* READ-ONLY: The package id, public for fast access in dependency solver * READ-ONLY: The package id, public for fast access in dependency solver
* @var int * @var int
* @internal
* @readonly
*/ */
public $id; public $id;
/** @var string */ /** @var string */
protected $name; protected $name;
/** @var string */ /** @var string */
protected $prettyName; protected $prettyName;
/** @var RepositoryInterface */ /** @var ?RepositoryInterface */
protected $repository; protected $repository = null;
/** @var array */
protected $transportOptions = array();
/** /**
* All descendants' constructors should call this parent constructor * All descendants' constructors should call this parent constructor
@ -146,24 +146,6 @@ abstract class BasePackage implements PackageInterface
return $this->repository; return $this->repository;
} }
/**
* {@inheritDoc}
*/
public function getTransportOptions()
{
return $this->transportOptions;
}
/**
* Configures the list of options to download package dist files
*
* @param array $options
*/
public function setTransportOptions(array $options)
{
$this->transportOptions = $options;
}
/** /**
* checks if this package is a platform package * checks if this package is a platform package
* *

View File

@ -0,0 +1,167 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Package;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class CompleteAliasPackage extends AliasPackage implements CompletePackageInterface
{
/** @var CompletePackage */
protected $aliasOf;
/**
* All descendants' constructors should call this parent constructor
*
* @param CompletePackage $aliasOf The package this package is an alias of
* @param string $version The version the alias must report
* @param string $prettyVersion The alias's non-normalized version
*/
public function __construct(CompletePackage $aliasOf, $version, $prettyVersion)
{
parent::__construct($aliasOf, $version, $prettyVersion);
}
/**
* @return CompletePackage
*/
public function getAliasOf()
{
return $this->aliasOf;
}
public function getScripts()
{
return $this->aliasOf->getScripts();
}
public function setScripts(array $scripts)
{
$this->aliasOf->setScripts($scripts);
}
public function getRepositories()
{
return $this->aliasOf->getRepositories();
}
public function setRepositories(array $repositories)
{
$this->aliasOf->setRepositories($repositories);
}
public function getLicense()
{
return $this->aliasOf->getLicense();
}
public function setLicense(array $license)
{
$this->aliasOf->setLicense($license);
}
public function getKeywords()
{
return $this->aliasOf->getKeywords();
}
public function setKeywords(array $keywords)
{
$this->aliasOf->setKeywords($keywords);
}
public function getDescription()
{
return $this->aliasOf->getDescription();
}
public function setDescription($description)
{
$this->aliasOf->setDescription($description);
}
public function getHomepage()
{
return $this->aliasOf->getHomepage();
}
public function setHomepage($homepage)
{
$this->aliasOf->setHomepage($homepage);
}
public function getAuthors()
{
return $this->aliasOf->getAuthors();
}
public function setAuthors(array $authors)
{
$this->aliasOf->setAuthors($authors);
}
public function getSupport()
{
return $this->aliasOf->getSupport();
}
public function setSupport(array $support)
{
$this->aliasOf->setSupport($support);
}
public function getFunding()
{
return $this->aliasOf->getFunding();
}
public function setFunding(array $funding)
{
$this->aliasOf->setFunding($funding);
}
public function isAbandoned()
{
return $this->aliasOf->isAbandoned();
}
public function getReplacementPackage()
{
return $this->aliasOf->getReplacementPackage();
}
public function setAbandoned($abandoned)
{
$this->aliasOf->setAbandoned($abandoned);
}
public function getArchiveName()
{
return $this->aliasOf->getArchiveName();
}
public function setArchiveName($name)
{
$this->aliasOf->setArchiveName($name);
}
public function getArchiveExcludes()
{
return $this->aliasOf->getArchiveExcludes();
}
public function setArchiveExcludes(array $excludes)
{
$this->aliasOf->setArchiveExcludes($excludes);
}
}

View File

@ -29,9 +29,11 @@ class CompletePackage extends Package implements CompletePackageInterface
protected $support = array(); protected $support = array();
protected $funding = array(); protected $funding = array();
protected $abandoned = false; protected $abandoned = false;
protected $archiveName;
protected $archiveExcludes = array();
/** /**
* @param array $scripts * {@inheritDoc}
*/ */
public function setScripts(array $scripts) public function setScripts(array $scripts)
{ {
@ -47,11 +49,9 @@ class CompletePackage extends Package implements CompletePackageInterface
} }
/** /**
* Set the repositories * {@inheritDoc}
*
* @param array $repositories
*/ */
public function setRepositories($repositories) public function setRepositories(array $repositories)
{ {
$this->repositories = $repositories; $this->repositories = $repositories;
} }
@ -65,9 +65,7 @@ class CompletePackage extends Package implements CompletePackageInterface
} }
/** /**
* Set the license * {@inheritDoc}
*
* @param array $license
*/ */
public function setLicense(array $license) public function setLicense(array $license)
{ {
@ -83,9 +81,7 @@ class CompletePackage extends Package implements CompletePackageInterface
} }
/** /**
* Set the keywords * {@inheritDoc}
*
* @param array $keywords
*/ */
public function setKeywords(array $keywords) public function setKeywords(array $keywords)
{ {
@ -101,9 +97,7 @@ class CompletePackage extends Package implements CompletePackageInterface
} }
/** /**
* Set the authors * {@inheritDoc}
*
* @param array $authors
*/ */
public function setAuthors(array $authors) public function setAuthors(array $authors)
{ {
@ -119,9 +113,7 @@ class CompletePackage extends Package implements CompletePackageInterface
} }
/** /**
* Set the description * {@inheritDoc}
*
* @param string $description
*/ */
public function setDescription($description) public function setDescription($description)
{ {
@ -137,9 +129,7 @@ class CompletePackage extends Package implements CompletePackageInterface
} }
/** /**
* Set the homepage * {@inheritDoc}
*
* @param string $homepage
*/ */
public function setHomepage($homepage) public function setHomepage($homepage)
{ {
@ -155,9 +145,7 @@ class CompletePackage extends Package implements CompletePackageInterface
} }
/** /**
* Set the support information * {@inheritDoc}
*
* @param array $support
*/ */
public function setSupport(array $support) public function setSupport(array $support)
{ {
@ -173,9 +161,7 @@ class CompletePackage extends Package implements CompletePackageInterface
} }
/** /**
* Set the funding * {@inheritDoc}
*
* @param array $funding
*/ */
public function setFunding(array $funding) public function setFunding(array $funding)
{ {
@ -191,7 +177,7 @@ class CompletePackage extends Package implements CompletePackageInterface
} }
/** /**
* @return bool * {@inheritDoc}
*/ */
public function isAbandoned() public function isAbandoned()
{ {
@ -199,7 +185,7 @@ class CompletePackage extends Package implements CompletePackageInterface
} }
/** /**
* @param bool|string $abandoned * {@inheritDoc}
*/ */
public function setAbandoned($abandoned) public function setAbandoned($abandoned)
{ {
@ -207,12 +193,42 @@ class CompletePackage extends Package implements CompletePackageInterface
} }
/** /**
* If the package is abandoned and has a suggested replacement, this method returns it * {@inheritDoc}
*
* @return string|null
*/ */
public function getReplacementPackage() public function getReplacementPackage()
{ {
return \is_string($this->abandoned) ? $this->abandoned : null; return \is_string($this->abandoned) ? $this->abandoned : null;
} }
/**
* {@inheritDoc}
*/
public function setArchiveName($name)
{
$this->archiveName = $name;
}
/**
* {@inheritDoc}
*/
public function getArchiveName()
{
return $this->archiveName;
}
/**
* {@inheritDoc}
*/
public function setArchiveExcludes(array $excludes)
{
$this->archiveExcludes = $excludes;
}
/**
* {@inheritDoc}
*/
public function getArchiveExcludes()
{
return $this->archiveExcludes;
}
} }

View File

@ -22,19 +22,31 @@ interface CompletePackageInterface extends PackageInterface
/** /**
* Returns the scripts of this package * Returns the scripts of this package
* *
* @return array[] array('script name' => array('listeners')) * @return array<string, string[]> array('script name' => array('listeners'))
* @psalm-return array<string, string[]>
*/ */
public function getScripts(); public function getScripts();
/**
* @param array<string, string[]> $scripts
* @return void
*/
public function setScripts(array $scripts);
/** /**
* Returns an array of repositories * Returns an array of repositories
* *
* @return array[] Repositories * @return array<array{type: string, url?: string}> Repositories
* @psalm-return array<array{type: string, url?: string}>
*/ */
public function getRepositories(); public function getRepositories();
/**
* Set the repositories
*
* @param array<array{type: string, url?: string}> $repositories
* @return void
*/
public function setRepositories(array $repositories);
/** /**
* Returns the package license, e.g. MIT, BSD, GPL * Returns the package license, e.g. MIT, BSD, GPL
* *
@ -42,6 +54,14 @@ interface CompletePackageInterface extends PackageInterface
*/ */
public function getLicense(); public function getLicense();
/**
* Set the license
*
* @param string[] $license
* @return void
*/
public function setLicense(array $license);
/** /**
* Returns an array of keywords relating to the package * Returns an array of keywords relating to the package
* *
@ -49,6 +69,14 @@ interface CompletePackageInterface extends PackageInterface
*/ */
public function getKeywords(); public function getKeywords();
/**
* Set the keywords
*
* @param string[] $keywords
* @return void
*/
public function setKeywords(array $keywords);
/** /**
* Returns the package description * Returns the package description
* *
@ -56,6 +84,14 @@ interface CompletePackageInterface extends PackageInterface
*/ */
public function getDescription(); public function getDescription();
/**
* Set the description
*
* @param string $description
* @return void
*/
public function setDescription($description);
/** /**
* Returns the package homepage * Returns the package homepage
* *
@ -63,34 +99,63 @@ interface CompletePackageInterface extends PackageInterface
*/ */
public function getHomepage(); public function getHomepage();
/**
* Set the homepage
*
* @param string $homepage
* @return void
*/
public function setHomepage($homepage);
/** /**
* Returns an array of authors of the package * Returns an array of authors of the package
* *
* Each item can contain name/homepage/email keys * Each item can contain name/homepage/email keys
* *
* @return array[] * @return array<array{name?: string, homepage?: string, email?: string, role?: string}>
* @psalm-return array<array{?name: string, homepage?: string, email?: string, role?: string}>
*/ */
public function getAuthors(); public function getAuthors();
/**
* Set the authors
*
* @param array<array{name?: string, homepage?: string, email?: string, role?: string}> $authors
* @return void
*/
public function setAuthors(array $authors);
/** /**
* Returns the support information * Returns the support information
* *
* @return array * @return array<string, string>
* @psalm-return array<string, string>
*/ */
public function getSupport(); public function getSupport();
/**
* Set the support information
*
* @param array<string, string> $support
* @return void
*/
public function setSupport(array $support);
/** /**
* Returns an array of funding options for the package * Returns an array of funding options for the package
* *
* Each item will contain type and url keys * Each item will contain type and url keys
* *
* @return array[] * @return array<array{type: string, url: string}>
* @psalm-return array<array{type: string, url: string}>
*/ */
public function getFunding(); public function getFunding();
/**
* Set the funding
*
* @param array<array{type: string, url: string}> $funding
* @return void
*/
public function setFunding(array $funding);
/** /**
* Returns if the package is abandoned or not * Returns if the package is abandoned or not
* *
@ -101,7 +166,45 @@ interface CompletePackageInterface extends PackageInterface
/** /**
* If the package is abandoned and has a suggested replacement, this method returns it * If the package is abandoned and has a suggested replacement, this method returns it
* *
* @return string * @return string|null
*/ */
public function getReplacementPackage(); public function getReplacementPackage();
/**
* @param bool|string $abandoned
* @return void
*/
public function setAbandoned($abandoned);
/**
* Returns default base filename for archive
*
* @return array
*/
public function getArchiveName();
/**
* Sets default base filename for archive
*
* @param string $name
* @return void
*/
public function setArchiveName($name);
/**
* Returns a list of patterns to exclude from package archives
*
* @return array
*/
public function getArchiveExcludes();
/**
* Sets a list of patterns to be excluded from archives
*
* @param string[] $excludes
* @return void
*/
public function setArchiveExcludes(array $excludes);
} }

View File

@ -70,13 +70,6 @@ class ArrayDumper
} }
} }
if ($package->getArchiveName()) {
$data['archive']['name'] = $package->getArchiveName();
}
if ($package->getArchiveExcludes()) {
$data['archive']['exclude'] = $package->getArchiveExcludes();
}
foreach (BasePackage::$supportedLinkTypes as $type => $opts) { foreach (BasePackage::$supportedLinkTypes as $type => $opts) {
if ($links = $package->{'get'.ucfirst($opts['method'])}()) { if ($links = $package->{'get'.ucfirst($opts['method'])}()) {
foreach ($links as $link) { foreach ($links as $link) {
@ -102,6 +95,13 @@ class ArrayDumper
$data = $this->dumpValues($package, $keys, $data); $data = $this->dumpValues($package, $keys, $data);
if ($package instanceof CompletePackageInterface) { if ($package instanceof CompletePackageInterface) {
if ($package->getArchiveName()) {
$data['archive']['name'] = $package->getArchiveName();
}
if ($package->getArchiveExcludes()) {
$data['archive']['exclude'] = $package->getArchiveExcludes();
}
$keys = array( $keys = array(
'scripts', 'scripts',
'license', 'license',

View File

@ -26,6 +26,11 @@ 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';
/**
* TODO should be marked private once 5.3 is dropped
* @private
*/
const TYPE_UNKNOWN = 'relates to';
/** /**
* Will be converted into a constant once the min PHP version allows this * Will be converted into a constant once the min PHP version allows this
@ -58,7 +63,7 @@ class Link
/** /**
* @var string * @var string
* @phpstan-var self::TYPE_* $description * @psalm-var self::TYPE_* $description
*/ */
protected $description; protected $description;
@ -73,15 +78,14 @@ class Link
* @param string $source * @param string $source
* @param string $target * @param string $target
* @param ConstraintInterface $constraint Constraint applying to the target of this link * @param ConstraintInterface $constraint Constraint applying to the target of this link
* @param string $description Used to create a descriptive string representation * @param self::TYPE_* $description Used to create a descriptive string representation
* @phpstan-param self::TYPE_* $description
* @param string|null $prettyConstraint * @param string|null $prettyConstraint
*/ */
public function __construct( public function __construct(
$source, $source,
$target, $target,
ConstraintInterface $constraint, ConstraintInterface $constraint,
$description = 'relates to', $description = self::TYPE_UNKNOWN,
$prettyConstraint = null $prettyConstraint = null
) { ) {
$this->source = strtolower($source); $this->source = strtolower($source);

View File

@ -12,9 +12,15 @@
namespace Composer\Package\Loader; namespace Composer\Package\Loader;
use Composer\Package;
use Composer\Package\AliasPackage; use Composer\Package\AliasPackage;
use Composer\Package\BasePackage;
use Composer\Package\CompleteAliasPackage;
use Composer\Package\CompletePackage;
use Composer\Package\RootPackage;
use Composer\Package\PackageInterface;
use Composer\Package\CompletePackageInterface;
use Composer\Package\Link; use Composer\Package\Link;
use Composer\Package\Package;
use Composer\Package\RootAliasPackage; use Composer\Package\RootAliasPackage;
use Composer\Package\RootPackageInterface; use Composer\Package\RootPackageInterface;
use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionParser;
@ -37,11 +43,22 @@ class ArrayLoader implements LoaderInterface
$this->loadOptions = $loadOptions; $this->loadOptions = $loadOptions;
} }
/**
* @template PackageClass of CompletePackageInterface
* @param array $config package data
* @param string $class FQCN to be instantiated
* @return CompletePackage|CompleteAliasPackage
* @phpstan-param class-string<PackageClass> $class
*/
public function load(array $config, $class = 'Composer\Package\CompletePackage') public function load(array $config, $class = 'Composer\Package\CompletePackage')
{ {
if ($class !== 'Composer\Package\CompletePackage' && $class !== 'Composer\Package\RootPackage') {
trigger_error('The $class arg is deprecated, please reach out to Composer maintainers ASAP if you still need this.', E_USER_DEPRECATED);
}
$package = $this->createObject($config, $class); $package = $this->createObject($config, $class);
foreach (Package\BasePackage::$supportedLinkTypes as $type => $opts) { foreach (BasePackage::$supportedLinkTypes as $type => $opts) {
if (isset($config[$type])) { if (isset($config[$type])) {
$method = 'set'.ucfirst($opts['method']); $method = 'set'.ucfirst($opts['method']);
$package->{$method}( $package->{$method}(
@ -60,8 +77,19 @@ class ArrayLoader implements LoaderInterface
return $package; return $package;
} }
public function loadPackages(array $versions, $class) /**
* @template PackageClass of CompletePackageInterface
* @param array $versions
* @param string $class FQCN to be instantiated
* @return list<CompletePackage|CompleteAliasPackage>
* @phpstan-param class-string<PackageClass> $class
*/
public function loadPackages(array $versions, $class = 'Composer\Package\CompletePackage')
{ {
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();
@ -77,6 +105,13 @@ class ArrayLoader implements LoaderInterface
return $packages; return $packages;
} }
/**
* @template PackageClass of CompletePackageInterface
* @param array $config package data
* @param string $class FQCN to be instantiated
* @return CompletePackage|RootPackage
* @phpstan-param class-string<PackageClass> $class
*/
private function createObject(array $config, $class) private function createObject(array $config, $class)
{ {
if (!isset($config['name'])) { if (!isset($config['name'])) {
@ -101,8 +136,17 @@ class ArrayLoader implements LoaderInterface
return new $class($config['name'], $version, $config['version']); return new $class($config['name'], $version, $config['version']);
} }
private function configureObject($package, array $config) /**
* @param CompletePackageInterface $package
* @param array $config package data
* @return RootPackage|RootAliasPackage|CompletePackage|CompleteAliasPackage
*/
private function configureObject(PackageInterface $package, array $config)
{ {
if (!$package instanceof Package) {
throw new \LogicException('ArrayLoader expects instances of the Composer\Package\Package class to function correctly');
}
$package->setType(isset($config['type']) ? strtolower($config['type']) : 'library'); $package->setType(isset($config['type']) ? strtolower($config['type']) : 'library');
if (isset($config['target-dir'])) { if (isset($config['target-dir'])) {
@ -200,6 +244,7 @@ class ArrayLoader implements LoaderInterface
$package->setNotificationUrl($config['notification-url']); $package->setNotificationUrl($config['notification-url']);
} }
if ($package instanceof CompletePackageInterface) {
if (!empty($config['archive']['name'])) { if (!empty($config['archive']['name'])) {
$package->setArchiveName($config['archive']['name']); $package->setArchiveName($config['archive']['name']);
} }
@ -207,7 +252,6 @@ class ArrayLoader implements LoaderInterface
$package->setArchiveExcludes($config['archive']['exclude']); $package->setArchiveExcludes($config['archive']['exclude']);
} }
if ($package instanceof Package\CompletePackageInterface) {
if (isset($config['scripts']) && \is_array($config['scripts'])) { if (isset($config['scripts']) && \is_array($config['scripts'])) {
foreach ($config['scripts'] as $event => $listeners) { foreach ($config['scripts'] as $event => $listeners) {
$config['scripts'][$event] = (array) $listeners; $config['scripts'][$event] = (array) $listeners;
@ -262,18 +306,28 @@ class ArrayLoader implements LoaderInterface
return new RootAliasPackage($package, $aliasNormalized, $prettyAlias); return new RootAliasPackage($package, $aliasNormalized, $prettyAlias);
} }
if ($package instanceof CompletePackageInterface) {
return new CompleteAliasPackage($package, $aliasNormalized, $prettyAlias);
}
return new AliasPackage($package, $aliasNormalized, $prettyAlias); return new AliasPackage($package, $aliasNormalized, $prettyAlias);
} }
return $package; return $package;
} }
/**
* @param array $linkCache
* @param PackageInterface $package
* @param array $config
* @return void
*/
private function configureCachedLinks(&$linkCache, $package, array $config) private function configureCachedLinks(&$linkCache, $package, array $config)
{ {
$name = $package->getName(); $name = $package->getName();
$prettyVersion = $package->getPrettyVersion(); $prettyVersion = $package->getPrettyVersion();
foreach (Package\BasePackage::$supportedLinkTypes as $type => $opts) { foreach (BasePackage::$supportedLinkTypes as $type => $opts) {
if (isset($config[$type])) { if (isset($config[$type])) {
$method = 'set'.ucfirst($opts['method']); $method = 'set'.ucfirst($opts['method']);
@ -300,8 +354,7 @@ class ArrayLoader implements LoaderInterface
/** /**
* @param string $source source package name * @param string $source source package name
* @param string $sourceVersion source package version (pretty version ideally) * @param string $sourceVersion source package version (pretty version ideally)
* @param string $description link description (e.g. requires, replaces, ..) * @param Link::TYPE_* $description link description (e.g. requires, replaces, ..)
* @phpstan-param Link::TYPE_* $description
* @param array $links array of package name => constraint mappings * @param array $links array of package name => constraint mappings
* @return Link[] * @return Link[]
*/ */
@ -315,6 +368,14 @@ class ArrayLoader implements LoaderInterface
return $res; return $res;
} }
/**
* @param string $source source package name
* @param string $sourceVersion source package version (pretty version ideally)
* @param Link::TYPE_* $description link description (e.g. requires, replaces, ..)
* @param string $target target package name
* @param string $prettyConstraint constraint string
* @return Link
*/
private function createLink($source, $sourceVersion, $description, $target, $prettyConstraint) private function createLink($source, $sourceVersion, $description, $target, $prettyConstraint)
{ {
if (!\is_string($prettyConstraint)) { if (!\is_string($prettyConstraint)) {
@ -338,7 +399,7 @@ class ArrayLoader implements LoaderInterface
public function getBranchAlias(array $config) public function getBranchAlias(array $config)
{ {
if (strpos($config['version'], 'dev-') !== 0 && '-dev' !== substr($config['version'], -4)) { if (strpos($config['version'], 'dev-') !== 0 && '-dev' !== substr($config['version'], -4)) {
return; return null;
} }
if (isset($config['extra']['branch-alias']) && \is_array($config['extra']['branch-alias'])) { if (isset($config['extra']['branch-alias']) && \is_array($config['extra']['branch-alias'])) {
@ -382,5 +443,7 @@ class ArrayLoader implements LoaderInterface
) { ) {
return VersionParser::DEFAULT_BRANCH_ALIAS; return VersionParser::DEFAULT_BRANCH_ALIAS;
} }
return null;
} }
} }

View File

@ -13,6 +13,8 @@
namespace Composer\Package\Loader; namespace Composer\Package\Loader;
use Composer\Json\JsonFile; use Composer\Json\JsonFile;
use Composer\Package\CompletePackage;
use Composer\Package\CompleteAliasPackage;
/** /**
* @author Konstantin Kudryashiv <ever.zet@gmail.com> * @author Konstantin Kudryashiv <ever.zet@gmail.com>
@ -28,7 +30,7 @@ class JsonLoader
/** /**
* @param string|JsonFile $json A filename, json string or JsonFile instance to load the package from * @param string|JsonFile $json A filename, json string or JsonFile instance to load the package from
* @return \Composer\Package\PackageInterface * @return CompletePackage|CompleteAliasPackage
*/ */
public function load($json) public function load($json)
{ {

View File

@ -16,7 +16,9 @@ use Composer\Package\BasePackage;
use Composer\Package\AliasPackage; use Composer\Package\AliasPackage;
use Composer\Config; use Composer\Config;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Package\Package;
use Composer\Package\RootPackageInterface; use Composer\Package\RootPackageInterface;
use Composer\Package\RootAliasPackage;
use Composer\Repository\RepositoryFactory; use Composer\Repository\RepositoryFactory;
use Composer\Package\Version\VersionGuesser; use Composer\Package\Version\VersionGuesser;
use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionParser;
@ -58,13 +60,18 @@ class RootPackageLoader extends ArrayLoader
} }
/** /**
* @template PackageClass of RootPackage
* @param array $config package data * @param array $config package data
* @param string $class FQCN to be instantiated * @param class-string<PackageClass> $class FQCN to be instantiated
* @param string $cwd cwd of the root package to be used to guess the version if it is not provided * @param string $cwd cwd of the root package to be used to guess the version if it is not provided
* @return RootPackageInterface * @return RootPackage|RootAliasPackage
*/ */
public function load(array $config, $class = 'Composer\Package\RootPackage', $cwd = null) public function load(array $config, $class = 'Composer\Package\RootPackage', $cwd = null)
{ {
if ($class !== 'Composer\Package\RootPackage') {
trigger_error('The $class arg is deprecated, please reach out to Composer maintainers ASAP if you still need this.', E_USER_DEPRECATED);
}
if (!isset($config['name'])) { if (!isset($config['name'])) {
$config['name'] = '__root__'; $config['name'] = '__root__';
} elseif ($err = ValidatingArrayLoader::hasPackageNamingError($config['name'])) { } elseif ($err = ValidatingArrayLoader::hasPackageNamingError($config['name'])) {
@ -105,9 +112,16 @@ class RootPackageLoader extends ArrayLoader
} }
} }
$realPackage = $package = parent::load($config, $class); /** @var RootPackage|RootAliasPackage $package */
if ($realPackage instanceof AliasPackage) { $package = parent::load($config, $class);
if ($package instanceof RootAliasPackage) {
$realPackage = $package->getAliasOf(); $realPackage = $package->getAliasOf();
} else {
$realPackage = $package;
}
if (!$realPackage instanceof RootPackage) {
throw new \LogicException('Expecting a Composer\Package\RootPackage at this point');
} }
if ($autoVersioned) { if ($autoVersioned) {

View File

@ -186,7 +186,11 @@ 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']);
} else {
$aliasPkg = new AliasPackage($packageByName[$alias['package']], $alias['alias_normalized'], $alias['alias']); $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

@ -57,9 +57,9 @@ class Package extends BasePackage
protected $autoload = array(); protected $autoload = array();
protected $devAutoload = array(); protected $devAutoload = array();
protected $includePaths = array(); protected $includePaths = array();
protected $archiveName;
protected $archiveExcludes = array();
protected $isDefaultBranch = false; protected $isDefaultBranch = false;
/** @var array */
protected $transportOptions = array();
/** /**
* Creates a new in memory package. * Creates a new in memory package.
@ -125,7 +125,7 @@ class Package extends BasePackage
public function getTargetDir() public function getTargetDir()
{ {
if (null === $this->targetDir) { if (null === $this->targetDir) {
return; return null;
} }
return ltrim(preg_replace('{ (?:^|[\\\\/]+) \.\.? (?:[\\\\/]+|$) (?:\.\.? (?:[\\\\/]+|$) )*}x', '/', $this->targetDir), '/'); return ltrim(preg_replace('{ (?:^|[\\\\/]+) \.\.? (?:[\\\\/]+|$) (?:\.\.? (?:[\\\\/]+|$) )*}x', '/', $this->targetDir), '/');
@ -228,7 +228,7 @@ class Package extends BasePackage
} }
/** /**
* @param array|null $mirrors * {@inheritDoc}
*/ */
public function setSourceMirrors($mirrors) public function setSourceMirrors($mirrors)
{ {
@ -316,7 +316,7 @@ class Package extends BasePackage
} }
/** /**
* @param array|null $mirrors * {@inheritDoc}
*/ */
public function setDistMirrors($mirrors) public function setDistMirrors($mirrors)
{ {
@ -339,6 +339,22 @@ class Package extends BasePackage
return $this->getUrls($this->distUrl, $this->distMirrors, $this->distReference, $this->distType, 'dist'); return $this->getUrls($this->distUrl, $this->distMirrors, $this->distReference, $this->distType, 'dist');
} }
/**
* {@inheritDoc}
*/
public function getTransportOptions()
{
return $this->transportOptions;
}
/**
* {@inheritDoc}
*/
public function setTransportOptions(array $options)
{
$this->transportOptions = $options;
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@ -553,42 +569,6 @@ class Package extends BasePackage
return $this->notificationUrl; return $this->notificationUrl;
} }
/**
* Sets default base filename for archive
*
* @param string $name
*/
public function setArchiveName($name)
{
$this->archiveName = $name;
}
/**
* {@inheritDoc}
*/
public function getArchiveName()
{
return $this->archiveName;
}
/**
* Sets a list of patterns to be excluded from archives
*
* @param array $excludes
*/
public function setArchiveExcludes(array $excludes)
{
$this->archiveExcludes = $excludes;
}
/**
* {@inheritDoc}
*/
public function getArchiveExcludes()
{
return $this->archiveExcludes;
}
/** /**
* @param bool $defaultBranch * @param bool $defaultBranch
*/ */

View File

@ -142,6 +142,12 @@ interface PackageInterface
*/ */
public function getSourceMirrors(); public function getSourceMirrors();
/**
* @param array|null $mirrors
* @return void
*/
public function setSourceMirrors($mirrors);
/** /**
* 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
* *
@ -184,6 +190,12 @@ interface PackageInterface
*/ */
public function getDistMirrors(); public function getDistMirrors();
/**
* @param array|null $mirrors
* @return void
*/
public function setDistMirrors($mirrors);
/** /**
* Returns the version of this package * Returns the version of this package
* *
@ -357,20 +369,6 @@ interface PackageInterface
*/ */
public function getPrettyString(); public function getPrettyString();
/**
* Returns default base filename for archive
*
* @return array
*/
public function getArchiveName();
/**
* Returns a list of patterns to exclude from package archives
*
* @return array
*/
public function getArchiveExcludes();
/** /**
* @return bool * @return bool
*/ */
@ -383,6 +381,13 @@ interface PackageInterface
*/ */
public function getTransportOptions(); public function getTransportOptions();
/**
* Configures the list of options to download package dist files
*
* @return void
*/
public function setTransportOptions(array $options);
/** /**
* @param string $reference * @param string $reference
* *

View File

@ -15,13 +15,31 @@ namespace Composer\Package;
/** /**
* @author Jordi Boggiano <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
*/ */
class RootAliasPackage extends AliasPackage implements RootPackageInterface class RootAliasPackage extends CompleteAliasPackage implements RootPackageInterface
{ {
/** @var RootPackageInterface */
protected $aliasOf;
/**
* All descendants' constructors should call this parent constructor
*
* @param RootPackageInterface $aliasOf The package this package is an alias of
* @param string $version The version the alias must report
* @param string $prettyVersion The alias's non-normalized version
*/
public function __construct(RootPackageInterface $aliasOf, $version, $prettyVersion) public function __construct(RootPackageInterface $aliasOf, $version, $prettyVersion)
{ {
parent::__construct($aliasOf, $version, $prettyVersion); parent::__construct($aliasOf, $version, $prettyVersion);
} }
/**
* @return RootPackageInterface
*/
public function getAliasOf()
{
return $this->aliasOf;
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@ -117,14 +135,6 @@ class RootAliasPackage extends AliasPackage implements RootPackageInterface
$this->aliasOf->setReplaces($replaces); $this->aliasOf->setReplaces($replaces);
} }
/**
* {@inheritDoc}
*/
public function setRepositories($repositories)
{
$this->aliasOf->setRepositories($repositories);
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */

View File

@ -105,7 +105,7 @@ interface RootPackageInterface extends CompletePackageInterface
* *
* @param array $repositories * @param array $repositories
*/ */
public function setRepositories($repositories); public function setRepositories(array $repositories);
/** /**
* Set the autoload mapping * Set the autoload mapping

View File

@ -462,15 +462,20 @@ class PluginManager
) { ) {
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], 1));
} }
return null;
} }
/** /**
* @template CapabilityClass of Capability
* @param PluginInterface $plugin * @param PluginInterface $plugin
* @param string $capabilityClassName The fully qualified name of the API interface which the plugin may provide * @param class-string<CapabilityClass> $capabilityClassName The fully qualified name of the API interface which the plugin may provide
* an implementation of. * an implementation of.
* @param array $ctorArgs Arguments passed to Capability's constructor. * @param array $ctorArgs Arguments passed to Capability's constructor.
* Keeping it an array will allow future values to be passed w\o changing the signature. * Keeping it an array will allow future values to be passed w\o changing the signature.
* @return null|Capability * @return null|Capability
* @phpstan-param class-string<CapabilityClass> $capabilityClassName
* @phpstan-return null|CapabilityClass
*/ */
public function getPluginCapability(PluginInterface $plugin, $capabilityClassName, array $ctorArgs = array()) public function getPluginCapability(PluginInterface $plugin, $capabilityClassName, array $ctorArgs = array())
{ {
@ -491,14 +496,17 @@ class PluginManager
return $capabilityObj; return $capabilityObj;
} }
return null;
} }
/** /**
* @param string $capabilityClassName The fully qualified name of the API interface which the plugin may provide * @template CapabilityClass of Capability
* @param class-string<CapabilityClass> $capabilityClassName The fully qualified name of the API interface which the plugin may provide
* an implementation of. * an implementation of.
* @param array $ctorArgs Arguments passed to Capability's constructor. * @param array $ctorArgs Arguments passed to Capability's constructor.
* Keeping it an array will allow future values to be passed w\o changing the signature. * Keeping it an array will allow future values to be passed w\o changing the signature.
* @return Capability[] * @return CapabilityClass[]
*/ */
public function getPluginCapabilities($capabilityClassName, array $ctorArgs = array()) public function getPluginCapabilities($capabilityClassName, array $ctorArgs = array())
{ {

View File

@ -13,6 +13,7 @@
namespace Composer\Repository; namespace Composer\Repository;
use Composer\Package\AliasPackage; use Composer\Package\AliasPackage;
use Composer\Package\CompleteAliasPackage;
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;
@ -27,13 +28,13 @@ use Composer\Semver\Constraint\Constraint;
*/ */
class ArrayRepository implements RepositoryInterface class ArrayRepository implements RepositoryInterface
{ {
/** @var PackageInterface[] */ /** @var ?PackageInterface[] */
protected $packages; protected $packages = null;
/** /**
* @var PackageInterface[] indexed by package unique name and used to cache hasPackage calls * @var ?PackageInterface[] indexed by package unique name and used to cache hasPackage calls
*/ */
protected $packageMap; protected $packageMap = null;
public function __construct(array $packages = array()) public function __construct(array $packages = array())
{ {
@ -220,7 +221,7 @@ class ArrayRepository implements RepositoryInterface
if ($packageName === $link->getTarget()) { if ($packageName === $link->getTarget()) {
$result[$candidate->getName()] = array( $result[$candidate->getName()] = array(
'name' => $candidate->getName(), 'name' => $candidate->getName(),
'description' => $candidate->getDescription(), 'description' => $candidate instanceof CompletePackageInterface ? $candidate->getDescription() : null,
'type' => $candidate->getType(), 'type' => $candidate->getType(),
); );
continue 2; continue 2;
@ -233,7 +234,15 @@ class ArrayRepository implements RepositoryInterface
protected function createAliasPackage(PackageInterface $package, $alias, $prettyAlias) protected function createAliasPackage(PackageInterface $package, $alias, $prettyAlias)
{ {
return new AliasPackage($package instanceof AliasPackage ? $package->getAliasOf() : $package, $alias, $prettyAlias); while ($package instanceof AliasPackage) {
$package = $package->getAliasOf();
}
if ($package instanceof CompletePackageInterface) {
return new CompleteAliasPackage($package, $alias, $prettyAlias);
}
return new AliasPackage($package, $alias, $prettyAlias);
} }
/** /**

View File

@ -16,6 +16,8 @@ use Composer\Package\BasePackage;
use Composer\Package\Loader\ArrayLoader; use Composer\Package\Loader\ArrayLoader;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Package\AliasPackage; use Composer\Package\AliasPackage;
use Composer\Package\CompletePackage;
use Composer\Package\CompleteAliasPackage;
use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionParser;
use Composer\Package\Version\StabilityFilter; use Composer\Package\Version\StabilityFilter;
use Composer\Json\JsonFile; use Composer\Json\JsonFile;
@ -167,7 +169,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
} }
if ($this->hasAvailablePackageList && !$this->lazyProvidersRepoContains($name)) { if ($this->hasAvailablePackageList && !$this->lazyProvidersRepoContains($name)) {
return; return null;
} }
$packages = $this->loadAsyncPackages(array($name => $constraint)); $packages = $this->loadAsyncPackages(array($name => $constraint));
@ -182,7 +184,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
} }
} }
return; return null;
} }
return parent::findPackage($name, $constraint); return parent::findPackage($name, $constraint);
@ -428,7 +430,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
foreach ($search['results'] as $result) { foreach ($search['results'] as $result) {
// do not show virtual packages in results as they are not directly useful from a composer perspective // do not show virtual packages in results as they are not directly useful from a composer perspective
if (empty($result['virtual'])) { if (empty($result['virtual'])) {
$results[] = $result; $results[] = array('name' => $result['name'], 'description' => $result['description']);
} }
} }
@ -441,7 +443,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
foreach ($this->getPackageNames() as $name) { foreach ($this->getPackageNames() as $name) {
if (preg_match($regex, $name)) { if (preg_match($regex, $name)) {
$results[] = array('name' => $name); $results[] = array('name' => $name, 'description' => '');
} }
} }
@ -1039,6 +1041,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
* TODO v3 should make this private once we can drop PHP 5.3 support * TODO v3 should make this private once we can drop PHP 5.3 support
* *
* @private * @private
* @return list<CompletePackage|CompleteAliasPackage>
*/ */
public function createPackages(array $packages, $source = null) public function createPackages(array $packages, $source = null)
{ {
@ -1053,7 +1056,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
} }
} }
$packageInstances = $this->loader->loadPackages($packages, 'Composer\Package\CompletePackage'); $packageInstances = $this->loader->loadPackages($packages);
foreach ($packageInstances as $package) { foreach ($packageInstances as $package) {
if (isset($this->sourceMirrors[$package->getSourceType()])) { if (isset($this->sourceMirrors[$package->getSourceType()])) {

View File

@ -165,9 +165,9 @@ class FilterRepository implements RepositoryInterface
public function getProviders($packageName) public function getProviders($packageName)
{ {
$result = array(); $result = array();
foreach ($this->repo->getProviders($packageName) as $provider) { foreach ($this->repo->getProviders($packageName) as $name => $provider) {
if ($this->isAllowed($provider['name'])) { if ($this->isAllowed($provider['name'])) {
$result[] = $provider; $result[$name] = $provider;
} }
} }

View File

@ -14,6 +14,7 @@ namespace Composer\Repository;
use Composer\Composer; use Composer\Composer;
use Composer\Package\CompletePackage; use Composer\Package\CompletePackage;
use Composer\Package\CompletePackageInterface;
use Composer\Package\Link; use Composer\Package\Link;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionParser;
@ -491,7 +492,9 @@ class PlatformRepository extends ArrayRepository
} else { } else {
$actualText = 'actual: '.$package->getPrettyVersion(); $actualText = 'actual: '.$package->getPrettyVersion();
} }
if ($overrider instanceof CompletePackageInterface) {
$overrider->setDescription($overrider->getDescription().', '.$actualText); $overrider->setDescription($overrider->getDescription().', '.$actualText);
}
return; return;
} }
@ -512,6 +515,9 @@ class PlatformRepository extends ArrayRepository
parent::addPackage($package); parent::addPackage($package);
} }
/**
* @return CompletePackage
*/
private function addOverriddenPackage(array $override, $name = null) private function addOverriddenPackage(array $override, $name = null)
{ {
$version = $this->versionParser->normalize($override['version']); $version = $this->versionParser->normalize($override['version']);

View File

@ -71,15 +71,11 @@ interface RepositoryInterface extends \Countable
* - The namesFound returned are names which should be considered as canonically found in this repository, that should not be looked up in any further lower priority repositories * - The namesFound returned are names which should be considered as canonically found in this repository, that should not be looked up in any further lower priority repositories
* *
* @param ConstraintInterface[] $packageNameMap package names pointing to constraints * @param ConstraintInterface[] $packageNameMap package names pointing to constraints
* @param int[] $acceptableStabilities array of stability => BasePackage::STABILITY_* value * @param array<string, BasePackage::STABILITY_*> $acceptableStabilities array of stability => BasePackage::STABILITY_* value
* @psalm-param array<string, BasePackage::STABILITY_*> $acceptableStabilities * @param array<string, BasePackage::STABILITY_*> $stabilityFlags an array of package name => BasePackage::STABILITY_* value
* @param int[] $stabilityFlags an array of package name => BasePackage::STABILITY_* value * @param array<string, array<string, PackageInterface>> $alreadyLoaded an array of package name => package version => package
* @psalm-param array<string, BasePackage::STABILITY_*> $stabilityFlags
* @param array[] $alreadyLoaded an array of package name => package version => package
* @psalm-param array<string, array<string, PackageInterface>> $alreadyLoaded
* *
* @return array [namesFound => string[], packages => PackageInterface[]] * @return array{namesFound: string[], packages: PackageInterface[]}
* @psalm-return array{namesFound: string[], packages: 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

@ -20,6 +20,8 @@ use Composer\IO\IOInterface;
use Composer\IO\NullIO; 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\CompletePackageInterface;
use Composer\Semver\Constraint\ConstraintInterface; use Composer\Semver\Constraint\ConstraintInterface;
use Composer\Package\Version\StabilityFilter; use Composer\Package\Version\StabilityFilter;
@ -252,7 +254,11 @@ class RepositorySet
while ($package instanceof AliasPackage) { while ($package instanceof AliasPackage) {
$package = $package->getAliasOf(); $package = $package->getAliasOf();
} }
if ($package instanceof CompletePackageInterface) {
$aliasPackage = new CompleteAliasPackage($package, $alias['alias_normalized'], $alias['alias']);
} else {
$aliasPackage = new AliasPackage($package, $alias['alias_normalized'], $alias['alias']); $aliasPackage = new AliasPackage($package, $alias['alias_normalized'], $alias['alias']);
}
$aliasPackage->setRootPackageAlias(true); $aliasPackage->setRootPackageAlias(true);
$packages[] = $aliasPackage; $packages[] = $aliasPackage;
} }

View File

@ -33,9 +33,9 @@ abstract class BitbucketDriver extends VcsDriver
protected $cloneHttpsUrl = ''; protected $cloneHttpsUrl = '';
/** /**
* @var VcsDriver * @var ?VcsDriver
*/ */
protected $fallbackDriver; protected $fallbackDriver = null;
/** @var string|null if set either git or hg */ /** @var string|null if set either git or hg */
protected $vcsType; protected $vcsType;

View File

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

View File

@ -39,9 +39,9 @@ class GitHubDriver extends VcsDriver
/** /**
* Git Driver * Git Driver
* *
* @var GitDriver * @var ?GitDriver
*/ */
protected $gitDriver; protected $gitDriver = null;
/** /**
* {@inheritDoc} * {@inheritDoc}

View File

@ -56,9 +56,9 @@ class GitLabDriver extends VcsDriver
/** /**
* Git Driver * Git Driver
* *
* @var GitDriver * @var ?GitDriver
*/ */
protected $gitDriver; protected $gitDriver = null;
/** /**
* Defaults to true unless we can make sure it is public * Defaults to true unless we can make sure it is public

View File

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

View File

@ -125,7 +125,7 @@ class HgDriver extends VcsDriver
$this->process->execute($resource, $content, $this->repoDir); $this->process->execute($resource, $content, $this->repoDir);
if (!trim($content)) { if (!trim($content)) {
return; return null;
} }
return $content; return $content;

View File

@ -25,8 +25,8 @@ class PerforceDriver extends VcsDriver
{ {
protected $depot; protected $depot;
protected $branch; protected $branch;
/** @var Perforce */ /** @var ?Perforce */
protected $perforce; protected $perforce = null;
/** /**
* {@inheritDoc} * {@inheritDoc}
@ -147,7 +147,7 @@ class PerforceDriver extends VcsDriver
*/ */
public function getContents($url) public function getContents($url)
{ {
return false; throw new \BadMethodCallException('Not implemented/used in PerforceDriver');
} }
/** /**

View File

@ -154,7 +154,7 @@ class AuthHelper
} else { } else {
// 404s are only handled for github // 404s are only handled for github
if ($statusCode === 404) { if ($statusCode === 404) {
return; return null;
} }
// fail if the console is not interactive // fail if the console is not interactive

View File

@ -30,8 +30,8 @@ class Bitbucket
private $process; private $process;
/** @var HttpDownloader */ /** @var HttpDownloader */
private $httpDownloader; private $httpDownloader;
/** @var array */ /** @var array{access_token: string, expires_in?: int}|null */
private $token = array(); private $token = null;
/** @var int|null */ /** @var int|null */
private $time; private $time;
@ -191,7 +191,7 @@ class Bitbucket
*/ */
public function requestToken($originUrl, $consumerKey, $consumerSecret) public function requestToken($originUrl, $consumerKey, $consumerSecret)
{ {
if (!empty($this->token) || $this->getTokenFromConfig($originUrl)) { if ($this->token !== null || $this->getTokenFromConfig($originUrl)) {
return $this->token['access_token']; return $this->token['access_token'];
} }
@ -202,6 +202,10 @@ class Bitbucket
$this->storeInAuthConfig($originUrl, $consumerKey, $consumerSecret); $this->storeInAuthConfig($originUrl, $consumerKey, $consumerSecret);
if (!isset($this->token['expires_in']) || !isset($this->token['access_token'])) {
throw new \LogicException('Expected a token configured with expires_in and access_token present, got '.json_encode($this->token));
}
return $this->token['access_token']; return $this->token['access_token'];
} }
@ -215,6 +219,10 @@ class Bitbucket
{ {
$this->config->getConfigSource()->removeConfigSetting('bitbucket-oauth.'.$originUrl); $this->config->getConfigSource()->removeConfigSetting('bitbucket-oauth.'.$originUrl);
if (!isset($this->token['expires_in']) || !isset($this->token['access_token'])) {
throw new \LogicException('Expected a token configured with expires_in and access_token present, got '.json_encode($this->token));
}
$time = null === $this->time ? time() : $this->time; $time = null === $this->time ? time() : $this->time;
$consumer = array( $consumer = array(
"consumer-key" => $consumerKey, "consumer-key" => $consumerKey,

View File

@ -39,7 +39,7 @@ class ErrorHandler
{ {
// error code is not included in error_reporting // error code is not included in error_reporting
if (!(error_reporting() & $level)) { if (!(error_reporting() & $level)) {
return; return true;
} }
if (filter_var(ini_get('xdebug.scream'), FILTER_VALIDATE_BOOLEAN)) { if (filter_var(ini_get('xdebug.scream'), FILTER_VALIDATE_BOOLEAN)) {

View File

@ -12,7 +12,7 @@
namespace Composer\Util; namespace Composer\Util;
use React\Promise\Promise; use React\Promise\PromiseInterface;
use RecursiveDirectoryIterator; use RecursiveDirectoryIterator;
use RecursiveIteratorIterator; use RecursiveIteratorIterator;
use Symfony\Component\Filesystem\Exception\IOException; use Symfony\Component\Filesystem\Exception\IOException;
@ -128,7 +128,7 @@ class Filesystem
* *
* @param string $directory * @param string $directory
* @throws \RuntimeException * @throws \RuntimeException
* @return Promise * @return PromiseInterface
*/ */
public function removeDirectoryAsync($directory) public function removeDirectoryAsync($directory)
{ {
@ -569,7 +569,7 @@ class Filesystem
* And other possible unforeseen disasters, see https://github.com/composer/composer/pull/9422 * And other possible unforeseen disasters, see https://github.com/composer/composer/pull/9422
* *
* @param string $path * @param string $path
* @return bool * @return string
*/ */
public static function trimTrailingSlash($path) public static function trimTrailingSlash($path)
{ {

View File

@ -116,6 +116,8 @@ class ProxyHelper
return $_SERVER[$name]; return $_SERVER[$name];
} }
} }
return null;
} }
/** /**

View File

@ -29,11 +29,11 @@ class ProxyManager
private $hasProxy; private $hasProxy;
private $info; private $info;
private $lastProxy; private $lastProxy;
/** @var NoProxyPattern */ /** @var ?NoProxyPattern */
private $noProxyHandler; private $noProxyHandler = null;
/** @var ProxyManager */ /** @var ?ProxyManager */
private static $instance; private static $instance = null;
private function __construct() private function __construct()
{ {
@ -145,7 +145,7 @@ class ProxyManager
if ($this->hasProxy) { if ($this->hasProxy) {
$this->info = implode(', ', $info); $this->info = implode(', ', $info);
if ($noProxy) { if ($noProxy) {
$this->noProxyHandler = array(new NoProxyPattern($noProxy), 'test'); $this->noProxyHandler = new NoProxyPattern($noProxy);
} }
} }
} }
@ -176,7 +176,7 @@ class ProxyManager
private function noProxy($requestUrl) private function noProxy($requestUrl)
{ {
if ($this->noProxyHandler) { if ($this->noProxyHandler) {
if (call_user_func($this->noProxyHandler, $requestUrl)) { if ($this->noProxyHandler->test($requestUrl)) {
$this->lastProxy = 'excluded by no_proxy'; $this->lastProxy = 'excluded by no_proxy';
return true; return true;

View File

@ -25,7 +25,7 @@ class NoProxyPattern
protected $hostNames = array(); protected $hostNames = array();
/** /**
* @var object[] * @var (null|object)[]
*/ */
protected $rules = array(); protected $rules = array();
@ -74,7 +74,7 @@ class NoProxyPattern
* *
* @param string $url * @param string $url
* *
* @return bool|stdclass * @return bool|stdClass
*/ */
protected function getUrlData($url) protected function getUrlData($url)
{ {
@ -110,7 +110,7 @@ class NoProxyPattern
* *
* @param int $index * @param int $index
* @param string $hostName * @param string $hostName
* @param string $url * @param stdClass $url
* *
* @return bool * @return bool
*/ */
@ -198,7 +198,7 @@ class NoProxyPattern
* Creates an object containing IP data if the host is an IP address * Creates an object containing IP data if the host is an IP address
* *
* @param string $host * @param string $host
* @param null|stdclass $ipdata Set by method if IP address found * @param null|stdClass $ipdata Set by method if IP address found
* @param bool $allowPrefix Whether a CIDR prefix-length is expected * @param bool $allowPrefix Whether a CIDR prefix-length is expected
* *
* @return bool False if the host contains invalid data * @return bool False if the host contains invalid data
@ -334,9 +334,9 @@ class NoProxyPattern
* *
* @param string $host * @param string $host
* @param int $port * @param int $port
* @param null|stdclass $ipdata * @param null|stdClass $ipdata
* *
* @return stdclass * @return stdClass
*/ */
private function makeData($host, $port, $ipdata) private function makeData($host, $port, $ipdata)
{ {
@ -355,7 +355,7 @@ class NoProxyPattern
* @param int $size Byte size of in_addr * @param int $size Byte size of in_addr
* @param null|string $netmask Network mask * @param null|string $netmask Network mask
* *
* @return stdclass * @return stdClass
*/ */
private function makeIpData($ip, $size, $netmask) private function makeIpData($ip, $size, $netmask)
{ {

View File

@ -22,15 +22,15 @@ class PackageSorter
* *
* Packages of equal weight retain the original order * Packages of equal weight retain the original order
* *
* @param array $packages * @param PackageInterface[] $packages
* @return array * @return PackageInterface[] sorted array
*/ */
public static function sortPackages(array $packages) public static function sortPackages(array $packages)
{ {
$usageList = array(); $usageList = array();
foreach ($packages as $package) { /** @var PackageInterface $package */ foreach ($packages as $package) {
foreach (array_merge($package->getRequires(), $package->getDevRequires()) as $link) { /** @var Link $link */ foreach (array_merge($package->getRequires(), $package->getDevRequires()) as $link) {
$target = $link->getTarget(); $target = $link->getTarget();
$usageList[$target][] = $package->getName(); $usageList[$target][] = $package->getName();
} }

View File

@ -17,6 +17,7 @@ use Symfony\Component\Process\Process;
use Symfony\Component\Process\ProcessUtils; use Symfony\Component\Process\ProcessUtils;
use Symfony\Component\Process\Exception\RuntimeException; use Symfony\Component\Process\Exception\RuntimeException;
use React\Promise\Promise; use React\Promise\Promise;
use React\Promise\PromiseInterface;
/** /**
* @author Robert Schönthal <seroscho@googlemail.com> * @author Robert Schönthal <seroscho@googlemail.com>
@ -142,7 +143,7 @@ class ProcessExecutor
* *
* @param string $command the command to execute * @param string $command the command to execute
* @param string $cwd the working directory * @param string $cwd the working directory
* @return Promise * @return PromiseInterface
*/ */
public function executeAsync($command, $cwd = null) public function executeAsync($command, $cwd = null)
{ {

View File

@ -302,7 +302,7 @@ class RemoteFilesystem
$e->setStatusCode(self::findStatusCode($http_response_header)); $e->setStatusCode(self::findStatusCode($http_response_header));
try { try {
$e->setResponse($this->decodeResult($result, $http_response_header)); $e->setResponse($this->decodeResult($result, $http_response_header));
} catch (\Exception $e) { } catch (\Exception $discarded) {
$e->setResponse($result); $e->setResponse($result);
} }

View File

@ -30,7 +30,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
* @psalm-param array{http: array{follow_location?: int, max_redirects?: int, header?: string|array<string, string|int>}} $defaultOptions * @psalm-param array{http?: array{follow_location?: int, max_redirects?: int, header?: string|array<string, string|int>}} $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

@ -41,7 +41,7 @@ class SyncHelper
if ($type === 'update') { if ($type === 'update') {
self::await($loop, $downloader->update($package, $path, $prevPackage)); self::await($loop, $downloader->update($package, $path, $prevPackage));
} else { } else {
self::await($loop, $downloader->install($package, $path, $prevPackage)); self::await($loop, $downloader->install($package, $path));
} }
} catch (\Exception $e) { } catch (\Exception $e) {
self::await($loop, $downloader->cleanup($type, $package, $path, $prevPackage)); self::await($loop, $downloader->cleanup($type, $package, $path, $prevPackage));

View File

@ -26,7 +26,7 @@ use Composer\Util\Filesystem;
class PerforceDownloaderTest extends TestCase class PerforceDownloaderTest extends TestCase
{ {
protected $config; protected $config;
/** @var PerforceDownloader */ /** @var ?PerforceDownloader */
protected $downloader; protected $downloader;
protected $io; protected $io;
protected $package; protected $package;

View File

@ -386,12 +386,12 @@ class MockedZipDownloader extends ZipDownloader
{ {
public function download(PackageInterface $package, $path, PackageInterface $prevPackage = null, $output = true) public function download(PackageInterface $package, $path, PackageInterface $prevPackage = null, $output = true)
{ {
return; return \React\Promise\resolve();
} }
public function install(PackageInterface $package, $path, $output = true) public function install(PackageInterface $package, $path, $output = true)
{ {
return; return \React\Promise\resolve();
} }
public function extract(PackageInterface $package, $file, $path) public function extract(PackageInterface $package, $file, $path)

View File

@ -378,6 +378,7 @@ class InstallerTest extends TestCase
$this->assertSame($expectInstalled, $actualInstalled); $this->assertSame($expectInstalled, $actualInstalled);
} }
/** @var InstallationManagerMock $installationManager */
$installationManager = $composer->getInstallationManager(); $installationManager = $composer->getInstallationManager();
$this->assertSame(rtrim($expect), implode("\n", $installationManager->getTrace())); $this->assertSame(rtrim($expect), implode("\n", $installationManager->getTrace()));

View File

@ -34,7 +34,7 @@ class InstallationManagerMock extends InstallationManager
{ {
} }
public function execute(RepositoryInterface $repo, array $operations, $devMode = true, $runScripts = true) public function execute(InstalledRepositoryInterface $repo, array $operations, $devMode = true, $runScripts = true)
{ {
foreach ($operations as $operation) { foreach ($operations as $operation) {
$method = $operation->getOperationType(); $method = $operation->getOperationType();
@ -53,14 +53,14 @@ class InstallationManagerMock extends InstallationManager
return $repo->hasPackage($package); return $repo->hasPackage($package);
} }
public function install(RepositoryInterface $repo, InstallOperation $operation) public function install(InstalledRepositoryInterface $repo, InstallOperation $operation)
{ {
$this->installed[] = $operation->getPackage(); $this->installed[] = $operation->getPackage();
$this->trace[] = strip_tags((string) $operation); $this->trace[] = strip_tags((string) $operation);
$repo->addPackage(clone $operation->getPackage()); $repo->addPackage(clone $operation->getPackage());
} }
public function update(RepositoryInterface $repo, UpdateOperation $operation) public function update(InstalledRepositoryInterface $repo, UpdateOperation $operation)
{ {
$this->updated[] = array($operation->getInitialPackage(), $operation->getTargetPackage()); $this->updated[] = array($operation->getInitialPackage(), $operation->getTargetPackage());
$this->trace[] = strip_tags((string) $operation); $this->trace[] = strip_tags((string) $operation);
@ -70,14 +70,14 @@ class InstallationManagerMock extends InstallationManager
} }
} }
public function uninstall(RepositoryInterface $repo, UninstallOperation $operation) public function uninstall(InstalledRepositoryInterface $repo, UninstallOperation $operation)
{ {
$this->uninstalled[] = $operation->getPackage(); $this->uninstalled[] = $operation->getPackage();
$this->trace[] = strip_tags((string) $operation); $this->trace[] = strip_tags((string) $operation);
$repo->removePackage($operation->getPackage()); $repo->removePackage($operation->getPackage());
} }
public function markAliasInstalled(RepositoryInterface $repo, MarkAliasInstalledOperation $operation) public function markAliasInstalled(InstalledRepositoryInterface $repo, MarkAliasInstalledOperation $operation)
{ {
$package = $operation->getPackage(); $package = $operation->getPackage();
@ -87,7 +87,7 @@ class InstallationManagerMock extends InstallationManager
parent::markAliasInstalled($repo, $operation); parent::markAliasInstalled($repo, $operation);
} }
public function markAliasUninstalled(RepositoryInterface $repo, MarkAliasUninstalledOperation $operation) public function markAliasUninstalled(InstalledRepositoryInterface $repo, MarkAliasUninstalledOperation $operation)
{ {
$this->uninstalled[] = $operation->getPackage(); $this->uninstalled[] = $operation->getPackage();
$this->trace[] = strip_tags((string) $operation); $this->trace[] = strip_tags((string) $operation);

View File

@ -15,7 +15,7 @@ namespace Composer\Test\Package\Archiver;
use Composer\Test\TestCase; use Composer\Test\TestCase;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
use Composer\Util\ProcessExecutor; use Composer\Util\ProcessExecutor;
use Composer\Package\Package; use Composer\Package\CompletePackage;
abstract class ArchiverTest extends TestCase abstract class ArchiverTest extends TestCase
{ {
@ -49,11 +49,11 @@ abstract class ArchiverTest extends TestCase
/** /**
* Util method to quickly setup a package using the source path built. * Util method to quickly setup a package using the source path built.
* *
* @return \Composer\Package\Package * @return CompletePackage
*/ */
protected function setupPackage() protected function setupPackage()
{ {
$package = new Package('archivertest/archivertest', 'master', 'master'); $package = new CompletePackage('archivertest/archivertest', 'master', 'master');
$package->setSourceUrl(realpath($this->testDir)); $package->setSourceUrl(realpath($this->testDir));
$package->setSourceReference('master'); $package->setSourceReference('master');
$package->setSourceType('git'); $package->setSourceType('git');

View File

@ -82,7 +82,7 @@ class RootAliasPackageTest extends TestCase
protected function getMockRootPackageInterface() protected function getMockRootPackageInterface()
{ {
$root = $this->prophesize('Composer\\Package\\RootPackageInterface'); $root = $this->prophesize('Composer\\Package\\RootPackage');
$root->getName()->willReturn('something/something')->shouldBeCalled(); $root->getName()->willReturn('something/something')->shouldBeCalled();
$root->getRequires()->willReturn(array())->shouldBeCalled(); $root->getRequires()->willReturn(array())->shouldBeCalled();
$root->getDevRequires()->willReturn(array())->shouldBeCalled(); $root->getDevRequires()->willReturn(array())->shouldBeCalled();

View File

@ -54,17 +54,17 @@ class PluginInstallerTest extends TestCase
protected $directory; protected $directory;
/** /**
* @var \PHPUnit_Framework_MockObject_MockObject * @var \PHPUnit\Framework\MockObject\MockObject
*/ */
protected $im; protected $im;
/** /**
* @var \PHPUnit_Framework_MockObject_MockObject * @var \PHPUnit\Framework\MockObject\MockObject
*/ */
protected $repository; protected $repository;
/** /**
* @var \PHPUnit_Framework_MockObject_MockObject * @var BufferIO
*/ */
protected $io; protected $io;
@ -337,6 +337,7 @@ class PluginInstallerTest extends TestCase
$installer = new PluginInstaller($this->io, $this->composer); $installer = new PluginInstaller($this->io, $this->composer);
$this->pm->loadInstalledPlugins(); $this->pm->loadInstalledPlugins();
/** @var \Composer\Plugin\Capability\CommandProvider[] $caps */
$caps = $this->pm->getPluginCapabilities('Composer\Plugin\Capability\CommandProvider', array('composer' => $this->composer, 'io' => $this->io)); $caps = $this->pm->getPluginCapabilities('Composer\Plugin\Capability\CommandProvider', array('composer' => $this->composer, 'io' => $this->io));
$this->assertCount(1, $caps); $this->assertCount(1, $caps);
$this->assertInstanceOf('Composer\Plugin\Capability\CommandProvider', $caps[0]); $this->assertInstanceOf('Composer\Plugin\Capability\CommandProvider', $caps[0]);
@ -368,6 +369,7 @@ class PluginInstallerTest extends TestCase
return array($capabilityApi => $capabilityImplementation); return array($capabilityApi => $capabilityImplementation);
})); }));
/** @var \Composer\Test\Plugin\Mock\Capability $capability */
$capability = $this->pm->getPluginCapability($plugin, $capabilityApi, array('a' => 1, 'b' => 2)); $capability = $this->pm->getPluginCapability($plugin, $capabilityApi, array('a' => 1, 'b' => 2));
$this->assertInstanceOf($capabilityApi, $capability); $this->assertInstanceOf($capabilityApi, $capability);

View File

@ -119,6 +119,7 @@ class RepositoryManagerTest extends TestCase
); );
$rm->setRepositoryClass('path', 'Composer\Repository\PathRepository'); $rm->setRepositoryClass('path', 'Composer\Repository\PathRepository');
/** @var \Composer\Repository\FilterRepository $repo */
$repo = $rm->createRepository('path', array('type' => 'path', 'url' => __DIR__, 'only' => array('foo/bar'))); $repo = $rm->createRepository('path', array('type' => 'path', 'url' => __DIR__, 'only' => array('foo/bar')));
$this->assertInstanceOf('Composer\Repository\FilterRepository', $repo); $this->assertInstanceOf('Composer\Repository\FilterRepository', $repo);

View File

@ -118,7 +118,7 @@ abstract class TestCase extends PolyfillTestCase
* *
* @param string $executableName The name of the binary to test. * @param string $executableName The name of the binary to test.
* *
* @throws \PHPUnit_Framework_SkippedTestError * @throws \PHPUnit\Framework\SkippedTestError
*/ */
protected function skipIfNotExecutable($executableName) protected function skipIfNotExecutable($executableName)
{ {

View File

@ -42,6 +42,7 @@ class ErrorHandlerTest extends TestCase
} }
$array = array('foo' => 'bar'); $array = array('foo' => 'bar');
// @phpstan-ignore-next-line
$array['baz']; $array['baz'];
} }

View File

@ -23,13 +23,13 @@ class GitTest extends TestCase
{ {
/** @var Git */ /** @var Git */
private $git; private $git;
/** @var IOInterface&\PHPUnit_Framework_MockObject_MockObject */ /** @var IOInterface&\PHPUnit\Framework\MockObject\MockObject */
private $io; private $io;
/** @var Config&\PHPUnit_Framework_MockObject_MockObject */ /** @var Config&\PHPUnit\Framework\MockObject\MockObject */
private $config; private $config;
/** @var ProcessExecutor&\PHPUnit_Framework_MockObject_MockObject */ /** @var ProcessExecutor&\PHPUnit\Framework\MockObject\MockObject */
private $process; private $process;
/** @var Filesystem&\PHPUnit_Framework_MockObject_MockObject */ /** @var Filesystem&\PHPUnit\Framework\MockObject\MockObject */
private $fs; private $fs;
protected function setUp() protected function setUp()