Bump phpstan to level 3 (#9734)

Clean up PackageInterface/CompletePackageInterface, add missing methods, type things in solver as BasePackage, added CompleteAliasPackage, ..
main
Jordi Boggiano 3 years ago committed by GitHub
parent 8392508e23
commit 4940009f83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -52,5 +52,5 @@ jobs:
- name: Run PHPStan
# Locked to phpunit 7.5 here as newer ones have void return types which break inheritance
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

@ -1,6 +1,8 @@
includes:
- ../vendor/phpstan/phpstan-phpunit/extension.neon
parameters:
level: 1
checkClassCaseSensitivity: true # Level 2 rule
level: 3
excludes_analyse:
- '../tests/Composer/Test/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 method Composer\\Test\\[a-zA-Z0-9\\]+::(assertFileDoesNotExist|assertMatchesRegularExpression)\(\)\.$~'
# Mock errors
- '~^Call to an undefined method (PHPUnit\\Framework\\MockObject\\MockObject|Prophecy\\Prophecy\\ObjectProphecy)::.*$~'
bootstrapFiles:
- ../tests/bootstrap.php
@ -38,25 +43,3 @@ parameters:
rules:
- 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

@ -338,7 +338,7 @@ class ClassLoader
* Loads the given class or interface.
*
* @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)
{
@ -347,6 +347,8 @@ class ClassLoader
return true;
}
return null;
}
/**

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

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

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

@ -58,6 +58,10 @@ EOT
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
$tokens = preg_split('{\s+}', $input->__toString());
$args = array();

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

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

@ -266,7 +266,13 @@ EOT
if ($input->getOption('latest')) {
$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;
}
if ($input->getOption('path')) {
@ -330,6 +336,8 @@ EOT
$width = $terminal->getWidth();
} else {
// For versions of Symfony console before 3.2
// TODO remove in composer 2.2
// @phpstan-ignore-next-line
list($width) = $this->getApplication()->getTerminalDimensions();
}
if (null === $width) {
@ -386,6 +394,7 @@ EOT
$showMinorOnly = $input->getOption('minor-only');
$ignoredPackages = array_map('strtolower', $input->getOption('ignore'));
$indent = $showAllTypes ? ' ' : '';
/** @var PackageInterface[] $latestPackages */
$latestPackages = array();
$exitCode = 0;
$viewData = array();
@ -426,7 +435,7 @@ EOT
}
// 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);
if ($input->getOption('outdated') && ($packageIsUpToDate || $packageIsIgnored)) {
continue;
@ -454,7 +463,7 @@ EOT
$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())
? 'Use ' . $latestPackage->getReplacementPackage() . ' instead'
: 'No replacement was suggested';
@ -670,7 +679,7 @@ EOT
}
$io->write('<info>names</info> : ' . implode(', ', $package->getNames()));
if ($latestPackage->isAbandoned()) {
if ($latestPackage instanceof CompletePackageInterface && $latestPackage->isAbandoned()) {
$replacement = ($latestPackage->getReplacementPackage() !== null)
? ' The author suggests using the ' . $latestPackage->getReplacementPackage(). ' package instead.'
: null;
@ -836,7 +845,7 @@ EOT
}
}
if ($latestPackage->isAbandoned()) {
if ($latestPackage instanceof CompletePackageInterface && $latestPackage->isAbandoned()) {
$json['replacement'] = $latestPackage->getReplacementPackage();
}
@ -1045,7 +1054,7 @@ EOT
$tree = array(
'name' => $package->getPrettyName(),
'version' => $package->getPrettyVersion(),
'description' => $package->getDescription(),
'description' => $package instanceof CompletePackageInterface ? $package->getDescription() : '',
);
if ($children) {
@ -1111,16 +1120,16 @@ EOT
/**
* Display a package tree
*
* @param string $name
* @param PackageInterface|string $package
* @param InstalledRepository $installedRepo
* @param RepositoryInterface $remoteRepos
* @param array $packagesInTree
* @param string $name
* @param Link $link
* @param InstalledRepository $installedRepo
* @param RepositoryInterface $remoteRepos
* @param array $packagesInTree
* @return array
*/
protected function addTree(
$name,
$package,
Link $link,
InstalledRepository $installedRepo,
RepositoryInterface $remoteRepos,
array $packagesInTree
@ -1130,7 +1139,7 @@ EOT
$installedRepo,
$remoteRepos,
$name,
$package->getPrettyConstraint() === 'self.version' ? $package->getConstraint() : $package->getPrettyConstraint()
$link->getPrettyConstraint() === 'self.version' ? $link->getConstraint() : $link->getPrettyConstraint()
);
if (is_object($package)) {
$requires = $package->getRequires();

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

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

@ -12,9 +12,9 @@
namespace Composer\DependencyResolver;
use Composer\Package\PackageInterface;
use Composer\Package\AliasPackage;
use Composer\Package\BasePackage;
use Composer\Package\PackageInterface;
use Composer\Semver\Constraint\Constraint;
/**
@ -88,7 +88,7 @@ class DefaultPolicy implements PolicyInterface
/**
* @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
if ($a->getName() === $b->getName()) {
@ -139,11 +139,11 @@ class DefaultPolicy implements PolicyInterface
* Replace constraints are ignored. This method should only be used for
* prioritisation, not for actual constraint verification.
*
* @param PackageInterface $source
* @param PackageInterface $target
* @param BasePackage $source
* @param BasePackage $target
* @return bool
*/
protected function replaces(PackageInterface $source, PackageInterface $target)
protected function replaces(BasePackage $source, BasePackage $target)
{
foreach ($source->getReplaces() as $link) {
if ($link->getTarget() === $target->getName()

@ -12,7 +12,7 @@
namespace Composer\DependencyResolver;
use Composer\Package\PackageInterface;
use Composer\Package\BasePackage;
use Composer\Package\Link;
/**
@ -25,7 +25,7 @@ class GenericRule extends Rule
/**
* @param array $literals
* @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)
{

@ -12,7 +12,7 @@
namespace Composer\DependencyResolver;
use Composer\Package\PackageInterface;
use Composer\Package\BasePackage;
use Composer\Package\Link;
/**
@ -27,7 +27,7 @@ class MultiConflictRule extends Rule
/**
* @param array $literals
* @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)
{

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

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

@ -13,7 +13,7 @@
namespace Composer\DependencyResolver;
use Composer\Package\Link;
use Composer\Package\PackageInterface;
use Composer\Package\BasePackage;
use Composer\Package\AliasPackage;
use Composer\Repository\RepositorySet;
use Composer\Repository\PlatformRepository;
@ -46,8 +46,8 @@ abstract class Rule
protected $reasonData;
/**
* @param int $reason A RULE_* constant describing the reason for generating this rule
* @param Link|PackageInterface $reasonData
* @param int $reason A RULE_* constant describing the reason for generating this rule
* @param Link|BasePackage $reasonData
*/
public function __construct($reason, $reasonData)
{
@ -62,6 +62,8 @@ abstract class Rule
abstract public function getHash();
abstract public function __toString();
abstract public function equals(Rule $rule);
public function getReason()
@ -361,7 +363,7 @@ abstract class Rule
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) {
$package = $package->getAliasOf();

@ -12,7 +12,7 @@
namespace Composer\DependencyResolver;
use Composer\Package\PackageInterface;
use Composer\Package\BasePackage;
use Composer\Package\Link;
/**
@ -27,7 +27,7 @@ class Rule2Literals extends Rule
* @param int $literal1
* @param int $literal2
* @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)
{

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

@ -12,7 +12,7 @@
namespace Composer\DependencyResolver;
use Composer\Package\PackageInterface;
use Composer\Package\BasePackage;
use Composer\Package\AliasPackage;
use Composer\Repository\PlatformRepository;
@ -41,15 +41,15 @@ class RuleSetGenerator
* This rule is of the form (-A|B|C), where B and C are the providers of
* one requirement of the package A.
*
* @param PackageInterface $package The package with a requirement
* @param array $providers The providers of the requirement
* @param int $reason A RULE_* constant describing the
* @param BasePackage $package The package with a requirement
* @param array $providers The providers of the requirement
* @param int $reason A RULE_* constant describing the
* reason for generating this rule
* @param mixed $reasonData Any data, e.g. the requirement name,
* @param mixed $reasonData Any data, e.g. the requirement name,
* 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);
@ -70,11 +70,11 @@ class RuleSetGenerator
* 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.
*
* @param array $packages The set of packages to choose from
* @param int $reason A RULE_* constant describing the reason for
* generating this rule
* @param array $reasonData Additional data like the root require or fix request info
* @return Rule The generated rule
* @param BasePackage[] $packages The set of packages to choose from
* @param int $reason A RULE_* constant describing the reason for
* generating this rule
* @param array $reasonData Additional data like the root require or fix request info
* @return Rule The generated rule
*/
protected function createInstallOneOfRule(array $packages, $reason, $reasonData)
{
@ -92,15 +92,15 @@ class RuleSetGenerator
* The rule for conflicting packages A and B is (-A|-B). A is called the issuer
* and B the provider.
*
* @param PackageInterface $issuer The package declaring the conflict
* @param PackageInterface $provider The package causing the conflict
* @param int $reason A RULE_* constant describing the
* @param BasePackage $issuer The package declaring the conflict
* @param BasePackage $provider The package causing the conflict
* @param int $reason A RULE_* constant describing the
* 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
* @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
if ($issuer === $provider) {
@ -142,13 +142,13 @@ class RuleSetGenerator
$this->rules->add($newRule, $type);
}
protected function addRulesForPackage(PackageInterface $package, $ignorePlatformReqs)
protected function addRulesForPackage(BasePackage $package, $ignorePlatformReqs)
{
$workQueue = new \SplQueue;
$workQueue->enqueue($package);
while (!$workQueue->isEmpty()) {
/** @var PackageInterface $package */
/** @var BasePackage $package */
$package = $workQueue->dequeue();
if (isset($this->addedMap[$package->id])) {
continue;
@ -192,7 +192,7 @@ class RuleSetGenerator
protected function addConflictRules($ignorePlatformReqs = false)
{
/** @var PackageInterface $package */
/** @var BasePackage $package */
foreach ($this->addedMap as $package) {
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

@ -137,7 +137,7 @@ class DownloadManager
$installationSource = $package->getInstallationSource();
if ('metapackage' === $package->getType()) {
return;
return null;
}
if ('dist' === $installationSource) {
@ -256,6 +256,8 @@ class DownloadManager
if ($downloader) {
return $downloader->prepare($type, $package, $targetDir, $prevPackage);
}
return \React\Promise\resolve();
}
/**
@ -275,6 +277,8 @@ class DownloadManager
if ($downloader) {
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
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
@ -348,6 +352,8 @@ class DownloadManager
if ($downloader) {
return $downloader->remove($package, $targetDir);
}
return \React\Promise\resolve();
}
/**
@ -367,6 +373,8 @@ class DownloadManager
if ($downloader) {
return $downloader->cleanup($type, $package, $targetDir, $prevPackage);
}
return \React\Promise\resolve();
}
/**

@ -112,8 +112,10 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
};
$retries = 3;
$urls = $package->getDistUrls();
foreach ($urls as $index => $url) {
$distUrls = $package->getDistUrls();
/** @var array<array{base: string, processed: string, cacheKey: string}> $urls */
$urls = array();
foreach ($distUrls as $index => $url) {
$processedUrl = $this->processUrl($package, $url);
$urls[$index] = array(
'base' => $url,
@ -140,6 +142,7 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
$accept = null;
$reject = null;
$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);
$index = key($urls);
@ -271,6 +274,7 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
*/
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);
}
}
return \React\Promise\resolve();
}
/**
@ -324,6 +330,8 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
}
}
}
return \React\Promise\resolve();
}
/**

@ -25,6 +25,7 @@ class FossilDownloader extends VcsDownloader
*/
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))) {
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))) {
throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
}
return \React\Promise\resolve();
}
/**

@ -74,6 +74,8 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
} elseif (null === $gitVersion) {
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);
}
return \React\Promise\resolve();
}
/**
@ -192,6 +196,8 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
if ($updateOriginUrl) {
$this->updateOriginUrl($path, $target->getSourceUrl());
}
return \React\Promise\resolve();
}
/**
@ -201,7 +207,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
{
GitUtil::cleanEnv();
if (!$this->hasMetadataRepository($path)) {
return;
return null;
}
$command = 'git status --porcelain --untracked-files=no';
@ -217,7 +223,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
GitUtil::cleanEnv();
$path = $this->normalizePath($path);
if (!$this->hasMetadataRepository($path)) {
return;
return null;
}
$command = 'git show-ref --head -d';
@ -228,13 +234,13 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
$refs = trim($output);
if (!preg_match('{^([a-f0-9]+) HEAD$}mi', $refs, $match)) {
// could not match the HEAD for some reason
return;
return null;
}
$headRef = $match[1];
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
return;
return null;
}
$candidateBranches = $matches[1];

@ -33,14 +33,14 @@ class GzipDownloader extends ArchiveDownloader
$command = 'gzip -cd ' . ProcessExecutor::escape($file) . ' > ' . ProcessExecutor::escape($targetFilepath);
if (0 === $this->process->execute($command, $ignoredOutput)) {
return;
return \React\Promise\resolve();
}
if (extension_loaded('zlib')) {
// Fallback to using the PHP extension.
$this->extractUsingExt($file, $targetFilepath);
return;
return \React\Promise\resolve();
}
$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
$this->extractUsingExt($file, $targetFilepath);
return \React\Promise\resolve();
}
private function extractUsingExt($file, $targetFilepath)

@ -29,6 +29,8 @@ class HgDownloader extends VcsDownloader
if (null === HgUtils::getVersion($this->process)) {
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))) {
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);
return \React\Promise\resolve();
}
/**

@ -52,7 +52,7 @@ class PathDownloader extends FileDownloader implements VcsCapableDownloaderInter
}
if (realpath($path) === $realUrl) {
return;
return \React\Promise\resolve();
}
if (strpos(realpath($path) . DIRECTORY_SEPARATOR, $realUrl . DIRECTORY_SEPARATOR) === 0) {
@ -67,6 +67,8 @@ class PathDownloader extends FileDownloader implements VcsCapableDownloaderInter
$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));
}
return;
return \React\Promise\resolve();
}
// Get the transport options with default values
@ -151,6 +153,8 @@ class PathDownloader extends FileDownloader implements VcsCapableDownloaderInter
if ($output) {
$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>");
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) {
$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)) {
return $packageVersion['commit'];
}
return null;
}
/**

@ -29,6 +29,7 @@ class PerforceDownloader extends VcsDownloader
*/
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->syncCodeBase($label);
$this->perforce->cleanupClientSpec();
return \React\Promise\resolve();
}
private function getLabelFromSourceReference($ref)
@ -85,7 +88,7 @@ class PerforceDownloader extends VcsDownloader
*/
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)
{
$this->io->writeError('Perforce driver does not check for local changes before overriding');
return null;
}
/**

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

@ -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);
if (0 === $this->process->execute($command, $ignoredOutput)) {
return;
return \React\Promise\resolve();
}
$processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput();
@ -75,5 +75,7 @@ class RarDownloader extends ArchiveDownloader
}
$rarArchive->close();
}
return \React\Promise\resolve();
}
}

@ -35,6 +35,8 @@ class SvnDownloader extends VcsDownloader
if (null === $util->binaryVersion()) {
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->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->execute($target, $url, "svn switch" . $flags, sprintf("%s/%s", $url, $ref), $path);
return \React\Promise\resolve();
}
/**

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

@ -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') {
$this->cleanChanges($package, $path, false);
}
return \React\Promise\resolve();
}
/**
@ -112,6 +116,8 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa
$this->reapplyChanges($path);
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) {
throw $exception;
}
return \React\Promise\resolve();
}
/**
@ -238,6 +248,8 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa
if ($packageVersion = $guesser->guessVersion($packageConfig, $path)) {
return $packageVersion['commit'];
}
return null;
}
/**
@ -255,6 +267,8 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa
if (null !== $this->getLocalChanges($package, $path)) {
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);
/**
* @return string[]
*/
private function prepareUrls(array $urls)
{
foreach ($urls as $index => $url) {

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

@ -17,6 +17,7 @@ use Composer\Util\IniHelper;
use Composer\Util\Platform;
use Composer\Util\ProcessExecutor;
use Symfony\Component\Process\ExecutableFinder;
use React\Promise\PromiseInterface;
use ZipArchive;
/**
@ -69,9 +70,10 @@ class ZipDownloader extends ArchiveDownloader
/**
* extract $file to $path with "unzip" command
*
* @param string $file File to extract
* @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 string $file File to extract
* @param string $path Path where to extract file
* @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)
{
@ -154,9 +156,10 @@ class ZipDownloader extends ArchiveDownloader
/**
* extract $file to $path with ZipArchive
*
* @param string $file File to extract
* @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 string $file File to extract
* @param string $path Path where to extract file
* @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
* @protected
@ -212,8 +215,9 @@ class ZipDownloader extends ArchiveDownloader
/**
* extract $file to $path
*
* @param string $file File to extract
* @param string $path Path where to extract file
* @param string $file File to extract
* @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
* @protected

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

@ -154,119 +154,71 @@ abstract class BaseIO implements IOInterface
}
/**
* System is unusable.
*
* @param string $message
* @param array $context
* @return null
* {@inheritDoc}
*/
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.
*
* 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
* {@inheritDoc}
*/
public function alert($message, array $context = array())
{
return $this->log(LogLevel::ALERT, $message, $context);
$this->log(LogLevel::ALERT, $message, $context);
}
/**
* Critical conditions.
*
* Example: Application component unavailable, unexpected exception.
*
* @param string $message
* @param array $context
* @return null
* {@inheritDoc}
*/
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
* be logged and monitored.
*
* @param string $message
* @param array $context
* @return null
* {@inheritDoc}
*/
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.
*
* 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
* {@inheritDoc}
*/
public function warning($message, array $context = array())
{
return $this->log(LogLevel::WARNING, $message, $context);
$this->log(LogLevel::WARNING, $message, $context);
}
/**
* Normal but significant events.
*
* @param string $message
* @param array $context
* @return null
* {@inheritDoc}
*/
public function notice($message, array $context = array())
{
return $this->log(LogLevel::NOTICE, $message, $context);
$this->log(LogLevel::NOTICE, $message, $context);
}
/**
* Interesting events.
*
* Example: User logs in, SQL logs.
*
* @param string $message
* @param array $context
* @return null
* {@inheritDoc}
*/
public function info($message, array $context = array())
{
return $this->log(LogLevel::INFO, $message, $context);
$this->log(LogLevel::INFO, $message, $context);
}
/**
* Detailed debug information.
*
* @param string $message
* @param array $context
* @return null
* {@inheritDoc}
*/
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.
*
* @param mixed $level
* @param string $message
* @param array $context
* @return null
* {@inheritDoc}
*/
public function log($level, $message, array $context = array())
{

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

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

@ -135,13 +135,14 @@ class Installer
protected $writeLock;
protected $executeOperations = true;
/** @var bool */
protected $updateMirrors = false;
/**
* Array of package names/globs flagged for update
*
* @var array|null
*/
protected $updateMirrors = false;
protected $updateAllowList;
protected $updateAllowList = null;
protected $updateAllowTransitiveDependencies = Request::UPDATE_ONLY_LISTED;
/**
@ -918,7 +919,8 @@ class Installer
foreach ($packages as $key => $package) {
if ($package instanceof AliasPackage) {
$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(

@ -172,12 +172,12 @@ class InstallationManager
/**
* Executes solver operation.
*
* @param RepositoryInterface $repo repository in which to add/remove/update packages
* @param OperationInterface[] $operations operations to execute
* @param bool $devMode whether the install is being run in dev mode
* @param bool $runScripts whether to dispatch script events
* @param InstalledRepositoryInterface $repo repository in which to add/remove/update packages
* @param OperationInterface[] $operations operations to execute
* @param bool $devMode whether the install is being run in dev mode
* @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();
@ -243,8 +243,8 @@ class InstallationManager
$batches = array();
$batch = array();
foreach ($operations as $index => $operation) {
if (in_array($operation->getOperationType(), array('update', 'install'), true)) {
$package = $operation->getOperationType() === 'update' ? $operation->getTargetPackage() : $operation->getPackage();
if ($operation instanceof UpdateOperation || $operation instanceof InstallOperation) {
$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 ($batch) {
$batches[] = $batch;
@ -272,7 +272,7 @@ class InstallationManager
pcntl_signal(SIGINT, $prevHandler);
}
if ($handleInterruptsWindows) {
sapi_windows_set_ctrl_handler($prevHandler, false);
sapi_windows_set_ctrl_handler($windowsHandler, false);
}
throw $e;
@ -282,7 +282,7 @@ class InstallationManager
pcntl_signal(SIGINT, $prevHandler);
}
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
@ -295,7 +295,7 @@ class InstallationManager
* @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
*/
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();
@ -372,7 +372,7 @@ class InstallationManager
* @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
*/
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();
$postExecCallbacks = array();
@ -460,10 +460,10 @@ class InstallationManager
/**
* Executes install operation.
*
* @param RepositoryInterface $repo repository in which to check
* @param InstallOperation $operation operation instance
* @param InstalledRepositoryInterface $repo repository in which to check
* @param InstallOperation $operation operation instance
*/
public function install(RepositoryInterface $repo, InstallOperation $operation)
public function install(InstalledRepositoryInterface $repo, InstallOperation $operation)
{
$package = $operation->getPackage();
$installer = $this->getInstaller($package->getType());
@ -476,10 +476,10 @@ class InstallationManager
/**
* Executes update operation.
*
* @param RepositoryInterface $repo repository in which to check
* @param UpdateOperation $operation operation instance
* @param InstalledRepositoryInterface $repo repository in which to check
* @param UpdateOperation $operation operation instance
*/
public function update(RepositoryInterface $repo, UpdateOperation $operation)
public function update(InstalledRepositoryInterface $repo, UpdateOperation $operation)
{
$initial = $operation->getInitialPackage();
$target = $operation->getTargetPackage();
@ -509,10 +509,10 @@ class InstallationManager
/**
* Uninstalls package.
*
* @param RepositoryInterface $repo repository in which to check
* @param UninstallOperation $operation operation instance
* @param InstalledRepositoryInterface $repo repository in which to check
* @param UninstallOperation $operation operation instance
*/
public function uninstall(RepositoryInterface $repo, UninstallOperation $operation)
public function uninstall(InstalledRepositoryInterface $repo, UninstallOperation $operation)
{
$package = $operation->getPackage();
$installer = $this->getInstaller($package->getType());
@ -523,10 +523,10 @@ class InstallationManager
/**
* Executes markAliasInstalled operation.
*
* @param RepositoryInterface $repo repository in which to check
* @param MarkAliasInstalledOperation $operation operation instance
* @param InstalledRepositoryInterface $repo repository in which to check
* @param MarkAliasInstalledOperation $operation operation instance
*/
public function markAliasInstalled(RepositoryInterface $repo, MarkAliasInstalledOperation $operation)
public function markAliasInstalled(InstalledRepositoryInterface $repo, MarkAliasInstalledOperation $operation)
{
$package = $operation->getPackage();
@ -538,10 +538,10 @@ class InstallationManager
/**
* Executes markAlias operation.
*
* @param RepositoryInterface $repo repository in which to check
* @param InstalledRepositoryInterface $repo repository in which to check
* @param MarkAliasUninstalledOperation $operation operation instance
*/
public function markAliasUninstalled(RepositoryInterface $repo, MarkAliasUninstalledOperation $operation)
public function markAliasUninstalled(InstalledRepositoryInterface $repo, MarkAliasUninstalledOperation $operation)
{
$package = $operation->getPackage();

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

@ -45,6 +45,7 @@ class NoopInstaller implements InstallerInterface
*/
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)
{
return \React\Promise\resolve();
}
/**
@ -59,6 +61,7 @@ class NoopInstaller implements InstallerInterface
*/
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)) {
$repo->addPackage(clone $package);
}
return \React\Promise\resolve();
}
/**
@ -84,6 +89,8 @@ class NoopInstaller implements InstallerInterface
if (!$repo->hasPackage($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);
}
$repo->removePackage($package);
return \React\Promise\resolve();
}
/**

@ -101,7 +101,7 @@ class SuggestedPackagesReporter
* @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 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)
{
@ -122,7 +122,7 @@ class SuggestedPackagesReporter
$this->io->write(sprintf('<info>%s</info>', $name));
}
return 0;
return;
}
// 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>');
}
}
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 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)
{
@ -177,8 +175,6 @@ class SuggestedPackagesReporter
if ($suggestedPackages) {
$this->io->writeError('<info>'.count($suggestedPackages).' package suggestions were added by new dependencies, use `composer suggest` to see details.</info>');
}
return $this;
}
/**

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

@ -18,6 +18,7 @@ use Composer\Package\RootPackageInterface;
use Composer\Util\Filesystem;
use Composer\Util\Loop;
use Composer\Json\JsonFile;
use Composer\Package\CompletePackageInterface;
/**
* @author Matthieu Moquet <matthieu@moquet.net>
@ -74,11 +75,11 @@ class ArchiveManager
/**
* 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
*/
public function getPackageFilename(PackageInterface $package)
public function getPackageFilename(CompletePackageInterface $package)
{
if ($package->getArchiveName()) {
$baseName = $package->getArchiveName();
@ -107,7 +108,7 @@ class ArchiveManager
/**
* 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 $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
@ -117,7 +118,7 @@ class ArchiveManager
* @throws \RuntimeException
* @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)) {
throw new \InvalidArgumentException('Format must be specified');

@ -23,7 +23,7 @@ use Composer\Repository\PlatformRepository;
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(
'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
* @var int
* @internal
* @readonly
*/
public $id;
/** @var string */
protected $name;
/** @var string */
protected $prettyName;
/** @var RepositoryInterface */
protected $repository;
/** @var array */
protected $transportOptions = array();
/** @var ?RepositoryInterface */
protected $repository = null;
/**
* All descendants' constructors should call this parent constructor
@ -146,24 +146,6 @@ abstract class BasePackage implements PackageInterface
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
*

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

@ -29,9 +29,11 @@ class CompletePackage extends Package implements CompletePackageInterface
protected $support = array();
protected $funding = array();
protected $abandoned = false;
protected $archiveName;
protected $archiveExcludes = array();
/**
* @param array $scripts
* {@inheritDoc}
*/
public function setScripts(array $scripts)
{
@ -47,11 +49,9 @@ class CompletePackage extends Package implements CompletePackageInterface
}
/**
* Set the repositories
*
* @param array $repositories
* {@inheritDoc}
*/
public function setRepositories($repositories)
public function setRepositories(array $repositories)
{
$this->repositories = $repositories;
}
@ -65,9 +65,7 @@ class CompletePackage extends Package implements CompletePackageInterface
}
/**
* Set the license
*
* @param array $license
* {@inheritDoc}
*/
public function setLicense(array $license)
{
@ -83,9 +81,7 @@ class CompletePackage extends Package implements CompletePackageInterface
}
/**
* Set the keywords
*
* @param array $keywords
* {@inheritDoc}
*/
public function setKeywords(array $keywords)
{
@ -101,9 +97,7 @@ class CompletePackage extends Package implements CompletePackageInterface
}
/**
* Set the authors
*
* @param array $authors
* {@inheritDoc}
*/
public function setAuthors(array $authors)
{
@ -119,9 +113,7 @@ class CompletePackage extends Package implements CompletePackageInterface
}
/**
* Set the description
*
* @param string $description
* {@inheritDoc}
*/
public function setDescription($description)
{
@ -137,9 +129,7 @@ class CompletePackage extends Package implements CompletePackageInterface
}
/**
* Set the homepage
*
* @param string $homepage
* {@inheritDoc}
*/
public function setHomepage($homepage)
{
@ -155,9 +145,7 @@ class CompletePackage extends Package implements CompletePackageInterface
}
/**
* Set the support information
*
* @param array $support
* {@inheritDoc}
*/
public function setSupport(array $support)
{
@ -173,9 +161,7 @@ class CompletePackage extends Package implements CompletePackageInterface
}
/**
* Set the funding
*
* @param array $funding
* {@inheritDoc}
*/
public function setFunding(array $funding)
{
@ -191,7 +177,7 @@ class CompletePackage extends Package implements CompletePackageInterface
}
/**
* @return bool
* {@inheritDoc}
*/
public function isAbandoned()
{
@ -199,7 +185,7 @@ class CompletePackage extends Package implements CompletePackageInterface
}
/**
* @param bool|string $abandoned
* {@inheritDoc}
*/
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
*
* @return string|null
* {@inheritDoc}
*/
public function getReplacementPackage()
{
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;
}
}

@ -22,19 +22,31 @@ interface CompletePackageInterface extends PackageInterface
/**
* Returns the scripts of this package
*
* @return array[] array('script name' => array('listeners'))
* @psalm-return array<string, string[]>
* @return array<string, string[]> array('script name' => array('listeners'))
*/
public function getScripts();
/**
* @param array<string, string[]> $scripts
* @return void
*/
public function setScripts(array $scripts);
/**
* Returns an array of repositories
*
* @return array[] Repositories
* @psalm-return array<array{type: string, url?: string}>
* @return array<array{type: string, url?: string}> Repositories
*/
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
*
@ -42,6 +54,14 @@ interface CompletePackageInterface extends PackageInterface
*/
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
*
@ -49,6 +69,14 @@ interface CompletePackageInterface extends PackageInterface
*/
public function getKeywords();
/**
* Set the keywords
*
* @param string[] $keywords
* @return void
*/
public function setKeywords(array $keywords);
/**
* Returns the package description
*
@ -56,6 +84,14 @@ interface CompletePackageInterface extends PackageInterface
*/
public function getDescription();
/**
* Set the description
*
* @param string $description
* @return void
*/
public function setDescription($description);
/**
* Returns the package homepage
*
@ -63,34 +99,63 @@ interface CompletePackageInterface extends PackageInterface
*/
public function getHomepage();
/**
* Set the homepage
*
* @param string $homepage
* @return void
*/
public function setHomepage($homepage);
/**
* Returns an array of authors of the package
*
* Each item can contain name/homepage/email keys
*
* @return array[]
* @psalm-return array<array{?name: string, homepage?: string, email?: string, role?: string}>
* @return array<array{name?: string, homepage?: string, email?: string, role?: string}>
*/
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
*
* @return array
* @psalm-return array<string, string>
* @return array<string, string>
*/
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
*
* Each item will contain type and url keys
*
* @return array[]
* @psalm-return array<array{type: string, url: string}>
* @return array<array{type: string, url: string}>
*/
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
*
@ -101,7 +166,45 @@ interface CompletePackageInterface extends PackageInterface
/**
* If the package is abandoned and has a suggested replacement, this method returns it
*
* @return string
* @return string|null
*/
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);
}

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

@ -26,6 +26,11 @@ class Link
const TYPE_PROVIDE = 'provides';
const TYPE_CONFLICT = 'conflicts';
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
@ -58,7 +63,7 @@ class Link
/**
* @var string
* @phpstan-var self::TYPE_* $description
* @psalm-var self::TYPE_* $description
*/
protected $description;
@ -73,15 +78,14 @@ class Link
* @param string $source
* @param string $target
* @param ConstraintInterface $constraint Constraint applying to the target of this link
* @param string $description Used to create a descriptive string representation
* @phpstan-param self::TYPE_* $description
* @param self::TYPE_* $description Used to create a descriptive string representation
* @param string|null $prettyConstraint
*/
public function __construct(
$source,
$target,
ConstraintInterface $constraint,
$description = 'relates to',
$description = self::TYPE_UNKNOWN,
$prettyConstraint = null
) {
$this->source = strtolower($source);

@ -12,9 +12,15 @@
namespace Composer\Package\Loader;
use Composer\Package;
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\Package;
use Composer\Package\RootAliasPackage;
use Composer\Package\RootPackageInterface;
use Composer\Package\Version\VersionParser;
@ -37,11 +43,22 @@ class ArrayLoader implements LoaderInterface
$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')
{
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);
foreach (Package\BasePackage::$supportedLinkTypes as $type => $opts) {
foreach (BasePackage::$supportedLinkTypes as $type => $opts) {
if (isset($config[$type])) {
$method = 'set'.ucfirst($opts['method']);
$package->{$method}(
@ -60,8 +77,19 @@ class ArrayLoader implements LoaderInterface
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();
$linkCache = array();
@ -77,6 +105,13 @@ class ArrayLoader implements LoaderInterface
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)
{
if (!isset($config['name'])) {
@ -101,8 +136,17 @@ class ArrayLoader implements LoaderInterface
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');
if (isset($config['target-dir'])) {
@ -200,14 +244,14 @@ class ArrayLoader implements LoaderInterface
$package->setNotificationUrl($config['notification-url']);
}
if (!empty($config['archive']['name'])) {
$package->setArchiveName($config['archive']['name']);
}
if (!empty($config['archive']['exclude'])) {
$package->setArchiveExcludes($config['archive']['exclude']);
}
if ($package instanceof CompletePackageInterface) {
if (!empty($config['archive']['name'])) {
$package->setArchiveName($config['archive']['name']);
}
if (!empty($config['archive']['exclude'])) {
$package->setArchiveExcludes($config['archive']['exclude']);
}
if ($package instanceof Package\CompletePackageInterface) {
if (isset($config['scripts']) && \is_array($config['scripts'])) {
foreach ($config['scripts'] as $event => $listeners) {
$config['scripts'][$event] = (array) $listeners;
@ -262,18 +306,28 @@ class ArrayLoader implements LoaderInterface
return new RootAliasPackage($package, $aliasNormalized, $prettyAlias);
}
if ($package instanceof CompletePackageInterface) {
return new CompleteAliasPackage($package, $aliasNormalized, $prettyAlias);
}
return new AliasPackage($package, $aliasNormalized, $prettyAlias);
}
return $package;
}
/**
* @param array $linkCache
* @param PackageInterface $package
* @param array $config
* @return void
*/
private function configureCachedLinks(&$linkCache, $package, array $config)
{
$name = $package->getName();
$prettyVersion = $package->getPrettyVersion();
foreach (Package\BasePackage::$supportedLinkTypes as $type => $opts) {
foreach (BasePackage::$supportedLinkTypes as $type => $opts) {
if (isset($config[$type])) {
$method = 'set'.ucfirst($opts['method']);
@ -298,11 +352,10 @@ class ArrayLoader implements LoaderInterface
}
/**
* @param string $source source package name
* @param string $sourceVersion source package version (pretty version ideally)
* @param string $description link description (e.g. requires, replaces, ..)
* @phpstan-param Link::TYPE_* $description
* @param array $links array of package name => constraint mappings
* @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 array $links array of package name => constraint mappings
* @return Link[]
*/
public function parseLinks($source, $sourceVersion, $description, $links)
@ -315,6 +368,14 @@ class ArrayLoader implements LoaderInterface
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)
{
if (!\is_string($prettyConstraint)) {
@ -338,7 +399,7 @@ class ArrayLoader implements LoaderInterface
public function getBranchAlias(array $config)
{
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'])) {
@ -382,5 +443,7 @@ class ArrayLoader implements LoaderInterface
) {
return VersionParser::DEFAULT_BRANCH_ALIAS;
}
return null;
}
}

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

@ -16,7 +16,9 @@ use Composer\Package\BasePackage;
use Composer\Package\AliasPackage;
use Composer\Config;
use Composer\IO\IOInterface;
use Composer\Package\Package;
use Composer\Package\RootPackageInterface;
use Composer\Package\RootAliasPackage;
use Composer\Repository\RepositoryFactory;
use Composer\Package\Version\VersionGuesser;
use Composer\Package\Version\VersionParser;
@ -58,13 +60,18 @@ class RootPackageLoader extends ArrayLoader
}
/**
* @param array $config package data
* @param string $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
* @return RootPackageInterface
* @template PackageClass of RootPackage
* @param array $config package data
* @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
* @return RootPackage|RootAliasPackage
*/
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'])) {
$config['name'] = '__root__';
} elseif ($err = ValidatingArrayLoader::hasPackageNamingError($config['name'])) {
@ -105,9 +112,16 @@ class RootPackageLoader extends ArrayLoader
}
}
$realPackage = $package = parent::load($config, $class);
if ($realPackage instanceof AliasPackage) {
/** @var RootPackage|RootAliasPackage $package */
$package = parent::load($config, $class);
if ($package instanceof RootAliasPackage) {
$realPackage = $package->getAliasOf();
} else {
$realPackage = $package;
}
if (!$realPackage instanceof RootPackage) {
throw new \LogicException('Expecting a Composer\Package\RootPackage at this point');
}
if ($autoVersioned) {

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

@ -57,9 +57,9 @@ class Package extends BasePackage
protected $autoload = array();
protected $devAutoload = array();
protected $includePaths = array();
protected $archiveName;
protected $archiveExcludes = array();
protected $isDefaultBranch = false;
/** @var array */
protected $transportOptions = array();
/**
* Creates a new in memory package.
@ -125,7 +125,7 @@ class Package extends BasePackage
public function getTargetDir()
{
if (null === $this->targetDir) {
return;
return null;
}
return ltrim(preg_replace('{ (?:^|[\\\\/]+) \.\.? (?:[\\\\/]+|$) (?:\.\.? (?:[\\\\/]+|$) )*}x', '/', $this->targetDir), '/');
@ -228,7 +228,7 @@ class Package extends BasePackage
}
/**
* @param array|null $mirrors
* {@inheritDoc}
*/
public function setSourceMirrors($mirrors)
{
@ -316,7 +316,7 @@ class Package extends BasePackage
}
/**
* @param array|null $mirrors
* {@inheritDoc}
*/
public function setDistMirrors($mirrors)
{
@ -339,6 +339,22 @@ class Package extends BasePackage
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}
*/
@ -553,42 +569,6 @@ class Package extends BasePackage
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
*/

@ -142,6 +142,12 @@ interface PackageInterface
*/
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
*
@ -184,6 +190,12 @@ interface PackageInterface
*/
public function getDistMirrors();
/**
* @param array|null $mirrors
* @return void
*/
public function setDistMirrors($mirrors);
/**
* Returns the version of this package
*
@ -357,20 +369,6 @@ interface PackageInterface
*/
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
*/
@ -383,6 +381,13 @@ interface PackageInterface
*/
public function getTransportOptions();
/**
* Configures the list of options to download package dist files
*
* @return void
*/
public function setTransportOptions(array $options);
/**
* @param string $reference
*

@ -15,13 +15,31 @@ namespace Composer\Package;
/**
* @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)
{
parent::__construct($aliasOf, $version, $prettyVersion);
}
/**
* @return RootPackageInterface
*/
public function getAliasOf()
{
return $this->aliasOf;
}
/**
* {@inheritDoc}
*/
@ -117,14 +135,6 @@ class RootAliasPackage extends AliasPackage implements RootPackageInterface
$this->aliasOf->setReplaces($replaces);
}
/**
* {@inheritDoc}
*/
public function setRepositories($repositories)
{
$this->aliasOf->setRepositories($repositories);
}
/**
* {@inheritDoc}
*/

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

@ -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));
}
return null;
}
/**
* @template CapabilityClass of Capability
* @param PluginInterface $plugin
* @param string $capabilityClassName The fully qualified name of the API interface which the plugin may provide
* an implementation of.
* @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.
* @param class-string<CapabilityClass> $capabilityClassName The fully qualified name of the API interface which the plugin may provide
* an implementation of.
* @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.
* @return null|Capability
* @phpstan-param class-string<CapabilityClass> $capabilityClassName
* @phpstan-return null|CapabilityClass
*/
public function getPluginCapability(PluginInterface $plugin, $capabilityClassName, array $ctorArgs = array())
{
@ -491,14 +496,17 @@ class PluginManager
return $capabilityObj;
}
return null;
}
/**
* @param string $capabilityClassName The fully qualified name of the API interface which the plugin may provide
* an implementation of.
* @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.
* @return Capability[]
/**
* @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.
* @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.
* @return CapabilityClass[]
*/
public function getPluginCapabilities($capabilityClassName, array $ctorArgs = array())
{

@ -13,6 +13,7 @@
namespace Composer\Repository;
use Composer\Package\AliasPackage;
use Composer\Package\CompleteAliasPackage;
use Composer\Package\PackageInterface;
use Composer\Package\CompletePackageInterface;
use Composer\Package\Version\VersionParser;
@ -27,13 +28,13 @@ use Composer\Semver\Constraint\Constraint;
*/
class ArrayRepository implements RepositoryInterface
{
/** @var PackageInterface[] */
protected $packages;
/** @var ?PackageInterface[] */
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())
{
@ -220,7 +221,7 @@ class ArrayRepository implements RepositoryInterface
if ($packageName === $link->getTarget()) {
$result[$candidate->getName()] = array(
'name' => $candidate->getName(),
'description' => $candidate->getDescription(),
'description' => $candidate instanceof CompletePackageInterface ? $candidate->getDescription() : null,
'type' => $candidate->getType(),
);
continue 2;
@ -233,7 +234,15 @@ class ArrayRepository implements RepositoryInterface
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);
}
/**

@ -16,6 +16,8 @@ use Composer\Package\BasePackage;
use Composer\Package\Loader\ArrayLoader;
use Composer\Package\PackageInterface;
use Composer\Package\AliasPackage;
use Composer\Package\CompletePackage;
use Composer\Package\CompleteAliasPackage;
use Composer\Package\Version\VersionParser;
use Composer\Package\Version\StabilityFilter;
use Composer\Json\JsonFile;
@ -167,7 +169,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
}
if ($this->hasAvailablePackageList && !$this->lazyProvidersRepoContains($name)) {
return;
return null;
}
$packages = $this->loadAsyncPackages(array($name => $constraint));
@ -182,7 +184,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
}
}
return;
return null;
}
return parent::findPackage($name, $constraint);
@ -428,7 +430,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
foreach ($search['results'] as $result) {
// do not show virtual packages in results as they are not directly useful from a composer perspective
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) {
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
*
* @private
* @return list<CompletePackage|CompleteAliasPackage>
*/
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) {
if (isset($this->sourceMirrors[$package->getSourceType()])) {

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

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

@ -70,16 +70,12 @@ interface RepositoryInterface extends \Countable
* - The packages returned are the packages found which match the constraints, acceptable stability and stability flags provided
* - 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 int[] $acceptableStabilities array of stability => BasePackage::STABILITY_* value
* @psalm-param array<string, BasePackage::STABILITY_*> $acceptableStabilities
* @param int[] $stabilityFlags an array of package name => BasePackage::STABILITY_* value
* @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[]]
* @psalm-return array{namesFound: string[], packages: PackageInterface[]}
* @param ConstraintInterface[] $packageNameMap package names pointing to constraints
* @param array<string, BasePackage::STABILITY_*> $acceptableStabilities array of stability => BasePackage::STABILITY_* value
* @param array<string, BasePackage::STABILITY_*> $stabilityFlags an array of package name => BasePackage::STABILITY_* value
* @param array<string, array<string, PackageInterface>> $alreadyLoaded an array of package name => package version => package
*
* @return array{namesFound: string[], packages: PackageInterface[]}
*/
public function loadPackages(array $packageNameMap, array $acceptableStabilities, array $stabilityFlags, array $alreadyLoaded = array());

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

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

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

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

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

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

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

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

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

@ -30,8 +30,8 @@ class Bitbucket
private $process;
/** @var HttpDownloader */
private $httpDownloader;
/** @var array */
private $token = array();
/** @var array{access_token: string, expires_in?: int}|null */
private $token = null;
/** @var int|null */
private $time;
@ -191,7 +191,7 @@ class Bitbucket
*/
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'];
}
@ -202,6 +202,10 @@ class Bitbucket
$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'];
}
@ -215,6 +219,10 @@ class Bitbucket
{
$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;
$consumer = array(
"consumer-key" => $consumerKey,

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

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

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

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

@ -25,7 +25,7 @@ class NoProxyPattern
protected $hostNames = array();
/**
* @var object[]
* @var (null|object)[]
*/
protected $rules = array();
@ -74,7 +74,7 @@ class NoProxyPattern
*
* @param string $url
*
* @return bool|stdclass
* @return bool|stdClass
*/
protected function getUrlData($url)
{
@ -108,9 +108,9 @@ class NoProxyPattern
/**
* Returns true if the url is matched by a rule
*
* @param int $index
* @param string $hostName
* @param string $url
* @param int $index
* @param string $hostName
* @param stdClass $url
*
* @return bool
*/
@ -198,7 +198,7 @@ class NoProxyPattern
* Creates an object containing IP data if the host is an IP address
*
* @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
*
* @return bool False if the host contains invalid data
@ -334,9 +334,9 @@ class NoProxyPattern
*
* @param string $host
* @param int $port
* @param null|stdclass $ipdata
* @param null|stdClass $ipdata
*
* @return stdclass
* @return stdClass
*/
private function makeData($host, $port, $ipdata)
{
@ -355,7 +355,7 @@ class NoProxyPattern
* @param int $size Byte size of in_addr
* @param null|string $netmask Network mask
*
* @return stdclass
* @return stdClass
*/
private function makeIpData($ip, $size, $netmask)
{

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

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

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

@ -30,7 +30,7 @@ final class StreamContextFactory
* Creates a context supporting HTTP proxies
*
* @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 $defaultParams Parameters to specify on the context
* @throws \RuntimeException if https proxy required and OpenSSL uninstalled

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

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

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

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

@ -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) {
$method = $operation->getOperationType();
@ -53,14 +53,14 @@ class InstallationManagerMock extends InstallationManager
return $repo->hasPackage($package);
}
public function install(RepositoryInterface $repo, InstallOperation $operation)
public function install(InstalledRepositoryInterface $repo, InstallOperation $operation)
{
$this->installed[] = $operation->getPackage();
$this->trace[] = strip_tags((string) $operation);
$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->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->trace[] = strip_tags((string) $operation);
$repo->removePackage($operation->getPackage());
}
public function markAliasInstalled(RepositoryInterface $repo, MarkAliasInstalledOperation $operation)
public function markAliasInstalled(InstalledRepositoryInterface $repo, MarkAliasInstalledOperation $operation)
{
$package = $operation->getPackage();
@ -87,7 +87,7 @@ class InstallationManagerMock extends InstallationManager
parent::markAliasInstalled($repo, $operation);
}
public function markAliasUninstalled(RepositoryInterface $repo, MarkAliasUninstalledOperation $operation)
public function markAliasUninstalled(InstalledRepositoryInterface $repo, MarkAliasUninstalledOperation $operation)
{
$this->uninstalled[] = $operation->getPackage();
$this->trace[] = strip_tags((string) $operation);

@ -15,7 +15,7 @@ namespace Composer\Test\Package\Archiver;
use Composer\Test\TestCase;
use Composer\Util\Filesystem;
use Composer\Util\ProcessExecutor;
use Composer\Package\Package;
use Composer\Package\CompletePackage;
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.
*
* @return \Composer\Package\Package
* @return CompletePackage
*/
protected function setupPackage()
{
$package = new Package('archivertest/archivertest', 'master', 'master');
$package = new CompletePackage('archivertest/archivertest', 'master', 'master');
$package->setSourceUrl(realpath($this->testDir));
$package->setSourceReference('master');
$package->setSourceType('git');

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

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

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

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

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

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

Loading…
Cancel
Save