diff options
Diffstat (limited to 'apt-pkg/solver3.cc')
| -rw-r--r-- | apt-pkg/solver3.cc | 132 |
1 files changed, 26 insertions, 106 deletions
diff --git a/apt-pkg/solver3.cc b/apt-pkg/solver3.cc index d363cdee7..2d9e92c99 100644 --- a/apt-pkg/solver3.cc +++ b/apt-pkg/solver3.cc @@ -383,8 +383,25 @@ bool APT::Solver::Propagate() if (not AddWork(Work{clause.get(), depth()})) return false; } - else if ((*this)[var].decision == Decision::MUSTNOT && not PropagateReject(var)) - return false; + else if ((*this)[var].decision == Decision::MUSTNOT) + { + for (auto rclause : (*this)[var].rclauses) + { + if (rclause->negative || rclause->reason.empty() || rclause->optional || + std::any_of(rclause->solutions.begin(), rclause->solutions.end(), [this](auto var) + { return (*this)[var].decision != Decision::MUSTNOT; })) + continue; + + if ((*this)[rclause->reason].decision == Decision::MUSTNOT) + continue; + + if (unlikely(debug >= 3)) + std::cerr << "Propagate NOT " << var.toString(cache) << " to " << rclause->reason.toString(cache) << " for dep " << const_cast<Clause *>(rclause)->toString(cache) << std::endl; + + if (not Enqueue(rclause->reason, false, var)) // Last version invalidated + return false; + } + } } return true; } @@ -393,6 +410,9 @@ void APT::Solver::RegisterClause(Clause &&clause) { auto &clauses = (*this)[clause.reason].clauses; clauses.push_back(std::make_unique<Clause>(std::move(clause))); + auto const &inserted = clauses.back(); + for (auto var : inserted->solutions) + (*this)[var].rclauses.push_back(inserted.get()); } void APT::Solver::Discover(Var var) @@ -460,43 +480,6 @@ void APT::Solver::Discover(Var var) } } -bool APT::Solver::PropagateReject(Var var) -{ - if (auto Pkg = var.Pkg(cache); not Pkg.end()) - { - for (auto ver = Pkg.VersionList(); not ver.end(); ver++) - if (not Enqueue(Var(ver), false, Var(Pkg))) - return false; - } - else if (auto Ver = var.Ver(cache); not Ver.end()) - { - if (auto pkg = Ver.ParentPkg(); (*this)[pkg].decision != Decision::MUSTNOT) - { - bool anyInstallable = false; - for (auto otherVer = pkg.VersionList(); not otherVer.end(); otherVer++) - if (otherVer->ID != Ver->ID && (*this)[otherVer].decision != Decision::MUSTNOT) - anyInstallable = true; - - if (anyInstallable) - ; - else if ((*this)[pkg].decision == Decision::MUST) // Must install, but none available - { - _error->Error("Conflict: %s but no versions are installable", - WhyStr(Var(pkg)).c_str()); - for (auto otherVer = pkg.VersionList(); not otherVer.end(); otherVer++) - if ((*this)[otherVer].decision == Decision::MUSTNOT) - _error->Error("Uninstallable version: %s", WhyStr(Var(otherVer)).c_str()); - return _error->Error("Uninstallable version: %s", WhyStr(Var(Ver)).c_str()); - } - else if (not Enqueue(Var(Ver.ParentPkg()), false, Var(Ver))) // Last version invalidated - return false; - } - if (not RejectReverseDependencies(Ver)) - return false; - } - return true; -} - void APT::Solver::RegisterCommonDependencies(pkgCache::PkgIterator Pkg) { for (auto dep = Pkg.VersionList().DependsList(); not dep.end();) @@ -618,73 +601,6 @@ APT::Solver::Clause APT::Solver::TranslateOrGroup(pkgCache::DepIterator start, p return clause; } -// \brief Find the or group containing the given dependency. -static void FindOrGroup(pkgCache::DepIterator const &D, pkgCache::DepIterator &start, pkgCache::DepIterator &end) -{ - for (auto dep = D.ParentVer().DependsList(); not dep.end();) - { - dep.GlobOr(start, end); // advances dep - - for (auto member = start;;) - { - if (member == D) - return; - if (member == end) - break; - member++; - } - } - - _error->Fatal("Found a dependency that does not exist in its parent version"); - abort(); -} - -// This is the opposite of EnqueueOrDependencies, it rejects the reverse dependencies of the -// given version iterator. -bool APT::Solver::RejectReverseDependencies(pkgCache::VerIterator Ver) -{ - // This checks whether an or group is still satisfiable. - auto stillPossible = [this](pkgCache::DepIterator start, pkgCache::DepIterator end) - { - while (1) - { - std::unique_ptr<pkgCache::Version *[]> Ts{start.AllTargets()}; - for (size_t i = 0; Ts[i] != nullptr; ++i) - if ((*this)[Ts[i]].decision != Decision::MUSTNOT) - return true; - - if (start == end) - return false; - - start++; - } - }; - - for (auto RD = Ver.ParentPkg().RevDependsList(); not RD.end(); ++RD) - { - auto RDV = RD.ParentVer(); - if (RD.IsNegative() || not RD.IsCritical() || not RD.IsSatisfied(Ver)) - continue; - - if ((*this)[RDV].decision == Decision::MUSTNOT) - continue; - - pkgCache::DepIterator start; - pkgCache::DepIterator end; - FindOrGroup(RD, start, end); - - if (stillPossible(start, end)) - continue; - - if (unlikely(debug >= 3)) - std::cerr << "Propagate NOT " << Ver.ParentPkg().FullName() << "=" << Ver.VerStr() << " to " << RDV.ParentPkg().FullName() << "=" << RDV.VerStr() << " for dependency group starting with" << start.TargetPkg().FullName() << std::endl; - - if (not Enqueue(Var(RDV), false, Var(Ver))) - return false; - } - return true; -} - void APT::Solver::Push(Work work) { if (unlikely(debug >= 2)) @@ -1019,6 +935,10 @@ bool APT::Solver::FromDepCache(pkgDepCache &depcache) RegisterClause(std::move(shortcircuit)); if (not AddWork(Work{rootState->clauses.back().get(), depth()})) return false; + + // Discovery here is needed so the shortcircuit clause can actually become unit. + if (P.VersionList() && P.VersionList()->NextVer) + Discover(Var(P)); } } } |
