Browse Source

eipp: let apt make a plan, not make stuff plane

Julian noticed on IRC that I fall victim to a lovely false friend by
calling referring to a 'planer' all the time even through these are
machines to e.g. remove splinters from woodwork ("make stuff plane").
The term I meant is written in german in this way (= with a single n)
but in english there are two, aka: 'planner'.

As that is unreleased code switching all instances without any
transitional provisions. Also the reason why its skipped in changelog.

Thanks: Julian Andres Klode
Gbp-Dch: Ignore
tags/debian/1.3_pre1
David Kalnischkies 5 years ago
parent
commit
8e99b22c31
20 changed files with 134 additions and 133 deletions
  1. +14
    -14
      apt-pkg/edsp.cc
  2. +1
    -1
      apt-pkg/edsp.h
  3. +1
    -1
      apt-pkg/edsp/edspsystem.cc
  4. +1
    -1
      apt-pkg/init.cc
  5. +3
    -3
      apt-pkg/packagemanager.cc
  6. +1
    -1
      apt-pkg/packagemanager.h
  7. +5
    -5
      apt-private/private-cmndline.cc
  8. +1
    -1
      apt-private/private-cmndline.h
  9. +1
    -1
      apt-private/private-main.cc
  10. +10
    -10
      cmdline/apt-internal-planner.cc
  11. +3
    -3
      cmdline/makefile
  12. +1
    -1
      debian/apt-doc.docs
  13. +1
    -1
      debian/apt-utils.dirs
  14. +1
    -1
      debian/apt.dirs
  15. +3
    -3
      debian/rules
  16. +1
    -1
      debian/tests/run-tests
  17. +65
    -65
      doc/external-installation-planner-protocol.txt
  18. +7
    -6
      test/integration/framework
  19. +1
    -1
      test/integration/test-00-commands-have-help
  20. +13
    -13
      test/integration/test-external-installation-planner-protocol

+ 14
- 14
apt-pkg/edsp.cc View File

