diff --git a/src/Composer/DependencyResolver/RuleSet.php b/src/Composer/DependencyResolver/RuleSet.php index 9e8ecf29b..1f444c788 100644 --- a/src/Composer/DependencyResolver/RuleSet.php +++ b/src/Composer/DependencyResolver/RuleSet.php @@ -20,12 +20,16 @@ class RuleSet implements \IteratorAggregate, \Countable // highest priority => lowest number const TYPE_PACKAGE = 0; const TYPE_JOB = 1; - const TYPE_LEARNED = 4; + const TYPE_FEATURE = 3; + const TYPE_CHOICE = 4; + const TYPE_LEARNED = 5; 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', ); diff --git a/src/Composer/DependencyResolver/Solver.php b/src/Composer/DependencyResolver/Solver.php index afa8f6996..aa014035c 100644 --- a/src/Composer/DependencyResolver/Solver.php +++ b/src/Composer/DependencyResolver/Solver.php @@ -30,21 +30,13 @@ 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 $packageToUpdateRule = array(); - - protected $decisionQueue = array(); - protected $decisionQueueWhy = array(); - protected $decisionQueueFree = array(); - protected $propagateIndex; - protected $branches = array(); - protected $problems = array(); - protected $learnedPool = array(); - protected $recommendsIndex; + protected $packageToFeatureRule = array(); public function __construct(PolicyInterface $policy, Pool $pool, RepositoryInterface $installed) { @@ -245,38 +237,50 @@ class Solver } // check obsoletes and implicit obsoletes of a package - $isInstalled = (isset($this->installedMap[$package->getId()])); + // 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) { - $obsoleteProviders = $this->pool->whatProvides($link->getTarget(), $link->getConstraint()); + foreach ($package->getReplaces() as $link) { + $obsoleteProviders = $this->pool->whatProvides($link->getTarget(), $link->getConstraint()); - foreach ($obsoleteProviders as $provider) { - if ($provider === $package) { - continue; + foreach ($obsoleteProviders as $provider) { + if ($provider === $package) { + continue; + } + + $reason = ($isInstalled) ? Rule::RULE_INSTALLED_PACKAGE_OBSOLETES : Rule::RULE_PACKAGE_OBSOLETES; + $this->addRule(RuleSet::TYPE_PACKAGE, $this->createConflictRule($package, $provider, $reason, (string) $link)); } - - $reason = ($isInstalled) ? Rule::RULE_INSTALLED_PACKAGE_OBSOLETES : Rule::RULE_PACKAGE_OBSOLETES; - $this->addRule(RuleSet::TYPE_PACKAGE, $this->createConflictRule($package, $provider, $reason, (string) $link)); } - } - // check implicit obsoletes - // for installed packages we only need to check installed/installed problems, - // as the others are picked up when looking at the uninstalled package. - if (!$isInstalled) { - $obsoleteProviders = $this->pool->whatProvides($package->getName(), null); + // check implicit obsoletes + // for installed packages we only need to check installed/installed problems, + // as the others are picked up when looking at the uninstalled package. + if (!$isInstalled) { + $obsoleteProviders = $this->pool->whatProvides($package->getName(), null); - foreach ($obsoleteProviders as $provider) { - if ($provider === $package) { - continue; + foreach ($obsoleteProviders as $provider) { + if ($provider === $package) { + continue; + } + + if ($isInstalled && !isset($this->installedMap[$provider->getId()])) { + 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)); } - - if ($isInstalled && !isset($this->installedMap[$provider->getId()])) { - 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)); } } } @@ -427,7 +431,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(RuleSet::TYPE_JOB) as $assertRule) { + foreach ($this->rules->getIteratorFor(array(RuleSet::TYPE_JOB, RuleSet::TYPE_FEATURE)) as $assertRule) { if ($assertRule->isDisabled() || !$assertRule->isAssertion() || $assertRule->isWeak()) { continue; } @@ -488,22 +492,370 @@ class Solver } $this->disableProblem($why); + /** TODO solver_reenablepolicyrules(solv, -(v + 1)); */ } } - protected function setupInstalledMap() + protected function addChoiceRules() { - $this->installedMap = array(); - foreach ($this->installed->getPackages() as $package) { - $this->installedMap[$package->getId()] = $package; + +// 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']); + } } } public function solve(Request $request) { $this->jobs = $request->getJobs(); - - $this->setupInstalledMap(); + $installedPackages = $this->installed->getPackages(); + $this->installedMap = array(); + foreach ($installedPackages as $package) { + $this->installedMap[$package->getId()] = $package; + } if (version_compare(PHP_VERSION, '5.3.4', '>=')) { $this->decisionMap = new \SplFixedArray($this->pool->getMaxId() + 1); @@ -524,18 +876,18 @@ class Solver switch ($job['cmd']) { case 'update-all': - foreach ($this->installedMap as $package) { + foreach ($installedPackages as $package) { $this->updateMap[$package->getId()] = true; } break; } } - foreach ($this->installedMap as $package) { + foreach ($installedPackages as $package) { $this->addRulesForPackage($package); } - foreach ($this->installedMap as $package) { + foreach ($installedPackages as $package) { $this->addRulesForUpdatePackages($package); } @@ -551,11 +903,15 @@ class Solver } } - foreach ($this->installedMap as $package) { + // solver_addrpmrulesforweak(solv, &addedmap); + + foreach ($installedPackages as $package) { $updates = $this->policy->findUpdatePackages($this, $this->pool, $this->installedMap, $package); $rule = $this->createUpdateRule($package, $updates, Rule::RULE_INTERNAL_ALLOW_UPDATE, (string) $package); - $this->packageToUpdateRule[$package->getId()] = $rule; + $rule->setWeak(true); + $this->addRule(RuleSet::TYPE_FEATURE, $rule); + $this->packageToFeatureRule[$package->getId()] = $rule; } foreach ($this->jobs as $job) { @@ -596,15 +952,23 @@ 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); @@ -625,8 +989,8 @@ class Solver if (!$literal->isWanted() && isset($this->installedMap[$package->getId()])) { $literals = array(); - if (isset($this->packageToUpdateRule[$package->getId()])) { - $literals = array_merge($literals, $this->packageToUpdateRule[$package->getId()]->getLiterals()); + if (isset($this->packageToFeatureRule[$package->getId()])) { + $literals = array_merge($literals, $this->packageToFeatureRule[$package->getId()]->getLiterals()); } foreach ($literals as $updateLiteral) { @@ -668,21 +1032,18 @@ class Solver } } - foreach ($this->decisionMap as $packageId => $decision) { - if ($packageId === 0) { - continue; - } - - if (0 == $decision && isset($this->installedMap[$packageId])) { - $transaction[] = new Operation\UninstallOperation( - $this->pool->packageById($packageId), null - ); - } - } - 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) { $package = $this->pool->packageById(abs($id)); @@ -1175,7 +1536,17 @@ 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; @@ -1266,7 +1637,9 @@ 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 @@ -1281,6 +1654,8 @@ class Solver $minimizationSteps = 0; $installedPos = 0; + $this->installedPackages = $this->installed->getPackages(); + while (true) { if (1 === $level) { @@ -1352,6 +1727,125 @@ 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; } diff --git a/src/Composer/Downloader/FileDownloader.php b/src/Composer/Downloader/FileDownloader.php index 3e15acf80..356934514 100644 --- a/src/Composer/Downloader/FileDownloader.php +++ b/src/Composer/Downloader/FileDownloader.php @@ -64,7 +64,7 @@ class FileDownloader implements DownloaderInterface $fileName = $this->getFileName($package, $path); - $this->io->write(" - Installing " . $package->getName() . " (" . $package->getPrettyVersion() . ")"); + $this->io->write(" - Package " . $package->getName() . " (" . $package->getPrettyVersion() . ")"); $processUrl = $this->processUrl($url); @@ -101,7 +101,6 @@ class FileDownloader implements DownloaderInterface */ public function remove(PackageInterface $package, $path) { - $this->io->write(" - Removing " . $package->getName() . " (" . $package->getPrettyVersion() . ")"); if (!$this->filesystem->removeDirectory($path)) { throw new \RuntimeException('Could not completely delete '.$path.', aborting.'); } diff --git a/src/Composer/Downloader/VcsDownloader.php b/src/Composer/Downloader/VcsDownloader.php index cacc74fc4..2d19bba40 100644 --- a/src/Composer/Downloader/VcsDownloader.php +++ b/src/Composer/Downloader/VcsDownloader.php @@ -50,7 +50,7 @@ abstract class VcsDownloader implements DownloaderInterface throw new \InvalidArgumentException('Package '.$package->getPrettyName().' is missing reference information'); } - $this->io->write(" - Installing " . $package->getName() . " (" . $package->getPrettyVersion() . ")"); + $this->io->write(" - Package " . $package->getName() . " (" . $package->getPrettyVersion() . ")"); $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(" - Installing " . $target->getName() . " (" . $target->getPrettyVersion() . ")"); + $this->io->write(" - Package " . $target->getName() . " (" . $target->getPrettyVersion() . ")"); $this->enforceCleanDirectory($path); $this->doUpdate($initial, $target, $path); $this->io->write(''); @@ -77,7 +77,6 @@ abstract class VcsDownloader implements DownloaderInterface public function remove(PackageInterface $package, $path) { $this->enforceCleanDirectory($path); - $this->io->write(" - Removing " . $package->getName() . " (" . $package->getPrettyVersion() . ")"); if (!$this->filesystem->removeDirectory($path)) { throw new \RuntimeException('Could not completely delete '.$path.', aborting.'); } diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index d7f51badb..e4219c860 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -259,11 +259,9 @@ class Installer } } - // 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) + // fix the version all installed packages that are not in the current local repo to prevent rogue updates foreach ($installedRepo->getPackages() as $package) { - if ($package->getRepository() === $localRepo) { + if ($package->getRepository() === $localRepo || $package->getRepository() instanceof PlatformRepository) { continue; } diff --git a/src/Composer/Installer/LibraryInstaller.php b/src/Composer/Installer/LibraryInstaller.php index 9be2e1d1d..0da923654 100644 --- a/src/Composer/Installer/LibraryInstaller.php +++ b/src/Composer/Installer/LibraryInstaller.php @@ -127,13 +127,6 @@ 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); - } - } } /** diff --git a/tests/Composer/Test/DependencyResolver/RuleSetIteratorTest.php b/tests/Composer/Test/DependencyResolver/RuleSetIteratorTest.php index 56084f32a..28db18131 100644 --- a/tests/Composer/Test/DependencyResolver/RuleSetIteratorTest.php +++ b/tests/Composer/Test/DependencyResolver/RuleSetIteratorTest.php @@ -27,7 +27,7 @@ class ResultSetIteratorTest extends \PHPUnit_Framework_TestCase new Rule(array(), 'job1', null), new Rule(array(), 'job2', null), ), - RuleSet::TYPE_LEARNED => array( + RuleSet::TYPE_FEATURE => 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_LEARNED][0], + $this->rules[RuleSet::TYPE_FEATURE][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_LEARNED, + RuleSet::TYPE_FEATURE, ); $this->assertEquals($expected, $result); diff --git a/tests/Composer/Test/DependencyResolver/RuleSetTest.php b/tests/Composer/Test/DependencyResolver/RuleSetTest.php index f319651ae..54ad88a58 100644 --- a/tests/Composer/Test/DependencyResolver/RuleSetTest.php +++ b/tests/Composer/Test/DependencyResolver/RuleSetTest.php @@ -27,15 +27,17 @@ class RuleSetTest extends TestCase new Rule(array(), 'job1', null), new Rule(array(), 'job2', null), ), - RuleSet::TYPE_LEARNED => array( + RuleSet::TYPE_FEATURE => 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_LEARNED][0], RuleSet::TYPE_LEARNED); + $ruleSet->add($rules[RuleSet::TYPE_FEATURE][0], RuleSet::TYPE_FEATURE); $ruleSet->add($rules[RuleSet::TYPE_JOB][1], RuleSet::TYPE_JOB); $this->assertEquals($rules, $ruleSet->getRules()); @@ -78,7 +80,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_LEARNED); + $ruleSet->add($rule2, RuleSet::TYPE_FEATURE); $iterator = $ruleSet->getIterator(); @@ -94,9 +96,9 @@ class RuleSetTest extends TestCase $rule2 = new Rule(array(), 'job1', null); $ruleSet->add($rule1, RuleSet::TYPE_JOB); - $ruleSet->add($rule2, RuleSet::TYPE_LEARNED); + $ruleSet->add($rule2, RuleSet::TYPE_FEATURE); - $iterator = $ruleSet->getIteratorFor(RuleSet::TYPE_LEARNED); + $iterator = $ruleSet->getIteratorFor(RuleSet::TYPE_FEATURE); $this->assertSame($rule2, $iterator->current()); } @@ -108,7 +110,7 @@ class RuleSetTest extends TestCase $rule2 = new Rule(array(), 'job1', null); $ruleSet->add($rule1, RuleSet::TYPE_JOB); - $ruleSet->add($rule2, RuleSet::TYPE_LEARNED); + $ruleSet->add($rule2, RuleSet::TYPE_FEATURE); $iterator = $ruleSet->getIteratorWithout(RuleSet::TYPE_JOB); @@ -140,7 +142,7 @@ class RuleSetTest extends TestCase ->method('equal') ->will($this->returnValue(false)); - $ruleSet->add($rule, RuleSet::TYPE_LEARNED); + $ruleSet->add($rule, RuleSet::TYPE_FEATURE); $this->assertTrue($ruleSet->containsEqual($rule)); $this->assertFalse($ruleSet->containsEqual($rule2)); @@ -153,9 +155,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_JOB); + $ruleSet->add($rule, RuleSet::TYPE_FEATURE); - $this->assertContains('JOB : (+foo-2.1.0.0)', $ruleSet->__toString()); + $this->assertContains('FEATURE : (+foo-2.1.0.0)', $ruleSet->__toString()); } private function getRuleMock() diff --git a/tests/Composer/Test/DependencyResolver/SolverTest.php b/tests/Composer/Test/DependencyResolver/SolverTest.php index 2bc5a928a..49355a5a4 100644 --- a/tests/Composer/Test/DependencyResolver/SolverTest.php +++ b/tests/Composer/Test/DependencyResolver/SolverTest.php @@ -54,16 +54,6 @@ 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')); @@ -186,7 +176,6 @@ 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( @@ -202,7 +191,6 @@ 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(); @@ -221,7 +209,6 @@ 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()); @@ -236,8 +223,6 @@ class SolverTest extends TestCase $this->reposComplete(); - $this->request->install('A'); - $this->request->install('B'); $this->request->update('A'); $this->checkSolverResult(array( @@ -282,7 +267,7 @@ class SolverTest extends TestCase public function testSolverUpdateFullyConstrainedPrunesInstalledPackages() { $this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0')); - $this->repoInstalled->addPackage($packageB = $this->getPackage('B', '1.0')); + $this->repoInstalled->addPackage($this->getPackage('B', '1.0')); $this->repo->addPackage($newPackageA = $this->getPackage('A', '1.2')); $this->repo->addPackage($this->getPackage('A', '2.0')); $this->reposComplete(); @@ -290,15 +275,10 @@ 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( - 'job' => 'remove', - 'package' => $packageB, - ), - array( - 'job' => 'update', - 'from' => $packageA, - 'to' => $newPackageA, + $this->checkSolverResult(array(array( + 'job' => 'update', + 'from' => $packageA, + 'to' => $newPackageA, ))); } @@ -317,7 +297,6 @@ class SolverTest extends TestCase $this->reposComplete(); $this->request->install('A'); - $this->request->install('C'); $this->request->update('C'); $this->request->remove('D');