Explorar el Código

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.
David Kalnischkies hace 10 años
padre
commit
e7d4e0cf4f

+ 82 - 13
apt-pkg/deb/dpkgpm.cc

@@ -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");
 	 ADDARGC("--pending");
 	 break;
 	 break;
 
 
+	 case Item::RemovePending:
+	 ADDARGC("--remove");
+	 ADDARGC("--pending");
+	 break;
+
+	 case Item::PurgePending:
+	 ADDARGC("--purge");
+	 ADDARGC("--pending");
+	 break;
+
 	 case Item::Install:
 	 case Item::Install:
 	 ADDARGC("--unpack");
 	 ADDARGC("--unpack");
 	 ADDARGC("--auto-deconfigure");
 	 ADDARGC("--auto-deconfigure");
@@ -1741,6 +1795,17 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
    StopPtyMagic();
    StopPtyMagic();
    CloseLog();
    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)
    if (currentStates.Save(false) == false)
       _error->Error("Couldn't restore dpkg selection states which were present before this interaction!");
       _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)
    // attach dmesg log (to learn about segfaults)
    if (FileExists("/bin/dmesg"))
    if (FileExists("/bin/dmesg"))

+ 2 - 1
apt-pkg/deb/dpkgpm.h

@@ -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;
       std::string File;
       PkgIterator Pkg;
       PkgIterator Pkg;
       Item(Ops Op,PkgIterator Pkg,std::string File = "") : Op(Op),
       Item(Ops Op,PkgIterator Pkg,std::string File = "") : Op(Op),

+ 3 - 1
doc/external-installation-planner-protocol.txt

@@ -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
 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
 package which wasn't explicitly configured will be configured at the end
 automatically. That also means through that a planner is not allowed to
 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
 In terms of expressivity, all stanzas can carry one single field each, as
 APT-IDs are enough to pinpoint packages to be installed/removed.
 APT-IDs are enough to pinpoint packages to be installed/removed.

+ 1 - 1
test/integration/test-bug-673536-pre-depends-breaks-loop

@@ -11,7 +11,7 @@ buildsimplenativepackage 'advanced' 'native' '2' 'unstable' 'Pre-Depends: basic'
 buildsimplenativepackage 'basic' 'native' '2' 'unstable' 'Pre-Depends: common'
 buildsimplenativepackage 'basic' 'native' '2' 'unstable' 'Pre-Depends: common'
 
 
 buildsimplenativepackage 'common' 'native' '2~conflict' 'unstable-conflict' 'Conflicts: advanced (<= 1)'
 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