#include <iostream>
#include <sstream>
+#include <set>
+
#include <apti18n.h>
pkgDepCache::ActionGroup::ActionGroup(pkgDepCache &cache) :
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();
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<string> 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;
}
// 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);
}
}
- 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;
}
{
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))