Commit e7d4e0cf authored by David Kalnischkies's avatar David Kalnischkies

select remove/purge packages early on for dpkg

Telling dpkg early on that we are going to remove these packages later
helps it with auto-deconfiguration decisions and its another area where
a planner can ignore the nitty gritty details and let dpkg decide the
course of action if there are no special requirements.
parent b820fd59
......@@ -1372,6 +1372,50 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
return _error->Error("Couldn't clean the currently selected dpkg states");
APT::StateChanges approvedStates;
if (_config->FindB("dpkg::selection::remove::approved", true))
for (auto && I: List)
if (I.Op == Item::Remove && Cache[I.Pkg].Delete())
else if (I.Op == Item::Purge && Cache[I.Pkg].Purge())
if (approvedStates.Save(false) == false)
_error->Error("Couldn't record the approved state changes as dpkg selection states");
if (currentStates.Save(false) == false)
_error->Error("Couldn't restore dpkg selection states which were present before this interaction!");
return false;
std::vector<bool> toBeRemoved(Cache.Head().PackageCount, false);
std::vector<bool> toBePurged(Cache.Head().PackageCount, false);
for (auto Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
if (Cache[Pkg].Purge())
toBePurged[Pkg->ID] = true;
else if (Cache[Pkg].Delete())
toBeRemoved[Pkg->ID] = true;
for (auto && I: approvedStates.Remove())
toBeRemoved[I.ParentPkg()->ID] = false;
for (auto && I: approvedStates.Purge())
toBePurged[I.ParentPkg()->ID] = false;
if (std::find(toBeRemoved.begin(), toBeRemoved.end(), true) != toBeRemoved.end())
if (ConfigurePending)
List.emplace(std::prev(List.end()), Item::RemovePending, pkgCache::PkgIterator());
List.emplace_back(Item::RemovePending, pkgCache::PkgIterator());
if (std::find(toBePurged.begin(), toBePurged.end(), true) != toBePurged.end())
if (ConfigurePending)
List.emplace(std::prev(List.end()), Item::PurgePending, pkgCache::PkgIterator());
List.emplace_back(Item::PurgePending, pkgCache::PkgIterator());
d->stdin_is_dev_null = false;
......@@ -1460,6 +1504,16 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
case Item::RemovePending:
case Item::PurgePending:
case Item::Install:
......@@ -1741,6 +1795,17 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
if (d->dpkg_error.empty() == false)
APT::StateChanges undo;
auto && undoRem = approvedStates.Remove();
std::move(undoRem.begin(), undoRem.end(), std::back_inserter(undo.Remove()));
auto && undoPur = approvedStates.Purge();
std::move(undoPur.begin(), undoPur.end(), std::back_inserter(undo.Purge()));
if (undo.Save(false) == false)
_error->Error("Couldn't revert dpkg selection for approved remove/purge after an error was encountered!");
if (currentStates.Save(false) == false)
_error->Error("Couldn't restore dpkg selection states which were present before this interaction!");
......@@ -1991,20 +2056,24 @@ void pkgDPkgPM::WriteApportReport(const char *pkgpath, const char *errormsg)
// log the ordering, see dpkgpm.h and the "Ops" enum there
const char *ops_str[] = {
fprintf(report, "AptOrdering:\n");
for (vector<Item>::iterator I = List.begin(); I != List.end(); ++I)
if ((*I).Pkg != NULL)
fprintf(report, " %s: %s\n", (*I).Pkg.Name(), ops_str[(*I).Op]);
fprintf(report, " %s: %s\n", "NULL", ops_str[(*I).Op]);
for (auto && I : List)
char const * opstr = nullptr;
switch (I.Op)
case Item::Install: opstr = "Install"; break;
case Item::Configure: opstr = "Configure"; break;
case Item::Remove: opstr = "Remove"; break;
case Item::Purge: opstr = "Purge"; break;
case Item::ConfigurePending: opstr = "ConfigurePending"; break;
case Item::TriggersPending: opstr = "TriggersPending"; break;
case Item::RemovePending: opstr = "RemovePending"; break;
case Item::PurgePending: opstr = "PurgePending"; break;
auto const pkgname = I.Pkg.end() ? "NULL" : I.Pkg.FullName();
fprintf(report, " %s: %s\n", pkgname.c_str(), opstr);
// attach dmesg log (to learn about segfaults)
if (FileExists("/bin/dmesg"))
......@@ -79,7 +79,8 @@ class pkgDPkgPM : public pkgPackageManager
struct Item
enum Ops {Install, Configure, Remove, Purge, ConfigurePending, TriggersPending} Op;
enum Ops {Install, Configure, Remove, Purge, ConfigurePending, TriggersPending,
RemovePending, PurgePending } Op;
std::string File;
PkgIterator Pkg;
Item(Ops Op,PkgIterator Pkg,std::string File = "") : Op(Op),
......@@ -248,7 +248,9 @@ before it was unpacked, dependency relations must be satisfied, …), but
they don't need to be complete: A planner can and should expect that any
package which wasn't explicitly configured will be configured at the end
automatically. That also means through that a planner is not allowed to
produce a solution in which a package remains unconfigured.
produce a solution in which a package remains unconfigured. Also,
packages which are requested to be removed will be automatically removed
at the end if not marked for removal explicitly earlier.
In terms of expressivity, all stanzas can carry one single field each, as
APT-IDs are enough to pinpoint packages to be installed/removed.
......@@ -11,7 +11,7 @@ buildsimplenativepackage 'advanced' 'native' '2' 'unstable' 'Pre-Depends: basic'
buildsimplenativepackage 'basic' 'native' '2' 'unstable' 'Pre-Depends: common'
buildsimplenativepackage 'common' 'native' '2~conflict' 'unstable-conflict' 'Conflicts: advanced (<= 1)'
buildsimplenativepackage 'common' 'native' '2~break' 'unstable-break' 'Conflicts: advanced (<= 1)'
buildsimplenativepackage 'common' 'native' '2~break' 'unstable-break' 'Breaks: advanced (<= 1)'
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment