]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/statechanges.cc
CMake: Add coverage build type
[apt.git] / apt-pkg / statechanges.cc
index a20319d2df96251434ec33a5e1d8e3c8fea9152b..35af45538089029a9f4e933b30e0bd00bb8c1a58 100644 (file)
@@ -3,6 +3,7 @@
 #include <apt-pkg/debsystem.h>
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/statechanges.h>
+#include <apt-pkg/prettyprinters.h>
 
 #include <algorithm>
 #include <memory>
@@ -14,46 +15,64 @@ class StateChanges::Private
 {
 public:
    APT::VersionVector hold;
+   APT::VersionVector unhold;
    APT::VersionVector install;
+   APT::VersionVector deinstall;
+   APT::VersionVector purge;
    APT::VersionVector error;
 };
 
-void StateChanges::Hold(pkgCache::VerIterator const &Ver)
-{
-   d->hold.push_back(Ver);
-}
-APT::VersionVector& StateChanges::Hold()
-{
-   return d->hold;
-}
-void StateChanges::Unhold(pkgCache::VerIterator const &Ver)
-{
-   d->install.push_back(Ver);
-}
-APT::VersionVector& StateChanges::Unhold()
-{
-   return d->install;
+#define APT_GETTERSETTER(Name, Container) \
+void StateChanges::Name(pkgCache::VerIterator const &Ver) \
+{ \
+   if (Ver.end() == false) \
+      Container.push_back(Ver); \
+}\
+APT::VersionVector& StateChanges::Name() \
+{ \
+   return Container; \
 }
+APT_GETTERSETTER(Hold, d->hold)
+APT_GETTERSETTER(Unhold, d->unhold)
+APT_GETTERSETTER(Install, d->install)
+APT_GETTERSETTER(Remove, d->deinstall)
+APT_GETTERSETTER(Purge, d->purge)
+#undef APT_GETTERSETTER
 APT::VersionVector& StateChanges::Error()
 {
    return d->error;
 }
 
-void StateChanges::Discard()
+void StateChanges::clear()
 {
    d->hold.clear();
+   d->unhold.clear();
    d->install.clear();
+   d->deinstall.clear();
+   d->purge.clear();
    d->error.clear();
 }
 
+bool StateChanges::empty() const
+{
+   return d->hold.empty() &&
+      d->unhold.empty() &&
+      d->install.empty() &&
+      d->deinstall.empty() &&
+      d->purge.empty() &&
+      d->error.empty();
+}
+
 bool StateChanges::Save(bool const DiscardOutput)
 {
+   bool const Debug = _config->FindB("Debug::pkgDpkgPm", false);
    d->error.clear();
-   if (d->hold.empty() && d->install.empty())
+   if (d->hold.empty() && d->unhold.empty() && d->install.empty() && d->deinstall.empty() && d->purge.empty())
       return true;
 
    std::vector<std::string> Args = debSystem::GetDpkgBaseCommand();
    // ensure dpkg knows about the package so that it keeps the status we set
+   if (d->hold.empty() == false || d->install.empty() == false)
    {
       APT::VersionVector makeDpkgAvailable;
       auto const notInstalled = [](pkgCache::VerIterator const &V) { return V.ParentPkg()->CurrentVer == 0; };
@@ -67,54 +86,132 @@ bool StateChanges::Save(bool const DiscardOutput)
         // FIXME: supported only since 1.17.7 in dpkg
         Args.push_back("-");
         int dummyAvail = -1;
-        pid_t const dpkgMergeAvail = debSystem::ExecDpkg(Args, &dummyAvail, nullptr, true);
+        if (Debug)
+        {
+           for (auto const &V: makeDpkgAvailable)
+           {
+              std::clog << "echo 'Dummy record for " << V.ParentPkg().FullName(false) << "' | ";
+              std::copy(Args.begin(), Args.end(), std::ostream_iterator<std::string>(std::clog, " "));
+              std::clog << std::endl;
+           }
+        }
+        else
+        {
+           pid_t const dpkgMergeAvail = debSystem::ExecDpkg(Args, &dummyAvail, nullptr, true);
 
-        FILE* dpkg = fdopen(dummyAvail, "w");
-        for (auto const &V: makeDpkgAvailable)
-           fprintf(dpkg, "Package: %s\nVersion: 0~\nArchitecture: %s\nMaintainer: Dummy Example <dummy@example.org>\n"
-                 "Description: dummy package record\n A record is needed to put a package on hold, so here it is.\n\n", V.ParentPkg().Name(), V.Arch());
-        fclose(dpkg);
+           FILE* dpkg = fdopen(dummyAvail, "w");
+           for (auto const &V: makeDpkgAvailable)
+              fprintf(dpkg, "Package: %s\nVersion: 0~\nArchitecture: %s\nMaintainer: Dummy Example <dummy@example.org>\n"
+                    "Description: dummy package record\n A record is needed to put a package on hold, so here it is.\n\n", V.ParentPkg().Name(), V.Arch());
+           fclose(dpkg);
 
-        ExecWait(dpkgMergeAvail, "dpkg --merge-avail", true);
+           ExecWait(dpkgMergeAvail, "dpkg --merge-avail", true);
+        }
         Args.erase(Args.begin() + BaseArgs, Args.end());
       }
    }
    bool const dpkgMultiArch = _system->MultiArchSupported();
 
    Args.push_back("--set-selections");
-   int selections = -1;
-   pid_t const dpkgSelections = debSystem::ExecDpkg(Args, &selections, nullptr, DiscardOutput);
-
-   FILE* dpkg = fdopen(selections, "w");
-   std::string state;
-   auto const dpkgName = [&](pkgCache::VerIterator const &V) {
-      pkgCache::PkgIterator P = V.ParentPkg();
-      if (dpkgMultiArch == false)
-        fprintf(dpkg, "%s %s\n", P.FullName(true).c_str(), state.c_str());
-      else
-        fprintf(dpkg, "%s:%s %s\n", P.Name(), V.Arch(), state.c_str());
-   };
-   if (d->hold.empty() == false)
+   if (Debug)
    {
-      state = "hold";
-      std::for_each(d->hold.begin(), d->hold.end(), dpkgName);
+      std::string state;
+      auto const dpkgName = [&](pkgCache::VerIterator const &V) {
+        pkgCache::PkgIterator P = V.ParentPkg();
+        if (strcmp(V.Arch(), "none") == 0)
+           ioprintf(std::clog, "echo '%s %s' | ", P.Name(), state.c_str());
+        else if (dpkgMultiArch == false)
+           ioprintf(std::clog, "echo '%s %s' | ", P.FullName(true).c_str(), state.c_str());
+        else
+           ioprintf(std::clog, "echo '%s:%s %s' | ", P.Name(), V.Arch(), state.c_str());
+        std::copy(Args.begin(), Args.end(), std::ostream_iterator<std::string>(std::clog, " "));
+        std::clog << std::endl;
+      };
+      for (auto const &V: d->unhold)
+      {
+        if (V.ParentPkg()->CurrentVer != 0)
+           state = "install";
+        else
+           state = "deinstall";
+        dpkgName(V);
+      }
+      if (d->purge.empty() == false)
+      {
+        state = "purge";
+        std::for_each(d->purge.begin(), d->purge.end(), dpkgName);
+      }
+      if (d->deinstall.empty() == false)
+      {
+        state = "deinstall";
+        std::for_each(d->deinstall.begin(), d->deinstall.end(), dpkgName);
+      }
+      if (d->hold.empty() == false)
+      {
+        state = "hold";
+        std::for_each(d->hold.begin(), d->hold.end(), dpkgName);
+      }
+      if (d->install.empty() == false)
+      {
+        state = "install";
+        std::for_each(d->install.begin(), d->install.end(), dpkgName);
+      }
    }
-   if (d->install.empty() == false)
+   else
    {
-      state = "install";
-      std::for_each(d->install.begin(), d->install.end(), dpkgName);
-   }
-   fclose(dpkg);
+      int selections = -1;
+      pid_t const dpkgSelections = debSystem::ExecDpkg(Args, &selections, nullptr, DiscardOutput);
 
-   if (ExecWait(dpkgSelections, "dpkg --set-selections") == false)
-   {
-      if (d->hold.empty())
-        std::swap(d->install, d->error);
-      else if (d->install.empty())
-        std::swap(d->hold, d->error);
-      else
+      FILE* dpkg = fdopen(selections, "w");
+      std::string state;
+      auto const dpkgName = [&](pkgCache::VerIterator const &V) {
+        pkgCache::PkgIterator P = V.ParentPkg();
+        if (strcmp(V.Arch(), "none") == 0)
+           fprintf(dpkg, "%s %s\n", P.Name(), state.c_str());
+        else if (dpkgMultiArch == false)
+           fprintf(dpkg, "%s %s\n", P.FullName(true).c_str(), state.c_str());
+        else
+           fprintf(dpkg, "%s:%s %s\n", P.Name(), V.Arch(), state.c_str());
+      };
+      for (auto const &V: d->unhold)
+      {
+        if (V.ParentPkg()->CurrentVer != 0)
+           state = "install";
+        else
+           state = "deinstall";
+        dpkgName(V);
+      }
+      if (d->purge.empty() == false)
+      {
+        state = "purge";
+        std::for_each(d->purge.begin(), d->purge.end(), dpkgName);
+      }
+      if (d->deinstall.empty() == false)
+      {
+        state = "deinstall";
+        std::for_each(d->deinstall.begin(), d->deinstall.end(), dpkgName);
+      }
+      if (d->hold.empty() == false)
+      {
+        state = "hold";
+        std::for_each(d->hold.begin(), d->hold.end(), dpkgName);
+      }
+      if (d->install.empty() == false)
+      {
+        state = "install";
+        std::for_each(d->install.begin(), d->install.end(), dpkgName);
+      }
+      fclose(dpkg);
+
+      if (ExecWait(dpkgSelections, "dpkg --set-selections") == false)
       {
-        std::swap(d->hold, d->error);
+        std::move(d->purge.begin(), d->purge.end(), std::back_inserter(d->error));
+        d->purge.clear();
+        std::move(d->deinstall.begin(), d->deinstall.end(), std::back_inserter(d->error));
+        d->deinstall.clear();
+        std::move(d->hold.begin(), d->hold.end(), std::back_inserter(d->error));
+        d->hold.clear();
+        std::move(d->unhold.begin(), d->unhold.end(), std::back_inserter(d->error));
+        d->unhold.clear();
         std::move(d->install.begin(), d->install.end(), std::back_inserter(d->error));
         d->install.clear();
       }