Merge remote-tracking branch 'naderman/remove-packages-by-default'
commit
2988152602
|
@ -20,16 +20,12 @@ class RuleSet implements \IteratorAggregate, \Countable
|
|||
// highest priority => lowest number
|
||||
const TYPE_PACKAGE = 0;
|
||||
const TYPE_JOB = 1;
|
||||
const TYPE_FEATURE = 3;
|
||||
const TYPE_CHOICE = 4;
|
||||
const TYPE_LEARNED = 5;
|
||||
const TYPE_LEARNED = 4;
|
||||
|
||||
protected static $types = array(
|
||||
-1 => 'UNKNOWN',
|
||||
self::TYPE_PACKAGE => 'PACKAGE',
|
||||
self::TYPE_FEATURE => 'FEATURE',
|
||||
self::TYPE_JOB => 'JOB',
|
||||
self::TYPE_CHOICE => 'CHOICE',
|
||||
self::TYPE_LEARNED => 'LEARNED',
|
||||
);
|
||||
|
||||
|
|
|
@ -30,13 +30,21 @@ class Solver
|
|||
protected $ruleToJob = array();
|
||||
protected $addedMap = array();
|
||||
protected $updateMap = array();
|
||||
protected $noObsoletes = array();
|
||||
protected $watches = array();
|
||||
protected $removeWatches = array();
|
||||
protected $decisionMap;
|
||||
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)
|
||||
{
|
||||
|
@ -237,12 +245,6 @@ class Solver
|
|||
}
|
||||
|
||||
// check obsoletes and implicit obsoletes of a package
|
||||
// if ignoreinstalledsobsoletes is not set, we're also checking
|
||||
// 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) {
|
||||
|
@ -273,18 +275,12 @@ class Solver
|
|||
continue;
|
||||
}
|
||||
|
||||
// obsolete same packages even when noObsoletes
|
||||
if ($noObsoletes && (!$package->equals($provider))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all rules for all update packages of a given package
|
||||
|
@ -431,7 +427,7 @@ class Solver
|
|||
|
||||
// push all of our rules (can only be feature or job rules)
|
||||
// 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()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -492,370 +488,22 @@ class Solver
|
|||
}
|
||||
|
||||
$this->disableProblem($why);
|
||||
/** TODO solver_reenablepolicyrules(solv, -(v + 1)); */
|
||||
}
|
||||
}
|
||||
|
||||
protected function addChoiceRules()
|
||||
protected function setupInstalledMap()
|
||||
{
|
||||
|
||||
// void
|
||||
// solver_addchoicerules(Solver *solv)
|
||||
// {
|
||||
// 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']);
|
||||
}
|
||||
$this->installedMap = array();
|
||||
foreach ($this->installed->getPackages() as $package) {
|
||||
$this->installedMap[$package->getId()] = $package;
|
||||
}
|
||||
}
|
||||
|
||||
public function solve(Request $request)
|
||||
{
|
||||
$this->jobs = $request->getJobs();
|
||||
$installedPackages = $this->installed->getPackages();
|
||||
$this->installedMap = array();
|
||||
foreach ($installedPackages as $package) {
|
||||
$this->installedMap[$package->getId()] = $package;
|
||||
}
|
||||
|
||||
$this->setupInstalledMap();
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.3.4', '>=')) {
|
||||
$this->decisionMap = new \SplFixedArray($this->pool->getMaxId() + 1);
|
||||
|
@ -876,18 +524,18 @@ class Solver
|
|||
|
||||
switch ($job['cmd']) {
|
||||
case 'update-all':
|
||||
foreach ($installedPackages as $package) {
|
||||
foreach ($this->installedMap as $package) {
|
||||
$this->updateMap[$package->getId()] = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($installedPackages as $package) {
|
||||
foreach ($this->installedMap as $package) {
|
||||
$this->addRulesForPackage($package);
|
||||
}
|
||||
|
||||
foreach ($installedPackages as $package) {
|
||||
foreach ($this->installedMap as $package) {
|
||||
$this->addRulesForUpdatePackages($package);
|
||||
}
|
||||
|
||||
|
@ -903,15 +551,11 @@ class Solver
|
|||
}
|
||||
}
|
||||
|
||||
// solver_addrpmrulesforweak(solv, &addedmap);
|
||||
|
||||
foreach ($installedPackages as $package) {
|
||||
foreach ($this->installedMap as $package) {
|
||||
$updates = $this->policy->findUpdatePackages($this, $this->pool, $this->installedMap, $package);
|
||||
$rule = $this->createUpdateRule($package, $updates, Rule::RULE_INTERNAL_ALLOW_UPDATE, (string) $package);
|
||||
|
||||
$rule->setWeak(true);
|
||||
$this->addRule(RuleSet::TYPE_FEATURE, $rule);
|
||||
$this->packageToFeatureRule[$package->getId()] = $rule;
|
||||
$this->packageToUpdateRule[$package->getId()] = $rule;
|
||||
}
|
||||
|
||||
foreach ($this->jobs as $job) {
|
||||
|
@ -952,23 +596,15 @@ class Solver
|
|||
}
|
||||
}
|
||||
|
||||
$this->addChoiceRules();
|
||||
|
||||
foreach ($this->rules as $rule) {
|
||||
$this->addWatchesToRule($rule);
|
||||
}
|
||||
|
||||
/* disable update rules that conflict with our job */
|
||||
$this->disablePolicyRules();
|
||||
|
||||
/* make decisions based on job/update assertions */
|
||||
$this->makeAssertionRuleDecisions();
|
||||
|
||||
$installRecommended = 0;
|
||||
$this->runSat(true, $installRecommended);
|
||||
//$this->printDecisionMap();
|
||||
//findrecommendedsuggested(solv);
|
||||
//solver_prepare_solutions(solv);
|
||||
|
||||
if ($this->problems) {
|
||||
throw new SolverProblemsException($this->problems);
|
||||
|
@ -989,8 +625,8 @@ class Solver
|
|||
if (!$literal->isWanted() && isset($this->installedMap[$package->getId()])) {
|
||||
$literals = array();
|
||||
|
||||
if (isset($this->packageToFeatureRule[$package->getId()])) {
|
||||
$literals = array_merge($literals, $this->packageToFeatureRule[$package->getId()]->getLiterals());
|
||||
if (isset($this->packageToUpdateRule[$package->getId()])) {
|
||||
$literals = array_merge($literals, $this->packageToUpdateRule[$package->getId()]->getLiterals());
|
||||
}
|
||||
|
||||
foreach ($literals as $updateLiteral) {
|
||||
|
@ -1032,17 +668,20 @@ class Solver
|
|||
}
|
||||
}
|
||||
|
||||
return array_reverse($transaction);
|
||||
foreach ($this->decisionMap as $packageId => $decision) {
|
||||
if ($packageId === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
protected $decisionQueue = array();
|
||||
protected $decisionQueueWhy = array();
|
||||
protected $decisionQueueFree = array();
|
||||
protected $propagateIndex;
|
||||
protected $branches = array();
|
||||
protected $problems = array();
|
||||
protected $learnedPool = array();
|
||||
protected $recommendsIndex;
|
||||
if (0 == $decision && isset($this->installedMap[$packageId])) {
|
||||
$transaction[] = new Operation\UninstallOperation(
|
||||
$this->pool->packageById($packageId), null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return array_reverse($transaction);
|
||||
}
|
||||
|
||||
protected function literalFromId($id)
|
||||
{
|
||||
|
@ -1536,17 +1175,7 @@ class Solver
|
|||
$why = $lastWeakWhy;
|
||||
}
|
||||
|
||||
if ($lastWeakWhy->getType() == RuleSet::TYPE_CHOICE) {
|
||||
$this->disableChoiceRules($lastWeakWhy);
|
||||
}
|
||||
|
||||
$this->disableProblem($why);
|
||||
|
||||
/**
|
||||
@TODO what does v < 0 mean here? ($why == v)
|
||||
if (v < 0)
|
||||
solver_reenablepolicyrules(solv, -(v + 1));
|
||||
*/
|
||||
$this->resetSolver();
|
||||
|
||||
return true;
|
||||
|
@ -1637,9 +1266,7 @@ class Solver
|
|||
// * here's the main loop:
|
||||
// * 1) propagate new decisions (only needed once)
|
||||
// * 2) fulfill jobs
|
||||
// * 3) try to keep installed packages
|
||||
// * 4) fulfill all unresolved rules
|
||||
// * 5) install recommended packages
|
||||
// * 6) minimalize solution if we had choices
|
||||
// * if we encounter a problem, we rewind to a safe level and restart
|
||||
// * with step 1
|
||||
|
@ -1654,8 +1281,6 @@ class Solver
|
|||
$minimizationSteps = 0;
|
||||
$installedPos = 0;
|
||||
|
||||
$this->installedPackages = $this->installed->getPackages();
|
||||
|
||||
while (true) {
|
||||
|
||||
if (1 === $level) {
|
||||
|
@ -1727,125 +1352,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) {
|
||||
$systemLevel = $level;
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ class FileDownloader implements DownloaderInterface
|
|||
|
||||
$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);
|
||||
|
||||
|
@ -101,6 +101,7 @@ class FileDownloader implements DownloaderInterface
|
|||
*/
|
||||
public function remove(PackageInterface $package, $path)
|
||||
{
|
||||
$this->io->write(" - Removing <info>" . $package->getName() . "</info> (<comment>" . $package->getPrettyVersion() . "</comment>)");
|
||||
if (!$this->filesystem->removeDirectory($path)) {
|
||||
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');
|
||||
}
|
||||
|
||||
$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->doDownload($package, $path);
|
||||
$this->io->write('');
|
||||
|
@ -65,7 +65,7 @@ abstract class VcsDownloader implements DownloaderInterface
|
|||
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->doUpdate($initial, $target, $path);
|
||||
$this->io->write('');
|
||||
|
@ -77,6 +77,7 @@ abstract class VcsDownloader implements DownloaderInterface
|
|||
public function remove(PackageInterface $package, $path)
|
||||
{
|
||||
$this->enforceCleanDirectory($path);
|
||||
$this->io->write(" - Removing <info>" . $package->getName() . "</info> (<comment>" . $package->getPrettyVersion() . "</comment>)");
|
||||
if (!$this->filesystem->removeDirectory($path)) {
|
||||
throw new \RuntimeException('Could not completely delete '.$path.', aborting.');
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
if ($package->getRepository() === $localRepo || $package->getRepository() instanceof PlatformRepository) {
|
||||
if ($package->getRepository() === $localRepo) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -127,6 +127,13 @@ class LibraryInstaller implements InstallerInterface
|
|||
$this->downloadManager->remove($package, $downloadPath);
|
||||
$this->removeBinaries($package);
|
||||
$repo->removePackage($package);
|
||||
|
||||
if (strpos($package->getName(), '/')) {
|
||||
$packageVendorDir = dirname($downloadPath);
|
||||
if (is_dir($packageVendorDir) && !glob($packageVendorDir.'/*')) {
|
||||
@rmdir($packageVendorDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,7 +27,7 @@ class ResultSetIteratorTest extends \PHPUnit_Framework_TestCase
|
|||
new Rule(array(), 'job1', null),
|
||||
new Rule(array(), 'job2', null),
|
||||
),
|
||||
RuleSet::TYPE_FEATURE => array(
|
||||
RuleSet::TYPE_LEARNED => array(
|
||||
new Rule(array(), 'update1', null),
|
||||
),
|
||||
RuleSet::TYPE_PACKAGE => array(),
|
||||
|
@ -46,7 +46,7 @@ class ResultSetIteratorTest extends \PHPUnit_Framework_TestCase
|
|||
$expected = array(
|
||||
$this->rules[RuleSet::TYPE_JOB][0],
|
||||
$this->rules[RuleSet::TYPE_JOB][1],
|
||||
$this->rules[RuleSet::TYPE_FEATURE][0],
|
||||
$this->rules[RuleSet::TYPE_LEARNED][0],
|
||||
);
|
||||
|
||||
$this->assertEquals($expected, $result);
|
||||
|
@ -64,7 +64,7 @@ class ResultSetIteratorTest extends \PHPUnit_Framework_TestCase
|
|||
$expected = array(
|
||||
RuleSet::TYPE_JOB,
|
||||
RuleSet::TYPE_JOB,
|
||||
RuleSet::TYPE_FEATURE,
|
||||
RuleSet::TYPE_LEARNED,
|
||||
);
|
||||
|
||||
$this->assertEquals($expected, $result);
|
||||
|
|
|
@ -27,17 +27,15 @@ class RuleSetTest extends TestCase
|
|||
new Rule(array(), 'job1', null),
|
||||
new Rule(array(), 'job2', null),
|
||||
),
|
||||
RuleSet::TYPE_FEATURE => array(
|
||||
RuleSet::TYPE_LEARNED => array(
|
||||
new Rule(array(), 'update1', null),
|
||||
),
|
||||
RuleSet::TYPE_LEARNED => array(),
|
||||
RuleSet::TYPE_CHOICE => array(),
|
||||
);
|
||||
|
||||
$ruleSet = new RuleSet;
|
||||
|
||||
$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);
|
||||
|
||||
$this->assertEquals($rules, $ruleSet->getRules());
|
||||
|
@ -80,7 +78,7 @@ class RuleSetTest extends TestCase
|
|||
$rule1 = new Rule(array(), 'job1', null);
|
||||
$rule2 = new Rule(array(), 'job1', null);
|
||||
$ruleSet->add($rule1, RuleSet::TYPE_JOB);
|
||||
$ruleSet->add($rule2, RuleSet::TYPE_FEATURE);
|
||||
$ruleSet->add($rule2, RuleSet::TYPE_LEARNED);
|
||||
|
||||
$iterator = $ruleSet->getIterator();
|
||||
|
||||
|
@ -96,9 +94,9 @@ class RuleSetTest extends TestCase
|
|||
$rule2 = new Rule(array(), 'job1', null);
|
||||
|
||||
$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());
|
||||
}
|
||||
|
@ -110,7 +108,7 @@ class RuleSetTest extends TestCase
|
|||
$rule2 = new Rule(array(), 'job1', null);
|
||||
|
||||
$ruleSet->add($rule1, RuleSet::TYPE_JOB);
|
||||
$ruleSet->add($rule2, RuleSet::TYPE_FEATURE);
|
||||
$ruleSet->add($rule2, RuleSet::TYPE_LEARNED);
|
||||
|
||||
$iterator = $ruleSet->getIteratorWithout(RuleSet::TYPE_JOB);
|
||||
|
||||
|
@ -142,7 +140,7 @@ class RuleSetTest extends TestCase
|
|||
->method('equal')
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$ruleSet->add($rule, RuleSet::TYPE_FEATURE);
|
||||
$ruleSet->add($rule, RuleSet::TYPE_LEARNED);
|
||||
|
||||
$this->assertTrue($ruleSet->containsEqual($rule));
|
||||
$this->assertFalse($ruleSet->containsEqual($rule2));
|
||||
|
@ -155,9 +153,9 @@ class RuleSetTest extends TestCase
|
|||
$literal = new Literal($this->getPackage('foo', '2.1'), true);
|
||||
$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()
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
$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->reposComplete();
|
||||
|
||||
$this->request->install('A');
|
||||
$this->request->update('A');
|
||||
|
||||
$this->checkSolverResult(array(
|
||||
|
@ -191,6 +202,7 @@ class SolverTest extends TestCase
|
|||
$this->repo->addPackage($newPackageB = $this->getPackage('B', '1.1'));
|
||||
|
||||
$packageA->setRequires(array(new Link('A', 'B', null, 'requires')));
|
||||
$newPackageA->setRequires(array(new Link('A', 'B', null, 'requires')));
|
||||
|
||||
$this->reposComplete();
|
||||
|
||||
|
@ -209,6 +221,7 @@ class SolverTest extends TestCase
|
|||
$this->repo->addPackage($this->getPackage('A', '1.0'));
|
||||
$this->reposComplete();
|
||||
|
||||
$this->request->install('A');
|
||||
$this->request->update('A');
|
||||
|
||||
$this->checkSolverResult(array());
|
||||
|
@ -223,6 +236,8 @@ class SolverTest extends TestCase
|
|||
|
||||
$this->reposComplete();
|
||||
|
||||
$this->request->install('A');
|
||||
$this->request->install('B');
|
||||
$this->request->update('A');
|
||||
|
||||
$this->checkSolverResult(array(
|
||||
|
@ -267,7 +282,7 @@ class SolverTest extends TestCase
|
|||
public function testSolverUpdateFullyConstrainedPrunesInstalledPackages()
|
||||
{
|
||||
$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($this->getPackage('A', '2.0'));
|
||||
$this->reposComplete();
|
||||
|
@ -275,7 +290,12 @@ class SolverTest extends TestCase
|
|||
$this->request->install('A', $this->getVersionConstraint('<', '2.0.0.0'));
|
||||
$this->request->update('A', $this->getVersionConstraint('=', '1.0.0.0'));
|
||||
|
||||
$this->checkSolverResult(array(array(
|
||||
$this->checkSolverResult(array(
|
||||
array(
|
||||
'job' => 'remove',
|
||||
'package' => $packageB,
|
||||
),
|
||||
array(
|
||||
'job' => 'update',
|
||||
'from' => $packageA,
|
||||
'to' => $newPackageA,
|
||||
|
@ -297,6 +317,7 @@ class SolverTest extends TestCase
|
|||
$this->reposComplete();
|
||||
|
||||
$this->request->install('A');
|
||||
$this->request->install('C');
|
||||
$this->request->update('C');
|
||||
$this->request->remove('D');
|
||||
|
||||
|
|
Loading…
Reference in New Issue