From 11a3cc6307839d73cd6298a11d30cbe2a8fa0b86 Mon Sep 17 00:00:00 2001 From: Aleksei Nikiforov Date: Fri, 27 Oct 2017 18:05:47 +0300 Subject: [PATCH] apt-get: implement 'autoremove' action. --- apt/apt-pkg/algorithms.cc | 66 ++++++++++++++++++++++++++++++++++++++- apt/apt-pkg/algorithms.h | 1 + apt/cmdline/apt-get.cc | 29 ++++++++++++++++- 3 files changed, 94 insertions(+), 2 deletions(-) diff --git a/apt/apt-pkg/algorithms.cc b/apt/apt-pkg/algorithms.cc index 1abd5df..c28c233 100644 --- a/apt/apt-pkg/algorithms.cc +++ b/apt/apt-pkg/algorithms.cc @@ -31,6 +31,7 @@ #include #include +#include /*}}}*/ using namespace std; @@ -590,7 +591,70 @@ bool pkgMinimizeUpgrade(pkgDepCache &Cache) return true; } - /*}}}*/ + +static bool all_revdeps_may_be_removed(const pkgDepCache &Cache, const pkgCache::PkgIterator &pkg_iter, std::map &states_cache_map) +{ + // Don't try to recursively traverse dependency loops + { + auto iter = states_cache_map.find(pkg_iter.Name()); + if (iter != states_cache_map.end()) + { + return iter->second; + } + } + + bool mark_auto = Cache.getMarkAuto(pkg_iter); + + // set auto mark to current state (this may be used to get out of infinite dependencies loop + states_cache_map[pkg_iter.Name()] = mark_auto; + + // recursively check all dependencies + if (mark_auto) + { + for (pkgCache::DepIterator dep_iter = pkg_iter.RevDependsList(); mark_auto && (not dep_iter.end()); ++dep_iter) + { + // Skip packages not installed + if (dep_iter.ParentPkg()->CurrentState == pkgCache::State::Installed) + { + mark_auto &= all_revdeps_may_be_removed(Cache, dep_iter.ParentPkg(), states_cache_map); + } + } + + // update mark to the final value + states_cache_map[pkg_iter.Name()] = mark_auto; + } + + return mark_auto; +} + +bool pkgAutoremove(pkgDepCache &Cache) +{ + if (Cache.BrokenCount() != 0) + { + return false; + } + + // Check every installed package + for (pkgCache::PkgIterator pkg_iter = Cache.PkgBegin(); not pkg_iter.end(); ++pkg_iter) + { + // Skip packages not installed + if (pkg_iter->CurrentState == pkgCache::State::Installed) + { + // Keep a cache of dependencies for current package. + // Need to create clean cache for each package, + // otherwise when processing cyclic dependencies + // it may report invalid result and remove actually still needed package + std::map states_cache_map; + + if (all_revdeps_may_be_removed(Cache, pkg_iter, states_cache_map)) + { + Cache.MarkDelete(pkg_iter, _config->FindB("APT::Get::Purge",false)); + } + } + } + + return true; +} // ProblemResolver::pkgProblemResolver - Constructor /*{{{*/ // --------------------------------------------------------------------- diff --git a/apt/apt-pkg/algorithms.h b/apt/apt-pkg/algorithms.h index 2117f77..f7ee654 100644 --- a/apt/apt-pkg/algorithms.h +++ b/apt/apt-pkg/algorithms.h @@ -134,6 +134,7 @@ bool pkgApplyStatus(pkgDepCache &Cache); bool pkgFixBroken(pkgDepCache &Cache); bool pkgAllUpgrade(pkgDepCache &Cache); bool pkgMinimizeUpgrade(pkgDepCache &Cache); +bool pkgAutoremove(pkgDepCache &Cache); void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List); diff --git a/apt/cmdline/apt-get.cc b/apt/cmdline/apt-get.cc index 2a41b88..841f89d 100644 --- a/apt/cmdline/apt-get.cc +++ b/apt/cmdline/apt-get.cc @@ -2525,7 +2525,33 @@ bool DoMoo(CommandLine &CmdL) return true; } - /*}}}*/ + +bool DoAutoremove(CommandLine &/*CmdL*/) +{ + CacheFile Cache(c1out); + + if ((not Cache.OpenForInstall()) || (not Cache.CheckDeps())) + { + return false; + } + + c0out << _("Calculating Autoremove... ") << std::flush; + if (not pkgAutoremove(*Cache)) + { + c0out << _("Failed") << std::endl; + ShowBroken(std::cerr, Cache, false); + return false; + } + + if (CheckOnly(Cache)) + { + return true; + } + + c0out << _("Done") << std::endl; + + return InstallPackages(Cache, false); +} // CNC:2003-03-18 // DoScript - Scripting stuff. /*{{{*/ @@ -2747,6 +2773,7 @@ int main(int argc,const char *argv[]) {"check",&DoCheck}, {"source",&DoSource}, {"moo",&DoMoo}, + {"autoremove", &DoAutoremove}, {"help",&ShowHelp}, // CNC:2003-03-19 #ifdef WITH_LUA