summaryrefslogtreecommitdiff
path: root/apt-pkg
diff options
context:
space:
mode:
authorDavid Kalnischkies <david@kalnischkies.de>2016-05-28 15:40:59 +0200
committerDavid Kalnischkies <david@kalnischkies.de>2016-06-27 11:57:12 +0200
commitf74d99c6a78caafdc6e32d8cb135683b7154795c (patch)
tree3056bcf8fa40dd70c65ae073e634aa142ab8e628 /apt-pkg
parentdae197476f1831269d13f4e990276ce25c483842 (diff)
eipp: provide the internal planer as an external one
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.
Diffstat (limited to 'apt-pkg')
-rw-r--r--apt-pkg/edsp.cc154
-rw-r--r--apt-pkg/edsp.h21
-rw-r--r--apt-pkg/edsp/edspindexfile.cc37
-rw-r--r--apt-pkg/edsp/edspindexfile.h13
-rw-r--r--apt-pkg/edsp/edsplistparser.cc54
-rw-r--r--apt-pkg/edsp/edsplistparser.h10
-rw-r--r--apt-pkg/edsp/edspsystem.cc18
-rw-r--r--apt-pkg/edsp/edspsystem.h9
-rw-r--r--apt-pkg/packagemanager.cc6
-rw-r--r--apt-pkg/packagemanager.h9
10 files changed, 311 insertions, 20 deletions
diff --git a/apt-pkg/edsp.cc b/apt-pkg/edsp.cc
index e37ab04b4..ae5c7a373 100644
--- a/apt-pkg/edsp.cc
+++ b/apt-pkg/edsp.cc
@@ -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;
diff --git a/apt-pkg/edsp.h b/apt-pkg/edsp.h
index 3e0982a56..271cbb6a8 100644
--- a/apt-pkg/edsp.h
+++ b/apt-pkg/edsp.h
@@ -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
diff --git a/apt-pkg/edsp/edspindexfile.cc b/apt-pkg/edsp/edspindexfile.cc
index e2863a2cc..042a88cf9 100644
--- a/apt-pkg/edsp/edspindexfile.cc
+++ b/apt-pkg/edsp/edspindexfile.cc
@@ -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() {}
diff --git a/apt-pkg/edsp/edspindexfile.h b/apt-pkg/edsp/edspindexfile.h
index 26bd1232b..e146ca80c 100644
--- a/apt-pkg/edsp/edspindexfile.h
+++ b/apt-pkg/edsp/edspindexfile.h
@@ -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
diff --git a/apt-pkg/edsp/edsplistparser.cc b/apt-pkg/edsp/edsplistparser.cc
index 39a6e8a6e..dd8890f0e 100644
--- a/apt-pkg/edsp/edsplistparser.cc
+++ b/apt-pkg/edsp/edsplistparser.cc
@@ -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() {}
diff --git a/apt-pkg/edsp/edsplistparser.h b/apt-pkg/edsp/edsplistparser.h
index 7cd5ab2b3..84138d6a8 100644
--- a/apt-pkg/edsp/edsplistparser.h
+++ b/apt-pkg/edsp/edsplistparser.h
@@ -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
diff --git a/apt-pkg/edsp/edspsystem.cc b/apt-pkg/edsp/edspsystem.cc
index 2a78efe58..b0e7b8a21 100644
--- a/apt-pkg/edsp/edspsystem.cc
+++ b/apt-pkg/edsp/edspsystem.cc
@@ -35,6 +35,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 /*{{{*/
bool edspLikeSystem::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;
diff --git a/apt-pkg/edsp/edspsystem.h b/apt-pkg/edsp/edspsystem.h
index 2c429c3d6..c0c9526b5 100644
--- a/apt-pkg/edsp/edspsystem.h
+++ b/apt-pkg/edsp/edspsystem.h
@@ -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
diff --git a/apt-pkg/packagemanager.cc b/apt-pkg/packagemanager.cc
index 8f884eac6..173fa8085 100644
--- a/apt-pkg/packagemanager.cc
+++ b/apt-pkg/packagemanager.cc
@@ -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) ?
diff --git a/apt-pkg/packagemanager.h b/apt-pkg/packagemanager.h
index 83d26115f..145fe40a8 100644
--- a/apt-pkg/packagemanager.h
+++ b/apt-pkg/packagemanager.h
@@ -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() {