X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/aac2e51078714d5130861035e9b3b5d4d6b84471..3ca658384917297fdb75112a2b2df26054678934:/apt-pkg/depcache.cc diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc index 4e9488121..87443f9f3 100644 --- a/apt-pkg/depcache.cc +++ b/apt-pkg/depcache.cc @@ -24,6 +24,7 @@ #include #include +#include #include @@ -178,30 +179,86 @@ bool pkgDepCache::readStateFile(OpProgress *Prog) return true; } -bool pkgDepCache::writeStateFile(OpProgress *prog) +bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly) { + if(_config->FindB("Debug::pkgAutoRemove",false)) + std::clog << "pkgDepCache::writeStateFile()" << std::endl; + FileFd StateFile; string state = _config->FindDir("Dir::State") + "extended_states"; - if(_config->FindB("Debug::pkgAutoRemove",false)) - std::clog << "pkgDepCache::writeStateFile()" << std::endl; + // if it does not exist, create a empty one + if(!FileExists(state)) + { + StateFile.Open(state, FileFd::WriteEmpty); + StateFile.Close(); + } - if(!StateFile.Open(state, FileFd::WriteEmpty)) - return _error->Error(_("Failed to write StateFile %s"), + // open it + if(!StateFile.Open(state, FileFd::ReadOnly)) + return _error->Error(_("Failed to open StateFile %s"), state.c_str()); + FILE *OutFile; + string outfile = state + ".tmp"; + if((OutFile = fopen(outfile.c_str(),"w")) == NULL) + return _error->Error(_("Failed to write temporary StateFile %s"), + outfile.c_str()); + + // first merge with the existing sections + pkgTagFile tagfile(&StateFile); + pkgTagSection section; + std::set pkgs_seen; + const char *nullreorderlist[] = {0}; + while(tagfile.Step(section)) { + string pkgname = section.FindS("Package"); + // Silently ignore unknown packages and packages with no actual + // version. + pkgCache::PkgIterator pkg=Cache->FindPkg(pkgname); + if(pkg.end() || pkg.VersionList().end()) + continue; + bool oldAuto = section.FindI("Auto-Installed"); + bool newAuto = (PkgState[pkg->ID].Flags & Flag::Auto); + if(_config->FindB("Debug::pkgAutoRemove",false)) + std::clog << "Update exisiting AutoInstall info: " + << pkg.Name() << std::endl; + TFRewriteData rewrite[2]; + rewrite[0].Tag = "Auto-Installed"; + rewrite[0].Rewrite = newAuto ? "1" : "0"; + rewrite[0].NewTag = 0; + rewrite[1].Tag = 0; + TFRewrite(OutFile, section, nullreorderlist, rewrite); + fprintf(OutFile,"\n"); + pkgs_seen.insert(pkgname); + } + + // then write the ones we have not seen yet std::ostringstream ostr; - for(pkgCache::PkgIterator pkg=Cache->PkgBegin(); !pkg.end();pkg++) { - + for(pkgCache::PkgIterator pkg=Cache->PkgBegin(); !pkg.end(); pkg++) { if(PkgState[pkg->ID].Flags & Flag::Auto) { + if (pkgs_seen.find(pkg.Name()) != pkgs_seen.end()) { + if(_config->FindB("Debug::pkgAutoRemove",false)) + std::clog << "Skipping already written " << pkg.Name() << std::endl; + continue; + } + // skip not installed ones if requested + if(InstalledOnly && pkg->CurrentVer == 0) + continue; if(_config->FindB("Debug::pkgAutoRemove",false)) - std::clog << "AutoInstall: " << pkg.Name() << std::endl; + std::clog << "Writing new AutoInstall: " + << pkg.Name() << std::endl; ostr.str(string("")); ostr << "Package: " << pkg.Name() << "\nAuto-Installed: 1\n\n"; - StateFile.Write(ostr.str().c_str(), ostr.str().size()); + fprintf(OutFile,ostr.str().c_str()); + fprintf(OutFile,"\n"); } } + fclose(OutFile); + + // move the outfile over the real file + rename(outfile.c_str(), state.c_str()); + return true; } @@ -219,7 +276,7 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res) we allow it anyhow because dpkg does. Technically it is a packaging bug. Conflicts may never self match */ if (Dep.TargetPkg() != Dep.ParentPkg() || - (Dep->Type != Dep::Conflicts && Dep->Type != Dep::Obsoletes)) + (Dep->Type != Dep::Conflicts && Dep->Type != Dep::DpkgBreaks && Dep->Type != Dep::Obsoletes)) { PkgIterator Pkg = Dep.TargetPkg(); // Check the base package @@ -249,7 +306,8 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res) { /* Provides may never be applied against the same package if it is a conflicts. See the comment above. */ - if (P.OwnerPkg() == Pkg && Dep->Type == Dep::Conflicts) + if (P.OwnerPkg() == Pkg && + (Dep->Type == Dep::Conflicts || Dep->Type == Dep::DpkgBreaks)) continue; // Check if the provides is a hit @@ -345,9 +403,11 @@ void pkgDepCache::AddStates(const PkgIterator &Pkg,int Add) { StateCache &State = PkgState[Pkg->ID]; - // The Package is broken + // The Package is broken (either minimal dep or policy dep) if ((State.DepState & DepInstMin) != DepInstMin) iBrokenCount += Add; + if ((State.DepState & DepInstPolicy) != DepInstPolicy) + iPolicyBrokenCount += Add; // Bad state if (Pkg.State() != PkgIterator::NeedsNothing) @@ -401,7 +461,9 @@ void pkgDepCache::BuildGroupOrs(VerIterator const &V) /* Invert for Conflicts. We have to do this twice to get the right sense for a conflicts group */ - if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes) + if (D->Type == Dep::Conflicts || + D->Type == Dep::DpkgBreaks || + D->Type == Dep::Obsoletes) State = ~State; // Add to the group if we are within an or.. @@ -412,7 +474,9 @@ void pkgDepCache::BuildGroupOrs(VerIterator const &V) Group = 0; // Invert for Conflicts - if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes) + if (D->Type == Dep::Conflicts || + D->Type == Dep::DpkgBreaks || + D->Type == Dep::Obsoletes) State = ~State; } } @@ -545,7 +609,9 @@ void pkgDepCache::Update(OpProgress *Prog) Group = 0; // Invert for Conflicts - if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes) + if (D->Type == Dep::Conflicts || + D->Type == Dep::DpkgBreaks || + D->Type == Dep::Obsoletes) State = ~State; } } @@ -575,7 +641,9 @@ void pkgDepCache::Update(DepIterator D) State = DependencyState(D); // Invert for Conflicts - if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes) + if (D->Type == Dep::Conflicts || + D->Type == Dep::DpkgBreaks || + D->Type == Dep::Obsoletes) State = ~State; RemoveStates(D.ParentPkg()); @@ -647,9 +715,18 @@ void pkgDepCache::MarkKeep(PkgIterator const &Pkg, bool Soft, bool FromUser) // We dont even try to keep virtual packages.. if (Pkg->VersionList == 0) return; - + +#if 0 // reseting the autoflag here means we lose the + // auto-mark information if a user selects a package for removal + // but changes his mind then and sets it for keep again + // - this makes sense as default when all Garbage dependencies + // are automatically marked for removal (as aptitude does). + // setting a package for keep then makes it no longer autoinstalled + // for all other use-case this action is rather suprising if(FromUser && !P.Marked) P.Flags &= ~Flag::Auto; +#endif + RemoveSizes(Pkg); RemoveStates(Pkg); @@ -709,7 +786,8 @@ void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge) // --------------------------------------------------------------------- /* */ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, - unsigned long Depth, bool FromUser) + unsigned long Depth, bool FromUser, + bool ForceImportantDeps) { if (Depth > 100) return; @@ -724,7 +802,8 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, installed */ StateCache &P = PkgState[Pkg->ID]; P.iFlags &= ~AutoKept; - if (P.InstBroken() == false && (P.Mode == ModeInstall || + if ((P.InstPolicyBroken() == false && P.InstBroken() == false) && + (P.Mode == ModeInstall || P.CandidateVer == (Version *)Pkg.CurrentVer())) { if (P.CandidateVer == (Version *)Pkg.CurrentVer() && P.InstallVer == 0) @@ -735,11 +814,9 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, // See if there is even any possible instalation candidate if (P.CandidateVer == 0) return; - // We dont even try to install virtual packages.. if (Pkg->VersionList == 0) return; - /* Target the candidate version and remove the autoflag. We reset the autoflag below if this was called recursively. Otherwise the user should have the ability to de-auto a package by changing its state */ @@ -793,10 +870,43 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, /* Check if this dep should be consider for install. If it is a user defined important dep and we are installed a new package then - it will be installed. Otherwise we only worry about critical deps */ + it will be installed. Otherwise we only check for important + deps that have changed from the installed version + */ if (IsImportantDep(Start) == false) continue; - if (Pkg->CurrentVer != 0 && Start.IsCritical() == false) + + /* check if any ImportantDep() (but not Critial) where added + * since we installed the package + */ + bool isNewImportantDep = false; + if(!ForceImportantDeps && !Start.IsCritical()) + { + bool found=false; + VerIterator instVer = Pkg.CurrentVer(); + if(!instVer.end()) + { + for (DepIterator D = instVer.DependsList(); D.end() != true; D++) + { + //FIXME: deal better with or-groups(?) + DepIterator LocalStart = D; + + if(IsImportantDep(D) && Start.TargetPkg() == D.TargetPkg()) + found=true; + } + // this is a new dep if it was not found to be already + // a important dep of the installed pacakge + isNewImportantDep = !found; + } + } + if(isNewImportantDep) + if(_config->FindB("Debug::pkgDepCache::AutoInstall",false) == true) + std::clog << "new important dependency: " + << Start.TargetPkg().Name() << std::endl; + + // skip important deps if the package is already installed + if (Pkg->CurrentVer != 0 && Start.IsCritical() == false + && !isNewImportantDep && !ForceImportantDeps) continue; /* If we are in an or group locate the first or that can @@ -807,7 +917,8 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, /* This bit is for processing the possibilty of an install/upgrade fixing the problem */ SPtrArray List = Start.AllTargets(); - if ((DepState[Start->ID] & DepCVer) == DepCVer) + if (Start->Type != Dep::DpkgBreaks && + (DepState[Start->ID] & DepCVer) == DepCVer) { // Right, find the best version to install.. Version **Cur = List; @@ -844,21 +955,31 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, std::clog << "Installing " << InstPkg.Name() << " as dep of " << Pkg.Name() << std::endl; - MarkInstall(InstPkg, true, Depth + 1, false); + MarkInstall(InstPkg,true,Depth + 1, false, ForceImportantDeps); + + // Set the autoflag, after MarkInstall because MarkInstall unsets it + if (P->CurrentVer == 0) + PkgState[InstPkg->ID].Flags |= Flag::Auto; } continue; } - + /* For conflicts we just de-install the package and mark as auto, - Conflicts may not have or groups */ - if (Start->Type == Dep::Conflicts || Start->Type == Dep::Obsoletes) + Conflicts may not have or groups. For dpkg's Breaks we try to + upgrade the package. */ + if (Start->Type == Dep::Conflicts || Start->Type == Dep::Obsoletes || + Start->Type == Dep::DpkgBreaks) { for (Version **I = List; *I != 0; I++) { VerIterator Ver(*this,*I); PkgIterator Pkg = Ver.ParentPkg(); - - MarkDelete(Pkg); + + if (Start->Type != Dep::DpkgBreaks) + MarkDelete(Pkg); + else + if (PkgState[Pkg->ID].CandidateVer != *I) + MarkInstall(Pkg,true,Depth + 1, false, ForceImportantDeps); } continue; } @@ -1001,13 +1122,6 @@ pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator Pkg) return Last; } /*}}}*/ -// Policy::IsImportantDep - True if the dependency is important /*{{{*/ -// --------------------------------------------------------------------- -/* */ -bool pkgDepCache::Policy::IsImportantDep(DepIterator Dep) -{ - return Dep.IsCritical(); -} /*}}}*/ pkgDepCache::DefaultRootSetFunc::DefaultRootSetFunc() @@ -1211,8 +1325,7 @@ bool pkgDepCache::Sweep() StateCache &state=PkgState[p->ID]; // if it is not marked and it is installed, it's garbage - if(!state.Marked && (!p.CurrentVer().end() || state.Install()) && - !state.Delete()) + if(!state.Marked && (!p.CurrentVer().end() || state.Install())) { state.Garbage=true; if(_config->FindB("Debug::pkgAutoRemove",false)) @@ -1222,3 +1335,33 @@ bool pkgDepCache::Sweep() return true; } + +// Policy::IsImportantDep - True if the dependency is important /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool pkgDepCache::Policy::IsImportantDep(DepIterator Dep) +{ + if(Dep.IsCritical()) + return true; + else if(Dep->Type == pkgCache::Dep::Recommends) + { + if ( _config->FindB("APT::Install-Recommends", false)) + return true; + // we suport a special mode to only install-recommends for certain + // sections + // FIXME: this is a meant as a temporarly solution until the + // recommends are cleaned up + string s = _config->Find("APT::Install-Recommends-Section",""); + if(s.size() > 0) + { + const char *sec = Dep.ParentVer().Section(); + if (sec && strcmp(sec, s.c_str()) == 0) + return true; + } + } + else if(Dep->Type == pkgCache::Dep::Suggests) + return _config->FindB("APT::Install-Suggests", false); + + return false; +} + /*}}}*/