diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 60b9afaf2..327d640c7 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -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 diff --git a/phpstan/config.neon b/phpstan/config.neon index fdb2dfdce..f68034588 100644 --- a/phpstan/config.neon +++ b/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 diff --git a/src/Composer/Autoload/ClassLoader.php b/src/Composer/Autoload/ClassLoader.php index 247294d66..6d0c3f2d0 100644 --- a/src/Composer/Autoload/ClassLoader.php +++ b/src/Composer/Autoload/ClassLoader.php @@ -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; } /** diff --git a/src/Composer/Command/ArchiveCommand.php b/src/Composer/Command/ArchiveCommand.php index aa725395a..6f30d5f24 100644 --- a/src/Composer/Command/ArchiveCommand.php +++ b/src/Composer/Command/ArchiveCommand.php @@ -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('Searching for the specified package.'); @@ -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; } } diff --git a/src/Composer/Command/BaseCommand.php b/src/Composer/Command/BaseCommand.php index d4c90a196..279b2652d 100644 --- a/src/Composer/Command/BaseCommand.php +++ b/src/Composer/Command/BaseCommand.php @@ -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 '); diff --git a/src/Composer/Command/DiagnoseCommand.php b/src/Composer/Command/DiagnoseCommand.php index 5f35fc4c5..ace5381e1 100644 --- a/src/Composer/Command/DiagnoseCommand.php +++ b/src/Composer/Command/DiagnoseCommand.php @@ -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(); } diff --git a/src/Composer/Command/GlobalCommand.php b/src/Composer/Command/GlobalCommand.php index 958643dee..96a6b5f5e 100644 --- a/src/Composer/Command/GlobalCommand.php +++ b/src/Composer/Command/GlobalCommand.php @@ -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(); diff --git a/src/Composer/Command/InitCommand.php b/src/Composer/Command/InitCommand.php index c63366bca..e9ac03978 100644 --- a/src/Composer/Command/InitCommand.php +++ b/src/Composer/Command/InitCommand.php @@ -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 @@ -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.'.'; diff --git a/src/Composer/Command/LicensesCommand.php b/src/Composer/Command/LicensesCommand.php index ec0c38acc..b4544cf50 100644 --- a/src/Composer/Command/LicensesCommand.php +++ b/src/Composer/Command/LicensesCommand.php @@ -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 '); diff --git a/src/Composer/Command/ShowCommand.php b/src/Composer/Command/ShowCommand.php index 2586cfc2e..d8969e670 100644 --- a/src/Composer/Command/ShowCommand.php +++ b/src/Composer/Command/ShowCommand.php @@ -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('names : ' . 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(); diff --git a/src/Composer/Console/Application.php b/src/Composer/Console/Application.php index 9d3557e27..9f0753eb7 100644 --- a/src/Composer/Console/Application.php +++ b/src/Composer/Console/Application.php @@ -44,7 +44,7 @@ use Composer\Exception\NoSslException; class Application extends BaseApplication { /** - * @var Composer + * @var ?Composer */ protected $composer; diff --git a/src/Composer/DependencyResolver/Decisions.php b/src/Composer/DependencyResolver/Decisions.php index 02997819e..648b533df 100644 --- a/src/Composer/DependencyResolver/Decisions.php +++ b/src/Composer/DependencyResolver/Decisions.php @@ -164,7 +164,7 @@ class Decisions implements \Iterator, \Countable public function next() { - return prev($this->decisionQueue); + prev($this->decisionQueue); } public function valid() diff --git a/src/Composer/DependencyResolver/DefaultPolicy.php b/src/Composer/DependencyResolver/DefaultPolicy.php index e26555bf7..dc8e17736 100644 --- a/src/Composer/DependencyResolver/DefaultPolicy.php +++ b/src/Composer/DependencyResolver/DefaultPolicy.php @@ -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() diff --git a/src/Composer/DependencyResolver/GenericRule.php b/src/Composer/DependencyResolver/GenericRule.php index 2d2cec7b1..9441ada77 100644 --- a/src/Composer/DependencyResolver/GenericRule.php +++ b/src/Composer/DependencyResolver/GenericRule.php @@ -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) { diff --git a/src/Composer/DependencyResolver/MultiConflictRule.php b/src/Composer/DependencyResolver/MultiConflictRule.php index 60d849962..e5be1f1ec 100644 --- a/src/Composer/DependencyResolver/MultiConflictRule.php +++ b/src/Composer/DependencyResolver/MultiConflictRule.php @@ -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) { diff --git a/src/Composer/DependencyResolver/Pool.php b/src/Composer/DependencyResolver/Pool.php index 23d412ac4..348583513 100644 --- a/src/Composer/DependencyResolver/Pool.php +++ b/src/Composer/DependencyResolver/Pool.php @@ -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 */ 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); } diff --git a/src/Composer/DependencyResolver/PoolBuilder.php b/src/Composer/DependencyResolver/PoolBuilder.php index 74434a5cb..e4a4afc49 100644 --- a/src/Composer/DependencyResolver/PoolBuilder.php +++ b/src/Composer/DependencyResolver/PoolBuilder.php @@ -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> */ private $rootAliases; /** + * @var string[] * @psalm-var array */ private $rootReferences; @@ -59,27 +63,32 @@ class PoolBuilder */ private $io; /** - * @psalm-var array + * @var array[] + * @psalm-var array */ private $aliasMap = array(); /** + * @var ConstraintInterface[] * @psalm-var array */ private $packagesToLoad = array(); /** + * @var ConstraintInterface[] * @psalm-var array */ private $loadedPackages = array(); /** + * @var array[] * @psalm-var array>> */ private $loadedPerRepo = array(); /** - * @psalm-var Package[] + * @var PackageInterface[] */ private $packages = array(); /** - * @psalm-var list + * @var PackageInterface[] + * @psalm-var list */ private $unacceptableFixedOrLockedPackages = array(); private $updateAllowList = array(); @@ -95,6 +104,7 @@ class PoolBuilder */ private $maxExtendedReqs = array(); /** + * @var array * @psalm-var array */ 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++; diff --git a/src/Composer/DependencyResolver/Rule.php b/src/Composer/DependencyResolver/Rule.php index 5571ec676..d29e4c57d 100644 --- a/src/Composer/DependencyResolver/Rule.php +++ b/src/Composer/DependencyResolver/Rule.php @@ -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(); diff --git a/src/Composer/DependencyResolver/Rule2Literals.php b/src/Composer/DependencyResolver/Rule2Literals.php index b67843c96..4d6b86c50 100644 --- a/src/Composer/DependencyResolver/Rule2Literals.php +++ b/src/Composer/DependencyResolver/Rule2Literals.php @@ -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) { diff --git a/src/Composer/DependencyResolver/RuleSet.php b/src/Composer/DependencyResolver/RuleSet.php index 5151b3d7e..aff0d4c65 100644 --- a/src/Composer/DependencyResolver/RuleSet.php +++ b/src/Composer/DependencyResolver/RuleSet.php @@ -113,6 +113,9 @@ class RuleSet implements \IteratorAggregate, \Countable return $this->rules; } + /** + * @return RuleSetIterator + */ public function getIterator() { return new RuleSetIterator($this->getRules()); diff --git a/src/Composer/DependencyResolver/RuleSetGenerator.php b/src/Composer/DependencyResolver/RuleSetGenerator.php index ec8f9ed8c..26977e567 100644 --- a/src/Composer/DependencyResolver/RuleSetGenerator.php +++ b/src/Composer/DependencyResolver/RuleSetGenerator.php @@ -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 diff --git a/src/Composer/Downloader/DownloadManager.php b/src/Composer/Downloader/DownloadManager.php index aebbf5039..f55cb9a28 100644 --- a/src/Composer/Downloader/DownloadManager.php +++ b/src/Composer/Downloader/DownloadManager.php @@ -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(); } /** diff --git a/src/Composer/Downloader/FileDownloader.php b/src/Composer/Downloader/FileDownloader.php index 236390066..74fd12474 100644 --- a/src/Composer/Downloader/FileDownloader.php +++ b/src/Composer/Downloader/FileDownloader.php @@ -112,8 +112,10 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface }; $retries = 3; - $urls = $package->getDistUrls(); - foreach ($urls as $index => $url) { + $distUrls = $package->getDistUrls(); + /** @var array $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(); } /** diff --git a/src/Composer/Downloader/FossilDownloader.php b/src/Composer/Downloader/FossilDownloader.php index a597d51d5..df77c14ea 100644 --- a/src/Composer/Downloader/FossilDownloader.php +++ b/src/Composer/Downloader/FossilDownloader.php @@ -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(); } /** diff --git a/src/Composer/Downloader/GitDownloader.php b/src/Composer/Downloader/GitDownloader.php index 78270f4da..3a8d60fa5 100644 --- a/src/Composer/Downloader/GitDownloader.php +++ b/src/Composer/Downloader/GitDownloader.php @@ -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]; diff --git a/src/Composer/Downloader/GzipDownloader.php b/src/Composer/Downloader/GzipDownloader.php index 04dd5e7ed..18f00253a 100644 --- a/src/Composer/Downloader/GzipDownloader.php +++ b/src/Composer/Downloader/GzipDownloader.php @@ -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) diff --git a/src/Composer/Downloader/HgDownloader.php b/src/Composer/Downloader/HgDownloader.php index 737dd8758..c0d7498b1 100644 --- a/src/Composer/Downloader/HgDownloader.php +++ b/src/Composer/Downloader/HgDownloader.php @@ -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(); } /** diff --git a/src/Composer/Downloader/PathDownloader.php b/src/Composer/Downloader/PathDownloader.php index 94fe8e0dc..bdcf39984 100644 --- a/src/Composer/Downloader/PathDownloader.php +++ b/src/Composer/Downloader/PathDownloader.php @@ -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(" Could not remove junction at " . $path . " - is another process locking it?"); 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; } /** diff --git a/src/Composer/Downloader/PerforceDownloader.php b/src/Composer/Downloader/PerforceDownloader.php index 0b9e7a683..dc30f8361 100644 --- a/src/Composer/Downloader/PerforceDownloader.php +++ b/src/Composer/Downloader/PerforceDownloader.php @@ -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; } /** diff --git a/src/Composer/Downloader/PharDownloader.php b/src/Composer/Downloader/PharDownloader.php index 62741ee0e..89ef4363f 100644 --- a/src/Composer/Downloader/PharDownloader.php +++ b/src/Composer/Downloader/PharDownloader.php @@ -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(); } } diff --git a/src/Composer/Downloader/RarDownloader.php b/src/Composer/Downloader/RarDownloader.php index 8951d9636..0ca23ea29 100644 --- a/src/Composer/Downloader/RarDownloader.php +++ b/src/Composer/Downloader/RarDownloader.php @@ -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(); + } } diff --git a/src/Composer/Downloader/SvnDownloader.php b/src/Composer/Downloader/SvnDownloader.php index 80454f855..2e100c57e 100644 --- a/src/Composer/Downloader/SvnDownloader.php +++ b/src/Composer/Downloader/SvnDownloader.php @@ -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(); } /** diff --git a/src/Composer/Downloader/TarDownloader.php b/src/Composer/Downloader/TarDownloader.php index e48407230..65346030e 100644 --- a/src/Composer/Downloader/TarDownloader.php +++ b/src/Composer/Downloader/TarDownloader.php @@ -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(); } } diff --git a/src/Composer/Downloader/VcsDownloader.php b/src/Composer/Downloader/VcsDownloader.php index 59bd097ea..b44c7264b 100644 --- a/src/Composer/Downloader/VcsDownloader.php +++ b/src/Composer/Downloader/VcsDownloader.php @@ -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) { diff --git a/src/Composer/Downloader/XzDownloader.php b/src/Composer/Downloader/XzDownloader.php index 9431d4fa0..7e69a52bc 100644 --- a/src/Composer/Downloader/XzDownloader.php +++ b/src/Composer/Downloader/XzDownloader.php @@ -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(); diff --git a/src/Composer/Downloader/ZipDownloader.php b/src/Composer/Downloader/ZipDownloader.php index d496ef446..8e899366b 100644 --- a/src/Composer/Downloader/ZipDownloader.php +++ b/src/Composer/Downloader/ZipDownloader.php @@ -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 diff --git a/src/Composer/EventDispatcher/EventDispatcher.php b/src/Composer/EventDispatcher/EventDispatcher.php index 84e537839..a5c1ced0a 100644 --- a/src/Composer/EventDispatcher/EventDispatcher.php +++ b/src/Composer/EventDispatcher/EventDispatcher.php @@ -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; diff --git a/src/Composer/IO/BaseIO.php b/src/Composer/IO/BaseIO.php index e66360edc..32a9171f3 100644 --- a/src/Composer/IO/BaseIO.php +++ b/src/Composer/IO/BaseIO.php @@ -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()) { diff --git a/src/Composer/IO/BufferIO.php b/src/Composer/IO/BufferIO.php index e35918bfc..e86500e2d 100644 --- a/src/Composer/IO/BufferIO.php +++ b/src/Composer/IO/BufferIO.php @@ -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 diff --git a/src/Composer/IO/NullIO.php b/src/Composer/IO/NullIO.php index cc6d5eba1..9dc9d3a0f 100644 --- a/src/Composer/IO/NullIO.php +++ b/src/Composer/IO/NullIO.php @@ -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; } diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index 53ea964d9..52049b467 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -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( diff --git a/src/Composer/Installer/InstallationManager.php b/src/Composer/Installer/InstallationManager.php index 01148583a..5f72b4192 100644 --- a/src/Composer/Installer/InstallationManager.php +++ b/src/Composer/Installer/InstallationManager.php @@ -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(); diff --git a/src/Composer/Installer/MetapackageInstaller.php b/src/Composer/Installer/MetapackageInstaller.php index e9933cec5..f5a2a43b6 100644 --- a/src/Composer/Installer/MetapackageInstaller.php +++ b/src/Composer/Installer/MetapackageInstaller.php @@ -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(); } /** diff --git a/src/Composer/Installer/NoopInstaller.php b/src/Composer/Installer/NoopInstaller.php index 4fe581ff5..1342db4ac 100644 --- a/src/Composer/Installer/NoopInstaller.php +++ b/src/Composer/Installer/NoopInstaller.php @@ -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(); } /** diff --git a/src/Composer/Installer/SuggestedPackagesReporter.php b/src/Composer/Installer/SuggestedPackagesReporter.php index 1134fb9b6..5e905cd7c 100644 --- a/src/Composer/Installer/SuggestedPackagesReporter.php +++ b/src/Composer/Installer/SuggestedPackagesReporter.php @@ -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('%s', $name)); } - return 0; + return; } // Grouped by package @@ -160,8 +160,6 @@ class SuggestedPackagesReporter $this->io->write(''.$diff.' additional suggestions by transitive dependencies can be shown with --all'); } } - - 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(''.count($suggestedPackages).' package suggestions were added by new dependencies, use `composer suggest` to see details.'); } - - return $this; } /** diff --git a/src/Composer/Package/AliasPackage.php b/src/Composer/Package/AliasPackage.php index 4a304e3dc..2e5d757bc 100644 --- a/src/Composer/Package/AliasPackage.php +++ b/src/Composer/Package/AliasPackage.php @@ -18,7 +18,7 @@ use Composer\Package\Version\VersionParser; /** * @author Jordi Boggiano */ -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); } } diff --git a/src/Composer/Package/Archiver/ArchiveManager.php b/src/Composer/Package/Archiver/ArchiveManager.php index c0a75f696..14db48dd6 100644 --- a/src/Composer/Package/Archiver/ArchiveManager.php +++ b/src/Composer/Package/Archiver/ArchiveManager.php @@ -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 @@ -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'); diff --git a/src/Composer/Package/BasePackage.php b/src/Composer/Package/BasePackage.php index 2bf2cc1b4..f90f20d91 100644 --- a/src/Composer/Package/BasePackage.php +++ b/src/Composer/Package/BasePackage.php @@ -23,7 +23,7 @@ use Composer\Repository\PlatformRepository; abstract class BasePackage implements PackageInterface { /** - * @phpstan-var array + * @psalm-var array */ 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 * diff --git a/src/Composer/Package/CompleteAliasPackage.php b/src/Composer/Package/CompleteAliasPackage.php new file mode 100644 index 000000000..6326eedbc --- /dev/null +++ b/src/Composer/Package/CompleteAliasPackage.php @@ -0,0 +1,167 @@ + + * Jordi Boggiano + * + * 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 + */ +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); + } +} diff --git a/src/Composer/Package/CompletePackage.php b/src/Composer/Package/CompletePackage.php index 85056405b..e09158053 100644 --- a/src/Composer/Package/CompletePackage.php +++ b/src/Composer/Package/CompletePackage.php @@ -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; + } } diff --git a/src/Composer/Package/CompletePackageInterface.php b/src/Composer/Package/CompletePackageInterface.php index 01e5f65cd..595338296 100644 --- a/src/Composer/Package/CompletePackageInterface.php +++ b/src/Composer/Package/CompletePackageInterface.php @@ -22,19 +22,31 @@ interface CompletePackageInterface extends PackageInterface /** * Returns the scripts of this package * - * @return array[] array('script name' => array('listeners')) - * @psalm-return array + * @return array array('script name' => array('listeners')) */ public function getScripts(); + /** + * @param array $scripts + * @return void + */ + public function setScripts(array $scripts); + /** * Returns an array of repositories * - * @return array[] Repositories - * @psalm-return array + * @return array Repositories */ public function getRepositories(); + /** + * Set the repositories + * + * @param array $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 + * @return array */ public function getAuthors(); + /** + * Set the authors + * + * @param array $authors + * @return void + */ + public function setAuthors(array $authors); + /** * Returns the support information * - * @return array - * @psalm-return array + * @return array */ public function getSupport(); + /** + * Set the support information + * + * @param array $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 + * @return array */ public function getFunding(); + /** + * Set the funding + * + * @param array $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); + + } diff --git a/src/Composer/Package/Dumper/ArrayDumper.php b/src/Composer/Package/Dumper/ArrayDumper.php index 903997601..e3b053b87 100644 --- a/src/Composer/Package/Dumper/ArrayDumper.php +++ b/src/Composer/Package/Dumper/ArrayDumper.php @@ -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', diff --git a/src/Composer/Package/Link.php b/src/Composer/Package/Link.php index db8e0f4ad..052181187 100644 --- a/src/Composer/Package/Link.php +++ b/src/Composer/Package/Link.php @@ -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); diff --git a/src/Composer/Package/Loader/ArrayLoader.php b/src/Composer/Package/Loader/ArrayLoader.php index 7f6263a65..d8a69b76a 100644 --- a/src/Composer/Package/Loader/ArrayLoader.php +++ b/src/Composer/Package/Loader/ArrayLoader.php @@ -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 $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 + * @phpstan-param class-string $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 $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; } } diff --git a/src/Composer/Package/Loader/JsonLoader.php b/src/Composer/Package/Loader/JsonLoader.php index f8c6e8c88..66f75c034 100644 --- a/src/Composer/Package/Loader/JsonLoader.php +++ b/src/Composer/Package/Loader/JsonLoader.php @@ -13,6 +13,8 @@ namespace Composer\Package\Loader; use Composer\Json\JsonFile; +use Composer\Package\CompletePackage; +use Composer\Package\CompleteAliasPackage; /** * @author Konstantin Kudryashiv @@ -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) { diff --git a/src/Composer/Package/Loader/RootPackageLoader.php b/src/Composer/Package/Loader/RootPackageLoader.php index 843a94e69..76e8f29f4 100644 --- a/src/Composer/Package/Loader/RootPackageLoader.php +++ b/src/Composer/Package/Loader/RootPackageLoader.php @@ -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 $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) { diff --git a/src/Composer/Package/Locker.php b/src/Composer/Package/Locker.php index 5f485fd03..4bbbb1d4c 100644 --- a/src/Composer/Package/Locker.php +++ b/src/Composer/Package/Locker.php @@ -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); } diff --git a/src/Composer/Package/Package.php b/src/Composer/Package/Package.php index 29d700d13..9223fba93 100644 --- a/src/Composer/Package/Package.php +++ b/src/Composer/Package/Package.php @@ -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 */ diff --git a/src/Composer/Package/PackageInterface.php b/src/Composer/Package/PackageInterface.php index 34dab77c0..0c2ac8ec3 100644 --- a/src/Composer/Package/PackageInterface.php +++ b/src/Composer/Package/PackageInterface.php @@ -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 * diff --git a/src/Composer/Package/RootAliasPackage.php b/src/Composer/Package/RootAliasPackage.php index 231cd34de..836a9ce3d 100644 --- a/src/Composer/Package/RootAliasPackage.php +++ b/src/Composer/Package/RootAliasPackage.php @@ -15,13 +15,31 @@ namespace Composer\Package; /** * @author Jordi Boggiano */ -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} */ diff --git a/src/Composer/Package/RootPackageInterface.php b/src/Composer/Package/RootPackageInterface.php index 7a3be9d8e..3d891eab2 100644 --- a/src/Composer/Package/RootPackageInterface.php +++ b/src/Composer/Package/RootPackageInterface.php @@ -105,7 +105,7 @@ interface RootPackageInterface extends CompletePackageInterface * * @param array $repositories */ - public function setRepositories($repositories); + public function setRepositories(array $repositories); /** * Set the autoload mapping diff --git a/src/Composer/Plugin/PluginManager.php b/src/Composer/Plugin/PluginManager.php index 961d8368e..0cd44408d 100644 --- a/src/Composer/Plugin/PluginManager.php +++ b/src/Composer/Plugin/PluginManager.php @@ -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 $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 $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 $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()) { diff --git a/src/Composer/Repository/ArrayRepository.php b/src/Composer/Repository/ArrayRepository.php index b0d8443c6..90cf938f4 100644 --- a/src/Composer/Repository/ArrayRepository.php +++ b/src/Composer/Repository/ArrayRepository.php @@ -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); } /** diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index b4ec499d4..49e0e5b90 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -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 */ 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()])) { diff --git a/src/Composer/Repository/FilterRepository.php b/src/Composer/Repository/FilterRepository.php index 361c2fe67..61b31e91a 100644 --- a/src/Composer/Repository/FilterRepository.php +++ b/src/Composer/Repository/FilterRepository.php @@ -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; } } diff --git a/src/Composer/Repository/PlatformRepository.php b/src/Composer/Repository/PlatformRepository.php index f0ae43d13..7e48b49b5 100644 --- a/src/Composer/Repository/PlatformRepository.php +++ b/src/Composer/Repository/PlatformRepository.php @@ -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']); diff --git a/src/Composer/Repository/RepositoryInterface.php b/src/Composer/Repository/RepositoryInterface.php index d54057b9f..60d73c992 100644 --- a/src/Composer/Repository/RepositoryInterface.php +++ b/src/Composer/Repository/RepositoryInterface.php @@ -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 $acceptableStabilities - * @param int[] $stabilityFlags an array of package name => BasePackage::STABILITY_* value - * @psalm-param array $stabilityFlags - * @param array[] $alreadyLoaded an array of package name => package version => package - * @psalm-param array> $alreadyLoaded + * @param ConstraintInterface[] $packageNameMap package names pointing to constraints + * @param array $acceptableStabilities array of stability => BasePackage::STABILITY_* value + * @param array $stabilityFlags an array of package name => BasePackage::STABILITY_* value + * @param array> $alreadyLoaded an array of package name => package version => package * - * @return array [namesFound => string[], packages => PackageInterface[]] - * @psalm-return array{namesFound: string[], packages: PackageInterface[]} + * @return array{namesFound: string[], packages: PackageInterface[]} */ public function loadPackages(array $packageNameMap, array $acceptableStabilities, array $stabilityFlags, array $alreadyLoaded = array()); diff --git a/src/Composer/Repository/RepositorySet.php b/src/Composer/Repository/RepositorySet.php index 1ef60a719..71ddba393 100644 --- a/src/Composer/Repository/RepositorySet.php +++ b/src/Composer/Repository/RepositorySet.php @@ -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; } diff --git a/src/Composer/Repository/Vcs/BitbucketDriver.php b/src/Composer/Repository/Vcs/BitbucketDriver.php index aa6c9a2f8..e1c45acde 100644 --- a/src/Composer/Repository/Vcs/BitbucketDriver.php +++ b/src/Composer/Repository/Vcs/BitbucketDriver.php @@ -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; diff --git a/src/Composer/Repository/Vcs/GitBitbucketDriver.php b/src/Composer/Repository/Vcs/GitBitbucketDriver.php index 482fb1537..ab59c23e1 100644 --- a/src/Composer/Repository/Vcs/GitBitbucketDriver.php +++ b/src/Composer/Repository/Vcs/GitBitbucketDriver.php @@ -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(); } diff --git a/src/Composer/Repository/Vcs/GitHubDriver.php b/src/Composer/Repository/Vcs/GitHubDriver.php index 46f7ef2ed..b312edeac 100644 --- a/src/Composer/Repository/Vcs/GitHubDriver.php +++ b/src/Composer/Repository/Vcs/GitHubDriver.php @@ -39,9 +39,9 @@ class GitHubDriver extends VcsDriver /** * Git Driver * - * @var GitDriver + * @var ?GitDriver */ - protected $gitDriver; + protected $gitDriver = null; /** * {@inheritDoc} diff --git a/src/Composer/Repository/Vcs/GitLabDriver.php b/src/Composer/Repository/Vcs/GitLabDriver.php index 4f3c35cd2..a3d4a18f6 100644 --- a/src/Composer/Repository/Vcs/GitLabDriver.php +++ b/src/Composer/Repository/Vcs/GitLabDriver.php @@ -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 diff --git a/src/Composer/Repository/Vcs/HgBitbucketDriver.php b/src/Composer/Repository/Vcs/HgBitbucketDriver.php index 9706e2a00..71505cf52 100644 --- a/src/Composer/Repository/Vcs/HgBitbucketDriver.php +++ b/src/Composer/Repository/Vcs/HgBitbucketDriver.php @@ -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(); } diff --git a/src/Composer/Repository/Vcs/HgDriver.php b/src/Composer/Repository/Vcs/HgDriver.php index 4fa737168..75f10a185 100644 --- a/src/Composer/Repository/Vcs/HgDriver.php +++ b/src/Composer/Repository/Vcs/HgDriver.php @@ -125,7 +125,7 @@ class HgDriver extends VcsDriver $this->process->execute($resource, $content, $this->repoDir); if (!trim($content)) { - return; + return null; } return $content; diff --git a/src/Composer/Repository/Vcs/PerforceDriver.php b/src/Composer/Repository/Vcs/PerforceDriver.php index 38a3ab65e..861b67038 100644 --- a/src/Composer/Repository/Vcs/PerforceDriver.php +++ b/src/Composer/Repository/Vcs/PerforceDriver.php @@ -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'); } /** diff --git a/src/Composer/Util/AuthHelper.php b/src/Composer/Util/AuthHelper.php index 096c73008..fa00e5bd6 100644 --- a/src/Composer/Util/AuthHelper.php +++ b/src/Composer/Util/AuthHelper.php @@ -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 diff --git a/src/Composer/Util/Bitbucket.php b/src/Composer/Util/Bitbucket.php index ea082806d..38611ac55 100644 --- a/src/Composer/Util/Bitbucket.php +++ b/src/Composer/Util/Bitbucket.php @@ -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, diff --git a/src/Composer/Util/ErrorHandler.php b/src/Composer/Util/ErrorHandler.php index c4dabd1d7..10f1c2472 100644 --- a/src/Composer/Util/ErrorHandler.php +++ b/src/Composer/Util/ErrorHandler.php @@ -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)) { diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index 23d747095..c1a122b11 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -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) { diff --git a/src/Composer/Util/Http/ProxyHelper.php b/src/Composer/Util/Http/ProxyHelper.php index e291f5b81..611980676 100644 --- a/src/Composer/Util/Http/ProxyHelper.php +++ b/src/Composer/Util/Http/ProxyHelper.php @@ -116,6 +116,8 @@ class ProxyHelper return $_SERVER[$name]; } } + + return null; } /** diff --git a/src/Composer/Util/Http/ProxyManager.php b/src/Composer/Util/Http/ProxyManager.php index edd486ef3..586b08e83 100644 --- a/src/Composer/Util/Http/ProxyManager.php +++ b/src/Composer/Util/Http/ProxyManager.php @@ -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; diff --git a/src/Composer/Util/NoProxyPattern.php b/src/Composer/Util/NoProxyPattern.php index f74ab7cf0..c391a7535 100644 --- a/src/Composer/Util/NoProxyPattern.php +++ b/src/Composer/Util/NoProxyPattern.php @@ -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) { diff --git a/src/Composer/Util/PackageSorter.php b/src/Composer/Util/PackageSorter.php index ae3728077..ac20b106e 100644 --- a/src/Composer/Util/PackageSorter.php +++ b/src/Composer/Util/PackageSorter.php @@ -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(); } diff --git a/src/Composer/Util/ProcessExecutor.php b/src/Composer/Util/ProcessExecutor.php index 5ec43859a..47ea0b359 100644 --- a/src/Composer/Util/ProcessExecutor.php +++ b/src/Composer/Util/ProcessExecutor.php @@ -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 @@ -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) { diff --git a/src/Composer/Util/RemoteFilesystem.php b/src/Composer/Util/RemoteFilesystem.php index 8b8e0c3e0..9aed13ac2 100644 --- a/src/Composer/Util/RemoteFilesystem.php +++ b/src/Composer/Util/RemoteFilesystem.php @@ -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); } diff --git a/src/Composer/Util/StreamContextFactory.php b/src/Composer/Util/StreamContextFactory.php index 50ecaca6f..82e1e9ec3 100644 --- a/src/Composer/Util/StreamContextFactory.php +++ b/src/Composer/Util/StreamContextFactory.php @@ -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}} $defaultOptions + * @psalm-param array{http?: array{follow_location?: int, max_redirects?: int, header?: string|array}} $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 diff --git a/src/Composer/Util/SyncHelper.php b/src/Composer/Util/SyncHelper.php index 27685693b..a970028a9 100644 --- a/src/Composer/Util/SyncHelper.php +++ b/src/Composer/Util/SyncHelper.php @@ -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)); diff --git a/tests/Composer/Test/Downloader/PerforceDownloaderTest.php b/tests/Composer/Test/Downloader/PerforceDownloaderTest.php index ca9386332..370fc9d31 100644 --- a/tests/Composer/Test/Downloader/PerforceDownloaderTest.php +++ b/tests/Composer/Test/Downloader/PerforceDownloaderTest.php @@ -26,7 +26,7 @@ use Composer\Util\Filesystem; class PerforceDownloaderTest extends TestCase { protected $config; - /** @var PerforceDownloader */ + /** @var ?PerforceDownloader */ protected $downloader; protected $io; protected $package; diff --git a/tests/Composer/Test/Downloader/ZipDownloaderTest.php b/tests/Composer/Test/Downloader/ZipDownloaderTest.php index e21078469..4d8b8460b 100644 --- a/tests/Composer/Test/Downloader/ZipDownloaderTest.php +++ b/tests/Composer/Test/Downloader/ZipDownloaderTest.php @@ -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) diff --git a/tests/Composer/Test/InstallerTest.php b/tests/Composer/Test/InstallerTest.php index 0d503a479..3ab4d6e39 100644 --- a/tests/Composer/Test/InstallerTest.php +++ b/tests/Composer/Test/InstallerTest.php @@ -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())); diff --git a/tests/Composer/Test/Mock/InstallationManagerMock.php b/tests/Composer/Test/Mock/InstallationManagerMock.php index adf94b9f4..4642a4800 100644 --- a/tests/Composer/Test/Mock/InstallationManagerMock.php +++ b/tests/Composer/Test/Mock/InstallationManagerMock.php @@ -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); diff --git a/tests/Composer/Test/Package/Archiver/ArchiverTest.php b/tests/Composer/Test/Package/Archiver/ArchiverTest.php index 8926d760b..62e62cce0 100644 --- a/tests/Composer/Test/Package/Archiver/ArchiverTest.php +++ b/tests/Composer/Test/Package/Archiver/ArchiverTest.php @@ -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'); diff --git a/tests/Composer/Test/Package/RootAliasPackageTest.php b/tests/Composer/Test/Package/RootAliasPackageTest.php index 459f935e5..f3db670a7 100644 --- a/tests/Composer/Test/Package/RootAliasPackageTest.php +++ b/tests/Composer/Test/Package/RootAliasPackageTest.php @@ -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(); diff --git a/tests/Composer/Test/Plugin/PluginInstallerTest.php b/tests/Composer/Test/Plugin/PluginInstallerTest.php index c5c587b3e..9af15a41a 100644 --- a/tests/Composer/Test/Plugin/PluginInstallerTest.php +++ b/tests/Composer/Test/Plugin/PluginInstallerTest.php @@ -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); diff --git a/tests/Composer/Test/Repository/RepositoryManagerTest.php b/tests/Composer/Test/Repository/RepositoryManagerTest.php index 1d59b63af..516e992d3 100644 --- a/tests/Composer/Test/Repository/RepositoryManagerTest.php +++ b/tests/Composer/Test/Repository/RepositoryManagerTest.php @@ -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); diff --git a/tests/Composer/Test/TestCase.php b/tests/Composer/Test/TestCase.php index 4f8fcc48c..c511e67bb 100644 --- a/tests/Composer/Test/TestCase.php +++ b/tests/Composer/Test/TestCase.php @@ -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) { diff --git a/tests/Composer/Test/Util/ErrorHandlerTest.php b/tests/Composer/Test/Util/ErrorHandlerTest.php index c7651b80a..89e97f653 100644 --- a/tests/Composer/Test/Util/ErrorHandlerTest.php +++ b/tests/Composer/Test/Util/ErrorHandlerTest.php @@ -42,6 +42,7 @@ class ErrorHandlerTest extends TestCase } $array = array('foo' => 'bar'); + // @phpstan-ignore-next-line $array['baz']; } diff --git a/tests/Composer/Test/Util/GitTest.php b/tests/Composer/Test/Util/GitTest.php index 66ad8ffa0..4fbc1826a 100644 --- a/tests/Composer/Test/Util/GitTest.php +++ b/tests/Composer/Test/Util/GitTest.php @@ -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()