X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/308b793694774eece8765d172b8e989d8ed29925..3c54407f8783d5e27363eabf41dbc3d031526ffe:/apt-pkg/depcache.cc diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc index 3ae5f5953..ddbd37699 100644 --- a/apt-pkg/depcache.cc +++ b/apt-pkg/depcache.cc @@ -10,6 +10,7 @@ // Include Files /*{{{*/ #include #include +#include #include #include #include @@ -166,7 +167,7 @@ bool pkgDepCache::readStateFile(OpProgress *Prog) /*{{{*/ { FileFd state_file; string const state = _config->FindFile("Dir::State::extended_states"); - if(FileExists(state)) { + if(RealFileExists(state)) { state_file.Open(state, FileFd::ReadOnly); int const file_size = state_file.Size(); if(Prog != NULL) @@ -225,9 +226,9 @@ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly) /*{{{*/ string const state = _config->FindFile("Dir::State::extended_states"); // if it does not exist, create a empty one - if(!FileExists(state)) + if(!RealFileExists(state)) { - StateFile.Open(state, FileFd::WriteEmpty); + StateFile.Open(state, FileFd::WriteAtomic); StateFile.Close(); } @@ -338,7 +339,7 @@ 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() || + if (Dep.TargetPkg() != Dep.ParentPkg() || (Dep->Type != Dep::Conflicts && Dep->Type != Dep::DpkgBreaks && Dep->Type != Dep::Obsoletes)) { PkgIterator Pkg = Dep.TargetPkg(); @@ -367,9 +368,9 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res) PkgIterator Pkg = Dep.ParentPkg(); for (; P.end() != true; P++) { - /* Provides may never be applied against the same package if it is - a conflicts. See the comment above. */ - if (P.OwnerPkg() == Pkg && + /* Provides may never be applied against the same package (or group) + if it is a conflicts. See the comment above. */ + if (P.OwnerPkg()->Group == Pkg->Group && (Dep->Type == Dep::Conflicts || Dep->Type == Dep::DpkgBreaks)) continue; @@ -1149,7 +1150,7 @@ void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge, return; if (DebugMarker == true) - std::clog << OutputInDepth(Depth) << "MarkDelete " << Pkg << " FU=" << FromUser << std::endl; + std::clog << OutputInDepth(Depth) << (rPurge ? "MarkPurge " : "MarkDelete ") << Pkg << " FU=" << FromUser << std::endl; RemoveSizes(Pkg); RemoveStates(Pkg); @@ -1167,6 +1168,15 @@ void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge, // if we remove the pseudo package, we also need to remove the "real" if (Pkg->CurrentVer != 0 && Pkg.CurrentVer().Pseudo() == true) MarkDelete(Pkg.Group().FindPkg("all"), rPurge, Depth+1, FromUser); + else if (rPurge == true && Pkg->CurrentVer == 0 && + Pkg->CurrentState != pkgCache::State::NotInstalled && + strcmp(Pkg.Arch(), "all") != 0) + { + PkgIterator const allPkg = Pkg.Group().FindPkg("all"); + if (allPkg.end() == false && allPkg->CurrentVer == 0 && + allPkg->CurrentState != pkgCache::State::NotInstalled) + MarkDelete(allPkg, rPurge, Depth+1, FromUser); + } } /*}}}*/ // DepCache::IsDeleteOk - check if it is ok to remove this package /*{{{*/ @@ -1183,6 +1193,16 @@ bool pkgDepCache::IsDeleteOk(PkgIterator const &Pkg,bool rPurge, std::clog << OutputInDepth(Depth) << "Hold prevents MarkDelete of " << Pkg << " FU=" << FromUser << std::endl; return false; } + else if (FromUser == false && Pkg->CurrentVer == 0) + { + StateCache &P = PkgState[Pkg->ID]; + if (P.InstallVer != 0 && P.Status == 2 && (P.Flags & Flag::Auto) != Flag::Auto) + { + if (DebugMarker == true) + std::clog << OutputInDepth(Depth) << "Manual install request prevents MarkDelete of " << Pkg << std::endl; + return false; + } + } return true; } /*}}}*/ @@ -1237,9 +1257,10 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, if(FromUser) { - // Set it to manual if it's a new install or cancelling the - // removal of a garbage package. - if(P.Status == 2 || (!Pkg.CurrentVer().end() && !P.Marked)) + // Set it to manual if it's a new install or already installed, + // but only if its not marked by the autoremover (aptitude depend on this behavior) + // or if we do automatic installation (aptitude never does it) + if(P.Status == 2 || (Pkg->CurrentVer != 0 && (AutoInst == true || P.Marked == false))) P.Flags &= ~Flag::Auto; } else @@ -1255,6 +1276,10 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, Update(Pkg); AddSizes(Pkg); + // always trigger the install of the all package for a pseudo package + if (P.CandidateVerIter(*Cache).Pseudo() == true) + MarkInstall(Pkg.Group().FindPkg("all"), AutoInst, Depth, FromUser, ForceImportantDeps); + if (AutoInst == false) return; @@ -1306,8 +1331,6 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, for (DepIterator D = instVer.DependsList(); D.end() != true; D++) { //FIXME: deal better with or-groups(?) - DepIterator LocalStart = D; - if(IsImportantDep(D) && !D.IsCritical() && Start.TargetPkg() == D.TargetPkg()) { @@ -1421,10 +1444,16 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, VerIterator Ver(*this,*I); PkgIterator Pkg = Ver.ParentPkg(); - if (Start->Type != Dep::DpkgBreaks) - MarkDelete(Pkg,false,Depth + 1, false); - else if (PkgState[Pkg->ID].CandidateVer != *I) + /* The List includes all packages providing this dependency, + even providers which are not installed, so skip them. */ + if (PkgState[Pkg->ID].InstallVer == 0) + continue; + + if (PkgState[Pkg->ID].CandidateVer != *I && + Start->Type == Dep::DpkgBreaks) MarkInstall(Pkg,true,Depth + 1, false, ForceImportantDeps); + else + MarkDelete(Pkg,false,Depth + 1, false); } continue; } @@ -1453,6 +1482,9 @@ bool pkgDepCache::IsInstallOk(PkgIterator const &Pkg,bool AutoInst, /* */ void pkgDepCache::SetReInstall(PkgIterator const &Pkg,bool To) { + if (unlikely(Pkg.end() == true)) + return; + ActionGroup group(*this); RemoveSizes(Pkg); @@ -1466,22 +1498,31 @@ void pkgDepCache::SetReInstall(PkgIterator const &Pkg,bool To) AddStates(Pkg); AddSizes(Pkg); + + if (unlikely(Pkg.CurrentVer().end() == true) || Pkg.CurrentVer().Pseudo() == false) + return; + + SetReInstall(Pkg.Group().FindPkg("all"), To); } /*}}}*/ // DepCache::SetCandidateVersion - Change the candidate version /*{{{*/ // --------------------------------------------------------------------- /* */ -void pkgDepCache::SetCandidateVersion(VerIterator TargetVer) +void pkgDepCache::SetCandidateVersion(VerIterator TargetVer, bool const &Pseudo) { - ActionGroup group(*this); pkgCache::PkgIterator Pkg = TargetVer.ParentPkg(); StateCache &P = PkgState[Pkg->ID]; + if (P.CandidateVer == TargetVer) + return; + + ActionGroup group(*this); + RemoveSizes(Pkg); RemoveStates(Pkg); - if (P.CandidateVer == P.InstallVer) + if (P.CandidateVer == P.InstallVer && P.Install() == true) P.InstallVer = (Version *)TargetVer; P.CandidateVer = (Version *)TargetVer; P.Update(Pkg,*this); @@ -1489,8 +1530,194 @@ void pkgDepCache::SetCandidateVersion(VerIterator TargetVer) AddStates(Pkg); Update(Pkg); AddSizes(Pkg); + + if (TargetVer.Pseudo() == false || Pseudo == false) + return; + + // the version was pseudo: set all other pseudos also + pkgCache::GrpIterator Grp = Pkg.Group(); + for (Pkg = Grp.FindPkg("any"); Pkg.end() == false; ++Pkg) + { + StateCache &P = PkgState[Pkg->ID]; + if (TargetVer.SimilarVer(P.CandidateVerIter(*this)) == true || + (P.CandidateVerIter(*this).Pseudo() == false && + strcmp(Pkg.Arch(), "all") != 0)) + continue; + + for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver) + { + if (TargetVer.SimilarVer(Ver) == false) + continue; + SetCandidateVersion(Ver, false); + break; + } + } +} + /*}}}*/ +// DepCache::SetCandidateRelease - Change the candidate version /*{{{*/ +// --------------------------------------------------------------------- +/* changes the candidate of a package and walks over all its dependencies + to check if it needs to change the candidate of the dependency, too, + to reach a installable versionstate */ +bool pkgDepCache::SetCandidateRelease(pkgCache::VerIterator TargetVer, + std::string const &TargetRel) +{ + std::list > Changed; + return SetCandidateRelease(TargetVer, TargetRel, Changed); } +bool pkgDepCache::SetCandidateRelease(pkgCache::VerIterator TargetVer, + std::string const &TargetRel, + std::list > &Changed) +{ + ActionGroup group(*this); + SetCandidateVersion(TargetVer); + + if (TargetRel == "installed" || TargetRel == "candidate") // both doesn't make sense in this context + return true; + + pkgVersionMatch Match(TargetRel, pkgVersionMatch::Release); + // save the position of the last element we will not undo - if we have to + std::list >::iterator newChanged = --(Changed.end()); + + for (pkgCache::DepIterator D = TargetVer.DependsList(); D.end() == false; ++D) + { + if (D->Type != pkgCache::Dep::PreDepends && D->Type != pkgCache::Dep::Depends && + ((D->Type != pkgCache::Dep::Recommends && D->Type != pkgCache::Dep::Suggests) || + IsImportantDep(D) == false)) + continue; + + // walk over an or-group and check if we need to do anything + // for simpilicity no or-group is handled as a or-group including one dependency + pkgCache::DepIterator Start = D; + bool itsFine = false; + for (bool stillOr = true; stillOr == true; ++Start) + { + stillOr = (Start->CompareOp & Dep::Or) == Dep::Or; + pkgCache::PkgIterator const P = Start.TargetPkg(); + // virtual packages can't be a solution + if (P.end() == true || (P->ProvidesList == 0 && P->VersionList == 0)) + continue; + pkgCache::VerIterator const Cand = PkgState[P->ID].CandidateVerIter(*this); + // no versioned dependency - but is it installable? + if (Start.TargetVer() == 0 || Start.TargetVer()[0] == '\0') + { + // Check if one of the providers is installable + if (P->ProvidesList != 0) + { + pkgCache::PrvIterator Prv = P.ProvidesList(); + for (; Prv.end() == false; ++Prv) + { + pkgCache::VerIterator const C = PkgState[Prv.OwnerPkg()->ID].CandidateVerIter(*this); + if (C.end() == true || C != Prv.OwnerVer() || + (VersionState(C.DependsList(), DepInstall, DepCandMin, DepCandPolicy) & DepCandMin) != DepCandMin) + continue; + break; + } + if (Prv.end() == true) + continue; + } + // no providers, so check if we have an installable candidate version + else if (Cand.end() == true || + (VersionState(Cand.DependsList(), DepInstall, DepCandMin, DepCandPolicy) & DepCandMin) != DepCandMin) + continue; + itsFine = true; + break; + } + 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 && + (VersionState(Cand.DependsList(), DepInstall, DepCandMin, DepCandPolicy) & DepCandMin) == DepCandMin) + { + itsFine = true; + break; + } + } + if (itsFine == true) { + // something in the or-group was fine, skip all other members + for (; (D->CompareOp & Dep::Or) == Dep::Or; ++D); + continue; + } + + // walk again over the or-group and check each if a candidate switch would help + itsFine = false; + for (bool stillOr = true; stillOr == true; ++D) + { + stillOr = (D->CompareOp & Dep::Or) == Dep::Or; + // changing candidate will not help if the dependency is not versioned + if (D.TargetVer() == 0 || D.TargetVer()[0] == '\0') + { + if (stillOr == true) + continue; + break; + } + + pkgCache::VerIterator V; + if (TargetRel == "newest") + V = D.TargetPkg().VersionList(); + else + 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 (stillOr == true) + continue; + break; + } + + pkgCache::VerIterator oldCand = PkgState[D.TargetPkg()->ID].CandidateVerIter(*this); + if (V == oldCand) + { + // Do we already touched this Version? If so, their versioned dependencies are okay, no need to check again + for (std::list >::const_iterator c = Changed.begin(); + c != Changed.end(); ++c) + { + if (c->first->ParentPkg != V->ParentPkg) + continue; + itsFine = true; + break; + } + } + + if (itsFine == false) + { + // change the candidate + Changed.push_back(make_pair(oldCand, TargetVer)); + if (SetCandidateRelease(V, TargetRel, Changed) == false) + { + if (stillOr == false) + break; + // undo the candidate changing + SetCandidateVersion(oldCand); + Changed.pop_back(); + continue; + } + itsFine = true; + } + + // something in the or-group was fine, skip all other members + for (; (D->CompareOp & Dep::Or) == Dep::Or; ++D); + break; + } + + if (itsFine == false && (D->Type == pkgCache::Dep::PreDepends || D->Type == pkgCache::Dep::Depends)) + { + // undo all changes which aren't lead to a solution + for (std::list >::const_iterator c = ++newChanged; + c != Changed.end(); ++c) + SetCandidateVersion(c->first); + Changed.erase(newChanged, Changed.end()); + return false; + } + } + return true; +} + /*}}}*/ +// DepCache::MarkAuto - set the Auto flag for a package /*{{{*/ +// --------------------------------------------------------------------- +/* */ void pkgDepCache::MarkAuto(const PkgIterator &Pkg, bool Auto) { StateCache &state = PkgState[Pkg->ID]; @@ -1551,7 +1778,7 @@ const char *pkgDepCache::StateCache::StripEpoch(const char *Ver) // --------------------------------------------------------------------- /* The default just returns the highest available version that is not a source and automatic. */ -pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator Pkg) +pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator const &Pkg) { /* Not source/not automatic versions cannot be a candidate version unless they are already installed */ @@ -1569,7 +1796,8 @@ pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator Pkg) /* Stash the highest version of a not-automatic source, we use it if there is nothing better */ - if ((J.File()->Flags & Flag::NotAutomatic) != 0) + if ((J.File()->Flags & Flag::NotAutomatic) != 0 || + (J.File()->Flags & Flag::ButAutomaticUpgrades) != 0) { if (Last.end() == true) Last = I; @@ -1586,7 +1814,7 @@ pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator Pkg) // Policy::IsImportantDep - True if the dependency is important /*{{{*/ // --------------------------------------------------------------------- /* */ -bool pkgDepCache::Policy::IsImportantDep(DepIterator Dep) +bool pkgDepCache::Policy::IsImportantDep(DepIterator const &Dep) { if(Dep.IsCritical()) return true; @@ -1605,54 +1833,6 @@ bool pkgDepCache::Policy::IsImportantDep(DepIterator Dep) else if(Dep->Type == pkgCache::Dep::Suggests) return _config->FindB("APT::Install-Suggests", false); - return false; -} - /*}}}*/ -pkgDepCache::DefaultRootSetFunc::DefaultRootSetFunc() /*{{{*/ - : constructedSuccessfully(false) -{ - Configuration::Item const *Opts; - Opts = _config->Tree("APT::NeverAutoRemove"); - if (Opts != 0 && Opts->Child != 0) - { - Opts = Opts->Child; - for (; Opts != 0; Opts = Opts->Next) - { - if (Opts->Value.empty() == true) - continue; - - regex_t *p = new regex_t; - if(regcomp(p,Opts->Value.c_str(), - REG_EXTENDED | REG_ICASE | REG_NOSUB) != 0) - { - regfree(p); - delete p; - _error->Error("Regex compilation error for APT::NeverAutoRemove"); - return; - } - - rootSetRegexp.push_back(p); - } - } - - constructedSuccessfully = true; -} - /*}}}*/ -pkgDepCache::DefaultRootSetFunc::~DefaultRootSetFunc() /*{{{*/ -{ - for(unsigned int i = 0; i < rootSetRegexp.size(); i++) - { - regfree(rootSetRegexp[i]); - delete rootSetRegexp[i]; - } -} - /*}}}*/ -bool pkgDepCache::DefaultRootSetFunc::InRootSet(const pkgCache::PkgIterator &pkg) /*{{{*/ -{ - for(unsigned int i = 0; i < rootSetRegexp.size(); i++) - if (regexec(rootSetRegexp[i], pkg.Name(), 0, 0, 0) == 0) - return true; - return false; } /*}}}*/ @@ -1740,10 +1920,11 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg, return; VerIterator const currver = pkg.CurrentVer(); - VerIterator const candver = state.CandidateVerIter(*this); VerIterator const instver = state.InstVerIter(*this); #if 0 + VerIterator const candver = state.CandidateVerIter(*this); + // If a package was garbage-collected but is now being marked, we // should re-select it // For cases when a pkg is set to upgrade and this trigger the