summaryrefslogtreecommitdiffstats
path: root/apt-pkg
diff options
context:
space:
mode:
Diffstat (limited to 'apt-pkg')
-rw-r--r--apt-pkg/deb/deblistparser.cc85
-rw-r--r--apt-pkg/depcache.cc19
-rw-r--r--apt-pkg/edsp.cc23
-rw-r--r--apt-pkg/pkgcachegen.cc4
-rw-r--r--apt-pkg/solver3.cc100
5 files changed, 149 insertions, 82 deletions
diff --git a/apt-pkg/deb/deblistparser.cc b/apt-pkg/deb/deblistparser.cc
index 9177d54..13e8fd0 100644
--- a/apt-pkg/deb/deblistparser.cc
+++ b/apt-pkg/deb/deblistparser.cc
@@ -635,63 +635,60 @@ const char *debListParser::ParseDepends(const char *Start, const char *Stop,
// Skip whitespace
for (;I != Stop && isspace_ascii(*I) != 0; I++);
- if (unlikely(ParseArchFlags == true))
+ // Parse architecture restrictions
+ if (ParseArchFlags && I != Stop && *I == '[')
{
+ for (++I; I != Stop && isspace_ascii(*I) != 0 && *I != ']'; ++I);
+ // malformed
+ if (unlikely(I == Stop || *I == ']'))
+ return 0;
+
APT::CacheFilter::PackageArchitectureMatchesSpecification matchesArch(Arch, false);
- // Parse an architecture
- if (I != Stop && *I == '[')
+ bool Found = false;
+ bool NegArch = false;
+ while (I < Stop && *I != ']')
{
- ++I;
- // malformed
- if (unlikely(I == Stop))
- return 0;
-
+ // look for whitespace or ending ']' to end current Arch
const char *End = I;
- bool Found = false;
- bool NegArch = false;
- while (I != Stop)
- {
- // look for whitespace or ending ']'
- for (;End != Stop && !isspace_ascii(*End) && *End != ']'; ++End);
-
- if (unlikely(End == Stop))
- return 0;
-
- if (*I == '!')
- {
- NegArch = true;
- ++I;
- }
-
- std::string const arch(I, End);
- if (arch.empty() == false && matchesArch(arch.c_str()) == true)
- {
- Found = true;
- if (I[-1] != '!')
- NegArch = false;
- // we found a match, so fast-forward to the end of the wildcards
- for (; End != Stop && *End != ']'; ++End);
- }
+ for (;End < Stop && isspace_ascii(*End) == 0 && *End != ']'; ++End);
- if (*End++ == ']') {
- I = End;
- break;
- }
+ if (unlikely(End >= Stop))
+ return 0;
- I = End;
- for (;I != Stop && isspace_ascii(*I) != 0; I++);
+ bool CurNegArch = false;
+ if (*I == '!')
+ {
+ NegArch = true;
+ CurNegArch = true;
+ ++I;
}
- if (NegArch == true)
- Found = !Found;
+ if (I >= End)
+ return 0;
+ std::string const arch(I, End);
+ if (matchesArch(arch.c_str()))
+ {
+ Found = true;
+ if (not CurNegArch)
+ NegArch = false;
+ // we found a match, so fast-forward to the end of the wildcards
+ for (; End < Stop && *End != ']'; ++End);
+ }
+ else
+ for (; End < Stop && isspace_ascii(*End) != 0; ++End);
- if (Found == false)
- Package = ""; /* not for this arch */
+ I = End;
}
+ if (NegArch == true)
+ Found = not Found;
+
+ if (Found == false)
+ Package = ""; /* not for this arch */
+
// Skip whitespace
- for (;I != Stop && isspace_ascii(*I) != 0; I++);
+ for (++I; I < Stop && isspace_ascii(*I) != 0; ++I);
}
if (unlikely(ParseRestrictionsList == true))
diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc
index 72cbf8d..4e8f522 100644
--- a/apt-pkg/depcache.cc
+++ b/apt-pkg/depcache.cc
@@ -2455,6 +2455,25 @@ static bool MarkPackage(pkgCache::PkgIterator const &Pkg,
if (not unsatisfied_choice)
fullyExplored[T->ID] = true;
+
+ // do not follow newly installed providers if we have already installed providers
+ if (providers_by_source.size() >= 2)
+ {
+ if (std::any_of(providers_by_source.begin(), providers_by_source.end(), [](auto const PV) {
+ return std::any_of(PV.second.begin(), PV.second.end(), [](auto const &Prv) {
+ auto const PP = Prv.ParentPkg();
+ return not PP.end() && PP->CurrentVer != 0;
+ });}))
+ {
+ for (auto &providers : providers_by_source)
+ providers.second.erase(std::remove_if(providers.second.begin(), providers.second.end(),
+ [](auto const &Prv) {
+ auto const PP = Prv.ParentPkg();
+ return not PP.end() && PP->CurrentVer == 0;
+ }), providers.second.end());
+ }
+ }
+
for (auto const &providers : providers_by_source)
{
for (auto const &PV : providers.second)
diff --git a/apt-pkg/edsp.cc b/apt-pkg/edsp.cc
index 5894008..0ffde46 100644
--- a/apt-pkg/edsp.cc
+++ b/apt-pkg/edsp.cc
@@ -770,13 +770,22 @@ bool EDSP::ResolveExternal(const char* const solver, pkgDepCache &Cache,
{
APT::Solver s(Cache.GetCache(), Cache.GetPolicy());
FileFd output;
- if (not s.FromDepCache(Cache))
- return false;
- if (not s.Solve())
- return false;
- if (not s.ToDepCache(Cache))
- return false;
- return true;
+ bool res = true;
+ if (Progress != NULL)
+ Progress->OverallProgress(0, 100, 1, _config->FindB("APT::Solver::Upgrade") ? _("Calculating upgrade") : _("Solving dependencies"));
+ if (res && not s.FromDepCache(Cache))
+ res = false;
+ if (Progress != NULL)
+ Progress->Progress(10);
+ if (res && not s.Solve())
+ res = false;
+ if (Progress != NULL)
+ Progress->Progress(90);
+ if (res && not s.ToDepCache(Cache))
+ res = false;
+ if (Progress != NULL)
+ Progress->Done();
+ return res;
}
if (strcmp(solver, "internal") == 0)
{
diff --git a/apt-pkg/pkgcachegen.cc b/apt-pkg/pkgcachegen.cc
index 5047561..981d360 100644
--- a/apt-pkg/pkgcachegen.cc
+++ b/apt-pkg/pkgcachegen.cc
@@ -1637,6 +1637,10 @@ static DynamicMMap* CreateDynamicMMap(FileFd * const CacheF, unsigned long Flags
static bool writeBackMMapToFile(pkgCacheGenerator * const Gen, DynamicMMap * const Map,
std::string const &FileName)
{
+ // Do not write the file back to /dev/null or try to change its mode...
+ if (FileName == "/dev/null")
+ return true;
+
FileFd SCacheF(FileName, FileFd::WriteAtomic);
if (SCacheF.IsOpen() == false || SCacheF.Failed())
return false;
diff --git a/apt-pkg/solver3.cc b/apt-pkg/solver3.cc
index d43bd5b..9831f7e 100644
--- a/apt-pkg/solver3.cc
+++ b/apt-pkg/solver3.cc
@@ -46,8 +46,15 @@ struct CompareProviders3 /*{{{*/
{
if (AV == BV)
return false;
- if (not upgrade && A->CurrentVer != 0 && A.CurrentVer() == AV)
- return true;
+ // The current version should win, unless we are upgrading and the other is the
+ // candidate.
+ // If AV is the current version, AV only wins on upgrades if BV is not the candidate.
+ if (A.CurrentVer() == AV)
+ return upgrade ? Policy.GetCandidateVer(A) != BV : true;
+ // If BV is the current version, AV only wins on upgrades if it is the candidate.
+ if (A.CurrentVer() == BV)
+ return upgrade ? Policy.GetCandidateVer(A) == AV : false;
+ // If neither are the current version, order them by priority.
if (Policy.GetPriority(AV) < Policy.GetPriority(BV))
return false;
@@ -182,6 +189,8 @@ bool APT::Solver::Work::operator<(APT::Solver::Work const &b) const
return std::any_of(solutions.begin(), solutions.end(), [b](auto sol) -> bool
{ return std::find(b.solutions.begin(), b.solutions.end(), sol) != b.solutions.end(); });
}
+ if (optional && b.optional && reason.empty() != b.reason.empty())
+ return reason.empty();
// An optional item is less important than a required one.
if (optional != b.optional)
return optional;
@@ -281,7 +290,7 @@ bool APT::Solver::Install(pkgCache::PkgIterator Pkg, Reason reason)
for (auto ver = Pkg.VersionList(); not ver.end(); ver++)
if (IsAllowedVersion(ver))
workItem.solutions.push_back(ver);
- std::sort(workItem.solutions.begin(), workItem.solutions.end(), CompareProviders3{cache, policy, Pkg});
+ std::stable_sort(workItem.solutions.begin(), workItem.solutions.end(), CompareProviders3{cache, policy, Pkg});
assert(workItem.solutions.size() > 0);
if (workItem.solutions.size() > 1 || workItem.optional)
@@ -341,8 +350,6 @@ bool APT::Solver::Install(pkgCache::VerIterator Ver, Reason reason)
pkgCache::DepIterator end;
dep.GlobOr(start, end); // advances dep
- if (not policy.IsImportantDep(start))
- continue;
if (not EnqueueOrGroup(start, end, Reason(Ver)))
return false;
}
@@ -445,8 +452,6 @@ bool APT::Solver::EnqueueCommonDependencies(pkgCache::PkgIterator Pkg)
}
if (not allHaveDep)
continue;
- if (not policy.IsImportantDep(start))
- continue;
if (not EnqueueOrGroup(start, end, Reason(Pkg)))
return false;
}
@@ -460,6 +465,11 @@ bool APT::Solver::EnqueueOrGroup(pkgCache::DepIterator start, pkgCache::DepItera
auto Ver = start.ParentVer();
auto fixPolicy = _config->FindB("APT::Get::Fix-Policy-Broken");
+ // Non-important dependencies can only be installed if they are currently satisfied, see the check further
+ // below once we have calculated all possible solutions.
+ if (start.ParentPkg()->CurrentVer == 0 && not policy.IsImportantDep(start))
+ return true;
+
if (unlikely(debug >= 3))
std::cerr << "Found dependency critical " << Ver.ParentPkg().FullName() << "=" << Ver.VerStr() << " -> " << start.TargetPkg().FullName() << "\n";
@@ -496,7 +506,7 @@ bool APT::Solver::EnqueueOrGroup(pkgCache::DepIterator start, pkgCache::DepItera
// FIXME: This is not really true, though, we should fix the CompareProviders to ignore the
// installed state
if (fixPolicy)
- std::sort(workItem.solutions.begin() + begin, workItem.solutions.end(), CompareProviders3{cache, policy, TgtPkg});
+ std::stable_sort(workItem.solutions.begin() + begin, workItem.solutions.end(), CompareProviders3{cache, policy, TgtPkg});
if (start == end)
break;
@@ -504,34 +514,59 @@ bool APT::Solver::EnqueueOrGroup(pkgCache::DepIterator start, pkgCache::DepItera
} while (1);
if (not fixPolicy)
- std::sort(workItem.solutions.begin(), workItem.solutions.end(), CompareProviders3{cache, policy, TgtPkg});
-
- // Figure out if the reason is installed
- bool reasonInstalled = false;
- if (auto p = workItem.reason.Pkg())
- reasonInstalled = pkgCache::PkgIterator(cache, cache.PkgP + p)->CurrentVer != 0;
- else if (auto v = workItem.reason.Ver())
- reasonInstalled = pkgCache::VerIterator(cache, cache.VerP + v).ParentPkg()->CurrentVer != 0;
+ std::stable_sort(workItem.solutions.begin(), workItem.solutions.end(), CompareProviders3{cache, policy, TgtPkg});
// Try to perserve satisfied Recommends. FIXME: We should check if the Recommends was there in the installed version?
- if (workItem.optional && reasonInstalled && not fixPolicy &&
- not std::any_of(workItem.solutions.begin(), workItem.solutions.end(), [this](auto ver)
- { return pkgCache::VerIterator(cache, ver).ParentPkg()->CurrentVer != 0; }))
+ if (workItem.optional && start.ParentPkg()->CurrentVer)
{
- if (unlikely(debug >= 3))
+ bool important = policy.IsImportantDep(start);
+ bool newOptional = true;
+ bool wasImportant = false;
+ for (auto D = start.ParentPkg().CurrentVer().DependsList(); not D.end(); D++)
+ if (not D.IsCritical() && not D.IsNegative() && D.TargetPkg() == start.TargetPkg())
+ newOptional = false, wasImportant = policy.IsImportantDep(D);
+
+ bool satisfied = std::any_of(workItem.solutions.begin(), workItem.solutions.end(), [this](auto ver)
+ { return pkgCache::VerIterator(cache, ver).ParentPkg()->CurrentVer != 0; });
+
+ if (important && wasImportant && not newOptional && not satisfied)
{
- std::cerr << "Ignoring currently unsatisfied Recommends ";
- workItem.Dump(cache);
- std::cerr << "\n";
+ if (unlikely(debug >= 3))
+ {
+ std::cerr << "Ignoring unsatisfied Recommends ";
+ workItem.Dump(cache);
+ std::cerr << "\n";
+ }
+ return true;
+ }
+ if (not important && not wasImportant && not newOptional && satisfied)
+ {
+ if (unlikely(debug >= 3))
+ {
+ std::cerr << "Promoting satisfied Suggests to Recommends: ";
+ workItem.Dump(cache);
+ std::cerr << "\n";
+ }
+ important = true;
+ }
+ if (not important)
+ {
+ if (unlikely(debug >= 3))
+ {
+ std::cerr << "Ignoring Suggests ";
+ workItem.Dump(cache);
+ std::cerr << "\n";
+ }
+ return true;
}
- return true;
}
+
if (not workItem.solutions.empty())
{
- // std::sort(workItem.solutions.begin(), workItem.solutions.end(), CompareProviders3{cache, TgtPkg});
+ // std::stable_sort(workItem.solutions.begin(), workItem.solutions.end(), CompareProviders3{cache, TgtPkg});
if (unlikely(debug >= 3 && workItem.optional))
{
- std::cerr << "Enqueuing currently satisfied Recommends ";
+ std::cerr << "Enqueuing Recommends ";
workItem.Dump(cache);
std::cerr << "\n";
}
@@ -675,7 +710,7 @@ bool APT::Solver::Pop()
if (w.depth > depth) // Deeper decision level is no longer valid.
return true;
// This item is still solved, keep it on the solved list.
- if (not std::any_of(w.solutions.begin(), w.solutions.end(), [this](auto ver)
+ if (std::any_of(w.solutions.begin(), w.solutions.end(), [this](auto ver)
{ return (*this)[ver].decision == Decision::MUST; }))
return false;
// We are not longer solved, move it back to work.
@@ -853,6 +888,7 @@ bool APT::Solver::FromDepCache(pkgDepCache &depcache)
bool KeepAuto = not _config->FindB("APT::Get::AutomaticRemove");
bool AllowRemove = _config->FindB("APT::Solver::Remove", true);
bool AllowInstall = _config->FindB("APT::Solver::Install", true);
+ bool AllowRemoveManual = _config->FindB("APT::Solver::RemoveManual", false);
DefaultRootSetFunc2 rootSet(&cache);
for (auto P = cache.PkgBegin(); not P.end(); P++)
@@ -863,6 +899,8 @@ bool APT::Solver::FromDepCache(pkgDepCache &depcache)
auto state = depcache[P];
auto maybeInstall = state.Install() || (state.Keep() && P->CurrentVer);
auto reject = state.Delete() || (depcache[P].Keep() && not P->CurrentVer && depcache[P].Protect());
+ auto isAuto = (depcache[P].Flags & pkgCache::Flag::Auto);
+ auto isOptional = isAuto || (AllowRemoveManual && not depcache[P].Protect());
if (P->SelectedState == pkgCache::State::Hold && not state.Protect())
{
if (unlikely(debug >= 1))
@@ -884,14 +922,14 @@ bool APT::Solver::FromDepCache(pkgDepCache &depcache)
if (depcache[P].Keep() ? not Install(P, {}) : not Install(depcache.GetCandidateVersion(P), {}))
return false;
}
- else if (maybeInstall && not(depcache[P].Flags & pkgCache::Flag::Auto))
+ else if (maybeInstall && not isOptional)
{
if (unlikely(debug >= 1))
std::cerr << "MANUAL " << P.FullName() << "\n";
if (depcache[P].Keep() ? not Install(P, {}) : not Install(depcache.GetCandidateVersion(P), {}))
return false;
}
- else if (maybeInstall && (KeepAuto || rootSet.InRootSet(P)) && (depcache[P].Flags & pkgCache::Flag::Auto))
+ else if (maybeInstall && isOptional && (KeepAuto || rootSet.InRootSet(P) || not isAuto))
{
auto Upgrade = depcache.GetCandidateVersion(P) != P.CurrentVer();
if (unlikely(debug >= 1))
@@ -908,7 +946,7 @@ bool APT::Solver::FromDepCache(pkgDepCache &depcache)
for (auto V = P.VersionList(); not V.end(); ++V)
if (IsAllowedVersion(V))
w.solutions.push_back(V);
- std::sort(w.solutions.begin(), w.solutions.end(), CompareProviders3{cache, policy, P});
+ std::stable_sort(w.solutions.begin(), w.solutions.end(), CompareProviders3{cache, policy, P});
AddWork(std::move(w));
}
}
@@ -949,7 +987,7 @@ bool APT::Solver::ToDepCache(pkgDepCache &depcache)
depcache[P].Marked = 1;
depcache[P].Garbage = 0;
}
- else if (P->CurrentVer)
+ else if (P->CurrentVer || depcache[P].Install())
{
depcache.MarkDelete(P, false, 0, (*this)[P].reason.empty());
depcache[P].Marked = 0;