]> git.saurik.com Git - apt.git/commitdiff
eipp: provide the internal planer as an external one
authorDavid Kalnischkies <david@kalnischkies.de>
Sat, 28 May 2016 13:40:59 +0000 (15:40 +0200)
committerDavid Kalnischkies <david@kalnischkies.de>
Mon, 27 Jun 2016 09:57:12 +0000 (11:57 +0200)
Testing the current implementation can benefit from being able to be
feed an EIPP request and produce a fully compliant response. It is also
a great test for EIPP in general.

23 files changed:
apt-pkg/edsp.cc
apt-pkg/edsp.h
apt-pkg/edsp/edspindexfile.cc
apt-pkg/edsp/edspindexfile.h
apt-pkg/edsp/edsplistparser.cc
apt-pkg/edsp/edsplistparser.h
apt-pkg/edsp/edspsystem.cc
apt-pkg/edsp/edspsystem.h
apt-pkg/packagemanager.cc
apt-pkg/packagemanager.h
apt-private/private-cmndline.cc
apt-private/private-cmndline.h
apt-private/private-main.cc
cmdline/apt-internal-planer.cc [new file with mode: 0644]
cmdline/makefile
debian/apt-utils.dirs
debian/apt.dirs
debian/apt.lintian-overrides
debian/rules
debian/tests/run-tests
test/integration/framework
test/integration/test-00-commands-have-help
test/integration/test-external-installation-planer-protocol

index e37ab04b4731497e0ec6668f8b2d01d793f03443..ae5c7a3733d88a6ffbf6a1dca6f51026b3372ae5 100644 (file)
@@ -12,6 +12,8 @@
 #include <apt-pkg/depcache.h>
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/cacheiterators.h>
+#include <apt-pkg/prettyprinters.h>
+#include <apt-pkg/packagemanager.h>
 #include <apt-pkg/progress.h>
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/edsp.h>
@@ -659,8 +661,12 @@ bool EDSP::ReadResponse(int const input, pkgDepCache &Cache, OpProgress *Progres
                        return false;
                } else if (section.Exists("Autoremove") == true)
                        type = "Autoremove";
