X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/c7ed2c0e34546e12a035e4c4c2f034a6ee765748..49e1672884bf8d50713812bdd4eca26ab2076711:/apt-pkg/depcache.cc diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc index 9449c7306..2c6eb43bf 100644 --- a/apt-pkg/depcache.cc +++ b/apt-pkg/depcache.cc @@ -346,23 +346,20 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res) /* Check simple depends. A depends -should- never self match but we allow it anyhow because dpkg does. Technically it is a packaging bug. Conflicts may never self match */ - if (Dep.TargetPkg() != Dep.ParentPkg() || Dep.IsNegative() == false) + if (Dep.IsIgnorable(Res) == false) { PkgIterator Pkg = Dep.TargetPkg(); // Check the base package if (Type == NowVersion && Pkg->CurrentVer != 0) - if (VS().CheckDep(Pkg.CurrentVer().VerStr(),Dep->CompareOp, - Dep.TargetVer()) == true) + if (Dep.IsSatisfied(Pkg.CurrentVer()) == true) return true; if (Type == InstallVersion && PkgState[Pkg->ID].InstallVer != 0) - if (VS().CheckDep(PkgState[Pkg->ID].InstVerIter(*this).VerStr(), - Dep->CompareOp,Dep.TargetVer()) == true) + if (Dep.IsSatisfied(PkgState[Pkg->ID].InstVerIter(*this)) == true) return true; if (Type == CandidateVersion && PkgState[Pkg->ID].CandidateVer != 0) - if (VS().CheckDep(PkgState[Pkg->ID].CandidateVerIter(*this).VerStr(), - Dep->CompareOp,Dep.TargetVer()) == true) + if (Dep.IsSatisfied(PkgState[Pkg->ID].CandidateVerIter(*this)) == true) return true; } @@ -398,7 +395,7 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res) } // Compare the versions. - if (VS().CheckDep(P.ProvideVersion(),Dep->CompareOp,Dep.TargetVer()) == true) + if (Dep.IsSatisfied(P) == true) { Res = P.OwnerPkg(); return true; @@ -867,6 +864,11 @@ bool pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge, dpkg holds are enforced by the private IsModeChangeOk */ bool pkgDepCache::IsDeleteOk(PkgIterator const &Pkg,bool rPurge, unsigned long Depth, bool FromUser) +{ + return IsDeleteOkProtectInstallRequests(Pkg, rPurge, Depth, FromUser); +} +bool pkgDepCache::IsDeleteOkProtectInstallRequests(PkgIterator const &Pkg, + bool const rPurge, unsigned long const Depth, bool const FromUser) { if (FromUser == false && Pkg->CurrentVer == 0) { @@ -913,11 +915,15 @@ bool pkgDepCache::IsModeChangeOk(ModeList const mode, PkgIterator const &Pkg, return true; StateCache &P = PkgState[Pkg->ID]; + // not changing the mode is obviously also fine as we might want to call + // e.g. MarkInstall multiple times with different arguments for the same package + if (P.Mode == mode) + return true; // if previous state was set by user only user can reset it if ((P.iFlags & Protected) == Protected) { - if (unlikely(DebugMarker == true) && P.Mode != mode) + if (unlikely(DebugMarker == true)) std::clog << OutputInDepth(Depth) << "Ignore Mark" << PrintMode(mode) << " of " << Pkg << " as its mode (" << PrintMode(P.Mode) << ") is protected" << std::endl; @@ -927,7 +933,7 @@ bool pkgDepCache::IsModeChangeOk(ModeList const mode, PkgIterator const &Pkg, else if (mode != ModeKeep && Pkg->SelectedState == pkgCache::State::Hold && _config->FindB("APT::Ignore-Hold",false) == false) { - if (unlikely(DebugMarker == true) && P.Mode != mode) + if (unlikely(DebugMarker == true)) std::clog << OutputInDepth(Depth) << "Hold prevents Mark" << PrintMode(mode) << " of " << Pkg << std::endl; return false; @@ -947,6 +953,37 @@ struct CompareProviders { { pkgCache::PkgIterator const A = AV.ParentPkg(); pkgCache::PkgIterator const B = BV.ParentPkg(); + // Prefer MA:same packages if other architectures for it are installed + if ((AV->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same || + (BV->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same) + { + bool instA = false; + if ((AV->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same) + { + pkgCache::GrpIterator Grp = A.Group(); + for (pkgCache::PkgIterator P = Grp.PackageList(); P.end() == false; P = Grp.NextPkg(P)) + if (P->CurrentVer != 0) + { + instA = true; + break; + } + } + bool instB = false; + if ((BV->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same) + { + pkgCache::GrpIterator Grp = B.Group(); + for (pkgCache::PkgIterator P = Grp.PackageList(); P.end() == false; P = Grp.NextPkg(P)) + { + if (P->CurrentVer != 0) + { + instB = true; + break; + } + } + } + if (instA != instB) + return instA == false; + } // Prefer packages in the same group as the target; e.g. foo:i386, foo:amd64 if (A->Group != B->Group) { @@ -963,9 +1000,16 @@ struct CompareProviders { else if ((B->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential) return true; } + if ((A->Flags & pkgCache::Flag::Important) != (B->Flags & pkgCache::Flag::Important)) + { + if ((A->Flags & pkgCache::Flag::Important) == pkgCache::Flag::Important) + return false; + else if ((B->Flags & pkgCache::Flag::Important) == pkgCache::Flag::Important) + return true; + } // higher priority seems like a good idea if (AV->Priority != BV->Priority) - return AV->Priority < BV->Priority; + return AV->Priority > BV->Priority; // prefer native architecture if (strcmp(A.Arch(), B.Arch()) != 0) { @@ -1008,9 +1052,10 @@ bool pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, return true; } - // check if we are allowed to install the package - if (IsInstallOk(Pkg,AutoInst,Depth,FromUser) == false) - return false; + // check if we are allowed to install the package (if we haven't already) + if (P.Mode != ModeInstall || P.InstallVer != P.CandidateVer) + if (IsInstallOk(Pkg,AutoInst,Depth,FromUser) == false) + return false; ActionGroup group(*this); P.iFlags &= ~AutoKept; @@ -1145,59 +1190,58 @@ bool pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, } /* This bit is for processing the possibilty of an install/upgrade - fixing the problem */ - if (Start->Type != Dep::DpkgBreaks && - (DepState[Start->ID] & DepCVer) == DepCVer) + fixing the problem for "positive" dependencies */ + if (Start.IsNegative() == false && (DepState[Start->ID] & DepCVer) == DepCVer) { APT::VersionList verlist; pkgCache::VerIterator Cand = PkgState[Start.TargetPkg()->ID].CandidateVerIter(*this); - if (Cand.end() == false && VS().CheckDep(Cand.VerStr(), Start->CompareOp, Start.TargetVer()) == true) + if (Cand.end() == false && Start.IsSatisfied(Cand) == true) verlist.insert(Cand); for (PrvIterator Prv = Start.TargetPkg().ProvidesList(); Prv.end() != true; ++Prv) { pkgCache::VerIterator V = Prv.OwnerVer(); pkgCache::VerIterator Cand = PkgState[Prv.OwnerPkg()->ID].CandidateVerIter(*this); - if (Cand.end() == true || V != Cand || - VS().CheckDep(Cand.VerStr(), Start->CompareOp, Start.TargetVer()) == false) + if (Cand.end() == true || V != Cand || Start.IsSatisfied(Prv) == false) continue; verlist.insert(Cand); } CompareProviders comp(Start); - APT::VersionList::iterator InstVer = std::max_element(verlist.begin(), verlist.end(), comp); - if (InstVer != verlist.end()) - { + do { + APT::VersionList::iterator InstVer = std::max_element(verlist.begin(), verlist.end(), comp); + + if (InstVer == verlist.end()) + break; + pkgCache::PkgIterator InstPkg = InstVer.ParentPkg(); if(DebugAutoInstall == true) std::clog << OutputInDepth(Depth) << "Installing " << InstPkg.Name() << " as " << Start.DepType() << " of " << Pkg.Name() << std::endl; - // now check if we should consider it a automatic dependency or not - if(Pkg.Section() && ConfigValueInSubTree("APT::Never-MarkAuto-Sections", Pkg.Section())) - { + if (MarkInstall(InstPkg, true, Depth + 1, false, ForceImportantDeps) == false) + { + verlist.erase(InstVer); + continue; + } + // now check if we should consider it a automatic dependency or not + if(InstPkg->CurrentVer == 0 && Pkg->Section != 0 && ConfigValueInSubTree("APT::Never-MarkAuto-Sections", Pkg.Section())) + { if(DebugAutoInstall == true) std::clog << OutputInDepth(Depth) << "Setting NOT as auto-installed (direct " << Start.DepType() << " of pkg in APT::Never-MarkAuto-Sections)" << std::endl; - MarkInstall(InstPkg,true,Depth + 1, true); - } - else - { - // mark automatic dependency - MarkInstall(InstPkg,true,Depth + 1, false, ForceImportantDeps); - // Set the autoflag, after MarkInstall because MarkInstall unsets it - if (InstPkg->CurrentVer == 0) - PkgState[InstPkg->ID].Flags |= Flag::Auto; - } - } + MarkAuto(InstPkg, false); + } + break; + } while(true); continue; } - - /* For conflicts we just de-install the package and mark as auto, - Conflicts may not have or groups. For dpkg's Breaks we try to - upgrade the package. */ - if (Start.IsNegative() == true) + /* Negative dependencies have no or-group + If the dependency isn't versioned, we try if an upgrade might solve the problem. + Otherwise we remove the offender if needed */ + else if (Start.IsNegative() == true && Start->Type != pkgCache::Dep::Obsoletes) { SPtrArray List = Start.AllTargets(); + pkgCache::PkgIterator TrgPkg = Start.TargetPkg(); for (Version **I = List; *I != 0; I++) { VerIterator Ver(*this,*I); @@ -1208,15 +1252,24 @@ bool pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, if (PkgState[Pkg->ID].InstallVer == 0) continue; - if (PkgState[Pkg->ID].CandidateVer != *I && - Start->Type == Dep::DpkgBreaks && + if ((Start->Version != 0 || TrgPkg != Pkg) && + PkgState[Pkg->ID].CandidateVer != PkgState[Pkg->ID].InstallVer && + PkgState[Pkg->ID].CandidateVer != *I && MarkInstall(Pkg,true,Depth + 1, false, ForceImportantDeps) == true) continue; - else if (MarkDelete(Pkg,false,Depth + 1, false) == false) - break; + else if (Start->Type == pkgCache::Dep::Conflicts || + Start->Type == pkgCache::Dep::DpkgBreaks) + { + if(DebugAutoInstall == true) + std::clog << OutputInDepth(Depth) + << " Removing: " << Pkg.Name() + << std::endl; + if (MarkDelete(Pkg,false,Depth + 1, false) == false) + break; + } } continue; - } + } } return Dep.end() == true; @@ -1224,11 +1277,50 @@ bool pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, /*}}}*/ // DepCache::IsInstallOk - check if it is ok to install this package /*{{{*/ // --------------------------------------------------------------------- -/* The default implementation does nothing. +/* The default implementation checks if the installation of an M-A:same + package would lead us into a version-screw and if so forbids it. dpkg holds are enforced by the private IsModeChangeOk */ bool pkgDepCache::IsInstallOk(PkgIterator const &Pkg,bool AutoInst, unsigned long Depth, bool FromUser) { + return IsInstallOkMultiArchSameVersionSynced(Pkg,AutoInst, Depth, FromUser); +} +bool pkgDepCache::IsInstallOkMultiArchSameVersionSynced(PkgIterator const &Pkg, + bool const AutoInst, unsigned long const Depth, bool const FromUser) +{ + if (FromUser == true) // as always: user is always right + return true; + + // ignore packages with none-M-A:same candidates + VerIterator const CandVer = PkgState[Pkg->ID].CandidateVerIter(*this); + if (unlikely(CandVer.end() == true) || CandVer == Pkg.CurrentVer() || + (CandVer->MultiArch & pkgCache::Version::Same) != pkgCache::Version::Same) + return true; + + GrpIterator const Grp = Pkg.Group(); + for (PkgIterator P = Grp.PackageList(); P.end() == false; P = Grp.NextPkg(P)) + { + // not installed or version synced: fine by definition + // (simple string-compare as stuff like '1' == '0:1-0' can't happen here) + if (P->CurrentVer == 0 || strcmp(Pkg.CandVersion(), P.CandVersion()) == 0) + continue; + // packages loosing M-A:same can be out-of-sync + VerIterator CV = PkgState[P->ID].CandidateVerIter(*this); + if (unlikely(CV.end() == true) || + (CV->MultiArch & pkgCache::Version::Same) != pkgCache::Version::Same) + continue; + + // not downloadable means the package is obsolete, so allow out-of-sync + if (CV.Downloadable() == false) + continue; + + PkgState[Pkg->ID].iFlags |= AutoKept; + if (unlikely(DebugMarker == true)) + std::clog << OutputInDepth(Depth) << "Ignore MarkInstall of " << Pkg + << " as its M-A:same siblings are not version-synced" << std::endl; + return false; + } + return true; } /*}}}*/ @@ -1371,7 +1463,7 @@ bool pkgDepCache::SetCandidateRelease(pkgCache::VerIterator TargetVer, if (Cand.end() == true) continue; // check if the current candidate is enough for the versioned dependency - and installable? - if (VS().CheckDep(P.CandVersion(), Start->CompareOp, Start.TargetVer()) == true && + if (Start.IsSatisfied(Cand) == true && (VersionState(Cand.DependsList(), DepInstall, DepCandMin, DepCandPolicy) & DepCandMin) == DepCandMin) { itsFine = true; @@ -1405,7 +1497,7 @@ bool pkgDepCache::SetCandidateRelease(pkgCache::VerIterator TargetVer, V = Match.Find(D.TargetPkg()); // check if the version from this release could satisfy the dependency - if (V.end() == true || VS().CheckDep(V.VerStr(), D->CompareOp, D.TargetVer()) == false) + if (V.end() == true || D.IsSatisfied(V) == false) { if (stillOr == true) continue; @@ -1641,6 +1733,7 @@ bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc) { if(!(PkgState[p->ID].Flags & Flag::Auto) || (p->Flags & Flag::Essential) || + (p->Flags & Flag::Important) || userFunc.InRootSet(p) || // be nice even then a required package violates the policy (#583517) // and do the full mark process also for required packages @@ -1734,7 +1827,7 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg, for(VerIterator V = d.TargetPkg().VersionList(); !V.end(); ++V) { - if(_system->VS->CheckDep(V.VerStr(), d->CompareOp, d.TargetVer())) + if(d.IsSatisfied(V)) { if(debug_autoremove) { @@ -1756,8 +1849,7 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg, for(PrvIterator prv=d.TargetPkg().ProvidesList(); !prv.end(); ++prv) { - if(_system->VS->CheckDep(prv.ProvideVersion(), d->CompareOp, - d.TargetVer())) + if(d.IsSatisfied(prv)) { if(debug_autoremove) {