Merge commit '45a2070feebdaf9ead7eccf5cd679cb92f0d24c9'
commit
5959493679
|
@ -61,6 +61,6 @@ class InstallOperation extends SolverOperation
|
||||||
*/
|
*/
|
||||||
public function __toString()
|
public function __toString()
|
||||||
{
|
{
|
||||||
return 'Installing '.$this->package->getPrettyName().' ('.$this->package->getPrettyVersion().')';
|
return 'Installing '.$this->package->getPrettyName().' ('.$this->formatVersion($this->package).')';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
<?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\DependencyResolver\Operation;
|
||||||
|
|
||||||
|
use Composer\Package\AliasPackage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Solver install operation.
|
||||||
|
*
|
||||||
|
* @author Nils Adermann <naderman@naderman.de>
|
||||||
|
*/
|
||||||
|
class MarkAliasInstalledOperation extends SolverOperation
|
||||||
|
{
|
||||||
|
protected $package;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes operation.
|
||||||
|
*
|
||||||
|
* @param PackageInterface $package package instance
|
||||||
|
* @param string $reason operation reason
|
||||||
|
*/
|
||||||
|
public function __construct(AliasPackage $package, $reason = null)
|
||||||
|
{
|
||||||
|
parent::__construct($reason);
|
||||||
|
|
||||||
|
$this->package = $package;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns package instance.
|
||||||
|
*
|
||||||
|
* @return PackageInterface
|
||||||
|
*/
|
||||||
|
public function getPackage()
|
||||||
|
{
|
||||||
|
return $this->package;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns job type.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getJobType()
|
||||||
|
{
|
||||||
|
return 'markAliasInstalled';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return 'Marking '.$this->package->getPrettyName().' ('.$this->package->getPrettyVersion().') as installed, alias of '.$this->package->getAliasOf()->getPrettyName().' ('.$this->package->getAliasOf()->getPrettyVersion().')';
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
<?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\DependencyResolver\Operation;
|
||||||
|
|
||||||
|
use Composer\Package\AliasPackage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Solver install operation.
|
||||||
|
*
|
||||||
|
* @author Nils Adermann <naderman@naderman.de>
|
||||||
|
*/
|
||||||
|
class MarkAliasUninstalledOperation extends SolverOperation
|
||||||
|
{
|
||||||
|
protected $package;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes operation.
|
||||||
|
*
|
||||||
|
* @param PackageInterface $package package instance
|
||||||
|
* @param string $reason operation reason
|
||||||
|
*/
|
||||||
|
public function __construct(AliasPackage $package, $reason = null)
|
||||||
|
{
|
||||||
|
parent::__construct($reason);
|
||||||
|
|
||||||
|
$this->package = $package;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns package instance.
|
||||||
|
*
|
||||||
|
* @return PackageInterface
|
||||||
|
*/
|
||||||
|
public function getPackage()
|
||||||
|
{
|
||||||
|
return $this->package;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns job type.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getJobType()
|
||||||
|
{
|
||||||
|
return 'markAliasUninstalled';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return 'Marking '.$this->package->getPrettyName().' ('.$this->package->getPrettyVersion().') as uninstalled, alias of '.$this->package->getAliasOf()->getPrettyName().' ('.$this->package->getAliasOf()->getPrettyVersion().')';
|
||||||
|
}
|
||||||
|
}
|
|
@ -42,4 +42,13 @@ abstract class SolverOperation implements OperationInterface
|
||||||
{
|
{
|
||||||
return $this->reason;
|
return $this->reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function formatVersion(PackageInterface $package)
|
||||||
|
{
|
||||||
|
if (!$package->isDev() || !in_array($package->getSourceType(), array('hg', 'git'))) {
|
||||||
|
return $package->getPrettyVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $package->getPrettyVersion().' '.substr($package->getSourceReference(), 0, 6);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,6 @@ class UninstallOperation extends SolverOperation
|
||||||
*/
|
*/
|
||||||
public function __toString()
|
public function __toString()
|
||||||
{
|
{
|
||||||
return 'Uninstalling '.$this->package->getPrettyName().' ('.$this->package->getPrettyVersion().')';
|
return 'Uninstalling '.$this->package->getPrettyName().' ('.$this->formatVersion($this->package).')';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ class UpdateOperation extends SolverOperation
|
||||||
*/
|
*/
|
||||||
public function __toString()
|
public function __toString()
|
||||||
{
|
{
|
||||||
return 'Updating '.$this->initialPackage->getPrettyName().' ('.$this->initialPackage->getPrettyVersion().') to '.
|
return 'Updating '.$this->initialPackage->getPrettyName().' ('.$this->formatVersion($this->initialPackage).') to '.
|
||||||
$this->targetPackage->getPrettyName(). ' ('.$this->targetPackage->getPrettyVersion().')';
|
$this->targetPackage->getPrettyName(). ' ('.$this->formatVersion($this->targetPackage).')';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ class Rule
|
||||||
const RULE_PACKAGE_SAME_NAME = 10;
|
const RULE_PACKAGE_SAME_NAME = 10;
|
||||||
const RULE_PACKAGE_IMPLICIT_OBSOLETES = 11;
|
const RULE_PACKAGE_IMPLICIT_OBSOLETES = 11;
|
||||||
const RULE_LEARNED = 12;
|
const RULE_LEARNED = 12;
|
||||||
|
const RULE_PACKAGE_ALIAS = 13;
|
||||||
|
|
||||||
protected $disabled;
|
protected $disabled;
|
||||||
protected $literals;
|
protected $literals;
|
||||||
|
@ -235,6 +236,8 @@ class Rule
|
||||||
return $ruleText;
|
return $ruleText;
|
||||||
case self::RULE_LEARNED:
|
case self::RULE_LEARNED:
|
||||||
return 'learned: '.$ruleText;
|
return 'learned: '.$ruleText;
|
||||||
|
case self::RULE_PACKAGE_ALIAS:
|
||||||
|
return $ruleText;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,16 +20,12 @@ class RuleSet implements \IteratorAggregate, \Countable
|
||||||
// highest priority => lowest number
|
// highest priority => lowest number
|
||||||
const TYPE_PACKAGE = 0;
|
const TYPE_PACKAGE = 0;
|
||||||
const TYPE_JOB = 1;
|
const TYPE_JOB = 1;
|
||||||
const TYPE_FEATURE = 3;
|
const TYPE_LEARNED = 4;
|
||||||
const TYPE_CHOICE = 4;
|
|
||||||
const TYPE_LEARNED = 5;
|
|
||||||
|
|
||||||
protected static $types = array(
|
protected static $types = array(
|
||||||
-1 => 'UNKNOWN',
|
-1 => 'UNKNOWN',
|
||||||
self::TYPE_PACKAGE => 'PACKAGE',
|
self::TYPE_PACKAGE => 'PACKAGE',
|
||||||
self::TYPE_FEATURE => 'FEATURE',
|
|
||||||
self::TYPE_JOB => 'JOB',
|
self::TYPE_JOB => 'JOB',
|
||||||
self::TYPE_CHOICE => 'CHOICE',
|
|
||||||
self::TYPE_LEARNED => 'LEARNED',
|
self::TYPE_LEARNED => 'LEARNED',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ namespace Composer\DependencyResolver;
|
||||||
|
|
||||||
use Composer\Repository\RepositoryInterface;
|
use Composer\Repository\RepositoryInterface;
|
||||||
use Composer\Package\PackageInterface;
|
use Composer\Package\PackageInterface;
|
||||||
|
use Composer\Package\AliasPackage;
|
||||||
use Composer\DependencyResolver\Operation;
|
use Composer\DependencyResolver\Operation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,13 +31,21 @@ class Solver
|
||||||
protected $ruleToJob = array();
|
protected $ruleToJob = array();
|
||||||
protected $addedMap = array();
|
protected $addedMap = array();
|
||||||
protected $updateMap = array();
|
protected $updateMap = array();
|
||||||
protected $noObsoletes = array();
|
|
||||||
protected $watches = array();
|
protected $watches = array();
|
||||||
protected $removeWatches = array();
|
protected $removeWatches = array();
|
||||||
protected $decisionMap;
|
protected $decisionMap;
|
||||||
protected $installedMap;
|
protected $installedMap;
|
||||||
|
|
||||||
protected $packageToFeatureRule = array();
|
protected $packageToUpdateRule = array();
|
||||||
|
|
||||||
|
protected $decisionQueue = array();
|
||||||
|
protected $decisionQueueWhy = array();
|
||||||
|
protected $decisionQueueFree = array();
|
||||||
|
protected $propagateIndex;
|
||||||
|
protected $branches = array();
|
||||||
|
protected $problems = array();
|
||||||
|
protected $learnedPool = array();
|
||||||
|
protected $recommendsIndex;
|
||||||
|
|
||||||
public function __construct(PolicyInterface $policy, Pool $pool, RepositoryInterface $installed)
|
public function __construct(PolicyInterface $policy, Pool $pool, RepositoryInterface $installed)
|
||||||
{
|
{
|
||||||
|
@ -237,47 +246,37 @@ class Solver
|
||||||
}
|
}
|
||||||
|
|
||||||
// check obsoletes and implicit obsoletes of a package
|
// check obsoletes and implicit obsoletes of a package
|
||||||
// if ignoreinstalledsobsoletes is not set, we're also checking
|
$isInstalled = (isset($this->installedMap[$package->getId()]));
|
||||||
// obsoletes of installed packages (like newer rpm versions)
|
|
||||||
//
|
|
||||||
/** TODO if ($this->noInstalledObsoletes) */
|
|
||||||
if (true) {
|
|
||||||
$noObsoletes = isset($this->noObsoletes[$package->getId()]);
|
|
||||||
$isInstalled = (isset($this->installedMap[$package->getId()]));
|
|
||||||
|
|
||||||
foreach ($package->getReplaces() as $link) {
|
foreach ($package->getReplaces() as $link) {
|
||||||
$obsoleteProviders = $this->pool->whatProvides($link->getTarget(), $link->getConstraint());
|
$obsoleteProviders = $this->pool->whatProvides($link->getTarget(), $link->getConstraint());
|
||||||
|
|
||||||
foreach ($obsoleteProviders as $provider) {
|
foreach ($obsoleteProviders as $provider) {
|
||||||
if ($provider === $package) {
|
if ($provider === $package) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$this->obsoleteImpossibleForAlias($package, $provider)) {
|
||||||
$reason = ($isInstalled) ? Rule::RULE_INSTALLED_PACKAGE_OBSOLETES : Rule::RULE_PACKAGE_OBSOLETES;
|
$reason = ($isInstalled) ? Rule::RULE_INSTALLED_PACKAGE_OBSOLETES : Rule::RULE_PACKAGE_OBSOLETES;
|
||||||
$this->addRule(RuleSet::TYPE_PACKAGE, $this->createConflictRule($package, $provider, $reason, (string) $link));
|
$this->addRule(RuleSet::TYPE_PACKAGE, $this->createConflictRule($package, $provider, $reason, (string) $link));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// check implicit obsoletes
|
// check implicit obsoletes
|
||||||
// for installed packages we only need to check installed/installed problems,
|
// for installed packages we only need to check installed/installed problems,
|
||||||
// as the others are picked up when looking at the uninstalled package.
|
// as the others are picked up when looking at the uninstalled package.
|
||||||
if (!$isInstalled) {
|
if (!$isInstalled) {
|
||||||
$obsoleteProviders = $this->pool->whatProvides($package->getName(), null);
|
$obsoleteProviders = $this->pool->whatProvides($package->getName(), null);
|
||||||
|
|
||||||
foreach ($obsoleteProviders as $provider) {
|
foreach ($obsoleteProviders as $provider) {
|
||||||
if ($provider === $package) {
|
if ($provider === $package) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($isInstalled && !isset($this->installedMap[$provider->getId()])) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// obsolete same packages even when noObsoletes
|
|
||||||
if ($noObsoletes && (!$package->equals($provider))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (($package instanceof AliasPackage) && $package->getAliasOf() === $provider) {
|
||||||
|
$this->addRule(RuleSet::TYPE_PACKAGE, $rule = $this->createRequireRule($package, array($provider), Rule::RULE_PACKAGE_ALIAS, (string) $package));
|
||||||
|
} else if (!$this->obsoleteImpossibleForAlias($package, $provider)) {
|
||||||
$reason = ($package->getName() == $provider->getName()) ? Rule::RULE_PACKAGE_SAME_NAME : Rule::RULE_PACKAGE_IMPLICIT_OBSOLETES;
|
$reason = ($package->getName() == $provider->getName()) ? Rule::RULE_PACKAGE_SAME_NAME : Rule::RULE_PACKAGE_IMPLICIT_OBSOLETES;
|
||||||
$this->addRule(RuleSet::TYPE_PACKAGE, $rule = $this->createConflictRule($package, $provider, $reason, (string) $package));
|
$this->addRule(RuleSet::TYPE_PACKAGE, $rule = $this->createConflictRule($package, $provider, $reason, (string) $package));
|
||||||
}
|
}
|
||||||
|
@ -286,6 +285,20 @@ class Solver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function obsoleteImpossibleForAlias($package, $provider)
|
||||||
|
{
|
||||||
|
$packageIsAlias = $package instanceof AliasPackage;
|
||||||
|
$providerIsAlias = $provider instanceof AliasPackage;
|
||||||
|
|
||||||
|
$impossible = (
|
||||||
|
($packageIsAlias && $package->getAliasOf() === $provider) ||
|
||||||
|
($providerIsAlias && $provider->getAliasOf() === $package) ||
|
||||||
|
($packageIsAlias && $providerIsAlias && $provider->getAliasOf() === $package->getAliasOf())
|
||||||
|
);
|
||||||
|
|
||||||
|
return $impossible;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds all rules for all update packages of a given package
|
* Adds all rules for all update packages of a given package
|
||||||
*
|
*
|
||||||
|
@ -431,7 +444,7 @@ class Solver
|
||||||
|
|
||||||
// push all of our rules (can only be feature or job rules)
|
// push all of our rules (can only be feature or job rules)
|
||||||
// asserting this literal on the problem stack
|
// asserting this literal on the problem stack
|
||||||
foreach ($this->rules->getIteratorFor(array(RuleSet::TYPE_JOB, RuleSet::TYPE_FEATURE)) as $assertRule) {
|
foreach ($this->rules->getIteratorFor(RuleSet::TYPE_JOB) as $assertRule) {
|
||||||
if ($assertRule->isDisabled() || !$assertRule->isAssertion() || $assertRule->isWeak()) {
|
if ($assertRule->isDisabled() || !$assertRule->isAssertion() || $assertRule->isWeak()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -492,370 +505,22 @@ class Solver
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->disableProblem($why);
|
$this->disableProblem($why);
|
||||||
/** TODO solver_reenablepolicyrules(solv, -(v + 1)); */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function addChoiceRules()
|
protected function setupInstalledMap()
|
||||||
{
|
{
|
||||||
|
$this->installedMap = array();
|
||||||
// void
|
foreach ($this->installed->getPackages() as $package) {
|
||||||
// solver_addchoicerules(Solver *solv)
|
$this->installedMap[$package->getId()] = $package;
|
||||||
// {
|
|
||||||
// Pool *pool = solv->pool;
|
|
||||||
// Map m, mneg;
|
|
||||||
// Rule *r;
|
|
||||||
// Queue q, qi;
|
|
||||||
// int i, j, rid, havechoice;
|
|
||||||
// Id p, d, *pp;
|
|
||||||
// Id p2, pp2;
|
|
||||||
// Solvable *s, *s2;
|
|
||||||
//
|
|
||||||
// solv->choicerules = solv->nrules;
|
|
||||||
// if (!pool->installed)
|
|
||||||
// {
|
|
||||||
// solv->choicerules_end = solv->nrules;
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// solv->choicerules_ref = sat_calloc(solv->rpmrules_end, sizeof(Id));
|
|
||||||
// queue_init(&q);
|
|
||||||
// queue_init(&qi);
|
|
||||||
// map_init(&m, pool->nsolvables);
|
|
||||||
// map_init(&mneg, pool->nsolvables);
|
|
||||||
// /* set up negative assertion map from infarch and dup rules */
|
|
||||||
// for (rid = solv->infarchrules, r = solv->rules + rid; rid < solv->infarchrules_end; rid++, r++)
|
|
||||||
// if (r->p < 0 && !r->w2 && (r->d == 0 || r->d == -1))
|
|
||||||
// MAPSET(&mneg, -r->p);
|
|
||||||
// for (rid = solv->duprules, r = solv->rules + rid; rid < solv->duprules_end; rid++, r++)
|
|
||||||
// if (r->p < 0 && !r->w2 && (r->d == 0 || r->d == -1))
|
|
||||||
// MAPSET(&mneg, -r->p);
|
|
||||||
// for (rid = 1; rid < solv->rpmrules_end ; rid++)
|
|
||||||
// {
|
|
||||||
// r = solv->rules + rid;
|
|
||||||
// if (r->p >= 0 || ((r->d == 0 || r->d == -1) && r->w2 < 0))
|
|
||||||
// continue; /* only look at requires rules */
|
|
||||||
// // solver_printrule(solv, SAT_DEBUG_RESULT, r);
|
|
||||||
// queue_empty(&q);
|
|
||||||
// queue_empty(&qi);
|
|
||||||
// havechoice = 0;
|
|
||||||
// FOR_RULELITERALS(p, pp, r)
|
|
||||||
// {
|
|
||||||
// if (p < 0)
|
|
||||||
// continue;
|
|
||||||
// s = pool->solvables + p;
|
|
||||||
// if (!s->repo)
|
|
||||||
// continue;
|
|
||||||
// if (s->repo == pool->installed)
|
|
||||||
// {
|
|
||||||
// queue_push(&q, p);
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// /* check if this package is "blocked" by a installed package */
|
|
||||||
// s2 = 0;
|
|
||||||
// FOR_PROVIDES(p2, pp2, s->name)
|
|
||||||
// {
|
|
||||||
// s2 = pool->solvables + p2;
|
|
||||||
// if (s2->repo != pool->installed)
|
|
||||||
// continue;
|
|
||||||
// if (!pool->implicitobsoleteusesprovides && s->name != s2->name)
|
|
||||||
// continue;
|
|
||||||
// if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
|
|
||||||
// continue;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// if (p2)
|
|
||||||
// {
|
|
||||||
// /* found installed package p2 that we can update to p */
|
|
||||||
// if (MAPTST(&mneg, p))
|
|
||||||
// continue;
|
|
||||||
// if (policy_is_illegal(solv, s2, s, 0))
|
|
||||||
// continue;
|
|
||||||
// queue_push(&qi, p2);
|
|
||||||
// queue_push(&q, p);
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// if (s->obsoletes)
|
|
||||||
// {
|
|
||||||
// Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
|
|
||||||
// s2 = 0;
|
|
||||||
// while ((obs = *obsp++) != 0)
|
|
||||||
// {
|
|
||||||
// FOR_PROVIDES(p2, pp2, obs)
|
|
||||||
// {
|
|
||||||
// s2 = pool->solvables + p2;
|
|
||||||
// if (s2->repo != pool->installed)
|
|
||||||
// continue;
|
|
||||||
// if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
|
|
||||||
// continue;
|
|
||||||
// if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
|
|
||||||
// continue;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// if (p2)
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// if (obs)
|
|
||||||
// {
|
|
||||||
// /* found installed package p2 that we can update to p */
|
|
||||||
// if (MAPTST(&mneg, p))
|
|
||||||
// continue;
|
|
||||||
// if (policy_is_illegal(solv, s2, s, 0))
|
|
||||||
// continue;
|
|
||||||
// queue_push(&qi, p2);
|
|
||||||
// queue_push(&q, p);
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// /* package p is independent of the installed ones */
|
|
||||||
// havechoice = 1;
|
|
||||||
// }
|
|
||||||
// if (!havechoice || !q.count)
|
|
||||||
// continue; /* no choice */
|
|
||||||
//
|
|
||||||
// /* now check the update rules of the installed package.
|
|
||||||
// * if all packages of the update rules are contained in
|
|
||||||
// * the dependency rules, there's no need to set up the choice rule */
|
|
||||||
// map_empty(&m);
|
|
||||||
// FOR_RULELITERALS(p, pp, r)
|
|
||||||
// if (p > 0)
|
|
||||||
// MAPSET(&m, p);
|
|
||||||
// for (i = 0; i < qi.count; i++)
|
|
||||||
// {
|
|
||||||
// if (!qi.elements[i])
|
|
||||||
// continue;
|
|
||||||
// Rule *ur = solv->rules + solv->updaterules + (qi.elements[i] - pool->installed->start);
|
|
||||||
// if (!ur->p)
|
|
||||||
// ur = solv->rules + solv->featurerules + (qi.elements[i] - pool->installed->start);
|
|
||||||
// if (!ur->p)
|
|
||||||
// continue;
|
|
||||||
// FOR_RULELITERALS(p, pp, ur)
|
|
||||||
// if (!MAPTST(&m, p))
|
|
||||||
// break;
|
|
||||||
// if (p)
|
|
||||||
// break;
|
|
||||||
// for (j = i + 1; j < qi.count; j++)
|
|
||||||
// if (qi.elements[i] == qi.elements[j])
|
|
||||||
// qi.elements[j] = 0;
|
|
||||||
// }
|
|
||||||
// if (i == qi.count)
|
|
||||||
// {
|
|
||||||
// #if 0
|
|
||||||
// printf("skipping choice ");
|
|
||||||
// solver_printrule(solv, SAT_DEBUG_RESULT, solv->rules + rid);
|
|
||||||
// #endif
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// d = q.count ? pool_queuetowhatprovides(pool, &q) : 0;
|
|
||||||
// solver_addrule(solv, r->p, d);
|
|
||||||
// queue_push(&solv->weakruleq, solv->nrules - 1);
|
|
||||||
// solv->choicerules_ref[solv->nrules - 1 - solv->choicerules] = rid;
|
|
||||||
// #if 0
|
|
||||||
// printf("OLD ");
|
|
||||||
// solver_printrule(solv, SAT_DEBUG_RESULT, solv->rules + rid);
|
|
||||||
// printf("WEAK CHOICE ");
|
|
||||||
// solver_printrule(solv, SAT_DEBUG_RESULT, solv->rules + solv->nrules - 1);
|
|
||||||
// #endif
|
|
||||||
// }
|
|
||||||
// queue_free(&q);
|
|
||||||
// queue_free(&qi);
|
|
||||||
// map_free(&m);
|
|
||||||
// map_free(&mneg);
|
|
||||||
// solv->choicerules_end = solv->nrules;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
***
|
|
||||||
*** Policy rule disabling/reenabling
|
|
||||||
***
|
|
||||||
*** Disable all policy rules that conflict with our jobs. If a job
|
|
||||||
*** gets disabled later on, reenable the involved policy rules again.
|
|
||||||
***
|
|
||||||
*** /
|
|
||||||
|
|
||||||
#define DISABLE_UPDATE 1
|
|
||||||
#define DISABLE_INFARCH 2
|
|
||||||
#define DISABLE_DUP 3
|
|
||||||
*/
|
|
||||||
protected function jobToDisableQueue(array $job, array $disableQueue)
|
|
||||||
{
|
|
||||||
switch ($job['cmd']) {
|
|
||||||
case 'install':
|
|
||||||
foreach ($job['packages'] as $package) {
|
|
||||||
if (isset($this->installedMap[$package->getId()])) {
|
|
||||||
$disableQueue[] = array('type' => 'update', 'package' => $package);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* all job packages obsolete * /
|
|
||||||
qstart = q->count;
|
|
||||||
pass = 0;
|
|
||||||
memset(&omap, 0, sizeof(omap));
|
|
||||||
FOR_JOB_SELECT(p, pp, select, what)
|
|
||||||
{
|
|
||||||
Id p2, pp2;
|
|
||||||
|
|
||||||
if (pass == 1)
|
|
||||||
map_grow(&omap, installed->end - installed->start);
|
|
||||||
s = pool->solvables + p;
|
|
||||||
if (s->obsoletes)
|
|
||||||
{
|
|
||||||
Id obs, *obsp;
|
|
||||||
obsp = s->repo->idarraydata + s->obsoletes;
|
|
||||||
while ((obs = *obsp++) != 0)
|
|
||||||
FOR_PROVIDES(p2, pp2, obs)
|
|
||||||
{
|
|
||||||
Solvable *ps = pool->solvables + p2;
|
|
||||||
if (ps->repo != installed)
|
|
||||||
continue;
|
|
||||||
if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
|
|
||||||
continue;
|
|
||||||
if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
|
|
||||||
continue;
|
|
||||||
if (pass)
|
|
||||||
MAPSET(&omap, p2 - installed->start);
|
|
||||||
else
|
|
||||||
queue_push2(q, DISABLE_UPDATE, p2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FOR_PROVIDES(p2, pp2, s->name)
|
|
||||||
{
|
|
||||||
Solvable *ps = pool->solvables + p2;
|
|
||||||
if (ps->repo != installed)
|
|
||||||
continue;
|
|
||||||
if (!pool->implicitobsoleteusesprovides && ps->name != s->name)
|
|
||||||
continue;
|
|
||||||
if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
|
|
||||||
continue;
|
|
||||||
if (pass)
|
|
||||||
MAPSET(&omap, p2 - installed->start);
|
|
||||||
else
|
|
||||||
queue_push2(q, DISABLE_UPDATE, p2);
|
|
||||||
}
|
|
||||||
if (pass)
|
|
||||||
{
|
|
||||||
for (i = j = qstart; i < q->count; i += 2)
|
|
||||||
{
|
|
||||||
if (MAPTST(&omap, q->elements[i + 1] - installed->start))
|
|
||||||
{
|
|
||||||
MAPCLR(&omap, q->elements[i + 1] - installed->start);
|
|
||||||
q->elements[j + 1] = q->elements[i + 1];
|
|
||||||
j += 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
queue_truncate(q, j);
|
|
||||||
}
|
|
||||||
if (q->count == qstart)
|
|
||||||
break;
|
|
||||||
pass++;
|
|
||||||
}
|
|
||||||
if (omap.size)
|
|
||||||
map_free(&omap);
|
|
||||||
|
|
||||||
if (qstart == q->count)
|
|
||||||
return; /* nothing to prune * /
|
|
||||||
if ((set & (SOLVER_SETEVR | SOLVER_SETARCH | SOLVER_SETVENDOR)) == (SOLVER_SETEVR | SOLVER_SETARCH | SOLVER_SETVENDOR))
|
|
||||||
return; /* all is set */
|
|
||||||
|
|
||||||
/* now that we know which installed packages are obsoleted check each of them * /
|
|
||||||
for (i = j = qstart; i < q->count; i += 2)
|
|
||||||
{
|
|
||||||
Solvable *is = pool->solvables + q->elements[i + 1];
|
|
||||||
FOR_JOB_SELECT(p, pp, select, what)
|
|
||||||
{
|
|
||||||
int illegal = 0;
|
|
||||||
s = pool->solvables + p;
|
|
||||||
if ((set & SOLVER_SETEVR) != 0)
|
|
||||||
illegal |= POLICY_ILLEGAL_DOWNGRADE; /* ignore * /
|
|
||||||
if ((set & SOLVER_SETARCH) != 0)
|
|
||||||
illegal |= POLICY_ILLEGAL_ARCHCHANGE; /* ignore * /
|
|
||||||
if ((set & SOLVER_SETVENDOR) != 0)
|
|
||||||
illegal |= POLICY_ILLEGAL_VENDORCHANGE; /* ignore * /
|
|
||||||
illegal = policy_is_illegal(solv, is, s, illegal);
|
|
||||||
if (illegal && illegal == POLICY_ILLEGAL_DOWNGRADE && (set & SOLVER_SETEV) != 0)
|
|
||||||
{
|
|
||||||
/* it's ok if the EV is different * /
|
|
||||||
if (evrcmp(pool, is->evr, s->evr, EVRCMP_COMPARE_EVONLY) != 0)
|
|
||||||
illegal = 0;
|
|
||||||
}
|
|
||||||
if (illegal)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!p)
|
|
||||||
{
|
|
||||||
/* no package conflicts with the update rule * /
|
|
||||||
/* thus keep the DISABLE_UPDATE * /
|
|
||||||
q->elements[j + 1] = q->elements[i + 1];
|
|
||||||
j += 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
queue_truncate(q, j);
|
|
||||||
return;*/
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'remove':
|
|
||||||
foreach ($job['packages'] as $package) {
|
|
||||||
if (isset($this->installedMap[$package->getId()])) {
|
|
||||||
$disableQueue[] = array('type' => 'update', 'package' => $package);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $disableQueue;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function disableUpdateRule($package)
|
|
||||||
{
|
|
||||||
if (isset($this->packageToFeatureRule[$package->getId()])) {
|
|
||||||
$this->packageToFeatureRule[$package->getId()]->disable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disables all policy rules that conflict with jobs
|
|
||||||
*/
|
|
||||||
protected function disablePolicyRules()
|
|
||||||
{
|
|
||||||
$lastJob = null;
|
|
||||||
$allQueue = array();
|
|
||||||
|
|
||||||
$iterator = $this->rules->getIteratorFor(RuleSet::TYPE_JOB);
|
|
||||||
foreach ($iterator as $rule) {
|
|
||||||
if ($rule->isDisabled()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$job = $this->ruleToJob[$rule->getId()];
|
|
||||||
|
|
||||||
if ($job === $lastJob) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$lastJob = $job;
|
|
||||||
|
|
||||||
$allQueue = $this->jobToDisableQueue($job, $allQueue);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($allQueue as $disable) {
|
|
||||||
switch ($disable['type']) {
|
|
||||||
case 'update':
|
|
||||||
$this->disableUpdateRule($disable['package']);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new \RuntimeException("Unsupported disable type: " . $disable['type']);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function solve(Request $request)
|
public function solve(Request $request)
|
||||||
{
|
{
|
||||||
$this->jobs = $request->getJobs();
|
$this->jobs = $request->getJobs();
|
||||||
$installedPackages = $this->installed->getPackages();
|
|
||||||
$this->installedMap = array();
|
$this->setupInstalledMap();
|
||||||
foreach ($installedPackages as $package) {
|
|
||||||
$this->installedMap[$package->getId()] = $package;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version_compare(PHP_VERSION, '5.3.4', '>=')) {
|
if (version_compare(PHP_VERSION, '5.3.4', '>=')) {
|
||||||
$this->decisionMap = new \SplFixedArray($this->pool->getMaxId() + 1);
|
$this->decisionMap = new \SplFixedArray($this->pool->getMaxId() + 1);
|
||||||
|
@ -876,18 +541,18 @@ class Solver
|
||||||
|
|
||||||
switch ($job['cmd']) {
|
switch ($job['cmd']) {
|
||||||
case 'update-all':
|
case 'update-all':
|
||||||
foreach ($installedPackages as $package) {
|
foreach ($this->installedMap as $package) {
|
||||||
$this->updateMap[$package->getId()] = true;
|
$this->updateMap[$package->getId()] = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($installedPackages as $package) {
|
foreach ($this->installedMap as $package) {
|
||||||
$this->addRulesForPackage($package);
|
$this->addRulesForPackage($package);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($installedPackages as $package) {
|
foreach ($this->installedMap as $package) {
|
||||||
$this->addRulesForUpdatePackages($package);
|
$this->addRulesForUpdatePackages($package);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -903,15 +568,11 @@ class Solver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// solver_addrpmrulesforweak(solv, &addedmap);
|
foreach ($this->installedMap as $package) {
|
||||||
|
|
||||||
foreach ($installedPackages as $package) {
|
|
||||||
$updates = $this->policy->findUpdatePackages($this, $this->pool, $this->installedMap, $package);
|
$updates = $this->policy->findUpdatePackages($this, $this->pool, $this->installedMap, $package);
|
||||||
$rule = $this->createUpdateRule($package, $updates, Rule::RULE_INTERNAL_ALLOW_UPDATE, (string) $package);
|
$rule = $this->createUpdateRule($package, $updates, Rule::RULE_INTERNAL_ALLOW_UPDATE, (string) $package);
|
||||||
|
|
||||||
$rule->setWeak(true);
|
$this->packageToUpdateRule[$package->getId()] = $rule;
|
||||||
$this->addRule(RuleSet::TYPE_FEATURE, $rule);
|
|
||||||
$this->packageToFeatureRule[$package->getId()] = $rule;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->jobs as $job) {
|
foreach ($this->jobs as $job) {
|
||||||
|
@ -952,23 +613,15 @@ class Solver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->addChoiceRules();
|
|
||||||
|
|
||||||
foreach ($this->rules as $rule) {
|
foreach ($this->rules as $rule) {
|
||||||
$this->addWatchesToRule($rule);
|
$this->addWatchesToRule($rule);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* disable update rules that conflict with our job */
|
|
||||||
$this->disablePolicyRules();
|
|
||||||
|
|
||||||
/* make decisions based on job/update assertions */
|
/* make decisions based on job/update assertions */
|
||||||
$this->makeAssertionRuleDecisions();
|
$this->makeAssertionRuleDecisions();
|
||||||
|
|
||||||
$installRecommended = 0;
|
$installRecommended = 0;
|
||||||
$this->runSat(true, $installRecommended);
|
$this->runSat(true, $installRecommended);
|
||||||
//$this->printDecisionMap();
|
|
||||||
//findrecommendedsuggested(solv);
|
|
||||||
//solver_prepare_solutions(solv);
|
|
||||||
|
|
||||||
if ($this->problems) {
|
if ($this->problems) {
|
||||||
throw new SolverProblemsException($this->problems);
|
throw new SolverProblemsException($this->problems);
|
||||||
|
@ -989,8 +642,8 @@ class Solver
|
||||||
if (!$literal->isWanted() && isset($this->installedMap[$package->getId()])) {
|
if (!$literal->isWanted() && isset($this->installedMap[$package->getId()])) {
|
||||||
$literals = array();
|
$literals = array();
|
||||||
|
|
||||||
if (isset($this->packageToFeatureRule[$package->getId()])) {
|
if (isset($this->packageToUpdateRule[$package->getId()])) {
|
||||||
$literals = array_merge($literals, $this->packageToFeatureRule[$package->getId()]->getLiterals());
|
$literals = array_merge($literals, $this->packageToUpdateRule[$package->getId()]->getLiterals());
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($literals as $updateLiteral) {
|
foreach ($literals as $updateLiteral) {
|
||||||
|
@ -1010,7 +663,15 @@ class Solver
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($literal->isWanted()) {
|
if ($literal->isWanted()) {
|
||||||
|
if ($package instanceof AliasPackage) {
|
||||||
|
$transaction[] = new Operation\MarkAliasInstalledOperation(
|
||||||
|
$package, $this->decisionQueueWhy[$i]
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($installMeansUpdateMap[$literal->getPackageId()])) {
|
if (isset($installMeansUpdateMap[$literal->getPackageId()])) {
|
||||||
|
|
||||||
$source = $installMeansUpdateMap[$literal->getPackageId()];
|
$source = $installMeansUpdateMap[$literal->getPackageId()];
|
||||||
|
|
||||||
$transaction[] = new Operation\UpdateOperation(
|
$transaction[] = new Operation\UpdateOperation(
|
||||||
|
@ -1026,24 +687,75 @@ class Solver
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (!isset($ignoreRemove[$package->getId()])) {
|
} else if (!isset($ignoreRemove[$package->getId()])) {
|
||||||
$transaction[] = new Operation\UninstallOperation(
|
if ($package instanceof AliasPackage) {
|
||||||
$package, $this->decisionQueueWhy[$i]
|
$transaction[] = new Operation\MarkAliasInstalledOperation(
|
||||||
);
|
$package, $this->decisionQueueWhy[$i]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$transaction[] = new Operation\UninstallOperation(
|
||||||
|
$package, $this->decisionQueueWhy[$i]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$allDecidedMap = $this->decisionMap;
|
||||||
|
foreach ($this->decisionMap as $packageId => $decision) {
|
||||||
|
if ($decision != 0) {
|
||||||
|
$package = $this->pool->packageById($packageId);
|
||||||
|
if ($package instanceof AliasPackage) {
|
||||||
|
$allDecidedMap[$package->getAliasOf()->getId()] = $decision;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($allDecidedMap as $packageId => $decision) {
|
||||||
|
if ($packageId === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == $decision && isset($this->installedMap[$packageId])) {
|
||||||
|
$package = $this->pool->packageById($packageId);
|
||||||
|
|
||||||
|
if ($package instanceof AliasPackage) {
|
||||||
|
$transaction[] = new Operation\MarkAliasInstalledOperation(
|
||||||
|
$package, null
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$transaction[] = new Operation\UninstallOperation(
|
||||||
|
$package, null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->decisionMap[$packageId] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->decisionMap as $packageId => $decision) {
|
||||||
|
if ($packageId === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == $decision && isset($this->installedMap[$packageId])) {
|
||||||
|
$package = $this->pool->packageById($packageId);
|
||||||
|
|
||||||
|
if ($package instanceof AliasPackage) {
|
||||||
|
$transaction[] = new Operation\MarkAliasInstalledOperation(
|
||||||
|
$package, null
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$transaction[] = new Operation\UninstallOperation(
|
||||||
|
$package, null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->decisionMap[$packageId] = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return array_reverse($transaction);
|
return array_reverse($transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected $decisionQueue = array();
|
|
||||||
protected $decisionQueueWhy = array();
|
|
||||||
protected $decisionQueueFree = array();
|
|
||||||
protected $propagateIndex;
|
|
||||||
protected $branches = array();
|
|
||||||
protected $problems = array();
|
|
||||||
protected $learnedPool = array();
|
|
||||||
protected $recommendsIndex;
|
|
||||||
|
|
||||||
protected function literalFromId($id)
|
protected function literalFromId($id)
|
||||||
{
|
{
|
||||||
$package = $this->pool->packageById(abs($id));
|
$package = $this->pool->packageById(abs($id));
|
||||||
|
@ -1094,7 +806,7 @@ class Solver
|
||||||
protected function decisionsSatisfy(Literal $l)
|
protected function decisionsSatisfy(Literal $l)
|
||||||
{
|
{
|
||||||
return ($l->isWanted() && $this->decisionMap[$l->getPackageId()] > 0) ||
|
return ($l->isWanted() && $this->decisionMap[$l->getPackageId()] > 0) ||
|
||||||
(!$l->isWanted() && $this->decisionMap[$l->getPackageId()] <= 0);
|
(!$l->isWanted() && $this->decisionMap[$l->getPackageId()] < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function decisionsConflict(Literal $l)
|
protected function decisionsConflict(Literal $l)
|
||||||
|
@ -1237,11 +949,6 @@ class Solver
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** TODO: implement recommendations
|
|
||||||
*if (v > 0 && solv->recommendations.count && v == solv->recommendations.elements[solv->recommendations.count - 1])
|
|
||||||
* solv->recommendations.count--;
|
|
||||||
*/
|
|
||||||
|
|
||||||
$this->decisionMap[$literal->getPackageId()] = 0;
|
$this->decisionMap[$literal->getPackageId()] = 0;
|
||||||
array_pop($this->decisionQueue);
|
array_pop($this->decisionQueue);
|
||||||
array_pop($this->decisionQueueWhy);
|
array_pop($this->decisionQueueWhy);
|
||||||
|
@ -1421,14 +1128,19 @@ class Solver
|
||||||
$l1num++;
|
$l1num++;
|
||||||
$l1retry = true;
|
$l1retry = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$rule = $this->decisionQueueWhy[$decisionId];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$rule = $this->decisionQueueWhy[$decisionId];
|
||||||
}
|
}
|
||||||
|
|
||||||
$why = count($this->learnedPool) - 1;
|
$why = count($this->learnedPool) - 1;
|
||||||
assert($learnedLiterals[0] !== null);
|
|
||||||
$newRule = new Rule($learnedLiterals, Rule::RULE_LEARNED, $why);
|
if (count($learnedLiterals) === 1 && $learnedLiterals[0] === null) {
|
||||||
|
$newRule = new Rule(array(), Rule::RULE_LEARNED, $why);
|
||||||
|
} else {
|
||||||
|
assert($learnedLiterals[0] !== null);
|
||||||
|
$newRule = new Rule($learnedLiterals, Rule::RULE_LEARNED, $why);
|
||||||
|
}
|
||||||
|
|
||||||
return array($learnedLiterals[0], $ruleLevel, $newRule, $why);
|
return array($learnedLiterals[0], $ruleLevel, $newRule, $why);
|
||||||
}
|
}
|
||||||
|
@ -1536,20 +1248,10 @@ class Solver
|
||||||
$why = $lastWeakWhy;
|
$why = $lastWeakWhy;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($lastWeakWhy->getType() == RuleSet::TYPE_CHOICE) {
|
|
||||||
$this->disableChoiceRules($lastWeakWhy);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->disableProblem($why);
|
$this->disableProblem($why);
|
||||||
|
|
||||||
/**
|
|
||||||
@TODO what does v < 0 mean here? ($why == v)
|
|
||||||
if (v < 0)
|
|
||||||
solver_reenablepolicyrules(solv, -(v + 1));
|
|
||||||
*/
|
|
||||||
$this->resetSolver();
|
$this->resetSolver();
|
||||||
|
|
||||||
return true;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($disableRules) {
|
if ($disableRules) {
|
||||||
|
@ -1562,10 +1264,10 @@ class Solver
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->resetSolver();
|
$this->resetSolver();
|
||||||
return true;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function disableProblem($why)
|
private function disableProblem($why)
|
||||||
|
@ -1637,10 +1339,8 @@ class Solver
|
||||||
// * here's the main loop:
|
// * here's the main loop:
|
||||||
// * 1) propagate new decisions (only needed once)
|
// * 1) propagate new decisions (only needed once)
|
||||||
// * 2) fulfill jobs
|
// * 2) fulfill jobs
|
||||||
// * 3) try to keep installed packages
|
// * 3) fulfill all unresolved rules
|
||||||
// * 4) fulfill all unresolved rules
|
// * 4) minimalize solution if we had choices
|
||||||
// * 5) install recommended packages
|
|
||||||
// * 6) minimalize solution if we had choices
|
|
||||||
// * if we encounter a problem, we rewind to a safe level and restart
|
// * if we encounter a problem, we rewind to a safe level and restart
|
||||||
// * with step 1
|
// * with step 1
|
||||||
// */
|
// */
|
||||||
|
@ -1654,8 +1354,6 @@ class Solver
|
||||||
$minimizationSteps = 0;
|
$minimizationSteps = 0;
|
||||||
$installedPos = 0;
|
$installedPos = 0;
|
||||||
|
|
||||||
$this->installedPackages = $this->installed->getPackages();
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
if (1 === $level) {
|
if (1 === $level) {
|
||||||
|
@ -1727,125 +1425,6 @@ class Solver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle installed packages
|
|
||||||
if ($level < $systemLevel) {
|
|
||||||
// use two passes if any packages are being updated
|
|
||||||
// -> better user experience
|
|
||||||
for ($pass = (count($this->updateMap)) ? 0 : 1; $pass < 2; $pass++) {
|
|
||||||
$passLevel = $level;
|
|
||||||
for ($i = $installedPos, $n = 0; $n < count($this->installedPackages); $i++, $n++) {
|
|
||||||
$repeat = false;
|
|
||||||
|
|
||||||
if ($i == count($this->installedPackages)) {
|
|
||||||
$i = 0;
|
|
||||||
}
|
|
||||||
$literal = new Literal($this->installedPackages[$i], true);
|
|
||||||
|
|
||||||
if ($this->decisionsContain($literal)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// only process updates in first pass
|
|
||||||
/** TODO: && or || ? **/
|
|
||||||
if (0 === $pass && !isset($this->updateMap[$literal->getPackageId()])) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$rule = null;
|
|
||||||
|
|
||||||
if (isset($this->packageToFeatureRule[$literal->getPackageId()])) {
|
|
||||||
$rule = $this->packageToFeatureRule[$literal->getPackageId()];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$rule || $rule->isDisabled()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$updateRuleLiterals = $rule->getLiterals();
|
|
||||||
|
|
||||||
$decisionQueue = array();
|
|
||||||
if (!isset($this->noUpdate[$literal->getPackageId()]) && (
|
|
||||||
$this->decidedRemove($literal->getPackage()) ||
|
|
||||||
isset($this->updateMap[$literal->getPackageId()]) ||
|
|
||||||
!$literal->equals($updateRuleLiterals[0])
|
|
||||||
)) {
|
|
||||||
foreach ($updateRuleLiterals as $ruleLiteral) {
|
|
||||||
if ($this->decidedInstall($ruleLiteral->getPackage())) {
|
|
||||||
// already fulfilled
|
|
||||||
$decisionQueue = array();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ($this->undecided($ruleLiteral->getPackage())) {
|
|
||||||
$decisionQueue[] = $ruleLiteral;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sizeof($decisionQueue)) {
|
|
||||||
$oLevel = $level;
|
|
||||||
$level = $this->selectAndInstall($level, $decisionQueue, $disableRules, $rule);
|
|
||||||
|
|
||||||
if (0 === $level) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($level <= $oLevel) {
|
|
||||||
$repeat = true;
|
|
||||||
}
|
|
||||||
} else if (!$repeat && $this->undecided($literal->getPackage())) {
|
|
||||||
// still undecided? keep package.
|
|
||||||
$oLevel = $level;
|
|
||||||
if (isset($this->cleanDepsMap[$literal->getPackageId()])) {
|
|
||||||
// clean deps removes package
|
|
||||||
$level = $this->setPropagateLearn($level, $literal->invert(), $disableRules, null);
|
|
||||||
} else {
|
|
||||||
// ckeeping package
|
|
||||||
$level = $this->setPropagateLearn($level, $literal, $disableRules, $rule);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (0 === $level) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($level <= $oLevel) {
|
|
||||||
$repeat = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($repeat) {
|
|
||||||
if (1 === $level || $level < $passLevel) {
|
|
||||||
// trouble
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ($level < $oLevel) {
|
|
||||||
// redo all
|
|
||||||
$n = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// repeat
|
|
||||||
$i--;
|
|
||||||
$n--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($n < count($this->installedPackages)) {
|
|
||||||
$installedPos = $i; // retry this problem next time
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$installedPos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
$systemLevel = $level + 1;
|
|
||||||
|
|
||||||
if ($pass < 2) {
|
|
||||||
// had trouble => retry
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($level < $systemLevel) {
|
if ($level < $systemLevel) {
|
||||||
$systemLevel = $level;
|
$systemLevel = $level;
|
||||||
}
|
}
|
||||||
|
@ -1897,18 +1476,14 @@ class Solver
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// open suse sat-solver uses this, but why is $level == 1 trouble?
|
|
||||||
// SYSTEMSOLVABLE related? we don't have that, so should work
|
|
||||||
//if ($level < $systemLevel || $level == 1) {
|
|
||||||
|
|
||||||
if ($level < $systemLevel) {
|
|
||||||
break; // trouble
|
|
||||||
}
|
|
||||||
|
|
||||||
// something changed, so look at all rules again
|
// something changed, so look at all rules again
|
||||||
$n = -1;
|
$n = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($level < $systemLevel) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// minimization step
|
// minimization step
|
||||||
if (count($this->branches)) {
|
if (count($this->branches)) {
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ class FileDownloader implements DownloaderInterface
|
||||||
|
|
||||||
$fileName = $this->getFileName($package, $path);
|
$fileName = $this->getFileName($package, $path);
|
||||||
|
|
||||||
$this->io->write(" - Package <info>" . $package->getName() . "</info> (<comment>" . $package->getPrettyVersion() . "</comment>)");
|
$this->io->write(" - Installing <info>" . $package->getName() . "</info> (<comment>" . $package->getPrettyVersion() . "</comment>)");
|
||||||
|
|
||||||
$processUrl = $this->processUrl($url);
|
$processUrl = $this->processUrl($url);
|
||||||
|
|
||||||
|
@ -101,6 +101,7 @@ class FileDownloader implements DownloaderInterface
|
||||||
*/
|
*/
|
||||||
public function remove(PackageInterface $package, $path)
|
public function remove(PackageInterface $package, $path)
|
||||||
{
|
{
|
||||||
|
$this->io->write(" - Removing <info>" . $package->getName() . "</info> (<comment>" . $package->getPrettyVersion() . "</comment>)");
|
||||||
if (!$this->filesystem->removeDirectory($path)) {
|
if (!$this->filesystem->removeDirectory($path)) {
|
||||||
throw new \RuntimeException('Could not completely delete '.$path.', aborting.');
|
throw new \RuntimeException('Could not completely delete '.$path.', aborting.');
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ abstract class VcsDownloader implements DownloaderInterface
|
||||||
throw new \InvalidArgumentException('Package '.$package->getPrettyName().' is missing reference information');
|
throw new \InvalidArgumentException('Package '.$package->getPrettyName().' is missing reference information');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->io->write(" - Package <info>" . $package->getName() . "</info> (<comment>" . $package->getPrettyVersion() . "</comment>)");
|
$this->io->write(" - Installing <info>" . $package->getName() . "</info> (<comment>" . $package->getPrettyVersion() . "</comment>)");
|
||||||
$this->filesystem->removeDirectory($path);
|
$this->filesystem->removeDirectory($path);
|
||||||
$this->doDownload($package, $path);
|
$this->doDownload($package, $path);
|
||||||
$this->io->write('');
|
$this->io->write('');
|
||||||
|
@ -65,7 +65,7 @@ abstract class VcsDownloader implements DownloaderInterface
|
||||||
throw new \InvalidArgumentException('Package '.$target->getPrettyName().' is missing reference information');
|
throw new \InvalidArgumentException('Package '.$target->getPrettyName().' is missing reference information');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->io->write(" - Package <info>" . $target->getName() . "</info> (<comment>" . $target->getPrettyVersion() . "</comment>)");
|
$this->io->write(" - Installing <info>" . $target->getName() . "</info> (<comment>" . $target->getPrettyVersion() . "</comment>)");
|
||||||
$this->enforceCleanDirectory($path);
|
$this->enforceCleanDirectory($path);
|
||||||
$this->doUpdate($initial, $target, $path);
|
$this->doUpdate($initial, $target, $path);
|
||||||
$this->io->write('');
|
$this->io->write('');
|
||||||
|
@ -77,6 +77,7 @@ abstract class VcsDownloader implements DownloaderInterface
|
||||||
public function remove(PackageInterface $package, $path)
|
public function remove(PackageInterface $package, $path)
|
||||||
{
|
{
|
||||||
$this->enforceCleanDirectory($path);
|
$this->enforceCleanDirectory($path);
|
||||||
|
$this->io->write(" - Removing <info>" . $package->getName() . "</info> (<comment>" . $package->getPrettyVersion() . "</comment>)");
|
||||||
if (!$this->filesystem->removeDirectory($path)) {
|
if (!$this->filesystem->removeDirectory($path)) {
|
||||||
throw new \RuntimeException('Could not completely delete '.$path.', aborting.');
|
throw new \RuntimeException('Could not completely delete '.$path.', aborting.');
|
||||||
}
|
}
|
||||||
|
|
|
@ -242,7 +242,7 @@ class Installer
|
||||||
$version = $package->getVersion();
|
$version = $package->getVersion();
|
||||||
foreach ($aliases as $alias) {
|
foreach ($aliases as $alias) {
|
||||||
if ($alias['package'] === $package->getName() && $alias['version'] === $package->getVersion()) {
|
if ($alias['package'] === $package->getName() && $alias['version'] === $package->getVersion()) {
|
||||||
$version = $alias['alias'];
|
$version = $alias['alias_normalized'];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -259,9 +259,11 @@ class Installer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fix the version all installed packages that are not in the current local repo to prevent rogue updates
|
// fix the version of all installed packages (+ platform) that are not
|
||||||
|
// in the current local repo to prevent rogue updates (e.g. non-dev
|
||||||
|
// updating when in dev)
|
||||||
foreach ($installedRepo->getPackages() as $package) {
|
foreach ($installedRepo->getPackages() as $package) {
|
||||||
if ($package->getRepository() === $localRepo || $package->getRepository() instanceof PlatformRepository) {
|
if ($package->getRepository() === $localRepo) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,14 +326,6 @@ class Installer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// anti-alias local repository to allow updates to work fine
|
|
||||||
foreach ($localRepo->getPackages() as $package) {
|
|
||||||
if ($package instanceof AliasPackage) {
|
|
||||||
$package->getRepository()->addPackage(clone $package->getAliasOf());
|
|
||||||
$package->getRepository()->removePackage($package);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// execute operations
|
// execute operations
|
||||||
if (!$operations) {
|
if (!$operations) {
|
||||||
$this->io->write('Nothing to install or update');
|
$this->io->write('Nothing to install or update');
|
||||||
|
@ -354,7 +348,10 @@ class Installer
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->dryRun) {
|
if (!$this->dryRun) {
|
||||||
$this->eventDispatcher->dispatchPackageEvent(constant('Composer\Script\ScriptEvents::PRE_PACKAGE_'.strtoupper($operation->getJobType())), $operation);
|
$event = 'Composer\Script\ScriptEvents::PRE_PACKAGE_'.strtoupper($operation->getJobType());
|
||||||
|
if (defined($event)) {
|
||||||
|
$this->eventDispatcher->dispatchPackageEvent(constant($event), $operation);
|
||||||
|
}
|
||||||
|
|
||||||
// if installing from lock, restore dev packages' references to their locked state
|
// if installing from lock, restore dev packages' references to their locked state
|
||||||
if ($installFromLock) {
|
if ($installFromLock) {
|
||||||
|
@ -376,17 +373,15 @@ class Installer
|
||||||
}
|
}
|
||||||
$this->installationManager->execute($localRepo, $operation);
|
$this->installationManager->execute($localRepo, $operation);
|
||||||
|
|
||||||
$this->eventDispatcher->dispatchPackageEvent(constant('Composer\Script\ScriptEvents::POST_PACKAGE_'.strtoupper($operation->getJobType())), $operation);
|
$event = 'Composer\Script\ScriptEvents::POST_PACKAGE_'.strtoupper($operation->getJobType());
|
||||||
|
if (defined($event)) {
|
||||||
|
$this->eventDispatcher->dispatchPackageEvent(constant($event), $operation);
|
||||||
|
}
|
||||||
|
|
||||||
$localRepo->write();
|
$localRepo->write();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// reload local repository for the dev pass to work ok with aliases since it was anti-aliased above
|
|
||||||
if (!$devMode) {
|
|
||||||
$localRepo->reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -410,7 +405,6 @@ class Installer
|
||||||
$package->setAlias($alias['alias_normalized']);
|
$package->setAlias($alias['alias_normalized']);
|
||||||
$package->setPrettyAlias($alias['alias']);
|
$package->setPrettyAlias($alias['alias']);
|
||||||
$package->getRepository()->addPackage($aliasPackage = new AliasPackage($package, $alias['alias_normalized'], $alias['alias']));
|
$package->getRepository()->addPackage($aliasPackage = new AliasPackage($package, $alias['alias_normalized'], $alias['alias']));
|
||||||
$package->getRepository()->removePackage($package);
|
|
||||||
$aliasPackage->setRootPackageAlias(true);
|
$aliasPackage->setRootPackageAlias(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ use Composer\DependencyResolver\Operation\OperationInterface;
|
||||||
use Composer\DependencyResolver\Operation\InstallOperation;
|
use Composer\DependencyResolver\Operation\InstallOperation;
|
||||||
use Composer\DependencyResolver\Operation\UpdateOperation;
|
use Composer\DependencyResolver\Operation\UpdateOperation;
|
||||||
use Composer\DependencyResolver\Operation\UninstallOperation;
|
use Composer\DependencyResolver\Operation\UninstallOperation;
|
||||||
|
use Composer\DependencyResolver\Operation\MarkAliasInstalledOperation;
|
||||||
|
use Composer\DependencyResolver\Operation\MarkAliasUninstalledOperation;
|
||||||
use Composer\Util\Filesystem;
|
use Composer\Util\Filesystem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -104,6 +106,10 @@ class InstallationManager
|
||||||
*/
|
*/
|
||||||
public function isPackageInstalled(InstalledRepositoryInterface $repo, PackageInterface $package)
|
public function isPackageInstalled(InstalledRepositoryInterface $repo, PackageInterface $package)
|
||||||
{
|
{
|
||||||
|
if ($package instanceof AliasPackage) {
|
||||||
|
return $repo->hasPackage($package);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->getInstaller($package->getType())->isInstalled($repo, $package);
|
return $this->getInstaller($package->getType())->isInstalled($repo, $package);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +133,7 @@ class InstallationManager
|
||||||
*/
|
*/
|
||||||
public function install(RepositoryInterface $repo, InstallOperation $operation)
|
public function install(RepositoryInterface $repo, InstallOperation $operation)
|
||||||
{
|
{
|
||||||
$package = $this->antiAlias($operation->getPackage());
|
$package = $operation->getPackage();
|
||||||
$installer = $this->getInstaller($package->getType());
|
$installer = $this->getInstaller($package->getType());
|
||||||
$installer->install($repo, $package);
|
$installer->install($repo, $package);
|
||||||
$this->notifyInstall($package);
|
$this->notifyInstall($package);
|
||||||
|
@ -141,8 +147,8 @@ class InstallationManager
|
||||||
*/
|
*/
|
||||||
public function update(RepositoryInterface $repo, UpdateOperation $operation)
|
public function update(RepositoryInterface $repo, UpdateOperation $operation)
|
||||||
{
|
{
|
||||||
$initial = $this->antiAlias($operation->getInitialPackage());
|
$initial = $operation->getInitialPackage();
|
||||||
$target = $this->antiAlias($operation->getTargetPackage());
|
$target = $operation->getTargetPackage();
|
||||||
|
|
||||||
$initialType = $initial->getType();
|
$initialType = $initial->getType();
|
||||||
$targetType = $target->getType();
|
$targetType = $target->getType();
|
||||||
|
@ -165,11 +171,41 @@ class InstallationManager
|
||||||
*/
|
*/
|
||||||
public function uninstall(RepositoryInterface $repo, UninstallOperation $operation)
|
public function uninstall(RepositoryInterface $repo, UninstallOperation $operation)
|
||||||
{
|
{
|
||||||
$package = $this->antiAlias($operation->getPackage());
|
$package = $operation->getPackage();
|
||||||
$installer = $this->getInstaller($package->getType());
|
$installer = $this->getInstaller($package->getType());
|
||||||
$installer->uninstall($repo, $package);
|
$installer->uninstall($repo, $package);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes markAliasInstalled operation.
|
||||||
|
*
|
||||||
|
* @param RepositoryInterface $repo repository in which to check
|
||||||
|
* @param MarkAliasInstalledOperation $operation operation instance
|
||||||
|
*/
|
||||||
|
public function markAliasInstalled(RepositoryInterface $repo, MarkAliasInstalledOperation $operation)
|
||||||
|
{
|
||||||
|
$package = $operation->getPackage();
|
||||||
|
|
||||||
|
if (!$repo->hasPackage($package)) {
|
||||||
|
$repo->addPackage(clone $package);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->notifyInstall($package);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes markAlias operation.
|
||||||
|
*
|
||||||
|
* @param RepositoryInterface $repo repository in which to check
|
||||||
|
* @param MarkAliasUninstalledOperation $operation operation instance
|
||||||
|
*/
|
||||||
|
public function markAliasUninstalled(RepositoryInterface $repo, MarkAliasUninstalledOperation $operation)
|
||||||
|
{
|
||||||
|
$package = $operation->getPackage();
|
||||||
|
|
||||||
|
$repo->removePackage($package);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the installation path of a package
|
* Returns the installation path of a package
|
||||||
*
|
*
|
||||||
|
@ -203,17 +239,4 @@ class InstallationManager
|
||||||
$package->getRepository()->notifyInstall($package);
|
$package->getRepository()->notifyInstall($package);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function antiAlias(PackageInterface $package)
|
|
||||||
{
|
|
||||||
if ($package instanceof AliasPackage) {
|
|
||||||
$alias = $package;
|
|
||||||
$package = $package->getAliasOf();
|
|
||||||
$package->setInstalledAsAlias(true);
|
|
||||||
$package->setAlias($alias->getVersion());
|
|
||||||
$package->setPrettyAlias($alias->getPrettyVersion());
|
|
||||||
}
|
|
||||||
|
|
||||||
return $package;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,6 +127,13 @@ class LibraryInstaller implements InstallerInterface
|
||||||
$this->downloadManager->remove($package, $downloadPath);
|
$this->downloadManager->remove($package, $downloadPath);
|
||||||
$this->removeBinaries($package);
|
$this->removeBinaries($package);
|
||||||
$repo->removePackage($package);
|
$repo->removePackage($package);
|
||||||
|
|
||||||
|
if (strpos($package->getName(), '/')) {
|
||||||
|
$packageVendorDir = dirname($downloadPath);
|
||||||
|
if (is_dir($packageVendorDir) && !glob($packageVendorDir.'/*')) {
|
||||||
|
@rmdir($packageVendorDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -89,7 +89,13 @@ class Locker
|
||||||
$repo = $dev ? $this->repositoryManager->getLocalDevRepository() : $this->repositoryManager->getLocalRepository();
|
$repo = $dev ? $this->repositoryManager->getLocalDevRepository() : $this->repositoryManager->getLocalRepository();
|
||||||
|
|
||||||
foreach ($lockedPackages as $info) {
|
foreach ($lockedPackages as $info) {
|
||||||
$resolvedVersion = !empty($info['alias']) ? $info['alias'] : $info['version'];
|
// TODO BC remove this after June 10th
|
||||||
|
if (isset($info['alias']) && empty($warned)) {
|
||||||
|
$warned = true;
|
||||||
|
echo 'BC warning: your lock file appears to be of an older format than this composer version, it is recommended to run composer update'.PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
$resolvedVersion = !empty($info['alias-version']) ? $info['alias-version'] : $info['version'];
|
||||||
|
|
||||||
// try to find the package in the local repo (best match)
|
// try to find the package in the local repo (best match)
|
||||||
$package = $repo->findPackage($info['package'], $resolvedVersion);
|
$package = $repo->findPackage($info['package'], $resolvedVersion);
|
||||||
|
@ -100,10 +106,10 @@ class Locker
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to find the package in any repo (second pass without alias + rebuild alias since it disappeared)
|
// try to find the package in any repo (second pass without alias + rebuild alias since it disappeared)
|
||||||
if (!$package && !empty($info['alias'])) {
|
if (!$package && !empty($info['alias-version'])) {
|
||||||
$package = $this->repositoryManager->findPackage($info['package'], $info['version']);
|
$package = $this->repositoryManager->findPackage($info['package'], $info['version']);
|
||||||
if ($package) {
|
if ($package) {
|
||||||
$alias = new AliasPackage($package, $info['alias'], $info['alias']);
|
$alias = new AliasPackage($package, $info['alias-version'], $info['alias-pretty-version']);
|
||||||
$package->getRepository()->addPackage($alias);
|
$package->getRepository()->addPackage($alias);
|
||||||
$package = $alias;
|
$package = $alias;
|
||||||
}
|
}
|
||||||
|
@ -179,7 +185,10 @@ class Locker
|
||||||
$locked = array();
|
$locked = array();
|
||||||
|
|
||||||
foreach ($packages as $package) {
|
foreach ($packages as $package) {
|
||||||
|
$alias = null;
|
||||||
|
|
||||||
if ($package instanceof AliasPackage) {
|
if ($package instanceof AliasPackage) {
|
||||||
|
$alias = $package;
|
||||||
$package = $package->getAliasOf();
|
$package = $package->getAliasOf();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,8 +207,9 @@ class Locker
|
||||||
$spec['source-reference'] = $package->getSourceReference();
|
$spec['source-reference'] = $package->getSourceReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($package->getAlias() && $package->isInstalledAsAlias()) {
|
if ($alias) {
|
||||||
$spec['alias'] = $package->getAlias();
|
$spec['alias-pretty-version'] = $alias->getPrettyVersion();
|
||||||
|
$spec['alias-version'] = $alias->getVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
$locked[] = $spec;
|
$locked[] = $spec;
|
||||||
|
|
|
@ -46,7 +46,6 @@ class MemoryPackage extends BasePackage
|
||||||
protected $aliases = array();
|
protected $aliases = array();
|
||||||
protected $alias;
|
protected $alias;
|
||||||
protected $prettyAlias;
|
protected $prettyAlias;
|
||||||
protected $installedAsAlias;
|
|
||||||
protected $dev;
|
protected $dev;
|
||||||
|
|
||||||
protected $requires = array();
|
protected $requires = array();
|
||||||
|
@ -211,24 +210,6 @@ class MemoryPackage extends BasePackage
|
||||||
return $this->prettyAlias;
|
return $this->prettyAlias;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Enabled if the package is installed from its alias package
|
|
||||||
*
|
|
||||||
* @param string $installedAsAlias
|
|
||||||
*/
|
|
||||||
public function setInstalledAsAlias($installedAsAlias)
|
|
||||||
{
|
|
||||||
$this->installedAsAlias = $installedAsAlias;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function isInstalledAsAlias()
|
|
||||||
{
|
|
||||||
return $this->installedAsAlias;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -103,8 +103,8 @@ class ArrayRepository implements RepositoryInterface
|
||||||
$package->setRepository($this);
|
$package->setRepository($this);
|
||||||
$this->packages[] = $package;
|
$this->packages[] = $package;
|
||||||
|
|
||||||
// create alias package on the fly if needed (installed repos manage aliases themselves)
|
// create alias package on the fly if needed
|
||||||
if ($package->getAlias() && !$this instanceof InstalledRepositoryInterface) {
|
if ($package->getAlias()) {
|
||||||
$this->addPackage($this->createAliasPackage($package));
|
$this->addPackage($this->createAliasPackage($package));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ namespace Composer\Repository;
|
||||||
|
|
||||||
use Composer\Json\JsonFile;
|
use Composer\Json\JsonFile;
|
||||||
use Composer\Package\PackageInterface;
|
use Composer\Package\PackageInterface;
|
||||||
|
use Composer\Package\AliasPackage;
|
||||||
use Composer\Package\Loader\ArrayLoader;
|
use Composer\Package\Loader\ArrayLoader;
|
||||||
use Composer\Package\Dumper\ArrayDumper;
|
use Composer\Package\Dumper\ArrayDumper;
|
||||||
|
|
||||||
|
@ -54,21 +55,32 @@ class FilesystemRepository extends ArrayRepository implements WritableRepository
|
||||||
throw new \UnexpectedValueException('Could not parse package list from the '.$this->file->getPath().' repository');
|
throw new \UnexpectedValueException('Could not parse package list from the '.$this->file->getPath().' repository');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$aliases = array();
|
||||||
|
|
||||||
$loader = new ArrayLoader();
|
$loader = new ArrayLoader();
|
||||||
foreach ($packages as $packageData) {
|
foreach ($packages as $packageData) {
|
||||||
$package = $loader->load($packageData);
|
$package = $loader->load($packageData);
|
||||||
|
|
||||||
// package was installed as alias, so we only add the alias
|
// aliases need to be looked up in the end to set up references correctly
|
||||||
if ($this instanceof InstalledRepositoryInterface && !empty($packageData['installed-as-alias'])) {
|
if ($this instanceof InstalledRepositoryInterface && !empty($packageData['alias'])) {
|
||||||
$alias = $packageData['installed-as-alias'];
|
$aliases[] = array(
|
||||||
$package->setAlias($alias);
|
'package' => $package,
|
||||||
$package->setPrettyAlias($alias);
|
'alias' => $packageData['alias'],
|
||||||
$package->setInstalledAsAlias(true);
|
'alias_pretty' => $packageData['alias_pretty']
|
||||||
$this->addPackage($this->createAliasPackage($package, $alias, $alias));
|
);
|
||||||
} else {
|
|
||||||
// only add regular package - if it's not an installed repo the alias will be created on the fly
|
|
||||||
$this->addPackage($package);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->addPackage($package);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($aliases as $aliasData) {
|
||||||
|
$temporaryPackage = $aliasData['package'];
|
||||||
|
|
||||||
|
$package = $this->findPackage($package->getName(), $package->getVersion());
|
||||||
|
|
||||||
|
$package->setAlias($aliasData['alias']);
|
||||||
|
$package->setPrettyAlias($aliasData['alias_pretty']);
|
||||||
|
$this->addPackage($this->createAliasPackage($package, $aliasData['alias'], $aliasData['alias_pretty']));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,11 +98,10 @@ class FilesystemRepository extends ArrayRepository implements WritableRepository
|
||||||
$packages = array();
|
$packages = array();
|
||||||
$dumper = new ArrayDumper();
|
$dumper = new ArrayDumper();
|
||||||
foreach ($this->getPackages() as $package) {
|
foreach ($this->getPackages() as $package) {
|
||||||
$data = $dumper->dump($package);
|
if (!$package instanceof AliasPackage) {
|
||||||
if ($this instanceof InstalledRepositoryInterface && $package->isInstalledAsAlias()) {
|
$data = $dumper->dump($package);
|
||||||
$data['installed-as-alias'] = $package->getAlias();
|
$packages[] = $data;
|
||||||
}
|
}
|
||||||
$packages[] = $data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->file->write($packages);
|
$this->file->write($packages);
|
||||||
|
|
|
@ -27,7 +27,7 @@ class ResultSetIteratorTest extends \PHPUnit_Framework_TestCase
|
||||||
new Rule(array(), 'job1', null),
|
new Rule(array(), 'job1', null),
|
||||||
new Rule(array(), 'job2', null),
|
new Rule(array(), 'job2', null),
|
||||||
),
|
),
|
||||||
RuleSet::TYPE_FEATURE => array(
|
RuleSet::TYPE_LEARNED => array(
|
||||||
new Rule(array(), 'update1', null),
|
new Rule(array(), 'update1', null),
|
||||||
),
|
),
|
||||||
RuleSet::TYPE_PACKAGE => array(),
|
RuleSet::TYPE_PACKAGE => array(),
|
||||||
|
@ -46,7 +46,7 @@ class ResultSetIteratorTest extends \PHPUnit_Framework_TestCase
|
||||||
$expected = array(
|
$expected = array(
|
||||||
$this->rules[RuleSet::TYPE_JOB][0],
|
$this->rules[RuleSet::TYPE_JOB][0],
|
||||||
$this->rules[RuleSet::TYPE_JOB][1],
|
$this->rules[RuleSet::TYPE_JOB][1],
|
||||||
$this->rules[RuleSet::TYPE_FEATURE][0],
|
$this->rules[RuleSet::TYPE_LEARNED][0],
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals($expected, $result);
|
$this->assertEquals($expected, $result);
|
||||||
|
@ -64,7 +64,7 @@ class ResultSetIteratorTest extends \PHPUnit_Framework_TestCase
|
||||||
$expected = array(
|
$expected = array(
|
||||||
RuleSet::TYPE_JOB,
|
RuleSet::TYPE_JOB,
|
||||||
RuleSet::TYPE_JOB,
|
RuleSet::TYPE_JOB,
|
||||||
RuleSet::TYPE_FEATURE,
|
RuleSet::TYPE_LEARNED,
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals($expected, $result);
|
$this->assertEquals($expected, $result);
|
||||||
|
|
|
@ -27,17 +27,15 @@ class RuleSetTest extends TestCase
|
||||||
new Rule(array(), 'job1', null),
|
new Rule(array(), 'job1', null),
|
||||||
new Rule(array(), 'job2', null),
|
new Rule(array(), 'job2', null),
|
||||||
),
|
),
|
||||||
RuleSet::TYPE_FEATURE => array(
|
RuleSet::TYPE_LEARNED => array(
|
||||||
new Rule(array(), 'update1', null),
|
new Rule(array(), 'update1', null),
|
||||||
),
|
),
|
||||||
RuleSet::TYPE_LEARNED => array(),
|
|
||||||
RuleSet::TYPE_CHOICE => array(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
$ruleSet = new RuleSet;
|
$ruleSet = new RuleSet;
|
||||||
|
|
||||||
$ruleSet->add($rules[RuleSet::TYPE_JOB][0], RuleSet::TYPE_JOB);
|
$ruleSet->add($rules[RuleSet::TYPE_JOB][0], RuleSet::TYPE_JOB);
|
||||||
$ruleSet->add($rules[RuleSet::TYPE_FEATURE][0], RuleSet::TYPE_FEATURE);
|
$ruleSet->add($rules[RuleSet::TYPE_LEARNED][0], RuleSet::TYPE_LEARNED);
|
||||||
$ruleSet->add($rules[RuleSet::TYPE_JOB][1], RuleSet::TYPE_JOB);
|
$ruleSet->add($rules[RuleSet::TYPE_JOB][1], RuleSet::TYPE_JOB);
|
||||||
|
|
||||||
$this->assertEquals($rules, $ruleSet->getRules());
|
$this->assertEquals($rules, $ruleSet->getRules());
|
||||||
|
@ -80,7 +78,7 @@ class RuleSetTest extends TestCase
|
||||||
$rule1 = new Rule(array(), 'job1', null);
|
$rule1 = new Rule(array(), 'job1', null);
|
||||||
$rule2 = new Rule(array(), 'job1', null);
|
$rule2 = new Rule(array(), 'job1', null);
|
||||||
$ruleSet->add($rule1, RuleSet::TYPE_JOB);
|
$ruleSet->add($rule1, RuleSet::TYPE_JOB);
|
||||||
$ruleSet->add($rule2, RuleSet::TYPE_FEATURE);
|
$ruleSet->add($rule2, RuleSet::TYPE_LEARNED);
|
||||||
|
|
||||||
$iterator = $ruleSet->getIterator();
|
$iterator = $ruleSet->getIterator();
|
||||||
|
|
||||||
|
@ -96,9 +94,9 @@ class RuleSetTest extends TestCase
|
||||||
$rule2 = new Rule(array(), 'job1', null);
|
$rule2 = new Rule(array(), 'job1', null);
|
||||||
|
|
||||||
$ruleSet->add($rule1, RuleSet::TYPE_JOB);
|
$ruleSet->add($rule1, RuleSet::TYPE_JOB);
|
||||||
$ruleSet->add($rule2, RuleSet::TYPE_FEATURE);
|
$ruleSet->add($rule2, RuleSet::TYPE_LEARNED);
|
||||||
|
|
||||||
$iterator = $ruleSet->getIteratorFor(RuleSet::TYPE_FEATURE);
|
$iterator = $ruleSet->getIteratorFor(RuleSet::TYPE_LEARNED);
|
||||||
|
|
||||||
$this->assertSame($rule2, $iterator->current());
|
$this->assertSame($rule2, $iterator->current());
|
||||||
}
|
}
|
||||||
|
@ -110,7 +108,7 @@ class RuleSetTest extends TestCase
|
||||||
$rule2 = new Rule(array(), 'job1', null);
|
$rule2 = new Rule(array(), 'job1', null);
|
||||||
|
|
||||||
$ruleSet->add($rule1, RuleSet::TYPE_JOB);
|
$ruleSet->add($rule1, RuleSet::TYPE_JOB);
|
||||||
$ruleSet->add($rule2, RuleSet::TYPE_FEATURE);
|
$ruleSet->add($rule2, RuleSet::TYPE_LEARNED);
|
||||||
|
|
||||||
$iterator = $ruleSet->getIteratorWithout(RuleSet::TYPE_JOB);
|
$iterator = $ruleSet->getIteratorWithout(RuleSet::TYPE_JOB);
|
||||||
|
|
||||||
|
@ -142,7 +140,7 @@ class RuleSetTest extends TestCase
|
||||||
->method('equal')
|
->method('equal')
|
||||||
->will($this->returnValue(false));
|
->will($this->returnValue(false));
|
||||||
|
|
||||||
$ruleSet->add($rule, RuleSet::TYPE_FEATURE);
|
$ruleSet->add($rule, RuleSet::TYPE_LEARNED);
|
||||||
|
|
||||||
$this->assertTrue($ruleSet->containsEqual($rule));
|
$this->assertTrue($ruleSet->containsEqual($rule));
|
||||||
$this->assertFalse($ruleSet->containsEqual($rule2));
|
$this->assertFalse($ruleSet->containsEqual($rule2));
|
||||||
|
@ -155,9 +153,9 @@ class RuleSetTest extends TestCase
|
||||||
$literal = new Literal($this->getPackage('foo', '2.1'), true);
|
$literal = new Literal($this->getPackage('foo', '2.1'), true);
|
||||||
$rule = new Rule(array($literal), 'job1', null);
|
$rule = new Rule(array($literal), 'job1', null);
|
||||||
|
|
||||||
$ruleSet->add($rule, RuleSet::TYPE_FEATURE);
|
$ruleSet->add($rule, RuleSet::TYPE_JOB);
|
||||||
|
|
||||||
$this->assertContains('FEATURE : (+foo-2.1.0.0)', $ruleSet->__toString());
|
$this->assertContains('JOB : (+foo-2.1.0.0)', $ruleSet->__toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getRuleMock()
|
private function getRuleMock()
|
||||||
|
|
|
@ -54,6 +54,16 @@ class SolverTest extends TestCase
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSolverRemoveIfNotInstalled()
|
||||||
|
{
|
||||||
|
$this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
|
$this->reposComplete();
|
||||||
|
|
||||||
|
$this->checkSolverResult(array(
|
||||||
|
array('job' => 'remove', 'package' => $packageA),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
public function testInstallNonExistingPackageFails()
|
public function testInstallNonExistingPackageFails()
|
||||||
{
|
{
|
||||||
$this->repo->addPackage($this->getPackage('A', '1.0'));
|
$this->repo->addPackage($this->getPackage('A', '1.0'));
|
||||||
|
@ -176,6 +186,7 @@ class SolverTest extends TestCase
|
||||||
$this->repo->addPackage($newPackageA = $this->getPackage('A', '1.1'));
|
$this->repo->addPackage($newPackageA = $this->getPackage('A', '1.1'));
|
||||||
$this->reposComplete();
|
$this->reposComplete();
|
||||||
|
|
||||||
|
$this->request->install('A');
|
||||||
$this->request->update('A');
|
$this->request->update('A');
|
||||||
|
|
||||||
$this->checkSolverResult(array(
|
$this->checkSolverResult(array(
|
||||||
|
@ -191,6 +202,7 @@ class SolverTest extends TestCase
|
||||||
$this->repo->addPackage($newPackageB = $this->getPackage('B', '1.1'));
|
$this->repo->addPackage($newPackageB = $this->getPackage('B', '1.1'));
|
||||||
|
|
||||||
$packageA->setRequires(array(new Link('A', 'B', null, 'requires')));
|
$packageA->setRequires(array(new Link('A', 'B', null, 'requires')));
|
||||||
|
$newPackageA->setRequires(array(new Link('A', 'B', null, 'requires')));
|
||||||
|
|
||||||
$this->reposComplete();
|
$this->reposComplete();
|
||||||
|
|
||||||
|
@ -209,6 +221,7 @@ class SolverTest extends TestCase
|
||||||
$this->repo->addPackage($this->getPackage('A', '1.0'));
|
$this->repo->addPackage($this->getPackage('A', '1.0'));
|
||||||
$this->reposComplete();
|
$this->reposComplete();
|
||||||
|
|
||||||
|
$this->request->install('A');
|
||||||
$this->request->update('A');
|
$this->request->update('A');
|
||||||
|
|
||||||
$this->checkSolverResult(array());
|
$this->checkSolverResult(array());
|
||||||
|
@ -223,6 +236,8 @@ class SolverTest extends TestCase
|
||||||
|
|
||||||
$this->reposComplete();
|
$this->reposComplete();
|
||||||
|
|
||||||
|
$this->request->install('A');
|
||||||
|
$this->request->install('B');
|
||||||
$this->request->update('A');
|
$this->request->update('A');
|
||||||
|
|
||||||
$this->checkSolverResult(array(
|
$this->checkSolverResult(array(
|
||||||
|
@ -267,7 +282,7 @@ class SolverTest extends TestCase
|
||||||
public function testSolverUpdateFullyConstrainedPrunesInstalledPackages()
|
public function testSolverUpdateFullyConstrainedPrunesInstalledPackages()
|
||||||
{
|
{
|
||||||
$this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0'));
|
$this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
$this->repoInstalled->addPackage($this->getPackage('B', '1.0'));
|
$this->repoInstalled->addPackage($packageB = $this->getPackage('B', '1.0'));
|
||||||
$this->repo->addPackage($newPackageA = $this->getPackage('A', '1.2'));
|
$this->repo->addPackage($newPackageA = $this->getPackage('A', '1.2'));
|
||||||
$this->repo->addPackage($this->getPackage('A', '2.0'));
|
$this->repo->addPackage($this->getPackage('A', '2.0'));
|
||||||
$this->reposComplete();
|
$this->reposComplete();
|
||||||
|
@ -275,10 +290,15 @@ class SolverTest extends TestCase
|
||||||
$this->request->install('A', $this->getVersionConstraint('<', '2.0.0.0'));
|
$this->request->install('A', $this->getVersionConstraint('<', '2.0.0.0'));
|
||||||
$this->request->update('A', $this->getVersionConstraint('=', '1.0.0.0'));
|
$this->request->update('A', $this->getVersionConstraint('=', '1.0.0.0'));
|
||||||
|
|
||||||
$this->checkSolverResult(array(array(
|
$this->checkSolverResult(array(
|
||||||
'job' => 'update',
|
array(
|
||||||
'from' => $packageA,
|
'job' => 'remove',
|
||||||
'to' => $newPackageA,
|
'package' => $packageB,
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'job' => 'update',
|
||||||
|
'from' => $packageA,
|
||||||
|
'to' => $newPackageA,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,6 +317,7 @@ class SolverTest extends TestCase
|
||||||
$this->reposComplete();
|
$this->reposComplete();
|
||||||
|
|
||||||
$this->request->install('A');
|
$this->request->install('A');
|
||||||
|
$this->request->install('C');
|
||||||
$this->request->update('C');
|
$this->request->update('C');
|
||||||
$this->request->remove('D');
|
$this->request->remove('D');
|
||||||
|
|
||||||
|
@ -649,6 +670,55 @@ class SolverTest extends TestCase
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testInstallRecursiveAliasDependencies()
|
||||||
|
{
|
||||||
|
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
|
$this->repo->addPackage($packageB = $this->getPackage('B', '2.0'));
|
||||||
|
$this->repo->addPackage($packageA2 = $this->getPackage('A', '2.0'));
|
||||||
|
|
||||||
|
$packageA2->setRequires(array(
|
||||||
|
new Link('A', 'B', $this->getVersionConstraint('==', '2.0'), 'requires', '== 2.0'),
|
||||||
|
));
|
||||||
|
$packageB->setRequires(array(
|
||||||
|
new Link('B', 'A', $this->getVersionConstraint('>=', '2.0'), 'requires'),
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->repo->addPackage($packageA2Alias = $this->getAliasPackage($packageA2, '1.1'));
|
||||||
|
|
||||||
|
$this->reposComplete();
|
||||||
|
|
||||||
|
$this->request->install('A', $this->getVersionConstraint('==', '1.1.0.0'));
|
||||||
|
|
||||||
|
$this->checkSolverResult(array(
|
||||||
|
array('job' => 'install', 'package' => $packageB),
|
||||||
|
array('job' => 'install', 'package' => $packageA2),
|
||||||
|
array('job' => 'install', 'package' => $packageA2Alias),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInstallDevAlias()
|
||||||
|
{
|
||||||
|
$this->repo->addPackage($packageA = $this->getPackage('A', '2.0'));
|
||||||
|
$this->repo->addPackage($packageB = $this->getPackage('B', '1.0'));
|
||||||
|
|
||||||
|
$packageB->setRequires(array(
|
||||||
|
new Link('B', 'A', $this->getVersionConstraint('<', '2.0'), 'requires'),
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->repo->addPackage($packageAAlias = $this->getAliasPackage($packageA, '1.1'));
|
||||||
|
|
||||||
|
$this->reposComplete();
|
||||||
|
|
||||||
|
$this->request->install('A', $this->getVersionConstraint('==', '2.0'));
|
||||||
|
$this->request->install('B');
|
||||||
|
|
||||||
|
$this->checkSolverResult(array(
|
||||||
|
array('job' => 'install', 'package' => $packageAAlias),
|
||||||
|
array('job' => 'install', 'package' => $packageB),
|
||||||
|
array('job' => 'install', 'package' => $packageA),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
protected function reposComplete()
|
protected function reposComplete()
|
||||||
{
|
{
|
||||||
$this->pool->addRepository($this->repoInstalled);
|
$this->pool->addRepository($this->repoInstalled);
|
||||||
|
|
|
@ -14,6 +14,7 @@ namespace Composer\Test;
|
||||||
|
|
||||||
use Composer\Package\Version\VersionParser;
|
use Composer\Package\Version\VersionParser;
|
||||||
use Composer\Package\MemoryPackage;
|
use Composer\Package\MemoryPackage;
|
||||||
|
use Composer\Package\AliasPackage;
|
||||||
use Composer\Package\LinkConstraint\VersionConstraint;
|
use Composer\Package\LinkConstraint\VersionConstraint;
|
||||||
use Composer\Util\Filesystem;
|
use Composer\Util\Filesystem;
|
||||||
|
|
||||||
|
@ -45,6 +46,12 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
|
||||||
return new MemoryPackage($name, $normVersion, $version);
|
return new MemoryPackage($name, $normVersion, $version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getAliasPackage($package, $version)
|
||||||
|
{
|
||||||
|
$normVersion = self::getVersionParser()->normalize($version);
|
||||||
|
return new AliasPackage($package, $normVersion, $version);
|
||||||
|
}
|
||||||
|
|
||||||
protected function ensureDirectoryExistsAndClear($directory)
|
protected function ensureDirectoryExistsAndClear($directory)
|
||||||
{
|
{
|
||||||
$fs = new Filesystem();
|
$fs = new Filesystem();
|
||||||
|
|
Loading…
Reference in New Issue