#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>
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) {
}
/*}}}*/
-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;
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);
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;
}
/*}}}*/
// 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");
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;
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
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
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() {}
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
}
/*}}}*/
+// 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() {}
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
}
edspSystem::edspSystem() : edspLikeSystem("Debian APT solver interface")
{
+}
+eippSystem::eippSystem() : edspLikeSystem("Debian APT planer interface")
+{
}
/*}}}*/
// System::Lock - Get the lock /*{{{*/
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()
RemoveFile("~edspSystem", tempPrefsFile);
rmdir(tempDir.c_str());
}
+eippSystem::~eippSystem() {}
APT_HIDDEN edspSystem edspSys;
+APT_HIDDEN eippSystem eippSys;
virtual ~edspSystem();
};
+class APT_HIDDEN eippSystem : public edspLikeSystem
+{
+ public:
+ virtual bool AddStatusFiles(std::vector<pkgIndexFile *> &List) APT_OVERRIDE;
+
+ eippSystem();
+ virtual ~eippSystem();
+};
+
#endif
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) ?
#include <apt-pkg/pkgcache.h>
#include <apt-pkg/init.h>
+#include <apt-pkg/edsp.h>
#include <apt-pkg/macros.h>
#include <string>
class pkgSourceList;
class pkgOrderList;
class pkgRecords;
+class OpProgress;
+class pkgPackageManager;
namespace APT {
namespace Progress {
class PackageManager;
}
}
-
class pkgPackageManager : protected pkgCache::Namespace
{
public:
// 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() {
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;
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;
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"
APT_MARK,
APT_SORTPKG,
APT_DUMP_SOLVER,
+ APT_INTERNAL_PLANER,
};
struct aptDispatchWithHelp
{
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");
--- /dev/null
+// -*- 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, {});
+}
+ /*}}}*/
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)
usr/lib/apt/solvers
+usr/lib/apt/planers
usr/bin
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
var/log/apt
usr/share/bug/apt
usr/share/bash-completion/completions/
-lib/systemd/system/
\ No newline at end of file
+lib/systemd/system/
# 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
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
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$@
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
aptextracttemplates() { runapt apt-extracttemplates "$@"; }
aptinternalsolver() { runapt "${APTINTERNALSOLVER}" "$@"; }
aptdumpsolver() { runapt "${APTDUMPSOLVER}" "$@"; }
+aptinternalplaner() { runapt "${APTINTERNALPLANER}" "$@"; }
dpkg() {
"${TMPWORKINGDIRECTORY}/rootdir/usr/bin/dpkg" "$@"
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"
# -----
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
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
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