|
|
@@ -0,0 +1,295 @@
|
|
|
+# APT External Dependency Solver Protocol (EDSP) - version 0.3
|
|
|
+
|
|
|
+This document describes the communication protocol between APT and
|
|
|
+external dependency solvers. The protocol is called APT EDSP, for "APT
|
|
|
+External Dependency Solver Protocol".
|
|
|
+
|
|
|
+
|
|
|
+## Components
|
|
|
+
|
|
|
+- **APT**: we know this one.
|
|
|
+- APT is equipped with its own **internal solver** for dependencies,
|
|
|
+ which is identified by the string `internal`.
|
|
|
+- **External solver**: an *external* software component able to resolve
|
|
|
+ dependencies on behalf of APT.
|
|
|
+
|
|
|
+At each interaction with APT, a single solver is in use. When there is
|
|
|
+a total of 2 or more solvers, internals or externals, the user can
|
|
|
+choose which one to use.
|
|
|
+
|
|
|
+Each solver is identified by an unique string, the **solver
|
|
|
+name**. Solver names must be formed using only alphanumeric ASCII
|
|
|
+characters, dashes, and underscores; solver names must start with a
|
|
|
+lowercase ASCII letter. The special name `internal` denotes APT's
|
|
|
+internal solver, is reserved, and cannot be used by external solvers.
|
|
|
+
|
|
|
+
|
|
|
+## Installation
|
|
|
+
|
|
|
+Each external solver is installed as a file under
|
|
|
+`/usr/lib/apt/solvers`. The naming scheme is
|
|
|
+`/usr/lib/apt/solvers/NAME`, where `NAME` is the name of the external
|
|
|
+solver.
|
|
|
+
|
|
|
+Each file under `/usr/lib/apt/solvers` corresponding to an external
|
|
|
+solver must be executable.
|
|
|
+
|
|
|
+No non-solver files must be installed under `/usr/lib/apt/solvers`, so
|
|
|
+that an index of available external solvers can be obtained by listing
|
|
|
+the content of that directory.
|
|
|
+
|
|
|
+
|
|
|
+## Configuration
|
|
|
+
|
|
|
+Several APT options can be used to affect dependency solving 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::Solver::Name**: the name of the solver to be used for
|
|
|
+ dependency solving. Defaults to `internal`
|
|
|
+
|
|
|
+- **APT::Solver::Strict-Pinning**: whether pinning must be strictly
|
|
|
+ respected (as the internal solver does) or can be slightly deviated
|
|
|
+ from. Defaults to `yes`.
|
|
|
+
|
|
|
+- **APT::Solver::NAME::Preferences** (where NAME is a solver name):
|
|
|
+ solver-specific user preference string used during dependency solving,
|
|
|
+ when the solver NAME is in use. Check solver-specific documentation
|
|
|
+ for what is supported here. Defaults to the empty string.
|
|
|
+
|
|
|
+
|
|
|
+## Protocol
|
|
|
+
|
|
|
+When configured to use an external solver, APT will resort to it to
|
|
|
+decide which packages should be installed or removed.
|
|
|
+
|
|
|
+The interaction happens **in batch**: APT will invoke the external
|
|
|
+solver passing the current status of installed and available packages,
|
|
|
+as well as the user request to alter the set of installed packages. The
|
|
|
+external solver will compute a new complete set of installed packages
|
|
|
+and gives APT a "diff" listing of which *additional* packages should be
|
|
|
+installed and of which currently installed packages should be
|
|
|
+*removed*. (Note: the order in which those actions have to be performed
|
|
|
+will be up to APT to decide.)
|
|
|
+
|
|
|
+External solvers are invoked by executing them. Communications happens
|
|
|
+via the file descriptors: **stdin** (standard input) and **stdout**
|
|
|
+(standard output). stderr is not used by the EDSP protocol. Solvers 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 solver
|
|
|
+2. APT send to the solver a dependency solving **scenario**
|
|
|
+3. The solver solves dependencies. During this phase the solver may
|
|
|
+ send, repeatedly, **progress** information to APT.
|
|
|
+4. The solver sends back to APT an **answer**, i.e. either a *solution*
|
|
|
+ or an *error* report.
|
|
|
+5. The external solver exits
|
|
|
+
|
|
|
+
|
|
|
+### Scenario
|
|
|
+
|
|
|
+A scenario is a text file encoded in a format very similar to the "Deb
|
|
|
+822" format (AKA "the format used by Debian `Packages` files"). A
|
|
|
+scenario consists of two distinct parts: a **request** and a **package
|
|
|
+universe**, occurring in that order. The request consists of a single
|
|
|
+Deb 822 stanza, while the package universe consists of several such
|
|
|
+stanzas. All stanzas occurring in a scenario are separated by an empty
|
|
|
+line.
|
|
|
+
|
|
|
+
|
|
|
+#### Request
|
|
|
+
|
|
|
+Within a dependency solving scenario, a request represents the action on
|
|
|
+installed packages requested by the user.
|
|
|
+
|
|
|
+A request is a single Deb 822 stanza opened by a mandatory Request field
|
|
|
+and followed by a mixture of action and preference fields.
|
|
|
+
|
|
|
+The value of the **Request:** field is a string describing the EDSP
|
|
|
+protocol which will be used to communicate. At present, the string must
|
|
|
+be `EDSP 0.3`.
|
|
|
+
|
|
|
+a unique request identifier, such as an
|
|
|
+UUID. Request fields are mainly used to identify the beginning of a
|
|
|
+request stanza; their actual values are otherwise not used by the EDSP
|
|
|
+protocol.
|
|
|
+
|
|
|
+The following **action fields** are supported in request stanzas:
|
|
|
+
|
|
|
+- **Install:** (optional, defaults to the empty string) A space
|
|
|
+ separated list of package names, with *no version attached*, to
|
|
|
+ install. This field denotes a list of packages that the user wants to
|
|
|
+ install, usually via an APT `install` request.
|
|
|
+
|
|
|
+- **Remove:** (optional, defaults to the empty string) Same syntax of
|
|
|
+ Install. This field denotes a list of packages that the user wants to
|
|
|
+ remove, usually via APT `remove` or `purge` requests.
|
|
|
+
|
|
|
+- **Upgrade:** (optional, defaults to `no`). Allowed values: `yes`,
|
|
|
+ `no`. When set to `yes`, an upgrade of all installed packages has been
|
|
|
+ requested, usually via an APT `upgrade` request.
|
|
|
+
|
|
|
+- **Dist-Upgrade:** (optional, defaults to `no`). Allowed values: `yes`,
|
|
|
+ `no`. Same as Upgrade, but for APT `dist-upgrade` requests.
|
|
|
+
|
|
|
+- **Autoremove:** (optional, defaults to `no`). Allowed values: `yes`,
|
|
|
+ `no`. When set to `yes`, a clean up of unused automatically installed
|
|
|
+ packages has been requested, usually via an APT `autoremove` request.
|
|
|
+
|
|
|
+The following **preference fields** are supported in request stanzas:
|
|
|
+
|
|
|
+- **Strict-Pinning:** (optional, defaults to `yes`). Allowed values:
|
|
|
+ `yes`, `no`. When set to `yes`, APT pinning is strict, in the sense
|
|
|
+ that the solver must not propose to install packages which are not APT
|
|
|
+ candidates (see the `APT-Pin` and `APT-Candidate` fields in the
|
|
|
+ package universe). When set to `no`, the solver does only a best
|
|
|
+ effort attempt to install APT candidates. Usually, the value of this
|
|
|
+ field comes from the `APT::Solver::Strict-Pinning` configuration
|
|
|
+ option.
|
|
|
+
|
|
|
+- **Preferences:** a solver-specific optimization string, usually coming
|
|
|
+ from the `APT::Solver::Preferences` configuration option.
|
|
|
+
|
|
|
+
|
|
|
+#### Package universe
|
|
|
+
|
|
|
+A package universe is a list of Deb 822 stanzas, one per package, called
|
|
|
+**package stanzas**. Each package stanzas starts with a Package
|
|
|
+field. The following fields are supported in package stanzas:
|
|
|
+
|
|
|
+- All fields contained in the dpkg database, with the exception of
|
|
|
+ fields marked as "internal" (see the manpage `dpkg-query (1)`). Among
|
|
|
+ those fields, the following are mandatory for all package stanzas:
|
|
|
+ Package, Version, Architecture.
|
|
|
+
|
|
|
+ It is recommended not to pass the Description field to external
|
|
|
+ solvers or, alternatively, to trim it to the short description only.
|
|
|
+
|
|
|
+- **Installed:** (optional, defaults to `no`). Allowed values: `yes`,
|
|
|
+ `no`. When set to `yes`, the corresponding package is currently
|
|
|
+ installed.
|
|
|
+
|
|
|
+ Note: the Status field present in the dpkg database must not be passed
|
|
|
+ to the external solver, as it's an internal dpkg field. Installed and
|
|
|
+ other fields permit to encode the most relevant aspects of Status in
|
|
|
+ communications with solvers.
|
|
|
+
|
|
|
+- **Hold:** (optional, defaults to `no`). Allowed values: `yes`,
|
|
|
+ `no`. When set to `yes`, the corresponding package is marked as "on
|
|
|
+ hold" by dpkg.
|
|
|
+
|
|
|
+- **APT-ID:** (mandatory). Unique package identifier, according to APT.
|
|
|
+
|
|
|
+- **APT-Pin:** (mandatory). Must be an integer. Package pin value,
|
|
|
+ according to APT policy.
|
|
|
+
|
|
|
+- **APT-Candidate:** (optional, defaults to `no`). Allowed values:
|
|
|
+ `yes`, `no`. When set to `yes`, the corresponding package is the APT
|
|
|
+ candidate for installation among all available packages with the same
|
|
|
+ name.
|
|
|
+
|
|
|
+- **APT-Automatic:** (optional, defaults to `no`). Allowed values:
|
|
|
+ `yes`, `no`. When set to `yes`, the corresponding package is marked by
|
|
|
+ APT as automatic installed. Note that automatic installed packages
|
|
|
+ should be removed by the solver only when the Autoremove action is
|
|
|
+ requested (see Request section).
|
|
|
+
|
|
|
+### Answer
|
|
|
+
|
|
|
+An answer from the external solver to APT is either a *solution* or an
|
|
|
+*error*.
|
|
|
+
|
|
|
+The following invariant on **exit codes** must hold true. When the
|
|
|
+external solver 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 solver is *unable to find a solution* (and s 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 solver crash
|
|
|
+with no meaningful error about dependency resolution to convey to the
|
|
|
+user.
|
|
|
+
|
|
|
+
|
|
|
+#### Solution
|
|
|
+
|
|
|
+A solution is a list of Deb 822 stanzas. Each of them could be an
|
|
|
+install stanza (telling APT to install a specific package), a remove
|
|
|
+stanza (telling APT to remove one), or an autoremove stanza (telling APT
|
|
|
+about the *future* possibility of removing a package using the
|
|
|
+Autoremove action).
|
|
|
+
|
|
|
+An **install stanza** starts with an Install field and supports the
|
|
|
+following fields:
|
|
|
+
|
|
|
+- **Install:** (mandatory). The value is a package identifier,
|
|
|
+ referencing one of the package stanzas of the package universe via its
|
|
|
+ APT-ID field.
|
|
|
+
|
|
|
+- All fields supported by package stanzas.
|
|
|
+
|
|
|
+**Remove stanzas** are similar to install stanzas, but have **Remove**
|
|
|
+fields instead of Install fields.
|
|
|
+
|
|
|
+**Autoremove stanzas** are similar to install stanzas, but have
|
|
|
+**Autoremove** fields instead of Install fields. Autoremove stanzas
|
|
|
+should be output so that APT can inform the user of which packages they
|
|
|
+can now autoremove, as a consequence of the executed action. However,
|
|
|
+this protocol makes no assumption on the fact that a subsequent
|
|
|
+invocation of an Autoremove action will actually remove the very same
|
|
|
+packages indicated by Autoremove stanzas in the former solution.
|
|
|
+
|
|
|
+In terms of expressivity, install and remove 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 solvers 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
|
|
|
+
|
|
|
+An error is a single Deb 822 stanza, starting the field Error. The
|
|
|
+following fields are supported in error stanzas:
|
|
|
+
|
|
|
+- **Error:** (mandatory). The value of this field is ignored, although
|
|
|
+ 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 solver
|
|
|
+ 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.
|
|
|
+
|
|
|
+
|
|
|
+### Progress
|
|
|
+
|
|
|
+During dependency solving, an external solver may send progress
|
|
|
+information to APT using **progress stanzas**. A progress stanza starts
|
|
|
+with the Progress field and might contain the following fields:
|
|
|
+
|
|
|
+- **Progress:** (mandatory). The value of this field is a date and time
|
|
|
+ timestamp, in RFC 2822 format. The timestamp provides a time
|
|
|
+ annotation for the progress report.
|
|
|
+
|
|
|
+- **Percentage:** (optional). An integer from 0 to 100, representing the
|
|
|
+ completion of the dependency solving process, as declared by the
|
|
|
+ solver.
|
|
|
+
|
|
|
+- **Message:** (optional). A textual message, meant to be read by the
|
|
|
+ APT user, telling what is going on within the dependency solving
|
|
|
+ (e.g. the current phase of dependency solving, as declared by the
|
|
|
+ solver).
|
|
|
+
|
|
|
+
|
|
|
+# Future extensions
|
|
|
+
|
|
|
+Potential future extensions to this protocol, listed in no specific
|
|
|
+order, include:
|
|
|
+
|
|
|
+- fixed error types to identify common failures across solvers and
|
|
|
+ enable APT to translate error messages
|
|
|
+- structured error data to explain failures in terms of packages and
|
|
|
+ dependencies
|