]> git.saurik.com Git - apt.git/commitdiff
select remove/purge packages early on for dpkg
authorDavid Kalnischkies <david@kalnischkies.de>
Fri, 8 Jul 2016 07:40:46 +0000 (09:40 +0200)
committerDavid Kalnischkies <david@kalnischkies.de>
Wed, 10 Aug 2016 21:18:04 +0000 (23:18 +0200)
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.

apt-pkg/deb/dpkgpm.cc
apt-pkg/deb/dpkgpm.h
doc/external-installation-planner-protocol.txt
test/integration/test-bug-673536-pre-depends-breaks-loop

index 38285d14b34cc7741bc2e7b534cd11e95e4f0ba6..bc34e50e03a4b8faddd458c0cfd2e84cb036f09b 100644 (file)
@@ -1372,6 +1372,50 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
            return _error->Error("Couldn't clean the currently selected dpkg states");
       }
    }
            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())
+           approvedStates.Remove(FindToBeRemovedVersion(I.Pkg));
+        else if (I.Op == Item::Purge && Cache[I.Pkg].Purge())
+           approvedStates.Purge(FindToBeRemovedVersion(I.Pkg));
+      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());
+           else
+              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());
+           else
+              List.emplace_back(Item::PurgePending, pkgCache::PkgIterator());
+        }
+      }
+   }
 
    d->stdin_is_dev_null = false;
 
 
    d->stdin_is_dev_null = false;
 
@@ -1460,6 +1504,16 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
         ADDARGC("--pending");
         break;
 
         ADDARGC("--pending");
         break;
 
+        case Item::RemovePending:
+        ADDARGC("--remove");
+        ADDARGC("--pending");
+        break;
+
+        case Item::PurgePending:
+        ADDARGC("--purge");
+        ADDARGC("--pending");
+        break;
+
         case Item::Install:
         ADDARGC("--unpack");
         ADDARGC("--auto-deconfigure");
         case Item::Install:
         ADDARGC("--unpack");
         ADDARGC("--auto-deconfigure");
@@ -1741,6 +1795,17 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
    StopPtyMagic();
    CloseLog();
 
    StopPtyMagic();
    CloseLog();
 
+   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()));
+      approvedStates.clear();
+      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!");
 
    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
    }
 
    // log the ordering, see dpkgpm.h and the "Ops" enum there
-   const char *ops_str[] = {
-      "Install",
-      "Configure",
-      "Remove",
-      "Purge",
-      "ConfigurePending",
-      "TriggersPending",
-   };
    fprintf(report, "AptOrdering:\n");
    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]);
-      else
-         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"))
 
    // attach dmesg log (to learn about segfaults)
    if (FileExists("/bin/dmesg"))
index 408a373344f0beb7108e6787b46785390fd2ed15..07c99aeadd45f1193ae97f80cf80c3db4a70f27a 100644 (file)
@@ -79,7 +79,8 @@ class pkgDPkgPM : public pkgPackageManager
   
    struct Item
    {
   
    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),
       std::string File;
       PkgIterator Pkg;
       Item(Ops Op,PkgIterator Pkg,std::string File = "") : Op(Op),
index 44fa8ff5370d56de8405bb366a8690d0039d498f..4bad9da0a167837123bb415d20320958a0ef6e8e 100644 (file)
@@ -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
 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.
 
 In terms of expressivity, all stanzas can carry one single field each, as
 APT-IDs are enough to pinpoint packages to be installed/removed.
index bf3d2e2eb864ea09a7a0bfe6e2cb090bde29fe49..a4cf669739f2946f0c578a957db9c1a2a0983633 100755 (executable)
@@ -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 '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)'
 
 setupaptarchive
 
 
 setupaptarchive