@@ -1076,7 +1076,7 @@ bool EIPP::OrderInstall(char const * const solver, pkgPackageManager * const PM,
{
if (strcmp(solver, "internal") == 0)
{
auto const dumpfile = _config->FindFile("Dir::Log::Planer");
auto const dumpfile = _config->FindFile("Dir::Log::Planner");
if (dumpfile.empty())
return false;
auto const dumpdir = flNotFile(dumpfile);
@@ -1089,27 +1089,27 @@ bool EIPP::OrderInstall(char const * const solver, pkgPackageManager * const PM,
}

int solver_in, solver_out;
pid_t const solver_pid = ExecuteExternal("planer", solver, "Dir::Bin::Planers", &solver_in, &solver_out);
pid_t const solver_pid = ExecuteExternal("planner", solver, "Dir::Bin::Planners", &solver_in, &solver_out);
if (solver_pid == 0)
return false;

FileFd output;
if (output.OpenDescriptor(solver_in, FileFd::WriteOnly | FileFd::BufferedWrite, true) == false)
return _error->Errno("EIPP::OrderInstall", "Opening planer %s stdin on fd %d for writing failed", solver, solver_in);
return _error->Errno("EIPP::OrderInstall", "Opening planner %s stdin on fd %d for writing failed", solver, solver_in);

bool Okay = output.Failed() == false;
if (Progress != NULL)
Progress->OverallProgress(0, 100, 5, _("Execute external planer"));
Progress->OverallProgress(0, 100, 5, _("Execute external planner"));
Okay &= EIPP::WriteRequest(PM->Cache, output, flags, Progress);
if (Progress != NULL)
Progress->OverallProgress(5, 100, 20, _("Execute external planer"));
Progress->OverallProgress(5, 100, 20, _("Execute external planner"));
Okay &= EIPP::WriteScenario(PM->Cache, output, Progress);
output.Close();

if (Progress != NULL)
Progress->OverallProgress(25, 100, 75, _("Execute external planer"));
Progress->OverallProgress(25, 100, 75, _("Execute external planner"));

// we don't tell the external planers about boring things
// we don't tell the external planners about boring things
for (auto Pkg = PM->Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
{
if (Pkg->CurrentState == pkgCache::State::ConfigFiles && PM->Cache[Pkg].Purge() == true)
@@ -1127,7 +1127,7 @@ bool EIPP::WriteRequest(pkgDepCache &Cache, FileFd &output, /*{{{*/
OpProgress * const Progress)
{
if (Progress != NULL)
Progress->SubProgress(Cache.Head().PackageCount, _("Send request to planer"));
Progress->SubProgress(Cache.Head().PackageCount, _("Send request to planner"));
unsigned long p = 0;
string del, inst, reinst;
for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg, ++p)
@@ -1164,7 +1164,7 @@ bool EIPP::WriteRequest(pkgDepCache &Cache, FileFd &output, /*{{{*/
WriteOkay(Okay, output, "Install:", inst, "\n");
if (reinst.empty() == false)
WriteOkay(Okay, output, "ReInstall:", reinst, "\n");
WriteOkay(Okay, output, "Planer: ", _config->Find("APT::Planer", "internal"), "\n");
WriteOkay(Okay, output, "Planner: ", _config->Find("APT::Planner", "internal"), "\n");
if ((flags & Request::IMMEDIATE_CONFIGURATION_ALL) != 0)
WriteOkay(Okay, output, "Immediate-Configuration: yes\n");
else if ((flags & Request::NO_IMMEDIATE_CONFIGURATION) != 0)
@@ -1217,7 +1217,7 @@ template<typename forVersion> void forAllInterestingVersions(pkgDepCache &Cache,
bool EIPP::WriteScenario(pkgDepCache &Cache, FileFd &output, OpProgress * const Progress)
{
if (Progress != NULL)
Progress->SubProgress(Cache.Head().PackageCount, _("Send scenario to planer"));
Progress->SubProgress(Cache.Head().PackageCount, _("Send scenario to planner"));
unsigned long p = 0;
bool Okay = output.Failed() == false;
std::vector<std::string> archs = APT::Configuration::getArchitectures();
@@ -1318,13 +1318,13 @@ bool EIPP::ReadResponse(int const input, pkgPackageManager * const PM, OpProgres
} else if (section.Exists("Error") == true) {
std::string msg = SubstVar(SubstVar(section.FindS("Message"), "\n .\n", "\n\n"), "\n ", "\n");
if (msg.empty() == true) {
msg = _("External planer failed without a proper error message");
msg = _("External planner failed without a proper error message");
_error->Error("%s", msg.c_str());
} else
_error->Error("External planer failed with: %s", msg.substr(0,msg.find('\n')).c_str());
_error->Error("External planner failed with: %s", msg.substr(0,msg.find('\n')).c_str());
if (Progress != NULL)
Progress->Done();
std::cerr << "The planer encountered an error of type: " << section.FindS("Error") << std::endl;
std::cerr << "The planner encountered an error of type: " << section.FindS("Error") << std::endl;
std::cerr << "The following information might help you to understand what is wrong:" << std::endl;
std::cerr << msg << std::endl << std::endl;
return false;
@@ -1396,7 +1396,7 @@ bool EIPP::ReadRequest(int const input, std::list<std::pair<std::string,PKG_ACTI
_config->Set("APT::Architecture", line);
else if (LineStartsWithAndStrip(line, "Architectures:"))
_config->Set("APT::Architectures", SubstVar(line, " ", ","));
else if (LineStartsWithAndStrip(line, "Planer:"))
else if (LineStartsWithAndStrip(line, "Planner:"))
; // purely informational line
else if (LineStartsWithAndStrip(line, "Immediate-Configuration:"))
{


+ 1
- 1
apt-pkg/edsp.h View File

@@ -254,7 +254,7 @@ namespace EIPP /*{{{*/
APT_HIDDEN bool WriteScenario(pkgDepCache &Cache, FileFd &output,
OpProgress * const Progress);

APT_HIDDEN bool OrderInstall(char const * const planer, pkgPackageManager * const PM,
APT_HIDDEN bool OrderInstall(char const * const planner, pkgPackageManager * const PM,
unsigned int const version, OpProgress * const Progress);
APT_HIDDEN bool ReadResponse(int const input, pkgPackageManager * const PM,
OpProgress * const Progress);


+ 1
- 1
apt-pkg/edsp/edspsystem.cc View File

@@ -35,7 +35,7 @@ edspLikeSystem::edspLikeSystem(char const * const Label) : pkgSystem(Label, &deb
edspSystem::edspSystem() : edspLikeSystem("Debian APT solver interface")
{
}
eippSystem::eippSystem() : edspLikeSystem("Debian APT planer interface")
eippSystem::eippSystem() : edspLikeSystem("Debian APT planner interface")
{
}
/*}}}*/


+ 1
- 1
apt-pkg/init.cc View File

@@ -76,7 +76,7 @@ bool pkgInitConfig(Configuration &Cnf)
Cnf.CndSet("Dir::Log","var/log/apt");
Cnf.CndSet("Dir::Log::Terminal","term.log");
Cnf.CndSet("Dir::Log::History","history.log");
Cnf.CndSet("Dir::Log::Planer","eipp.log.xz");
Cnf.CndSet("Dir::Log::Planner","eipp.log.xz");

Cnf.Set("Dir::Ignore-Files-Silently::", "~$");
Cnf.Set("Dir::Ignore-Files-Silently::", "\\.disabled$");


+ 3
- 3
apt-pkg/packagemanager.cc View File

@@ -1037,7 +1037,7 @@ pkgPackageManager::OrderResult pkgPackageManager::OrderInstall()
if (Debug == true)
clog << "Beginning to order" << endl;

std::string const planer = _config->Find("APT::Planer", "internal");
std::string const planner = _config->Find("APT::Planner", "internal");
unsigned int flags = 0;
if (_config->FindB("APT::Immediate-Configure", true) == false)
flags |= EIPP::Request::NO_IMMEDIATE_CONFIGURATION;
@@ -1045,8 +1045,8 @@ pkgPackageManager::OrderResult pkgPackageManager::OrderInstall()
flags |= EIPP::Request::IMMEDIATE_CONFIGURATION_ALL;
else if (_config->FindB("APT::Force-LoopBreak", false))
flags |= EIPP::Request::ALLOW_TEMPORARY_REMOVE_OF_ESSENTIALS;
auto const ret = EIPP::OrderInstall(planer.c_str(), this, flags, nullptr);
if (planer != "internal")
auto const ret = EIPP::OrderInstall(planner.c_str(), this, flags, nullptr);
if (planner != "internal")
return ret ? Completed : Failed;

bool const ordering =


+ 1
- 1
apt-pkg/packagemanager.h View File

@@ -117,7 +117,7 @@ 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,
friend bool EIPP::OrderInstall(char const * const planner, pkgPackageManager * const PM,
unsigned int const version, OpProgress * const Progress);
friend bool EIPP::ReadResponse(int const input, pkgPackageManager * const PM,
OpProgress * const Progress);


+ 5
- 5
apt-private/private-cmndline.cc View File

@@ -160,7 +160,7 @@ static bool addArgumentsAPTFTPArchive(std::vector<CommandLine::Args> &Args, char
return true;
}
/*}}}*/
static bool addArgumentsAPTInternalPlaner(std::vector<CommandLine::Args> &, char const * const)/*{{{*/
static bool addArgumentsAPTInternalPlanner(std::vector<CommandLine::Args> &, char const * const)/*{{{*/
{
return true;
}
@@ -191,7 +191,7 @@ static bool addArgumentsAPTGet(std::vector<CommandLine::Args> &Args, char const
addArg(0, "auto-remove", "APT::Get::AutomaticRemove", 0);
addArg(0, "reinstall", "APT::Get::ReInstall", 0);
addArg(0, "solver", "APT::Solver", CommandLine::HasArg);
addArg(0, "planer", "APT::Planer", CommandLine::HasArg);
addArg(0, "planner", "APT::Planner", CommandLine::HasArg);
if (CmdMatches("upgrade"))
{
addArg(0, "new-pkgs", "APT::Get::Upgrade-Allow-New",
@@ -361,7 +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_PLANNER: addArgumentsAPTInternalPlanner(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;
@@ -418,7 +418,7 @@ 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_PLANNER: 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;
@@ -426,7 +426,7 @@ static bool ShowCommonHelp(APT_CMD const Binary, CommandLine &CmdL, std::vector<
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 &&
Binary != APT_CMD::APT_INTERNAL_PLANER)
Binary != APT_CMD::APT_INTERNAL_PLANNER)
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"


+ 1
- 1
apt-private/private-cmndline.h View File

@@ -22,7 +22,7 @@ enum class APT_CMD {
APT_MARK,
APT_SORTPKG,
APT_DUMP_SOLVER,
APT_INTERNAL_PLANER,
APT_INTERNAL_PLANNER,
};
struct aptDispatchWithHelp
{


+ 1
- 1
apt-private/private-main.cc View File

@@ -38,7 +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_PLANNER:
case APT_CMD::APT_INTERNAL_SOLVER:
case APT_CMD::APT_SORTPKG:
textdomain("apt-utils");


cmdline/apt-internal-planer.cc → cmdline/apt-internal-planner.cc View File

@@ -44,10 +44,10 @@
static bool ShowHelp(CommandLine &) /*{{{*/
{
std::cout <<
_("Usage: apt-internal-planer\n"
_("Usage: apt-internal-planner\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"
"apt-internal-planner is an interface to use the current internal\n"
"installation planner for the APT family like an external one,\n"
"for debugging or the like.\n");
return true;
}
@@ -118,7 +118,7 @@ int main(int argc,const char *argv[]) /*{{{*/
DropPrivileges();

CommandLine CmdL;
ParseCommandLine(CmdL, APT_CMD::APT_INTERNAL_PLANER, &_config, NULL, argc, argv, &ShowHelp, &GetCommands);
ParseCommandLine(CmdL, APT_CMD::APT_INTERNAL_PLANNER, &_config, NULL, argc, argv, &ShowHelp, &GetCommands);

// Deal with stdout not being a tty
if (!isatty(STDOUT_FILENO) && _config->FindI("quiet", -1) == -1)
@@ -127,8 +127,8 @@ int main(int argc,const char *argv[]) /*{{{*/
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("APT::System", "Debian APT planner interface");
_config->Set("APT::Planner", "internal");
_config->Set("eipp::scenario", "/nonexistent/stdin");
FileFd output;
if (output.OpenDescriptor(STDOUT_FILENO, FileFd::WriteOnly | FileFd::BufferedWrite, true) == false)
@@ -136,7 +136,7 @@ int main(int argc,const char *argv[]) /*{{{*/
int const input = STDIN_FILENO;
SetNonBlock(input, false);

EDSP::WriteProgress(0, "Start up planer…", output);
EDSP::WriteProgress(0, "Start up planner…", output);

if (pkgInitSystem(*_config,_system) == false)
DIE("System could not be initialized!");
@@ -144,7 +144,7 @@ int main(int argc,const char *argv[]) /*{{{*/
EDSP::WriteProgress(1, "Read request…", output);

if (WaitFd(input, false, 5) == false)
DIE("WAIT timed out in the planer");
DIE("WAIT timed out in the planner");

std::list<std::pair<std::string,EIPP::PKG_ACTION>> actions;
unsigned int flags;
@@ -180,12 +180,12 @@ int main(int argc,const char *argv[]) /*{{{*/
EDSP::WriteProgress(100, "Done", output);
break;
case pkgPackageManager::Incomplete:
broken << "Planer could only incompletely plan an installation order!" << std::endl;
broken << "Planner could only incompletely plan an installation order!" << std::endl;
_error->DumpErrors(broken, GlobalError::DEBUG);
EDSP::WriteError("pm-incomplete", broken.str(), output);
break;
case pkgPackageManager::Failed:
broken << "Planer failed to find an installation order!" << std::endl;
broken << "Planner failed to find an installation order!" << std::endl;
_error->DumpErrors(broken, GlobalError::DEBUG);
EDSP::WriteError("pm-failed", broken.str(), output);
break;

+ 3
- 3
cmdline/makefile View File

@@ -79,17 +79,17 @@ LIB_MAKES = apt-pkg/makefile apt-inst/makefile apt-private/makefile
SOURCE = apt-extracttemplates.cc
include $(PROGRAM_H)

# The internal solver/planer acting as an external
# The internal solver/planner 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
PROGRAM=apt-internal-planner
SLIBS = -lapt-pkg -lapt-private $(INTLLIBS)
LIB_MAKES = apt-pkg/makefile apt-private/makefile
SOURCE = apt-internal-planer.cc
SOURCE = apt-internal-planner.cc
include $(PROGRAM_H)

# This just dumps out the state


+ 1
- 1
debian/apt-doc.docs View File

@@ -2,5 +2,5 @@ build/docs/guide*
build/docs/offline*
README.progress-reporting
doc/external-dependency-solver-protocol.txt
doc/external-installation-planer-protocol.txt
doc/external-installation-planner-protocol.txt
doc/acquire-additional-files.txt

+ 1
- 1
debian/apt-utils.dirs View File

@@ -1,3 +1,3 @@
usr/lib/apt/solvers
usr/lib/apt/planers
usr/lib/apt/planners
usr/bin

+ 1
- 1
debian/apt.dirs View File

@@ -1,7 +1,7 @@
usr/bin
usr/lib/apt/methods
usr/lib/apt/solvers
usr/lib/apt/planers
usr/lib/apt/planners
usr/lib/dpkg/methods/apt
etc/apt
etc/apt/apt.conf.d


+ 3
- 3
debian/rules View File

@@ -189,9 +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 internal-planer)
rm $(addprefix debian/$@/usr/bin/apt-,$(APT_UTILS) dump-solver internal-solver internal-planner)
cp $(BLD)/bin/apt-dump-solver debian/$@/usr/lib/apt/solvers/dump
ln -s ../solvers/dump debian/$@/usr/lib/apt/planers/dump
ln -s ../solvers/dump debian/$@/usr/lib/apt/planners/dump

# https has its own package
rm debian/$@/usr/lib/apt/methods/https
@@ -253,7 +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
cp $(BLD)/bin/apt-internal-planner debian/$@/usr/lib/apt/planners/apt

dh_install -p$@ --sourcedir=$(BLD)
dh_link -p$@


+ 1
- 1
debian/tests/run-tests View File

@@ -17,7 +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_INTERNAL_PLANNER=/usr/lib/apt/planners/apt \
APT_INTEGRATION_TESTS_BUILD_DIR=/usr/bin \
APT_INTEGRATION_TESTS_LIBRARY_PATH=/dev/null/does/not/exist \
./test/integration/run-tests -q

doc/external-installation-planer-protocol.txt → doc/external-installation-planner-protocol.txt View File

@@ -1,8 +1,8 @@
# APT External Installation Planer Protocol (EIPP) - version 0.1
# APT External Installation Planner Protocol (EIPP) - version 0.1

This document describes the communication protocol between APT and
external installation planer. The protocol is called APT EIPP, for "APT
External Installation Planer Protocol".
external installation planner. The protocol is called APT EIPP, for "APT
External Installation Planner Protocol".


## Terminology
@@ -16,37 +16,37 @@ and "arch" a dpkg architecture.
## Components

- **APT**: we know this one.
- APT is equipped with its own **internal planer** for the order of
- APT is equipped with its own **internal planner** for the order of
package installation (and removal) which is identified by the string
`internal`.
- **External planer**: an *external* software component able to plan an
- **External planner**: an *external* software component able to plan an
installation on behalf of APT.

At each interaction with APT, a single planer is in use. When there is
a total of 2 or more planers, internals or externals, the user can
At each interaction with APT, a single planner is in use. When there is
a total of 2 or more planners, internals or externals, the user can
choose which one to use.

Each planer is identified by an unique string, the **planer name**.
Planer names must be formed using only alphanumeric ASCII characters,
dashes, and underscores; planer names must start with a lowercase ASCII
letter. The special name `internal` denotes APT's internal planer, is
reserved, and cannot be used by external planers.
Each planner is identified by an unique string, the **planner name**.
Planner names must be formed using only alphanumeric ASCII characters,
dashes, and underscores; planner names must start with a lowercase ASCII
letter. The special name `internal` denotes APT's internal planner, is
reserved, and cannot be used by external planners.


## Installation

Each external planer is installed as a file under Dir::Bin::Planers (see
below), which defaults to `/usr/lib/apt/planers`. We will assume in the
remainder of this section that such a default value is in effect.
Each external planner is installed as a file under Dir::Bin::Planners
(see below), which defaults to `/usr/lib/apt/planners`. We will assume
in the remainder of this section that such a default value is in effect.

The naming scheme is `/usr/lib/apt/planers/NAME`, where `NAME` is the
name of the external planer.
The naming scheme is `/usr/lib/apt/planners/NAME`, where `NAME` is the
name of the external planner.

Each file under `/usr/lib/apt/planers` corresponding to an external
planer must be executable.
Each file under `/usr/lib/apt/planners` corresponding to an external
planner must be executable.

No non-planer files must be installed under `/usr/lib/apt/planers`, so
that an index of available external planers can be obtained by listing
No non-planner files must be installed under `/usr/lib/apt/planners`, so
that an index of available external planners can be obtained by listing
the content of that directory.


@@ -56,41 +56,41 @@ Several APT options can be used to affect installation planing in APT.
An overview of them is given below. Please refer to proper APT
configuration documentation for more, and more up to date, information.

- **APT::Planer**: the name of the planer to be used for dependency
solving. Defaults to `internal`
- **APT::Planner**: the name of the planner to be used for dependency
solving. Defaults to `internal`

- **Dir::Bin::Planers**: absolute path of the directory where to look
for external solvers. Defaults to `/usr/lib/apt/planers`.
- **Dir::Bin::Planners**: absolute path of the directory where to look
for external solvers. Defaults to `/usr/lib/apt/planners`.


## Protocol

When configured to use an external planer, APT will resort to it to
When configured to use an external planner, APT will resort to it to
decide in which order packages should be installed, configured and
removed.

The interaction happens **in batch**: APT will invoke the external
planer passing the current status of (half-)installed packages and of
planner passing the current status of (half-)installed packages and of
packages which should be installed, as well as a request denoting the
packages to install, reinstall, remove and purge. The external planer
packages to install, reinstall, remove and purge. The external planner
will compute a valid plan of when and how to call the low-level package
manager (like dpkg) with each package to satisfy the request.

External planers are invoked by executing them. Communications happens
External planners are invoked by executing them. Communications happens
via the file descriptors: **stdin** (standard input) and **stdout**
(standard output). stderr is not used by the EIPP protocol. Planers can
(standard output). stderr is not used by the EIPP protocol. Planners can
therefore use stderr to dump debugging information that could be
inspected separately.

After invocation, the protocol passes through a sequence of phases:

1. APT invokes the external planer
2. APT send to the planer an installation planer **scenario**
3. The planer calculates the order. During this phase the planer may
1. APT invokes the external planner
2. APT send to the planner an installation planner **scenario**
3. The planner calculates the order. During this phase the planner may
send, repeatedly, **progress** information to APT.
4. The planer sends back to APT an **answer**, i.e. either a *solution*
4. The planner sends back to APT an **answer**, i.e. either a *solution*
or an *error* report.
5. The external planer exits
5. The external planner exits


### Scenario
@@ -106,14 +106,14 @@ line.

#### Request

Within an installation planer scenario, a request represents the action
Within an installation planner scenario, a request represents the action
on packages requested by the user explicitly as well as potentially
additions calculated by a dependency resolver which the user has
accepted.

An installation planer is not allowed to suggest the modification of
An installation planner is not allowed to suggest the modification of
package states (e.g. removing additional packages) even if it can't
calculate a solution otherwise – the planer must error out in such
calculate a solution otherwise – the planner must error out in such
a case. An exception is made for scenarios which contain packages which
aren't completely installed (like half-installed or trigger-awaiting):
Solvers are free to move these packages to a fully installed state (but
@@ -158,22 +158,22 @@ The following **action fields** are supported in request stanzas:

The following **preference fields** are supported in request stanzas:

- **Planer:** (optional, defaults to the empty string) a purely
informational string specifying to which planer this request was send
- **Planner:** (optional, defaults to the empty string) a purely
informational string specifying to which planner this request was send
initially.

- **Immediate-Configuration:** (option, unset by default) A boolean
value defining if the planer should try to configure all packages as
value defining if the planner should try to configure all packages as
quickly as possible (true) or shouldn't perform any kind of immediate
configuration at all (false). If not explicitly set with this field
the planer is free to pick either mode or implementing e.g. a mode
the planner is free to pick either mode or implementing e.g. a mode
which configures only packages immediately if they are flagged as
`Essential` (or are dependencies of packages marked as `Essential`).

- **Allow-Temporary-Remove-of-Essentials** (optional, defaults to `no`).
A boolean value allowing the planer (if set to yes) to temporarily
A boolean value allowing the planner (if set to yes) to temporarily
remove an essential package. Associated with the APT::Force-LoopBreak
configuration option its main use is highlighting that planers who do
configuration option its main use is highlighting that planners who do
temporary removes must take special care in terms of essentials. Legit
uses of this option by users is very uncommon, traditionally
a situation in which it is needed indicates a packaging error.
@@ -201,17 +201,17 @@ field. The following fields are supported in package stanzas:

### Answer

An answer from the external planer to APT is either a *solution* or an
An answer from the external planner to APT is either a *solution* or an
*error*.

The following invariant on **exit codes** must hold true. When the
external planer is *able to find a solution*, it will write the solution
to standard output and then exit with an exit code of 0. When the
external planer is *unable to find a solution* (and is aware of that),
it will write an error to standard output and then exit with an exit
code of 0. An exit code other than 0 will be interpreted as a planer
crash with no meaningful error about dependency resolution to convey to
the user.
external planner is *able to find a solution*, it will write the
solution to standard output and then exit with an exit code of 0. When
the external planner is *unable to find a solution* (and is aware of
that), it will write an error to standard output and then exit with an
exit code of 0. An exit code other than 0 will be interpreted as
a planner crash with no meaningful error about dependency resolution to
convey to the user.


#### Solution
@@ -245,18 +245,18 @@ a set isn't significant through.

The solution needs to be valid (it is not allowed to configure a package
before it was unpacked, dependency relations must be satisfied, …), but
they don't need to be complete: A planer can and should expect that any
they don't need to be complete: A planner can and should expect that any
package which wasn't explicitly configured will be configured at the end
automatically. That also means through that a planer is not allowed to
automatically. That also means through that a planner is not allowed to
produce a solution in which a package remains unconfigured.

In terms of expressivity, all stanzas can carry one single field each, as
APT-IDs are enough to pinpoint packages to be installed/removed. Nonetheless,
for protocol readability, it is recommended that planers either add
unconditionally the fields Package, Version, and Architecture to all
install/remove stanzas or, alternatively, that they support a `--verbose`
command line flag that explicitly enables the output of those fields in
solutions.
APT-IDs are enough to pinpoint packages to be installed/removed.
Nonetheless, for protocol readability, it is recommended that planners
either add unconditionally the fields Package, Version, and Architecture
to all install/remove stanzas or, alternatively, that they support
a `--verbose` command line flag that explicitly enables the output of
those fields in solutions.

#### Error

@@ -267,7 +267,7 @@ following fields are supported in error stanzas:
it should be a unique error identifier, such as a UUID.

- **Message:** (mandatory). The value of this field is a text string,
meant to be read by humans, that explains the cause of the planer
meant to be read by humans, that explains the cause of the planner
error. Message fields might be multi-line, like the Description field
in the dpkg database. The first line conveys a short message, which
can be explained in more details using subsequent lines.
@@ -275,7 +275,7 @@ following fields are supported in error stanzas:

### Progress

During dependency solving, an external planer may send progress
During dependency solving, an external planner may send progress
information to APT using **progress stanzas**. A progress stanza starts
with the Progress field and might contain the following fields:

@@ -285,11 +285,11 @@ with the Progress field and might contain the following fields:

- **Percentage:** (optional). An integer from 0 to 100, representing the
completion of the installation planning process, as declared by the
planer.
planner.

- **Message:** (optional). A textual message, meant to be read by the
APT user, telling what is going on within the installation planer
(e.g. the current phase of planning, as declared by the planer).
APT user, telling what is going on within the installation planner
(e.g. the current phase of planning, as declared by the planner).


# Future extensions

+ 7
- 6
test/integration/framework View File

@@ -191,7 +191,7 @@ aptitude() { runapt aptitude "$@"; }
aptextracttemplates() { runapt apt-extracttemplates "$@"; }
aptinternalsolver() { runapt "${APTINTERNALSOLVER}" "$@"; }
aptdumpsolver() { runapt "${APTDUMPSOLVER}" "$@"; }
aptinternalplaner() { runapt "${APTINTERNALPLANER}" "$@"; }
aptinternalplanner() { runapt "${APTINTERNALPLANNER}" "$@"; }

dpkg() {
"${TMPWORKINGDIRECTORY}/rootdir/usr/bin/dpkg" "$@"
@@ -290,7 +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"}"
APTINTERNALPLANNER="${APT_INTEGRATION_TESTS_INTERNAL_PLANNER:-"${BUILDDIRECTORY}/apt-internal-planner"}"
test -x "${BUILDDIRECTORY}/apt-get" || msgdie "You need to build tree first"
# -----

@@ -304,13 +304,13 @@ setupenvironment() {
mkdir -p usr/lib/apt
ln -s "${METHODSDIR}" usr/lib/apt/methods
if [ "$BUILDDIRECTORY" = "$LIBRARYPATH" ]; then
mkdir -p usr/lib/apt/solvers usr/lib/apt/planers
mkdir -p usr/lib/apt/solvers usr/lib/apt/planners
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-dump-solver" usr/lib/apt/planners/dump
ln -s "${BUILDDIRECTORY}/apt-internal-solver" usr/lib/apt/solvers/apt
ln -s "${BUILDDIRECTORY}/apt-internal-planer" usr/lib/apt/planers/apt
ln -s "${BUILDDIRECTORY}/apt-internal-planner" usr/lib/apt/planners/apt
echo "Dir::Bin::Solvers \"${TMPWORKINGDIRECTORY}/rootdir/usr/lib/apt/solvers\";" >> ../aptconfig.conf
echo "Dir::Bin::Planers \"${TMPWORKINGDIRECTORY}/rootdir/usr/lib/apt/planers\";" >> ../aptconfig.conf
echo "Dir::Bin::Planners \"${TMPWORKINGDIRECTORY}/rootdir/usr/lib/apt/planners\";" >> ../aptconfig.conf
fi
# use the autoremove from the BUILDDIRECTORY if its there, otherwise
# system
@@ -347,6 +347,7 @@ setupenvironment() {
echo 'Binary::gpgv::APT::Sandbox::User "root";' >> aptconfig.conf
# same for the solver executables
echo 'APT::Solver::RunAsUser "root";' >> aptconfig.conf
echo 'APT::Planner::RunAsUser "root";' >> aptconfig.conf
fi

cat > "${TMPWORKINGDIRECTORY}/rootdir/usr/bin/dpkg" <<EOF


+ 1
- 1
test/integration/test-00-commands-have-help View File

@@ -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' 'apt-internal-planer'; do
for CMD in 'apt-dump-solver' 'apt-internal-solver' 'apt-internal-planner'; do
checkoptions "$(echo "$CMD" | tr -d '-')"
done



test/integration/test-external-installation-planer-protocol → test/integration/test-external-installation-planner-protocol View File

@@ -21,17 +21,17 @@ insertinstalledpackage 'unrelated-1' 'all' '1'
setupaptarchive --no-update

EIPPLOG="${TMPWORKINGDIRECTORY}/rootdir/var/log/apt/eipp.log"
echo "Dir::Log::Planer \"$EIPPLOG\";" > ./rootdir/etc/apt/apt.conf.d/eipp-logging
echo "Dir::Log::Planner \"$EIPPLOG\";" > ./rootdir/etc/apt/apt.conf.d/eipp-logging

testsuccess apt update
export APT_EDSP_DUMP_FILENAME="${TMPWORKINGDIRECTORY}/eipp.dump"
export APT_EDSP_DUMP_FILENAME="${TMPWORKINGDIRECTORY}/downloaded/dump.eipp"
testfailure test -r "$EIPPLOG"
testfailure aptget install foo --planer dump -y
testfailure aptget install foo --planner dump -y
testfailure test -r "$EIPPLOG"
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"
testsuccessequal 'Planer: dump' grep '^Planer: ' "$APT_EDSP_DUMP_FILENAME"
testsuccessequal 'Planner: dump' grep '^Planner: ' "$APT_EDSP_DUMP_FILENAME"

testsuccess aptget install foo -s
testsuccess aptget install foo -y
@@ -41,13 +41,13 @@ Architecture: amd64
Architectures: amd64
Remove: bar:amd64
Install: libfoo:amd64 foo:amd64
Planer: internal' head -n 6 "$EIPPLOG"
aptinternalplaner < "$EIPPLOG" > planer.log || true
Planner: internal' head -n 6 "$EIPPLOG"
aptinternalplanner < "$EIPPLOG" > planner.log || true
testsuccessequal 'Remove: 6
Unpack: 2
Unpack: 4
Configure: 2
Configure: 4' grep -e '^Unpack:' -e '^Install:' -e '^Configure:' -e '^Remove:' planer.log
Configure: 4' grep -e '^Unpack:' -e '^Install:' -e '^Configure:' -e '^Remove:' planner.log

rm -f "$EIPPLOG"
testsuccess aptget install foo -s --reinstall
@@ -57,10 +57,10 @@ testsuccessequal 'Request: EIPP 0.1
Architecture: amd64
Architectures: amd64
ReInstall: foo:amd64
Planer: internal' head -n 5 "$EIPPLOG"
aptinternalplaner < "$EIPPLOG" > planer.log || true
Planner: internal' head -n 5 "$EIPPLOG"
aptinternalplanner < "$EIPPLOG" > planner.log || true
testsuccessequal 'Unpack: 4
Configure: 4' grep -e '^Unpack:' -e '^Install:' -e '^Configure:' -e '^Remove:' planer.log
Configure: 4' grep -e '^Unpack:' -e '^Install:' -e '^Configure:' -e '^Remove:' planner.log

rm -f "$EIPPLOG"
testsuccess aptget purge foo -s
@@ -70,6 +70,6 @@ testsuccessequal 'Request: EIPP 0.1
Architecture: amd64
Architectures: amd64
Remove: foo:amd64
Planer: internal' head -n 5 "$EIPPLOG"
aptinternalplaner < "$EIPPLOG" > planer.log || true
testsuccessequal 'Remove: 4' grep -e '^Unpack:' -e '^Install:' -e '^Configure:' -e '^Remove:' planer.log
Planner: internal' head -n 5 "$EIPPLOG"
aptinternalplanner < "$EIPPLOG" > planner.log || true
testsuccessequal 'Remove: 4' grep -e '^Unpack:' -e '^Install:' -e '^Configure:' -e '^Remove:' planner.log

Loading…
Cancel
Save