Merge pull request #8533 from Seldaek/remove-stability-callback
Remove callback and pass stabilities all the way insteadpull/8535/head
commit
b1c0d7fb61
|
@ -38,24 +38,26 @@ class Pool implements \Countable
|
||||||
protected $packageByExactName = array();
|
protected $packageByExactName = array();
|
||||||
protected $versionParser;
|
protected $versionParser;
|
||||||
protected $providerCache = array();
|
protected $providerCache = array();
|
||||||
|
protected $unacceptableFixedPackages;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct(array $packages = array(), array $unacceptableFixedPackages = array())
|
||||||
{
|
{
|
||||||
$this->versionParser = new VersionParser;
|
$this->versionParser = new VersionParser;
|
||||||
|
$this->setPackages($packages);
|
||||||
|
$this->unacceptableFixedPackages = $unacceptableFixedPackages;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setPackages(array $packages)
|
private function setPackages(array $packages)
|
||||||
{
|
{
|
||||||
$id = 1;
|
$id = 1;
|
||||||
|
|
||||||
foreach ($packages as $i => $package) {
|
foreach ($packages as $package) {
|
||||||
$this->packages[] = $package;
|
$this->packages[] = $package;
|
||||||
|
|
||||||
$package->id = $id++;
|
$package->id = $id++;
|
||||||
$names = $package->getNames();
|
|
||||||
$this->packageByExactName[$package->getName()][$package->id] = $package;
|
$this->packageByExactName[$package->getName()][$package->id] = $package;
|
||||||
|
|
||||||
foreach ($names as $provided) {
|
foreach ($package->getNames() as $provided) {
|
||||||
$this->packageByName[$provided][] = $package;
|
$this->packageByName[$provided][] = $package;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -227,4 +229,9 @@ class Pool implements \Countable
|
||||||
|
|
||||||
return self::MATCH_NONE;
|
return self::MATCH_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isUnacceptableFixedPackage(PackageInterface $package)
|
||||||
|
{
|
||||||
|
return in_array($package, $this->unacceptableFixedPackages, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,9 @@ use Composer\Package\AliasPackage;
|
||||||
use Composer\Package\BasePackage;
|
use Composer\Package\BasePackage;
|
||||||
use Composer\Package\Package;
|
use Composer\Package\Package;
|
||||||
use Composer\Package\PackageInterface;
|
use Composer\Package\PackageInterface;
|
||||||
|
use Composer\Package\Version\StabilityFilter;
|
||||||
use Composer\Repository\PlatformRepository;
|
use Composer\Repository\PlatformRepository;
|
||||||
|
use Composer\Repository\RootPackageRepository;
|
||||||
use Composer\Semver\Constraint\Constraint;
|
use Composer\Semver\Constraint\Constraint;
|
||||||
use Composer\Semver\Constraint\MultiConstraint;
|
use Composer\Semver\Constraint\MultiConstraint;
|
||||||
|
|
||||||
|
@ -25,29 +27,30 @@ use Composer\Semver\Constraint\MultiConstraint;
|
||||||
*/
|
*/
|
||||||
class PoolBuilder
|
class PoolBuilder
|
||||||
{
|
{
|
||||||
private $isPackageAcceptableCallable;
|
private $acceptableStabilities;
|
||||||
private $rootRequires;
|
private $stabilityFlags;
|
||||||
private $rootAliases;
|
private $rootAliases;
|
||||||
private $rootReferences;
|
private $rootReferences;
|
||||||
|
private $rootRequires;
|
||||||
|
|
||||||
private $aliasMap = array();
|
private $aliasMap = array();
|
||||||
private $nameConstraints = array();
|
private $nameConstraints = array();
|
||||||
|
|
||||||
private $loadedNames = array();
|
private $loadedNames = array();
|
||||||
|
|
||||||
private $packages = array();
|
private $packages = array();
|
||||||
|
private $unacceptableFixedPackages = array();
|
||||||
|
|
||||||
public function __construct($isPackageAcceptableCallable, array $rootRequires = array())
|
public function __construct(array $acceptableStabilities, array $stabilityFlags, array $rootAliases, array $rootReferences, array $rootRequires = array())
|
||||||
{
|
{
|
||||||
$this->isPackageAcceptableCallable = $isPackageAcceptableCallable;
|
$this->acceptableStabilities = $acceptableStabilities;
|
||||||
|
$this->stabilityFlags = $stabilityFlags;
|
||||||
|
$this->rootAliases = $rootAliases;
|
||||||
|
$this->rootReferences = $rootReferences;
|
||||||
$this->rootRequires = $rootRequires;
|
$this->rootRequires = $rootRequires;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildPool(array $repositories, array $rootAliases, array $rootReferences, Request $request)
|
public function buildPool(array $repositories, Request $request)
|
||||||
{
|
{
|
||||||
$pool = new Pool();
|
$pool = new Pool();
|
||||||
$this->rootAliases = $rootAliases;
|
|
||||||
$this->rootReferences = $rootReferences;
|
|
||||||
|
|
||||||
// TODO do we really want the request here? kind of want a root requirements thingy instead
|
// TODO do we really want the request here? kind of want a root requirements thingy instead
|
||||||
$loadNames = array();
|
$loadNames = array();
|
||||||
|
@ -55,7 +58,15 @@ class PoolBuilder
|
||||||
$this->nameConstraints[$package->getName()] = null;
|
$this->nameConstraints[$package->getName()] = null;
|
||||||
$this->loadedNames[$package->getName()] = true;
|
$this->loadedNames[$package->getName()] = true;
|
||||||
unset($loadNames[$package->getName()]);
|
unset($loadNames[$package->getName()]);
|
||||||
$loadNames += $this->loadPackage($request, $package);
|
if (
|
||||||
|
$package->getRepository() instanceof RootPackageRepository
|
||||||
|
|| $package->getRepository() instanceof PlatformRepository
|
||||||
|
|| StabilityFilter::isPackageAcceptable($this->acceptableStabilities, $this->stabilityFlags, $package->getNames(), $package->getStability())
|
||||||
|
) {
|
||||||
|
$loadNames += $this->loadPackage($request, $package);
|
||||||
|
} else {
|
||||||
|
$this->unacceptableFixedPackages[] = $package;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($request->getJobs() as $job) {
|
foreach ($request->getJobs() as $job) {
|
||||||
|
@ -87,17 +98,14 @@ class PoolBuilder
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO should we really pass the callable into here?
|
$result = $repository->loadPackages($loadNames, $this->acceptableStabilities, $this->stabilityFlags);
|
||||||
$result = $repository->loadPackages($loadNames, $this->isPackageAcceptableCallable);
|
|
||||||
|
|
||||||
foreach ($result['namesFound'] as $name) {
|
foreach ($result['namesFound'] as $name) {
|
||||||
// avoid loading the same package again from other repositories once it has been found
|
// avoid loading the same package again from other repositories once it has been found
|
||||||
unset($loadNames[$name]);
|
unset($loadNames[$name]);
|
||||||
}
|
}
|
||||||
foreach ($result['packages'] as $package) {
|
foreach ($result['packages'] as $package) {
|
||||||
if (call_user_func($this->isPackageAcceptableCallable, $package->getNames(), $package->getStability())) {
|
$newLoadNames += $this->loadPackage($request, $package);
|
||||||
$newLoadNames += $this->loadPackage($request, $package);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,11 +138,13 @@ class PoolBuilder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$pool->setPackages($this->packages);
|
$pool = new Pool($this->packages, $this->unacceptableFixedPackages);
|
||||||
|
|
||||||
unset($this->aliasMap);
|
$this->aliasMap = array();
|
||||||
unset($this->loadedNames);
|
$this->nameConstraints = array();
|
||||||
unset($this->nameConstraints);
|
$this->loadedNames = array();
|
||||||
|
$this->packages = array();
|
||||||
|
$this->unacceptableFixedPackages = array();
|
||||||
|
|
||||||
return $pool;
|
return $pool;
|
||||||
}
|
}
|
||||||
|
|
|
@ -224,10 +224,6 @@ class Problem
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'Installation request for '.$packageName.$this->constraintToText($constraint).' -> satisfiable by '.$this->getPackageList($packages).'.';
|
return 'Installation request for '.$packageName.$this->constraintToText($constraint).' -> satisfiable by '.$this->getPackageList($packages).'.';
|
||||||
case 'update':
|
|
||||||
return 'Update request for '.$packageName.$this->constraintToText($constraint).'.';
|
|
||||||
case 'remove':
|
|
||||||
return 'Removal request for '.$packageName.$this->constraintToText($constraint).'';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($constraint)) {
|
if (isset($constraint)) {
|
||||||
|
|
|
@ -38,11 +38,6 @@ class Request
|
||||||
$this->addJob($packageName, 'install', $constraint);
|
$this->addJob($packageName, 'install', $constraint);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function remove($packageName, ConstraintInterface $constraint = null)
|
|
||||||
{
|
|
||||||
$this->addJob($packageName, 'remove', $constraint);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark an existing package as being installed and having to remain installed
|
* Mark an existing package as being installed and having to remain installed
|
||||||
*
|
*
|
||||||
|
|
|
@ -291,7 +291,13 @@ class RuleSetGenerator
|
||||||
|
|
||||||
foreach ($request->getFixedPackages() as $package) {
|
foreach ($request->getFixedPackages() as $package) {
|
||||||
if ($package->id == -1) {
|
if ($package->id == -1) {
|
||||||
throw new \RuntimeException("Fixed package ".$package->getName()." ".$package->getVersion().($package instanceof AliasPackage ? " (alias)" : "")." was not added to solver pool.");
|
// fixed package was not added to the pool as it did not pass the stability requirements, this is fine
|
||||||
|
if ($this->pool->isUnacceptableFixedPackage($package)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, looks like a bug
|
||||||
|
throw new \LogicException("Fixed package ".$package->getName()." ".$package->getVersion().($package instanceof AliasPackage ? " (alias)" : "")." was not added to solver pool.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->addRulesForPackage($package, $ignorePlatformReqs);
|
$this->addRulesForPackage($package, $ignorePlatformReqs);
|
||||||
|
@ -324,15 +330,6 @@ class RuleSetGenerator
|
||||||
$this->addRule(RuleSet::TYPE_JOB, $rule);
|
$this->addRule(RuleSet::TYPE_JOB, $rule);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'remove':
|
|
||||||
// remove all packages with this name including uninstalled
|
|
||||||
// ones to make sure none of them are picked as replacements
|
|
||||||
$packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
|
|
||||||
foreach ($packages as $package) {
|
|
||||||
$rule = $this->createRemoveRule($package, Rule::RULE_JOB_REMOVE, $job);
|
|
||||||
$this->addRule(RuleSet::TYPE_JOB, $rule);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -364,19 +364,6 @@ class Installer
|
||||||
|
|
||||||
$request = $this->createRequest($this->fixedRootPackage, $platformRepo, $lockedRepository);
|
$request = $this->createRequest($this->fixedRootPackage, $platformRepo, $lockedRepository);
|
||||||
|
|
||||||
if ($lockedRepository) {
|
|
||||||
// TODO do we really always need this? Maybe only to skip fix() in updateWhitelist case cause these packages get removed on full update automatically?
|
|
||||||
foreach ($lockedRepository->getPackages() as $lockedPackage) {
|
|
||||||
if (!$repositorySet->isPackageAcceptable($lockedPackage->getNames(), $lockedPackage->getStability())) {
|
|
||||||
$constraint = new Constraint('=', $lockedPackage->getVersion());
|
|
||||||
$constraint->setPrettyString('(stability not acceptable)');
|
|
||||||
|
|
||||||
// if we can get rid of this remove() here, we can generally get rid of remove support in the request
|
|
||||||
$request->remove($lockedPackage->getName(), $constraint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->io->writeError('<info>Updating dependencies</info>');
|
$this->io->writeError('<info>Updating dependencies</info>');
|
||||||
|
|
||||||
$links = array_merge($this->package->getRequires(), $this->package->getDevRequires());
|
$links = array_merge($this->package->getRequires(), $this->package->getDevRequires());
|
||||||
|
@ -394,10 +381,9 @@ class Installer
|
||||||
|
|
||||||
// if the updateWhitelist is enabled, packages not in it are also fixed
|
// if the updateWhitelist is enabled, packages not in it are also fixed
|
||||||
// to the version specified in the lock
|
// to the version specified in the lock
|
||||||
if ($this->updateWhitelist) {
|
if ($this->updateWhitelist && $lockedRepository) {
|
||||||
foreach ($lockedRepository->getPackages() as $lockedPackage) {
|
foreach ($lockedRepository->getPackages() as $lockedPackage) {
|
||||||
// TODO should this really be checking acceptability here?
|
if (!$this->isUpdateable($lockedPackage)) {
|
||||||
if (!$this->isUpdateable($lockedPackage) && $repositorySet->isPackageAcceptable($lockedPackage->getNames(), $lockedPackage->getStability())) {
|
|
||||||
// TODO add reason for fix?
|
// TODO add reason for fix?
|
||||||
$request->fixPackage($lockedPackage);
|
$request->fixPackage($lockedPackage);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Composer.
|
||||||
|
*
|
||||||
|
* (c) Nils Adermann <naderman@naderman.de>
|
||||||
|
* Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer\Package\Version;
|
||||||
|
|
||||||
|
use Composer\Package\BasePackage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*/
|
||||||
|
class StabilityFilter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Checks if any of the provided package names in the given stability match the configured acceptable stability and flags
|
||||||
|
*
|
||||||
|
* @return bool true if any package name is acceptable
|
||||||
|
*/
|
||||||
|
public static function isPackageAcceptable(array $acceptableStabilities, array $stabilityFlags, $names, $stability)
|
||||||
|
{
|
||||||
|
foreach ($names as $name) {
|
||||||
|
// allow if package matches the package-specific stability flag
|
||||||
|
if (isset($stabilityFlags[$name])) {
|
||||||
|
if (BasePackage::$stabilities[$stability] <= $stabilityFlags[$name]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} elseif (isset($acceptableStabilities[$stability])) {
|
||||||
|
// allow if package matches the global stability requirement and has no exception
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ use Composer\Package\AliasPackage;
|
||||||
use Composer\Package\PackageInterface;
|
use Composer\Package\PackageInterface;
|
||||||
use Composer\Package\CompletePackageInterface;
|
use Composer\Package\CompletePackageInterface;
|
||||||
use Composer\Package\Version\VersionParser;
|
use Composer\Package\Version\VersionParser;
|
||||||
|
use Composer\Package\Version\StabilityFilter;
|
||||||
use Composer\Semver\Constraint\ConstraintInterface;
|
use Composer\Semver\Constraint\ConstraintInterface;
|
||||||
use Composer\Semver\Constraint\Constraint;
|
use Composer\Semver\Constraint\Constraint;
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ class ArrayRepository extends BaseRepository
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
public function loadPackages(array $packageMap, $isPackageAcceptableCallable)
|
public function loadPackages(array $packageMap, array $acceptableStabilities, array $stabilityFlags)
|
||||||
{
|
{
|
||||||
$packages = $this->getPackages();
|
$packages = $this->getPackages();
|
||||||
|
|
||||||
|
@ -54,7 +55,7 @@ class ArrayRepository extends BaseRepository
|
||||||
if (array_key_exists($package->getName(), $packageMap)) {
|
if (array_key_exists($package->getName(), $packageMap)) {
|
||||||
if (
|
if (
|
||||||
(!$packageMap[$package->getName()] || $packageMap[$package->getName()]->matches(new Constraint('==', $package->getVersion())))
|
(!$packageMap[$package->getName()] || $packageMap[$package->getName()]->matches(new Constraint('==', $package->getVersion())))
|
||||||
&& call_user_func($isPackageAcceptableCallable, $package->getNames(), $package->getStability())
|
&& StabilityFilter::isPackageAcceptable($acceptableStabilities, $stabilityFlags, $package->getNames(), $package->getStability())
|
||||||
) {
|
) {
|
||||||
$result[spl_object_hash($package)] = $package;
|
$result[spl_object_hash($package)] = $package;
|
||||||
if ($package instanceof AliasPackage && !isset($result[spl_object_hash($package->getAliasOf())])) {
|
if ($package instanceof AliasPackage && !isset($result[spl_object_hash($package->getAliasOf())])) {
|
||||||
|
|
|
@ -16,6 +16,7 @@ use Composer\Package\Loader\ArrayLoader;
|
||||||
use Composer\Package\PackageInterface;
|
use Composer\Package\PackageInterface;
|
||||||
use Composer\Package\AliasPackage;
|
use Composer\Package\AliasPackage;
|
||||||
use Composer\Package\Version\VersionParser;
|
use Composer\Package\Version\VersionParser;
|
||||||
|
use Composer\Package\Version\StabilityFilter;
|
||||||
use Composer\Json\JsonFile;
|
use Composer\Json\JsonFile;
|
||||||
use Composer\Cache;
|
use Composer\Cache;
|
||||||
use Composer\Config;
|
use Composer\Config;
|
||||||
|
@ -292,13 +293,13 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
return $names;
|
return $names;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loadPackages(array $packageNameMap, $isPackageAcceptableCallable)
|
public function loadPackages(array $packageNameMap, array $acceptableStabilities, array $stabilityFlags)
|
||||||
{
|
{
|
||||||
// this call initializes loadRootServerFile which is needed for the rest below to work
|
// this call initializes loadRootServerFile which is needed for the rest below to work
|
||||||
$hasProviders = $this->hasProviders();
|
$hasProviders = $this->hasProviders();
|
||||||
|
|
||||||
if (!$hasProviders && !$this->hasPartialPackages() && !$this->lazyProvidersUrl) {
|
if (!$hasProviders && !$this->hasPartialPackages() && !$this->lazyProvidersUrl) {
|
||||||
return parent::loadPackages($packageNameMap, $isPackageAcceptableCallable);
|
return parent::loadPackages($packageNameMap, $acceptableStabilities, $stabilityFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
$packages = array();
|
$packages = array();
|
||||||
|
@ -314,7 +315,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$candidates = $this->whatProvides($name, $isPackageAcceptableCallable);
|
$candidates = $this->whatProvides($name, $acceptableStabilities, $stabilityFlags);
|
||||||
foreach ($candidates as $candidate) {
|
foreach ($candidates as $candidate) {
|
||||||
if ($candidate->getName() !== $name) {
|
if ($candidate->getName() !== $name) {
|
||||||
throw new \LogicException('whatProvides should never return a package with a different name than the requested one');
|
throw new \LogicException('whatProvides should never return a package with a different name than the requested one');
|
||||||
|
@ -350,7 +351,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
}, ARRAY_FILTER_USE_KEY);
|
}, ARRAY_FILTER_USE_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $this->loadAsyncPackages($packageNameMap, $isPackageAcceptableCallable);
|
$result = $this->loadAsyncPackages($packageNameMap, $acceptableStabilities, $stabilityFlags);
|
||||||
$packages = array_merge($packages, $result['packages']);
|
$packages = array_merge($packages, $result['packages']);
|
||||||
$namesFound = array_merge($namesFound, $result['namesFound']);
|
$namesFound = array_merge($namesFound, $result['namesFound']);
|
||||||
}
|
}
|
||||||
|
@ -444,7 +445,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
* @param callable $isPackageAcceptableCallable
|
* @param callable $isPackageAcceptableCallable
|
||||||
* @return array|mixed
|
* @return array|mixed
|
||||||
*/
|
*/
|
||||||
private function whatProvides($name, $isPackageAcceptableCallable = null)
|
private function whatProvides($name, array $acceptableStabilities = null, array $stabilityFlags = null)
|
||||||
{
|
{
|
||||||
if (!$this->hasPartialPackages() || !isset($this->partialPackagesByName[$name])) {
|
if (!$this->hasPartialPackages() || !isset($this->partialPackagesByName[$name])) {
|
||||||
// skip platform packages, root package and composer-plugin-api
|
// skip platform packages, root package and composer-plugin-api
|
||||||
|
@ -533,7 +534,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
$version['version_normalized'] = $this->versionParser->normalize($version['version']);
|
$version['version_normalized'] = $this->versionParser->normalize($version['version']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->isVersionAcceptable($isPackageAcceptableCallable, null, $normalizedName, $version)) {
|
if ($this->isVersionAcceptable($acceptableStabilities, $stabilityFlags, null, $normalizedName, $version)) {
|
||||||
$versionsToLoad[$version['uid']] = $version;
|
$versionsToLoad[$version['uid']] = $version;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -590,7 +591,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
/**
|
/**
|
||||||
* @param array $packageNames array of package name => ConstraintInterface|null - if a constraint is provided, only packages matching it will be loaded
|
* @param array $packageNames array of package name => ConstraintInterface|null - if a constraint is provided, only packages matching it will be loaded
|
||||||
*/
|
*/
|
||||||
private function loadAsyncPackages(array $packageNames, $isPackageAcceptableCallable = null)
|
private function loadAsyncPackages(array $packageNames, array $acceptableStabilities = null, array $stabilityFlags = null)
|
||||||
{
|
{
|
||||||
$this->loadRootServerFile();
|
$this->loadRootServerFile();
|
||||||
|
|
||||||
|
@ -603,11 +604,11 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
throw new \LogicException('loadAsyncPackages only supports v2 protocol composer repos with a metadata-url');
|
throw new \LogicException('loadAsyncPackages only supports v2 protocol composer repos with a metadata-url');
|
||||||
}
|
}
|
||||||
|
|
||||||
// load ~dev variants as well if present
|
// load ~dev versions of the packages as well if needed
|
||||||
// TODO ideally there should be a flag set from the repositoryset/poolbuilder to know which packages should have the dev packages loaded
|
|
||||||
// so we can optimize away some requests entirely
|
|
||||||
foreach ($packageNames as $name => $constraint) {
|
foreach ($packageNames as $name => $constraint) {
|
||||||
$packageNames[$name.'~dev'] = $constraint;
|
if ($acceptableStabilities && $stabilityFlags && StabilityFilter::isPackageAcceptable($acceptableStabilities, $stabilityFlags, array($name), 'dev')) {
|
||||||
|
$packageNames[$name.'~dev'] = $constraint;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($packageNames as $name => $constraint) {
|
foreach ($packageNames as $name => $constraint) {
|
||||||
|
@ -629,7 +630,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
}
|
}
|
||||||
|
|
||||||
$promises[] = $this->asyncFetchFile($url, $cacheKey, $lastModified)
|
$promises[] = $this->asyncFetchFile($url, $cacheKey, $lastModified)
|
||||||
->then(function ($response) use (&$packages, &$namesFound, $contents, $realName, $constraint, $repo, $isPackageAcceptableCallable) {
|
->then(function ($response) use (&$packages, &$namesFound, $contents, $realName, $constraint, $repo, $acceptableStabilities, $stabilityFlags) {
|
||||||
if (true === $response) {
|
if (true === $response) {
|
||||||
$response = $contents;
|
$response = $contents;
|
||||||
}
|
}
|
||||||
|
@ -651,7 +652,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
$version['version_normalized'] = $repo->versionParser->normalize($version['version']);
|
$version['version_normalized'] = $repo->versionParser->normalize($version['version']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($repo->isVersionAcceptable($isPackageAcceptableCallable, $constraint, $realName, $version)) {
|
if ($repo->isVersionAcceptable($acceptableStabilities, $stabilityFlags, $constraint, $realName, $version)) {
|
||||||
$versionsToLoad[] = $version;
|
$versionsToLoad[] = $version;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -681,7 +682,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
* @param string $name package name (must be lowercased already)
|
* @param string $name package name (must be lowercased already)
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
public function isVersionAcceptable($isPackageAcceptableCallable, $constraint, $name, $versionData)
|
public function isVersionAcceptable(array $acceptableStabilities = null, array $stabilityFlags = null, $constraint = null, $name, $versionData)
|
||||||
{
|
{
|
||||||
$versions = array($versionData['version_normalized']);
|
$versions = array($versionData['version_normalized']);
|
||||||
|
|
||||||
|
@ -690,7 +691,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($versions as $version) {
|
foreach ($versions as $version) {
|
||||||
if ($isPackageAcceptableCallable && !call_user_func($isPackageAcceptableCallable, $name, VersionParser::parseStability($version))) {
|
if ($acceptableStabilities && $stabilityFlags && !StabilityFilter::isPackageAcceptable($acceptableStabilities, $stabilityFlags, array($name), VersionParser::parseStability($version))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,13 +97,13 @@ class CompositeRepository extends BaseRepository
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
public function loadPackages(array $packageMap, $isPackageAcceptableCallable)
|
public function loadPackages(array $packageMap, array $acceptableStabilities, array $stabilityFlags)
|
||||||
{
|
{
|
||||||
$packages = array();
|
$packages = array();
|
||||||
$namesFound = array();
|
$namesFound = array();
|
||||||
foreach ($this->repositories as $repository) {
|
foreach ($this->repositories as $repository) {
|
||||||
/* @var $repository RepositoryInterface */
|
/* @var $repository RepositoryInterface */
|
||||||
$result = $repository->findPackages($name, $constraint);
|
$result = $repository->loadPackages($packageMap, $acceptableStabilities, $stabilityFlags);
|
||||||
$packages[] = $result['packages'];
|
$packages[] = $result['packages'];
|
||||||
$namesFound[] = $result['namesFound'];
|
$namesFound[] = $result['namesFound'];
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,6 @@ interface RepositoryInterface extends \Countable
|
||||||
*/
|
*/
|
||||||
public function findPackages($name, $constraint = null);
|
public function findPackages($name, $constraint = null);
|
||||||
|
|
||||||
// TODO this should really not be in this generic interface anymore
|
|
||||||
/**
|
/**
|
||||||
* Returns list of registered packages.
|
* Returns list of registered packages.
|
||||||
*
|
*
|
||||||
|
@ -68,10 +67,11 @@ interface RepositoryInterface extends \Countable
|
||||||
* Returns list of registered packages with the supplied name
|
* Returns list of registered packages with the supplied name
|
||||||
*
|
*
|
||||||
* @param ConstraintInterface[] $packageNameMap package names pointing to constraints
|
* @param ConstraintInterface[] $packageNameMap package names pointing to constraints
|
||||||
* @param $isPackageAcceptableCallable
|
* @param array $acceptableStabilities
|
||||||
|
* @param array $stabilityFlags
|
||||||
* @return array [namesFound => string[], packages => PackageInterface[]]
|
* @return array [namesFound => string[], packages => PackageInterface[]]
|
||||||
*/
|
*/
|
||||||
public function loadPackages(array $packageNameMap, $isPackageAcceptableCallable);
|
public function loadPackages(array $packageNameMap, array $acceptableStabilities, array $stabilityFlags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches the repository for packages containing the query
|
* Searches the repository for packages containing the query
|
||||||
|
|
|
@ -22,7 +22,7 @@ use Composer\Repository\PlatformRepository;
|
||||||
use Composer\Repository\LockArrayRepository;
|
use Composer\Repository\LockArrayRepository;
|
||||||
use Composer\Repository\InstalledRepositoryInterface;
|
use Composer\Repository\InstalledRepositoryInterface;
|
||||||
use Composer\Semver\Constraint\ConstraintInterface;
|
use Composer\Semver\Constraint\ConstraintInterface;
|
||||||
use Composer\Test\DependencyResolver\PoolTest;
|
use Composer\Package\Version\StabilityFilter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Nils Adermann <naderman@naderman.de>
|
* @author Nils Adermann <naderman@naderman.de>
|
||||||
|
@ -89,23 +89,6 @@ class RepositorySet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isPackageAcceptable($name, $stability)
|
|
||||||
{
|
|
||||||
foreach ((array) $name as $n) {
|
|
||||||
// allow if package matches the global stability requirement and has no exception
|
|
||||||
if (!isset($this->stabilityFlags[$n]) && isset($this->acceptableStabilities[$stability])) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// allow if package matches the package-specific stability flag
|
|
||||||
if (isset($this->stabilityFlags[$n]) && BasePackage::$stabilities[$stability] <= $this->stabilityFlags[$n]) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find packages providing or matching a name and optionally meeting a constraint in all repositories
|
* Find packages providing or matching a name and optionally meeting a constraint in all repositories
|
||||||
*
|
*
|
||||||
|
@ -113,10 +96,11 @@ class RepositorySet
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param ConstraintInterface|null $constraint
|
* @param ConstraintInterface|null $constraint
|
||||||
* @param bool $exactMatch
|
* @param bool $exactMatch if set to false, packages which replace/provide the given name might be returned as well even if they do not match the name exactly
|
||||||
|
* @param bool $ignoreStability if set to true, packages are returned even though their stability does not match the required stability
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function findPackages($name, ConstraintInterface $constraint = null, $exactMatch = true)
|
public function findPackages($name, ConstraintInterface $constraint = null, $exactMatch = true, $ignoreStability = false)
|
||||||
{
|
{
|
||||||
$packages = array();
|
$packages = array();
|
||||||
foreach ($this->repositories as $repository) {
|
foreach ($this->repositories as $repository) {
|
||||||
|
@ -131,7 +115,7 @@ class RepositorySet
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->isPackageAcceptable($candidate->getNames(), $candidate->getStability())) {
|
if (!$ignoreStability && $this->isPackageAcceptable($candidate->getNames(), $candidate->getStability())) {
|
||||||
$result[] = $candidate;
|
$result[] = $candidate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,6 +123,11 @@ class RepositorySet
|
||||||
return $candidates;
|
return $candidates;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isPackageAcceptable($names, $stability)
|
||||||
|
{
|
||||||
|
return StabilityFilter::isPackageAcceptable($this->acceptableStabilities, $this->stabilityFlags, $names, $stability);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a pool for dependency resolution from the packages in this repository set.
|
* Create a pool for dependency resolution from the packages in this repository set.
|
||||||
*
|
*
|
||||||
|
@ -146,7 +135,7 @@ class RepositorySet
|
||||||
*/
|
*/
|
||||||
public function createPool(Request $request)
|
public function createPool(Request $request)
|
||||||
{
|
{
|
||||||
$poolBuilder = new PoolBuilder(array($this, 'isPackageAcceptable'), $this->rootRequires);
|
$poolBuilder = new PoolBuilder($this->acceptableStabilities, $this->stabilityFlags, $this->rootAliases, $this->rootReferences, $this->rootRequires);
|
||||||
|
|
||||||
foreach ($this->repositories as $repo) {
|
foreach ($this->repositories as $repo) {
|
||||||
if ($repo instanceof InstalledRepositoryInterface) {
|
if ($repo instanceof InstalledRepositoryInterface) {
|
||||||
|
@ -154,7 +143,7 @@ class RepositorySet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->pool = $poolBuilder->buildPool($this->repositories, $this->rootAliases, $this->rootReferences, $request);
|
return $this->pool = $poolBuilder->buildPool($this->repositories, $request);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO unify this with above in some simpler version without "request"?
|
// TODO unify this with above in some simpler version without "request"?
|
||||||
|
|
|
@ -21,10 +21,9 @@ class PoolTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testPool()
|
public function testPool()
|
||||||
{
|
{
|
||||||
$pool = $this->createPool();
|
|
||||||
$package = $this->getPackage('foo', '1');
|
$package = $this->getPackage('foo', '1');
|
||||||
|
|
||||||
$pool->setPackages(array($package));
|
$pool = $this->createPool(array($package));
|
||||||
|
|
||||||
$this->assertEquals(array($package), $pool->whatProvides('foo'));
|
$this->assertEquals(array($package), $pool->whatProvides('foo'));
|
||||||
$this->assertEquals(array($package), $pool->whatProvides('foo'));
|
$this->assertEquals(array($package), $pool->whatProvides('foo'));
|
||||||
|
@ -32,12 +31,11 @@ class PoolTest extends TestCase
|
||||||
|
|
||||||
public function testWhatProvidesPackageWithConstraint()
|
public function testWhatProvidesPackageWithConstraint()
|
||||||
{
|
{
|
||||||
$pool = $this->createPool();
|
|
||||||
|
|
||||||
$firstPackage = $this->getPackage('foo', '1');
|
$firstPackage = $this->getPackage('foo', '1');
|
||||||
$secondPackage = $this->getPackage('foo', '2');
|
$secondPackage = $this->getPackage('foo', '2');
|
||||||
|
|
||||||
$pool->setPackages(array(
|
$pool = $this->createPool(array(
|
||||||
$firstPackage,
|
$firstPackage,
|
||||||
$secondPackage,
|
$secondPackage,
|
||||||
));
|
));
|
||||||
|
@ -48,10 +46,9 @@ class PoolTest extends TestCase
|
||||||
|
|
||||||
public function testPackageById()
|
public function testPackageById()
|
||||||
{
|
{
|
||||||
$pool = $this->createPool();
|
|
||||||
$package = $this->getPackage('foo', '1');
|
$package = $this->getPackage('foo', '1');
|
||||||
|
|
||||||
$pool->setPackages(array($package));
|
$pool = $this->createPool(array($package));
|
||||||
|
|
||||||
$this->assertSame($package, $pool->packageById(1));
|
$this->assertSame($package, $pool->packageById(1));
|
||||||
}
|
}
|
||||||
|
@ -63,8 +60,8 @@ class PoolTest extends TestCase
|
||||||
$this->assertEquals(array(), $pool->whatProvides('foo'));
|
$this->assertEquals(array(), $pool->whatProvides('foo'));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function createPool()
|
protected function createPool(array $packages = array())
|
||||||
{
|
{
|
||||||
return new Pool();
|
return new Pool($packages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ use Composer\Test\TestCase;
|
||||||
|
|
||||||
class RequestTest extends TestCase
|
class RequestTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testRequestInstallAndRemove()
|
public function testRequestInstall()
|
||||||
{
|
{
|
||||||
$repo = new ArrayRepository;
|
$repo = new ArrayRepository;
|
||||||
$foo = $this->getPackage('foo', '1');
|
$foo = $this->getPackage('foo', '1');
|
||||||
|
@ -31,12 +31,10 @@ class RequestTest extends TestCase
|
||||||
|
|
||||||
$request = new Request();
|
$request = new Request();
|
||||||
$request->install('foo');
|
$request->install('foo');
|
||||||
$request->remove('foobar');
|
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
array(
|
array(
|
||||||
array('cmd' => 'install', 'packageName' => 'foo', 'constraint' => null),
|
array('cmd' => 'install', 'packageName' => 'foo', 'constraint' => null),
|
||||||
array('cmd' => 'remove', 'packageName' => 'foobar', 'constraint' => null),
|
|
||||||
),
|
),
|
||||||
$request->getJobs()
|
$request->getJobs()
|
||||||
);
|
);
|
||||||
|
|
|
@ -139,8 +139,7 @@ class RuleSetTest extends TestCase
|
||||||
|
|
||||||
public function testPrettyString()
|
public function testPrettyString()
|
||||||
{
|
{
|
||||||
$pool = new Pool();
|
$pool = new Pool(array(
|
||||||
$pool->setPackages(array(
|
|
||||||
$p = $this->getPackage('foo', '2.1'),
|
$p = $this->getPackage('foo', '2.1'),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
|
@ -93,8 +93,7 @@ class RuleTest extends TestCase
|
||||||
|
|
||||||
public function testPrettyString()
|
public function testPrettyString()
|
||||||
{
|
{
|
||||||
$pool = new Pool();
|
$pool = new Pool(array(
|
||||||
$pool->setPackages(array(
|
|
||||||
$p1 = $this->getPackage('foo', '2.1'),
|
$p1 = $this->getPackage('foo', '2.1'),
|
||||||
$p2 = $this->getPackage('baz', '1.1'),
|
$p2 = $this->getPackage('baz', '1.1'),
|
||||||
));
|
));
|
||||||
|
|
|
@ -196,28 +196,6 @@ class SolverTest extends TestCase
|
||||||
$this->checkSolverResult(array());
|
$this->checkSolverResult(array());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSolverRemoveSingle()
|
|
||||||
{
|
|
||||||
$this->repoLocked->addPackage($packageA = $this->getPackage('A', '1.0'));
|
|
||||||
$this->reposComplete();
|
|
||||||
|
|
||||||
$this->request->remove('A');
|
|
||||||
|
|
||||||
$this->checkSolverResult(array(
|
|
||||||
array('job' => 'remove', 'package' => $packageA),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testSolverRemoveUninstalled()
|
|
||||||
{
|
|
||||||
$this->repo->addPackage($this->getPackage('A', '1.0'));
|
|
||||||
$this->reposComplete();
|
|
||||||
|
|
||||||
$this->request->remove('A');
|
|
||||||
|
|
||||||
$this->checkSolverResult(array());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testSolverUpdateDoesOnlyUpdate()
|
public function testSolverUpdateDoesOnlyUpdate()
|
||||||
{
|
{
|
||||||
$this->repoLocked->addPackage($packageA = $this->getPackage('A', '1.0'));
|
$this->repoLocked->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
|
@ -367,7 +345,6 @@ class SolverTest extends TestCase
|
||||||
|
|
||||||
$this->request->install('A');
|
$this->request->install('A');
|
||||||
$this->request->install('C');
|
$this->request->install('C');
|
||||||
$this->request->remove('D');
|
|
||||||
|
|
||||||
$this->checkSolverResult(array(
|
$this->checkSolverResult(array(
|
||||||
array('job' => 'remove', 'package' => $packageD),
|
array('job' => 'remove', 'package' => $packageD),
|
||||||
|
|
|
@ -48,25 +48,23 @@ Partial update from lock file should apply lock file and downgrade unstable pack
|
||||||
]
|
]
|
||||||
--RUN--
|
--RUN--
|
||||||
update c/uptodate
|
update c/uptodate
|
||||||
--EXPECT-LOCK--
|
|
||||||
{
|
|
||||||
"packages": [
|
|
||||||
{ "name": "a/old", "version": "1.0.0", "type": "library" },
|
|
||||||
{ "name": "b/unstable", "version": "1.0.0", "type": "library" },
|
|
||||||
{ "name": "c/uptodate", "version": "1.0.0", "type": "library" },
|
|
||||||
{ "name": "d/removed", "version": "1.0.0", "type": "library" }
|
|
||||||
],
|
|
||||||
"packages-dev": [],
|
|
||||||
"aliases": [],
|
|
||||||
"minimum-stability": "stable",
|
|
||||||
"stability-flags": [],
|
|
||||||
"prefer-stable": false,
|
|
||||||
"prefer-lowest": false,
|
|
||||||
"platform": [],
|
|
||||||
"platform-dev": []
|
|
||||||
}
|
|
||||||
--EXPECT--
|
--EXPECT--
|
||||||
Updating a/old (0.9.0 => 1.0.0)
|
|
||||||
Updating b/unstable (1.1.0-alpha => 1.0.0)
|
--EXPECT-EXIT-CODE--
|
||||||
Updating c/uptodate (2.0.0 => 1.0.0)
|
2
|
||||||
Installing d/removed (1.0.0)
|
|
||||||
|
--EXPECT-OUTPUT--
|
||||||
|
Loading composer repositories with package information
|
||||||
|
Updating dependencies
|
||||||
|
Your requirements could not be resolved to an installable set of packages.
|
||||||
|
|
||||||
|
Problem 1
|
||||||
|
- The requested package b/unstable could not be found in any version, there may be a typo in the package name.
|
||||||
|
|
||||||
|
Potential causes:
|
||||||
|
- A typo in the package name
|
||||||
|
- The package is not available in a stable-enough version according to your minimum-stability setting
|
||||||
|
see <https://getcomposer.org/doc/04-schema.md#minimum-stability> for more details.
|
||||||
|
- It's a private package and you forgot to add a custom repository to find it
|
||||||
|
|
||||||
|
Read <https://getcomposer.org/doc/articles/troubleshooting.md> for further common problems.
|
||||||
|
|
Loading…
Reference in New Issue