summaryrefslogtreecommitdiff
path: root/apt-pkg/edsp.cc
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/edsp.cc
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/edsp.cc')
-rw-r--r--apt-pkg/edsp.cc154
1 files changed, 140 insertions, 14 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;