-               else
+               else {
+                       char const *Start, *End;
+                       section.GetSection(Start, End);
+                       _error->Warning("Encountered an unexpected section with %d fields: %s", section.Count(), std::string(Start, End).c_str());
                        continue;
+               }
 
                size_t const id = section.FindULL(type.c_str(), VersionCount);
                if (id == VersionCount) {
@@ -1065,7 +1071,7 @@ bool EDSP::ResolveExternal(const char* const solver, pkgDepCache &Cache,
 }
                                                                        /*}}}*/
 
-bool EIPP::OrderInstall(char const * const solver, pkgDepCache &Cache, /*{{{*/
+bool EIPP::OrderInstall(char const * const solver, pkgPackageManager * const PM,       /*{{{*/
                         unsigned int const flags, OpProgress * const Progress)
 {
    int solver_in, solver_out;
@@ -1080,15 +1086,15 @@ bool EIPP::OrderInstall(char const * const solver, pkgDepCache &Cache,  /*{{{*/
    bool Okay = output.Failed() == false;
    if (Progress != NULL)
       Progress->OverallProgress(0, 100, 5, _("Execute external planer"));
-   Okay &= EIPP::WriteRequest(Cache, output, flags, Progress);
+   Okay &= EIPP::WriteRequest(PM->Cache, output, flags, Progress);
    if (Progress != NULL)
       Progress->OverallProgress(5, 100, 20, _("Execute external planer"));
-   Okay &= EIPP::WriteScenario(Cache, output, Progress);
+   Okay &= EIPP::WriteScenario(PM->Cache, output, Progress);
    output.Close();
 
    if (Progress != NULL)
       Progress->OverallProgress(25, 100, 75, _("Execute external planer"));
-   if (Okay && EIPP::ReadResponse(solver_out, Cache, Progress) == false)
+   if (Okay && EIPP::ReadResponse(solver_out, PM, Progress) == false)
       return false;
 
    return ExecWait(solver_pid, solver);
@@ -1113,7 +1119,7 @@ bool EIPP::WriteRequest(pkgDepCache &Cache, FileFd &output,               /*{{{*/
         req = &purge;
       if (P.Delete() == true)
         req = &del;
-      else if (P.NewInstall() == true || P.Upgrade() == true)
+      else if (P.NewInstall() == true || P.Upgrade() == true || P.Downgrade() == true)
         req = &inst;
       else if (P.ReInstall() == true)
         req = &reinst;
@@ -1228,27 +1234,25 @@ bool EIPP::WriteScenario(pkgDepCache &Cache, FileFd &output, OpProgress * const
 }
                                                                        /*}}}*/
 // EIPP::ReadResponse - from the given file descriptor                 /*{{{*/
-bool EIPP::ReadResponse(int const input, pkgDepCache &Cache, OpProgress *Progress) {
+bool EIPP::ReadResponse(int const input, pkgPackageManager * const PM, OpProgress *Progress) {
    /* We build an map id to mmap offset here
       In theory we could use the offset as ID, but then VersionCount
       couldn't be used to create other versionmappings anymore and it
       would be too easy for a (buggy) solver to segfault APT… */
-   /*
-   unsigned long long const VersionCount = Cache.Head().VersionCount;
+   unsigned long long const VersionCount = PM->Cache.Head().VersionCount;
    unsigned long VerIdx[VersionCount];
-   for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; ++P) {
+   for (pkgCache::PkgIterator P = PM->Cache.PkgBegin(); P.end() == false; ++P) {
       for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; ++V)
         VerIdx[V->ID] = V.Index();
    }
-   */
 
    FileFd in;
    in.OpenDescriptor(input, FileFd::ReadOnly);
    pkgTagFile response(&in, 100);
    pkgTagSection section;
 
-   std::set<decltype(Cache.PkgBegin()->ID)> seenOnce;
    while (response.Step(section) == true) {
+      char const * type = nullptr;
       if (section.Exists("Progress") == true) {
         if (Progress != NULL) {
            string msg = section.FindS("Message");
@@ -1270,8 +1274,130 @@ bool EIPP::ReadResponse(int const input, pkgDepCache &Cache, OpProgress *Progres
         std::cerr << "The following information might help you to understand what is wrong:" << std::endl;
         std::cerr << msg << std::endl << std::endl;
         return false;
-      } else {
-        _error->Warning("Encountered an unexpected section with %d fields", section.Count());
+      } else if (section.Exists("Install") == true)
+        type = "Install";
+      else if (section.Exists("Configure") == true)
+        type = "Configure";
+      else if (section.Exists("Remove") == true)
+        type = "Remove";
+      else {
+        char const *Start, *End;
+        section.GetSection(Start, End);
+        _error->Warning("Encountered an unexpected section with %d fields: %s", section.Count(), std::string(Start, End).c_str());
+        continue;
+      }
+
+      if (type == nullptr)
+        continue;
+      size_t const id = section.FindULL(type, VersionCount);
+      if (id == VersionCount) {
+        _error->Warning("Unable to parse %s request with id value '%s'!", type, section.FindS(type).c_str());
+        continue;
+      } else if (id > PM->Cache.Head().VersionCount) {
+        _error->Warning("ID value '%s' in %s request stanza is to high to refer to a known version!", section.FindS(type).c_str(), type);
+        continue;
+      }
+
+      pkgCache::VerIterator Ver(PM->Cache.GetCache(), PM->Cache.GetCache().VerP + VerIdx[id]);
+      auto const Pkg = Ver.ParentPkg();
+      if (strcmp(type, "Install") == 0)
+        PM->Install(Pkg, PM->FileNames[Pkg->ID]);
+      else if (strcmp(type, "Configure") == 0)
+        PM->Configure(Pkg);
+      else if (strcmp(type, "Remove") == 0)
+        PM->Remove(Pkg, PM->Cache[Pkg].Purge());
+   }
+   return true;
+}
+                                                                       /*}}}*/
+bool EIPP::ReadRequest(int const input, std::list<std::pair<std::string,PKG_ACTION>> &actions,/*{{{*/
+      unsigned int &flags)
+{
+   actions.clear();
+   flags = 0;
+   std::string line;
+   while (ReadLine(input, line) == true)
+   {
+      // Skip empty lines before request
+      if (line.empty() == true)
+        continue;
+      // The first Tag must be a request, so search for it
+      if (line.compare(0, 8, "Request:") != 0)
+        continue;
+
+      while (ReadLine(input, line) == true)
+      {
+        // empty lines are the end of the request
+        if (line.empty() == true)
+           return true;
+
+        PKG_ACTION pkgact = PKG_ACTION::NOOP;
+        if (LineStartsWithAndStrip(line, "Install:"))
+           pkgact = PKG_ACTION::INSTALL;
+        else if (LineStartsWithAndStrip(line, "ReInstall:"))
+           pkgact = PKG_ACTION::REINSTALL;
+        else if (LineStartsWithAndStrip(line, "Remove:"))
+           pkgact = PKG_ACTION::REMOVE;
+        else if (LineStartsWithAndStrip(line, "Architecture:"))
+           _config->Set("APT::Architecture", line);
+        else if (LineStartsWithAndStrip(line, "Architectures:"))
+           _config->Set("APT::Architectures", SubstVar(line, " ", ","));
+        else if (LineStartsWithAndStrip(line, "Planer:"))
+           ; // purely informational line
+        else
+           _error->Warning("Unknown line in EIPP Request stanza: %s", line.c_str());
+
+        if (pkgact == PKG_ACTION::NOOP)
+           continue;
+        for (auto && p: VectorizeString(line, ' '))
+           actions.emplace_back(std::move(p), pkgact);
+      }
+   }
+   return false;
+
+
+   return false;
+}
+                                                                       /*}}}*/
+bool EIPP::ApplyRequest(std::list<std::pair<std::string,PKG_ACTION>> &actions,/*{{{*/
+        pkgDepCache &Cache)
+{
+   for (auto Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
+   {
+      short versions = 0;
+      for (auto Ver = Pkg.VersionList(); Ver.end() == false; ++Ver)
+      {
+        ++versions;
+        if (Pkg.CurrentVer() == Ver)
+           continue;
+        Cache.SetCandidateVersion(Ver);
+      }
+      if (unlikely(versions > 2))
+        _error->Warning("Package %s has %d versions, but should have at most 2!", Pkg.FullName().c_str(), versions);
+   }
+   for (auto && a: actions)
+   {
+      pkgCache::PkgIterator P = Cache.FindPkg(a.first);
+      if (P.end() == true)
+      {
+        _error->Warning("Package %s is not known, so can't be acted on", a.first.c_str());
+        continue;
+      }
+      switch (a.second)
+      {
+        case PKG_ACTION::NOOP:
+           _error->Warning("Package %s has NOOP as action?!?", a.first.c_str());
+           break;
+        case PKG_ACTION::INSTALL:
+           Cache.MarkInstall(P, false);
+           break;
+        case PKG_ACTION::REINSTALL:
+           Cache.MarkInstall(P, false);
+           Cache.SetReInstall(P, true);
+           break;
+        case PKG_ACTION::REMOVE:
+           Cache.MarkDelete(P);
+           break;
       }
    }
    return true;
index 3e0982a560fd0913d792ec03afdbd1b4d0595b75..271cbb6a83e3401f189266baac01d11de2c2fa01 100644 (file)
@@ -236,16 +236,31 @@ namespace EDSP                                                            /*{{{*/
                                    bool const autoRemove, OpProgress *Progress = NULL);
 }
                                                                        /*}}}*/
+class pkgPackageManager;
 namespace EIPP                                                         /*{{{*/
 {
-   APT_HIDDEN bool OrderInstall(char const * const solver, pkgDepCache &Cache,
-        unsigned int const version, OpProgress * const Progress);
    APT_HIDDEN bool WriteRequest(pkgDepCache &Cache, FileFd &output,
         unsigned int const version, OpProgress * const Progress);
    APT_HIDDEN bool WriteScenario(pkgDepCache &Cache, FileFd &output,
         OpProgress * const Progress);
-   APT_HIDDEN bool ReadResponse(int const input, pkgDepCache &Cache,
+
+   APT_HIDDEN bool OrderInstall(char const * const planer, pkgPackageManager * const PM,
+        unsigned int const version, OpProgress * const Progress);
+   APT_HIDDEN bool ReadResponse(int const input, pkgPackageManager * const PM,
         OpProgress * const Progress);
+
+   enum class PKG_ACTION
+   {
+      NOOP,
+      INSTALL,
+      REINSTALL,
+      REMOVE
+   };
+   bool ReadRequest(int const input,
+        std::list<std::pair<std::string,PKG_ACTION>> &actions,
+        unsigned int &flags);
+   bool ApplyRequest(std::list<std::pair<std::string,PKG_ACTION>> &actions,
+        pkgDepCache &Cache);
 }
                                                                        /*}}}*/
 #endif
index e2863a2cc4160cb2ab85927ae0a62113edb9079e..042a88cf93088ba09a691c6723c647095347f6bf 100644 (file)
@@ -69,6 +69,25 @@ pkgCacheListParser * edspIndex::CreateListParser(FileFd &Pkg)
    return newError ? NULL : Parser;
 }
                                                                        /*}}}*/
+// EIPP Index                                                          /*{{{*/
+eippIndex::eippIndex(std::string const &File) : edspLikeIndex(File)
+{
+}
+std::string eippIndex::GetComponent() const
+{
+   return "eipp";
+}
+pkgCacheListParser * eippIndex::CreateListParser(FileFd &Pkg)
+{
+   if (Pkg.IsOpen() == false)
+      return NULL;
+   _error->PushToStack();
+   pkgCacheListParser * const Parser = new eippListParser(&Pkg);
+   bool const newError = _error->PendingError();
+   _error->MergeWithStack();
+   return newError ? NULL : Parser;
+}
+                                                                       /*}}}*/
 
 // Index File types for APT                                            /*{{{*/
 class APT_HIDDEN edspIFType: public pkgIndexFile::Type
@@ -82,12 +101,28 @@ class APT_HIDDEN edspIFType: public pkgIndexFile::Type
    edspIFType() {Label = "EDSP scenario file";};
 };
 APT_HIDDEN edspIFType _apt_Edsp;
-
 const pkgIndexFile::Type *edspIndex::GetType() const
 {
    return &_apt_Edsp;
 }
+
+class APT_HIDDEN eippIFType: public pkgIndexFile::Type
+{
+   public:
+   virtual pkgRecords::Parser *CreatePkgParser(pkgCache::PkgFileIterator const &) const APT_OVERRIDE
+   {
+      // we don't have a record parser for this type as the file is not presistent
+      return NULL;
+   };
+   eippIFType() {Label = "EIPP scenario file";};
+};
+APT_HIDDEN eippIFType _apt_Eipp;
+const pkgIndexFile::Type *eippIndex::GetType() const
+{
+   return &_apt_Eipp;
+}
                                                                        /*}}}*/
 
 edspLikeIndex::~edspLikeIndex() {}
 edspIndex::~edspIndex() {}
+eippIndex::~eippIndex() {}
index 26bd1232b7d8a575b5ba1e0d221d4164225798d4..e146ca80c75122e2a1a16eb90481367a257726f6 100644 (file)
@@ -46,4 +46,17 @@ public:
    virtual ~edspIndex();
 };
 
+class APT_HIDDEN eippIndex : public edspLikeIndex
+{
+protected:
+   APT_HIDDEN virtual pkgCacheListParser * CreateListParser(FileFd &Pkg) APT_OVERRIDE;
+   virtual std::string GetComponent() const APT_OVERRIDE;
+
+public:
+   virtual const Type *GetType() const APT_OVERRIDE APT_CONST;
+
+   eippIndex(std::string const &File);
+   virtual ~eippIndex();
+};
+
 #endif
index 39a6e8a6e6650843f8e63e14c850d31274c8bb55..dd8890f0e52d40dcad180974ee52a9632f0e95a3 100644 (file)
@@ -125,5 +125,59 @@ bool edspListParser::ParseStatus(pkgCache::PkgIterator &Pkg,
 }
                                                                        /*}}}*/
 
+// ListParser::eippListParser - Constructor                            /*{{{*/
+eippListParser::eippListParser(FileFd *File) : edspLikeListParser(File)
+{
+}
+                                                                       /*}}}*/
+// ListParser::ParseStatus - Parse the status field                    /*{{{*/
+// ---------------------------------------------------------------------
+/* The Status: line here is not a normal dpkg one but just one which tells
+   use if the package is installed or not, where missing means not. */
+bool eippListParser::ParseStatus(pkgCache::PkgIterator &Pkg,
+                               pkgCache::VerIterator &Ver)
+{
+   // Process the flag field
+   static std::array<WordList, 8> const statusvalues = {{
+      {"not-installed",pkgCache::State::NotInstalled},
+      {"config-files",pkgCache::State::ConfigFiles},
+      {"half-installed",pkgCache::State::HalfInstalled},
+      {"unpacked",pkgCache::State::UnPacked},
+      {"half-configured",pkgCache::State::HalfConfigured},
+      {"triggers-awaited",pkgCache::State::TriggersAwaited},
+      {"triggers-pending",pkgCache::State::TriggersPending},
+      {"installed",pkgCache::State::Installed},
+   }};
+   auto const status = Section.Find("Status");
+   if (status.empty() == false)
+   {
+      for (auto && sv: statusvalues)
+      {
+        if (status != sv.Str)
+           continue;
+        Pkg->CurrentState = sv.Val;
+        switch (Pkg->CurrentState)
+        {
+           case pkgCache::State::NotInstalled:
+           case pkgCache::State::ConfigFiles:
+              break;
+           case pkgCache::State::HalfInstalled:
+           case pkgCache::State::UnPacked:
+           case pkgCache::State::HalfConfigured:
+           case pkgCache::State::TriggersAwaited:
+           case pkgCache::State::TriggersPending:
+           case pkgCache::State::Installed:
+              Pkg->CurrentVer = Ver.Index();
+              break;
+        }
+        break;
+      }
+   }
+
+   return true;
+}
+                                                                       /*}}}*/
+
 edspLikeListParser::~edspLikeListParser() {}
 edspListParser::~edspListParser() {}
+eippListParser::~eippListParser() {}
index 7cd5ab2b36ef5d921fcfade24910ecfa2ccaafb7..84138d6a8ba2b6e5e936a575e23c74488106ec9f 100644 (file)
@@ -51,4 +51,14 @@ public:
    edspListParser(FileFd *File);
    virtual ~edspListParser();
 };
+
+class APT_HIDDEN eippListParser : public edspLikeListParser
+{
+protected:
+   virtual bool ParseStatus(pkgCache::PkgIterator &Pkg,pkgCache::VerIterator &Ver) APT_OVERRIDE;
+
+public:
+   eippListParser(FileFd *File);
+   virtual ~eippListParser();
+};
 #endif
index 2a78efe58d6e0702f7919ec6f16bc80a6a5559a7..b0e7b8a21a3b46e2a1911f8954a8fa6fa6aa80d4 100644 (file)
@@ -34,6 +34,9 @@ edspLikeSystem::edspLikeSystem(char const * const Label) : pkgSystem(Label, &deb
 }
 edspSystem::edspSystem() : edspLikeSystem("Debian APT solver interface")
 {
+}
+eippSystem::eippSystem() : edspLikeSystem("Debian APT planer interface")
+{
 }
                                                                        /*}}}*/
 // System::Lock - Get the lock                                         /*{{{*/
@@ -134,6 +137,19 @@ bool edspSystem::AddStatusFiles(std::vector<pkgIndexFile *> &List) /*{{{*/
    return true;
 }
                                                                        /*}}}*/
+bool eippSystem::AddStatusFiles(std::vector<pkgIndexFile *> &List)     /*{{{*/
+{
+   if (StatusFile == nullptr)
+   {
+      if (_config->Find("eipp::scenario", "") == "/nonexistent/stdin")
+        StatusFile.reset(new eippIndex("/nonexistent/stdin"));
+      else
+        StatusFile.reset(new eippIndex(_config->FindFile("eipp::scenario")));
+   }
+   List.push_back(StatusFile.get());
+   return true;
+}
+                                                                       /*}}}*/
 
 edspLikeSystem::~edspLikeSystem() {}
 edspSystem::~edspSystem()
@@ -145,5 +161,7 @@ edspSystem::~edspSystem()
    RemoveFile("~edspSystem", tempPrefsFile);
    rmdir(tempDir.c_str());
 }
+eippSystem::~eippSystem() {}
 
 APT_HIDDEN edspSystem edspSys;
+APT_HIDDEN eippSystem eippSys;
index 2c429c3d6839368dbf6957763043bebaa08cea83..c0c9526b5327fcd87162fd9a5b58747ce665b338 100644 (file)
@@ -57,4 +57,13 @@ public:
    virtual ~edspSystem();
 };
 
+class APT_HIDDEN eippSystem : public edspLikeSystem
+{
+   public:
+   virtual bool AddStatusFiles(std::vector<pkgIndexFile *> &List) APT_OVERRIDE;
+
+   eippSystem();
+   virtual ~eippSystem();
+};
+
 #endif
index 8f884eac633087340ef623460b7e5396d6859ef4..173fa80857d3cd56e3873ef61b8a86a01eab41a2 100644 (file)
@@ -1039,8 +1039,12 @@ pkgPackageManager::OrderResult pkgPackageManager::OrderInstall()
 
    std::string const planer = _config->Find("APT::Planer", "internal");
    if (planer != "internal")
-      if (EIPP::OrderInstall(planer.c_str(), Cache, 0, nullptr) == false)
+   {
+      if (EIPP::OrderInstall(planer.c_str(), this, 0, nullptr))
+        return Completed;
+      else
         return Failed;
+   }
 
    bool const ordering =
        _config->FindB("PackageManager::UnpackAll",true) ?
index 83d26115fd5ea9460514cc41d5d5ea639f2858a3..145fe40a8266d570d15c1032b8185814895b25ba 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/init.h>
+#include <apt-pkg/edsp.h>
 #include <apt-pkg/macros.h>
 
 #include <string>
@@ -43,13 +44,14 @@ class pkgDepCache;
 class pkgSourceList;
 class pkgOrderList;
 class pkgRecords;
+class OpProgress;
+class pkgPackageManager;
 namespace APT {
    namespace Progress {
       class PackageManager;
    }
 }
 
-
 class pkgPackageManager : protected pkgCache::Namespace
 {
    public:
@@ -115,6 +117,11 @@ class pkgPackageManager : protected pkgCache::Namespace
    // compat
    APT_DEPRECATED_MSG("Use APT::Progress::PackageManager subclass instead of fd") OrderResult DoInstall(int statusFd=-1);
 
+   friend bool EIPP::OrderInstall(char const * const planer, pkgPackageManager * const PM,
+        unsigned int const version, OpProgress * const Progress);
+   friend bool EIPP::ReadResponse(int const input, pkgPackageManager * const PM,
+        OpProgress * const Progress);
+
    // stuff that needs to be done before the fork() of a library that
    // uses apt
    OrderResult DoInstallPreFork() {
index 839b559642c1c0b0817c26d57eb758b895a4f33f..8fb4a48dd6d644b35669cf83e9bb37c972b51cfc 100644 (file)
@@ -160,6 +160,11 @@ static bool addArgumentsAPTFTPArchive(std::vector<CommandLine::Args> &Args, char
    return true;
 }
                                                                        /*}}}*/
+static bool addArgumentsAPTInternalPlaner(std::vector<CommandLine::Args> &, char const * const)/*{{{*/
+{
+   return true;
+}
+                                                                       /*}}}*/
 static bool addArgumentsAPTInternalSolver(std::vector<CommandLine::Args> &, char const * const)/*{{{*/
 {
    return true;
@@ -356,6 +361,7 @@ std::vector<CommandLine::Args> getCommandArgs(APT_CMD const Program, char const
         case APT_CMD::APT_EXTRACTTEMPLATES: addArgumentsAPTExtractTemplates(Args, Cmd); break;
         case APT_CMD::APT_FTPARCHIVE: addArgumentsAPTFTPArchive(Args, Cmd); break;
         case APT_CMD::APT_HELPER: addArgumentsAPTHelper(Args, Cmd); break;
+        case APT_CMD::APT_INTERNAL_PLANER: addArgumentsAPTInternalPlaner(Args, Cmd); break;
         case APT_CMD::APT_INTERNAL_SOLVER: addArgumentsAPTInternalSolver(Args, Cmd); break;
         case APT_CMD::APT_MARK: addArgumentsAPTMark(Args, Cmd); break;
         case APT_CMD::APT_SORTPKG: addArgumentsAPTSortPkgs(Args, Cmd); break;
@@ -412,13 +418,15 @@ static bool ShowCommonHelp(APT_CMD const Binary, CommandLine &CmdL, std::vector<
       case APT_CMD::APT_FTPARCHIVE: cmd = "apt-ftparchive(1)"; break;
       case APT_CMD::APT_GET: cmd = "apt-get(8)"; break;
       case APT_CMD::APT_HELPER: cmd = nullptr; break;
+      case APT_CMD::APT_INTERNAL_PLANER: cmd = nullptr; break;
       case APT_CMD::APT_INTERNAL_SOLVER: cmd = nullptr; break;
       case APT_CMD::APT_MARK: cmd = "apt-mark(8)"; break;
       case APT_CMD::APT_SORTPKG: cmd = "apt-sortpkgs(1)"; break;
    }
    if (cmd != nullptr)
       ioprintf(std::cout, _("See %s for more information about the available commands."), cmd);
-   if (Binary != APT_CMD::APT_DUMP_SOLVER && Binary != APT_CMD::APT_INTERNAL_SOLVER)
+   if (Binary != APT_CMD::APT_DUMP_SOLVER && Binary != APT_CMD::APT_INTERNAL_SOLVER &&
+        Binary != APT_CMD::APT_INTERNAL_PLANER)
       std::cout << std::endl <<
         _("Configuration options and syntax is detailed in apt.conf(5).\n"
               "Information about how to configure sources can be found in sources.list(5).\n"
index c0c5a7455b46d92c536a6a476849a1b6cd218d74..6882add0c0880c6348da4a326e8f5090a9543cb6 100644 (file)
@@ -22,6 +22,7 @@ enum class APT_CMD {
    APT_MARK,
    APT_SORTPKG,
    APT_DUMP_SOLVER,
+   APT_INTERNAL_PLANER,
 };
 struct aptDispatchWithHelp
 {
index 64f4bc5634cd7fac3694e68d84ee7f2a6ceb5a51..6405b71b888478ea948bf8020eb5510a7fded8d5 100644 (file)
@@ -38,6 +38,7 @@ void InitLocale(APT_CMD const binary)                         /*{{{*/
         break;
       case APT_CMD::APT_EXTRACTTEMPLATES:
       case APT_CMD::APT_FTPARCHIVE:
+      case APT_CMD::APT_INTERNAL_PLANER:
       case APT_CMD::APT_INTERNAL_SOLVER:
       case APT_CMD::APT_SORTPKG:
         textdomain("apt-utils");
diff --git a/cmdline/apt-internal-planer.cc b/cmdline/apt-internal-planer.cc
new file mode 100644 (file)
index 0000000..676d840
--- /dev/null
@@ -0,0 +1,187 @@
+// -*- mode: cpp; mode: fold -*-
+// Description                                                         /*{{{*/
+/* #####################################################################
+
+   cover around the internal solver to be able to run it like an external
+
+   ##################################################################### */
+                                                                       /*}}}*/
+// Include Files                                                       /*{{{*/
+#include <config.h>
+
+#include <apt-pkg/error.h>
+#include <apt-pkg/cmndline.h>
+#include <apt-pkg/init.h>
+#include <apt-pkg/cachefile.h>
+#include <apt-pkg/cacheset.h>
+#include <apt-pkg/strutl.h>
+#include <apt-pkg/edsp.h>
+#include <apt-pkg/fileutl.h>
+#include <apt-pkg/pkgsystem.h>
+#include <apt-pkg/configuration.h>
+#include <apt-pkg/packagemanager.h>
+#include <apt-pkg/prettyprinters.h>
+#include <apt-pkg/depcache.h>
+#include <apt-pkg/pkgcache.h>
+#include <apt-pkg/cacheiterators.h>
+
+#include <apt-private/private-output.h>
+#include <apt-private/private-cmndline.h>
+#include <apt-private/private-main.h>
+
+#include <string.h>
+#include <iostream>
+#include <sstream>
+#include <list>
+#include <string>
+#include <unistd.h>
+#include <cstdio>
+#include <stdlib.h>
+
+#include <apti18n.h>
+                                                                       /*}}}*/
+
+static bool ShowHelp(CommandLine &)                                    /*{{{*/
+{
+       std::cout <<
+               _("Usage: apt-internal-planer\n"
+               "\n"
+               "apt-internal-planer is an interface to use the current internal\n"
+               "installation planer for the APT family like an external one,\n"
+               "for debugging or the like.\n");
+       return true;
+}
+                                                                       /*}}}*/
+APT_NORETURN static void DIE(std::string const &message) {             /*{{{*/
+       std::cerr << "ERROR: " << message << std::endl;
+       _error->DumpErrors(std::cerr);
+       exit(EXIT_FAILURE);
+}
+                                                                       /*}}}*/
+static std::vector<aptDispatchWithHelp> GetCommands()                  /*{{{*/
+{
+   return {};
+}
+                                                                       /*}}}*/
+class PMOutput: public pkgPackageManager                               /*{{{*/
+{
+   FileFd &output;
+   bool const Debug;
+
+protected:
+   virtual bool Install(PkgIterator Pkg,std::string) APT_OVERRIDE
+   {
+      //std::cerr << "INSTALL: " << APT::PrettyPkg(&Cache, Pkg) << std::endl;
+      return EDSP::WriteSolutionStanza(output, "Install", Cache[Pkg].InstVerIter(Cache));
+   }
+   virtual bool Configure(PkgIterator Pkg) APT_OVERRIDE
+   {
+      //std::cerr << "CONFIGURE: " << APT::PrettyPkg(&Cache, Pkg) << " " << std::endl;
+      return EDSP::WriteSolutionStanza(output, "Configure", Cache[Pkg].InstVerIter(Cache));
+   }
+   virtual bool Remove(PkgIterator Pkg,bool) APT_OVERRIDE
+   {
+      //std::cerr << "REMOVE: " << APT::PrettyPkg(&Cache, Pkg) << " " << std::endl;
+      return EDSP::WriteSolutionStanza(output, "Remove", Pkg.CurrentVer());
+   }
+public:
+   PMOutput(pkgDepCache *Cache, FileFd &file) : pkgPackageManager(Cache), output(file),
+      Debug(_config->FindB("Debug::EDSP::WriteSolution", false))
+   {}
+
+   bool ApplyRequest(std::list<std::pair<std::string,EIPP::PKG_ACTION>> const &actions)
+   {
+      for (auto && a: actions)
+      {
+        auto const Pkg = Cache.FindPkg(a.first);
+        if (unlikely(Pkg.end() == true))
+           continue;
+        switch (a.second)
+        {
+           case EIPP::PKG_ACTION::NOOP:
+              break;
+           case EIPP::PKG_ACTION::INSTALL:
+           case EIPP::PKG_ACTION::REINSTALL:
+              FileNames[Pkg->ID] = "EIPP";
+              break;
+           case EIPP::PKG_ACTION::REMOVE:
+              break;
+        }
+      }
+      return true;
+   }
+};
+                                                                       /*}}}*/
+int main(int argc,const char *argv[])                                  /*{{{*/
+{
+       // we really don't need anything
+       DropPrivileges();
+
+       CommandLine CmdL;
+       ParseCommandLine(CmdL, APT_CMD::APT_INTERNAL_PLANER, &_config, NULL, argc, argv, &ShowHelp, &GetCommands);
+
+       // Deal with stdout not being a tty
+       if (!isatty(STDOUT_FILENO) && _config->FindI("quiet", -1) == -1)
+               _config->Set("quiet","1");
+
+       if (_config->FindI("quiet", 0) < 1)
+               _config->Set("Debug::EIPP::WriteSolution", true);
+
+       _config->Set("APT::System", "Debian APT planer interface");
+       _config->Set("APT::Planer", "internal");
+       _config->Set("eipp::scenario", "/nonexistent/stdin");
+       FileFd output;
+       if (output.OpenDescriptor(STDOUT_FILENO, FileFd::WriteOnly | FileFd::BufferedWrite, true) == false)
+          DIE("stdout couldn't be opened");
+       int const input = STDIN_FILENO;
+       SetNonBlock(input, false);
+
+       EDSP::WriteProgress(0, "Start up planer…", output);
+
+       if (pkgInitSystem(*_config,_system) == false)
+               DIE("System could not be initialized!");
+
+       EDSP::WriteProgress(1, "Read request…", output);
+
+       if (WaitFd(input, false, 5) == false)
+               DIE("WAIT timed out in the planer");
+
+       std::list<std::pair<std::string,EIPP::PKG_ACTION>> actions;
+       unsigned int flags;
+       if (EIPP::ReadRequest(input, actions, flags) == false)
+               DIE("Parsing the request failed!");
+
+       EDSP::WriteProgress(5, "Read scenario…", output);
+
+       pkgCacheFile CacheFile;
+       if (CacheFile.Open(NULL, false) == false)
+               DIE("Failed to open CacheFile!");
+
+       EDSP::WriteProgress(50, "Apply request on scenario…", output);
+
+       if (EIPP::ApplyRequest(actions, CacheFile) == false)
+               DIE("Failed to apply request to depcache!");
+
+       EDSP::WriteProgress(60, "Call orderinstall on current scenario…", output);
+
+       //_config->Set("Debug::pkgOrderList", true);
+       //_config->Set("Debug::pkgPackageManager", true);
+       PMOutput PM(CacheFile, output);
+       if (PM.ApplyRequest(actions) == false)
+               DIE("Failed to apply request to packagemanager!");
+       pkgPackageManager::OrderResult const Res = PM.DoInstallPreFork();
+       switch (Res)
+       {
+          case pkgPackageManager::Completed:
+             EDSP::WriteProgress(100, "Done", output);
+             break;
+          case pkgPackageManager::Incomplete:
+             EDSP::WriteError("pm-incomplete", "Planer could only plan Incompletely", output);
+          case pkgPackageManager::Failed:
+             EDSP::WriteError("pm-failed", "Planer failed to find an order", output);
+             break;
+       }
+
+       return DispatchCommandLine(CmdL, {});
+}
+                                                                       /*}}}*/
index cd8ff8252f10e9112dbfd8f75bff649eaac867d0..ee50224e13bd511ab2919ee2088cad96f38115af 100644 (file)
@@ -79,13 +79,19 @@ LIB_MAKES = apt-pkg/makefile apt-inst/makefile apt-private/makefile
 SOURCE = apt-extracttemplates.cc 
 include $(PROGRAM_H)
 
-# The internal solver acting as an external
+# The internal solver/planer acting as an external
 PROGRAM=apt-internal-solver
 SLIBS = -lapt-pkg -lapt-private $(INTLLIBS)
 LIB_MAKES = apt-pkg/makefile apt-private/makefile
 SOURCE = apt-internal-solver.cc
 include $(PROGRAM_H)
 
+PROGRAM=apt-internal-planer
+SLIBS = -lapt-pkg -lapt-private $(INTLLIBS)
+LIB_MAKES = apt-pkg/makefile apt-private/makefile
+SOURCE = apt-internal-planer.cc
+include $(PROGRAM_H)
+
 # This just dumps out the state
 PROGRAM=apt-dump-solver
 SLIBS = -lapt-pkg -lapt-private $(INTLLIBS)
index 681e55192bd8aaab19b6d05d127d411cfe50b0be..cb3a9ebefa5964e5f41f0a6fff84436673cdd0d0 100644 (file)
@@ -1,2 +1,3 @@
 usr/lib/apt/solvers
+usr/lib/apt/planers
 usr/bin
index 4a83d1151de0c29123563014f402af4027c14608..7486a7b6981bc58d8c1fc563486521cad7103fe4 100644 (file)
@@ -1,6 +1,7 @@
 usr/bin
 usr/lib/apt/methods
 usr/lib/apt/solvers
+usr/lib/apt/planers
 usr/lib/dpkg/methods/apt
 etc/apt
 etc/apt/apt.conf.d
@@ -16,4 +17,4 @@ var/lib/apt/periodic
 var/log/apt
 usr/share/bug/apt
 usr/share/bash-completion/completions/
-lib/systemd/system/
\ No newline at end of file
+lib/systemd/system/
index 0c4d42d1b8d95c6cd64c2c2d62e57c88dfb42cac..e51d1119f8e6f8bd613872c05fedca7eabe7b29d 100644 (file)
@@ -1,4 +1,2 @@
 # the private library is for internal sharing only
 apt: package-name-doesnt-match-sonames
-# external solvers are shipped in here:
-apt: package-contains-empty-directory
index cd21f30ef1d11b3b4d2f418a70336ad8809aa4bb..43e979dc854b3c5bb35d7027b864228db65a3fe2 100755 (executable)
@@ -189,8 +189,9 @@ apt: build-binary build-manpages debian/apt.install
        dh_install -p$@ --sourcedir=$(BLD)
 
        # Remove the bits that are in apt-utils
-       rm $(addprefix debian/$@/usr/bin/apt-,$(APT_UTILS) dump-solver internal-solver)
+       rm $(addprefix debian/$@/usr/bin/apt-,$(APT_UTILS) dump-solver internal-solver internal-planer)
        cp $(BLD)/bin/apt-dump-solver debian/$@/usr/lib/apt/solvers/dump
+       ln -s ../solvers/dump debian/$@/usr/lib/apt/planers/dump
 
        # https has its own package
        rm debian/$@/usr/lib/apt/methods/https
@@ -252,6 +253,7 @@ apt-utils: build-binary build-manpages
 
        cp $(addprefix $(BLD)/bin/apt-,$(APT_UTILS)) debian/$@/usr/bin/
        cp $(BLD)/bin/apt-internal-solver debian/$@/usr/lib/apt/solvers/apt
+       cp $(BLD)/bin/apt-internal-planer debian/$@/usr/lib/apt/planers/apt
 
        dh_install -p$@ --sourcedir=$(BLD)
        dh_link -p$@
index f858adf5f138beedbe38422c83071f5bf24ef856..11139e3cd1816fcdcf5e91578c9c28901ab4c79a 100644 (file)
@@ -17,6 +17,7 @@ APT_INTEGRATION_TESTS_METHODS_DIR=/usr/lib/apt/methods \
 APT_INTEGRATION_TESTS_LIBEXEC_DIR=/usr/lib/apt/ \
 APT_INTEGRATION_TESTS_INTERNAL_SOLVER=/usr/lib/apt/solvers/apt \
 APT_INTEGRATION_TESTS_DUMP_SOLVER=/usr/lib/apt/solvers/dump \
+APT_INTEGRATION_TESTS_INTERNAL_PLANER=/usr/lib/apt/planers/apt \
 APT_INTEGRATION_TESTS_BUILD_DIR=/usr/bin \
 APT_INTEGRATION_TESTS_LIBRARY_PATH=/dev/null/does/not/exist \
 ./test/integration/run-tests -q
index 6276ae825e227ec8a3e683b3d731abb24c6d8d9f..93e17e4548ff346e993746e8b8f25fc73f8483b0 100644 (file)
@@ -191,6 +191,7 @@ aptitude() { runapt aptitude "$@"; }
 aptextracttemplates() { runapt apt-extracttemplates "$@"; }
 aptinternalsolver() { runapt "${APTINTERNALSOLVER}" "$@"; }
 aptdumpsolver() { runapt "${APTDUMPSOLVER}" "$@"; }
+aptinternalplaner() { runapt "${APTINTERNALPLANER}" "$@"; }
 
 dpkg() {
        "${TMPWORKINGDIRECTORY}/rootdir/usr/bin/dpkg" "$@"
@@ -289,6 +290,7 @@ setupenvironment() {
         APTWEBSERVERBINDIR="${APT_INTEGRATION_TESTS_WEBSERVER_BIN_DIR:-"${BUILDDIRECTORY}"}"
         APTINTERNALSOLVER="${APT_INTEGRATION_TESTS_INTERNAL_SOLVER:-"${BUILDDIRECTORY}/apt-internal-solver"}"
        APTDUMPSOLVER="${APT_INTEGRATION_TESTS_DUMP_SOLVER:-"${BUILDDIRECTORY}/apt-dump-solver"}"
+       APTINTERNALPLANER="${APT_INTEGRATION_TESTS_INTERNAL_PLANER:-"${BUILDDIRECTORY}/apt-internal-planer"}"
        test -x "${BUILDDIRECTORY}/apt-get" || msgdie "You need to build tree first"
         # -----
 
@@ -306,6 +308,7 @@ setupenvironment() {
                ln -s "${BUILDDIRECTORY}/apt-dump-solver" usr/lib/apt/solvers/dump
                ln -s "${BUILDDIRECTORY}/apt-dump-solver" usr/lib/apt/planers/dump
                ln -s "${BUILDDIRECTORY}/apt-internal-solver" usr/lib/apt/solvers/apt
+               ln -s "${BUILDDIRECTORY}/apt-internal-planer" usr/lib/apt/planers/apt
                echo "Dir::Bin::Solvers \"${TMPWORKINGDIRECTORY}/rootdir/usr/lib/apt/solvers\";" > etc/apt/apt.conf.d/externalsolver.conf
                echo "Dir::Bin::Planers \"${TMPWORKINGDIRECTORY}/rootdir/usr/lib/apt/planers\";" > etc/apt/apt.conf.d/externalplaner.conf
        fi
index c7d794b34fef219bb295a2ba767d8126c0db0a1f..ae724fb9e1f903b16f5060720c33f2969c0ee0d7 100755 (executable)
@@ -49,7 +49,7 @@ for CMD in 'apt-cache' 'apt-cdrom' 'apt-config' \
        checkoptions "$cmd"
 done
 
-for CMD in 'apt-dump-solver'  'apt-internal-solver'; do
+for CMD in 'apt-dump-solver'  'apt-internal-solver' 'apt-internal-planer'; do
        checkoptions "$(echo "$CMD" | tr -d '-')"
 done
 
index db43675e1bec918d84149b683c563fef54d8850c..605efcd7b1e0422db5a256bcb3e25cfae75a7884 100755 (executable)
@@ -26,3 +26,6 @@ testfailure aptget install foo --planer dump -y
 testfailure grep 'unrelated-2' "$APT_EDSP_DUMP_FILENAME"
 testsuccessequal '2' grep -c '^Package: foo$' "$APT_EDSP_DUMP_FILENAME"
 testsuccessequal '1' grep -c '^Package: libfoo$' "$APT_EDSP_DUMP_FILENAME"
+#less "$APT_EDSP_DUMP_FILENAME"
+
+aptget install foo -ys #--planer apt