X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/74a05226eff7041cd8f2380fe599862d350a1ac3..92b9551f03035f5a875a44588a318773f652da6a:/apt-pkg/depcache.cc diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc index 22dd53f97..f5673dd5d 100644 --- a/apt-pkg/depcache.cc +++ b/apt-pkg/depcache.cc @@ -24,6 +24,8 @@ #include #include +#include + #include pkgDepCache::ActionGroup::ActionGroup(pkgDepCache &cache) : @@ -141,7 +143,7 @@ bool pkgDepCache::Init(OpProgress *Prog) bool pkgDepCache::readStateFile(OpProgress *Prog) { FileFd state_file; - string state = _config->FindDir("Dir::State") + "pkgstates"; + string state = _config->FindDir("Dir::State") + "extended_states"; if(FileExists(state)) { state_file.Open(state, FileFd::ReadOnly); int file_size = state_file.Size(); @@ -179,28 +181,81 @@ bool pkgDepCache::readStateFile(OpProgress *Prog) bool pkgDepCache::writeStateFile(OpProgress *prog) { - FileFd StateFile; - string state = _config->FindDir("Dir::State") + "pkgstates"; - if(_config->FindB("Debug::pkgAutoRemove",false)) std::clog << "pkgDepCache::writeStateFile()" << std::endl; - if(!StateFile.Open(state, FileFd::WriteEmpty)) - return _error->Error(_("Failed to write StateFile %s"), + FileFd StateFile; + string state = _config->FindDir("Dir::State") + "extended_states"; + + // if it does not exist, create a empty one + if(!FileExists(state)) + { + StateFile.Open(state, FileFd::WriteEmpty); + StateFile.Close(); + } + + // 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; + } 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; } @@ -646,9 +701,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); @@ -837,9 +901,29 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, } } - if (InstPkg.end() == false) - MarkInstall(InstPkg, true, Depth + 1, false); - + if (InstPkg.end() == false) + { + if(_config->FindB("Debug::pkgDepCache::AutoInstall",false) == true) + std::clog << "Installing " << InstPkg.Name() + << " as dep of " << Pkg.Name() + << std::endl; + // now check if we should consider it a automatic dependency or not + string sec = _config->Find("APT::Never-MarkAuto-Section",""); + if(Pkg.Section() && (string(Pkg.Section()) == sec)) + { + if(_config->FindB("Debug::pkgDepCache::AutoInstall",false) == true) + std::clog << "Setting NOT as auto-installed because its a direct dep of a package in section " << sec << std::endl; + MarkInstall(InstPkg,true,Depth + 1, true); + } + else + { + // mark automatic dependency + MarkInstall(InstPkg,true,Depth + 1, false); + // Set the autoflag, after MarkInstall because MarkInstall unsets it + if (P->CurrentVer == 0) + PkgState[InstPkg->ID].Flags |= Flag::Auto; + } + } continue; } @@ -1204,9 +1288,13 @@ bool pkgDepCache::Sweep() { StateCache &state=PkgState[p->ID]; + // skip required packages + if (!p.CurrentVer().end() && + (p.CurrentVer()->Priority == pkgCache::State::Required)) + continue; + // 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))