| 1 | # APT External Dependency Solver Protocol (EDSP) - version 0.4 |
| 2 | |
| 3 | This document describes the communication protocol between APT and |
| 4 | external dependency solvers. The protocol is called APT EDSP, for "APT |
| 5 | External Dependency Solver Protocol". |
| 6 | |
| 7 | |
| 8 | ## Components |
| 9 | |
| 10 | - **APT**: we know this one. |
| 11 | - APT is equipped with its own **internal solver** for dependencies, |
| 12 | which is identified by the string `internal`. |
| 13 | - **External solver**: an *external* software component able to resolve |
| 14 | dependencies on behalf of APT. |
| 15 | |
| 16 | At each interaction with APT, a single solver is in use. When there is |
| 17 | a total of 2 or more solvers, internals or externals, the user can |
| 18 | choose which one to use. |
| 19 | |
| 20 | Each solver is identified by an unique string, the **solver |
| 21 | name**. Solver names must be formed using only alphanumeric ASCII |
| 22 | characters, dashes, and underscores; solver names must start with a |
| 23 | lowercase ASCII letter. The special name `internal` denotes APT's |
| 24 | internal solver, is reserved, and cannot be used by external solvers. |
| 25 | |
| 26 | |
| 27 | ## Installation |
| 28 | |
| 29 | Each external solver is installed as a file under Dir::Bin::Solvers (see |
| 30 | below), which defaults to `/usr/lib/apt/solvers`. We will assume in the |
| 31 | remainder of this section that such a default value is in effect. |
| 32 | |
| 33 | The naming scheme is `/usr/lib/apt/solvers/NAME`, where `NAME` is the |
| 34 | name of the external solver. |
| 35 | |
| 36 | Each file under `/usr/lib/apt/solvers` corresponding to an external |
| 37 | solver must be executable. |
| 38 | |
| 39 | No non-solver files must be installed under `/usr/lib/apt/solvers`, so |
| 40 | that an index of available external solvers can be obtained by listing |
| 41 | the content of that directory. |
| 42 | |
| 43 | |
| 44 | ## Configuration |
| 45 | |
| 46 | Several APT options can be used to affect dependency solving in APT. An |
| 47 | overview of them is given below. Please refer to proper APT |
| 48 | configuration documentation for more, and more up to date, information. |
| 49 | |
| 50 | - **APT::Solver**: the name of the solver to be used for |
| 51 | dependency solving. Defaults to `internal` |
| 52 | |
| 53 | - **APT::Solver::Strict-Pinning**: whether pinning must be strictly |
| 54 | respected (as the internal solver does) or can be slightly deviated |
| 55 | from. Defaults to `yes`. |
| 56 | |
| 57 | - **APT::Solver::NAME::Preferences** (where NAME is a solver name): |
| 58 | solver-specific user preference string used during dependency solving, |
| 59 | when the solver NAME is in use. Check solver-specific documentation |
| 60 | for what is supported here. Defaults to the empty string. |
| 61 | |
| 62 | - **Dir::Bin::Solvers**: absolute path of the directory where to look for |
| 63 | external solvers. Defaults to `/usr/lib/apt/solvers`. |
| 64 | |
| 65 | ## Protocol |
| 66 | |
| 67 | When configured to use an external solver, APT will resort to it to |
| 68 | decide which packages should be installed or removed. |
| 69 | |
| 70 | The interaction happens **in batch**: APT will invoke the external |
| 71 | solver passing the current status of installed and available packages, |
| 72 | as well as the user request to alter the set of installed packages. The |
| 73 | external solver will compute a new complete set of installed packages |
| 74 | and gives APT a "diff" listing of which *additional* packages should be |
| 75 | installed and of which currently installed packages should be |
| 76 | *removed*. (Note: the order in which those actions have to be performed |
| 77 | will be up to APT to decide.) |
| 78 | |
| 79 | External solvers are invoked by executing them. Communications happens |
| 80 | via the file descriptors: **stdin** (standard input) and **stdout** |
| 81 | (standard output). stderr is not used by the EDSP protocol. Solvers can |
| 82 | therefore use stderr to dump debugging information that could be |
| 83 | inspected separately. |
| 84 | |
| 85 | After invocation, the protocol passes through a sequence of phases: |
| 86 | |
| 87 | 1. APT invokes the external solver |
| 88 | 2. APT send to the solver a dependency solving **scenario** |
| 89 | 3. The solver solves dependencies. During this phase the solver may |
| 90 | send, repeatedly, **progress** information to APT. |
| 91 | 4. The solver sends back to APT an **answer**, i.e. either a *solution* |
| 92 | or an *error* report. |
| 93 | 5. The external solver exits |
| 94 | |
| 95 | |
| 96 | ### Scenario |
| 97 | |
| 98 | A scenario is a text file encoded in a format very similar to the "Deb |
| 99 | 822" format (AKA "the format used by Debian `Packages` files"). A |
| 100 | scenario consists of two distinct parts: a **request** and a **package |
| 101 | universe**, occurring in that order. The request consists of a single |
| 102 | Deb 822 stanza, while the package universe consists of several such |
| 103 | stanzas. All stanzas occurring in a scenario are separated by an empty |
| 104 | line. |
| 105 | |
| 106 | |
| 107 | #### Request |
| 108 | |
| 109 | Within a dependency solving scenario, a request represents the action on |
| 110 | installed packages requested by the user. |
| 111 | |
| 112 | A request is a single Deb 822 stanza opened by a mandatory Request field |
| 113 | and followed by a mixture of action and preference fields. |
| 114 | |
| 115 | The value of the **Request:** field is a string describing the EDSP |
| 116 | protocol which will be used to communicate. At present, the string must |
| 117 | be `EDSP 0.4`. |
| 118 | |
| 119 | a unique request identifier, such as an |
| 120 | UUID. Request fields are mainly used to identify the beginning of a |
| 121 | request stanza; their actual values are otherwise not used by the EDSP |
| 122 | protocol. |
| 123 | |
| 124 | The following **action fields** are supported in request stanzas: |
| 125 | |
| 126 | - **Install:** (optional, defaults to the empty string) A space |
| 127 | separated list of package names, with *no version attached*, to |
| 128 | install. This field denotes a list of packages that the user wants to |
| 129 | install, usually via an APT `install` request. |
| 130 | |
| 131 | - **Remove:** (optional, defaults to the empty string) Same syntax of |
| 132 | Install. This field denotes a list of packages that the user wants to |
| 133 | remove, usually via APT `remove` or `purge` requests. |
| 134 | |
| 135 | - **Upgrade:** (optional, defaults to `no`). Allowed values: `yes`, |
| 136 | `no`. When set to `yes`, an upgrade of all installed packages has been |
| 137 | requested, usually via an APT `upgrade` request. |
| 138 | |
| 139 | - **Dist-Upgrade:** (optional, defaults to `no`). Allowed values: `yes`, |
| 140 | `no`. Same as Upgrade, but for APT `dist-upgrade` requests. |
| 141 | |
| 142 | - **Autoremove:** (optional, defaults to `no`). Allowed values: `yes`, |
| 143 | `no`. When set to `yes`, a clean up of unused automatically installed |
| 144 | packages has been requested, usually via an APT `autoremove` request. |
| 145 | |
| 146 | The following **preference fields** are supported in request stanzas: |
| 147 | |
| 148 | - **Strict-Pinning:** (optional, defaults to `yes`). Allowed values: |
| 149 | `yes`, `no`. When set to `yes`, APT pinning is strict, in the sense |
| 150 | that the solver must not propose to install packages which are not APT |
| 151 | candidates (see the `APT-Pin` and `APT-Candidate` fields in the |
| 152 | package universe). When set to `no`, the solver does only a best |
| 153 | effort attempt to install APT candidates. Usually, the value of this |
| 154 | field comes from the `APT::Solver::Strict-Pinning` configuration |
| 155 | option. |
| 156 | |
| 157 | - **Preferences:** a solver-specific optimization string, usually coming |
| 158 | from the `APT::Solver::Preferences` configuration option. |
| 159 | |
| 160 | |
| 161 | #### Package universe |
| 162 | |
| 163 | A package universe is a list of Deb 822 stanzas, one per package, called |
| 164 | **package stanzas**. Each package stanzas starts with a Package |
| 165 | field. The following fields are supported in package stanzas: |
| 166 | |
| 167 | - All fields contained in the dpkg database, with the exception of |
| 168 | fields marked as "internal" (see the manpage `dpkg-query (1)`). Among |
| 169 | those fields, the following are mandatory for all package stanzas: |
| 170 | Package, Version, Architecture. |
| 171 | |
| 172 | It is recommended not to pass the Description field to external |
| 173 | solvers or, alternatively, to trim it to the short description only. |
| 174 | |
| 175 | - **Installed:** (optional, defaults to `no`). Allowed values: `yes`, |
| 176 | `no`. When set to `yes`, the corresponding package is currently |
| 177 | installed. |
| 178 | |
| 179 | Note: the Status field present in the dpkg database must not be passed |
| 180 | to the external solver, as it's an internal dpkg field. Installed and |
| 181 | other fields permit to encode the most relevant aspects of Status in |
| 182 | communications with solvers. |
| 183 | |
| 184 | - **Hold:** (optional, defaults to `no`). Allowed values: `yes`, |
| 185 | `no`. When set to `yes`, the corresponding package is marked as "on |
| 186 | hold" by dpkg. |
| 187 | |
| 188 | - **APT-ID:** (mandatory). Unique package identifier, according to APT. |
| 189 | |
| 190 | - **APT-Pin:** (mandatory). Must be an integer. Package pin value, |
| 191 | according to APT policy. |
| 192 | |
| 193 | - **APT-Candidate:** (optional, defaults to `no`). Allowed values: |
| 194 | `yes`, `no`. When set to `yes`, the corresponding package is the APT |
| 195 | candidate for installation among all available packages with the same |
| 196 | name. |
| 197 | |
| 198 | - **APT-Automatic:** (optional, defaults to `no`). Allowed values: |
| 199 | `yes`, `no`. When set to `yes`, the corresponding package is marked by |
| 200 | APT as automatic installed. Note that automatic installed packages |
| 201 | should be removed by the solver only when the Autoremove action is |
| 202 | requested (see Request section). |
| 203 | |
| 204 | ### Answer |
| 205 | |
| 206 | An answer from the external solver to APT is either a *solution* or an |
| 207 | *error*. |
| 208 | |
| 209 | The following invariant on **exit codes** must hold true. When the |
| 210 | external solver is *able to find a solution*, it will write the solution |
| 211 | to standard output and then exit with an exit code of 0. When the |
| 212 | external solver is *unable to find a solution* (and s aware of that), it |
| 213 | will write an error to standard output and then exit with an exit code |
| 214 | of 0. An exit code other than 0 will be interpreted as a solver crash |
| 215 | with no meaningful error about dependency resolution to convey to the |
| 216 | user. |
| 217 | |
| 218 | |
| 219 | #### Solution |
| 220 | |
| 221 | A solution is a list of Deb 822 stanzas. Each of them could be an |
| 222 | install stanza (telling APT to install a specific package), a remove |
| 223 | stanza (telling APT to remove one), or an autoremove stanza (telling APT |
| 224 | about the *future* possibility of removing a package using the |
| 225 | Autoremove action). |
| 226 | |
| 227 | An **install stanza** starts with an Install field and supports the |
| 228 | following fields: |
| 229 | |
| 230 | - **Install:** (mandatory). The value is a package identifier, |
| 231 | referencing one of the package stanzas of the package universe via its |
| 232 | APT-ID field. |
| 233 | |
| 234 | - All fields supported by package stanzas. |
| 235 | |
| 236 | **Remove stanzas** are similar to install stanzas, but have **Remove** |
| 237 | fields instead of Install fields. |
| 238 | |
| 239 | **Autoremove stanzas** are similar to install stanzas, but have |
| 240 | **Autoremove** fields instead of Install fields. Autoremove stanzas |
| 241 | should be output so that APT can inform the user of which packages they |
| 242 | can now autoremove, as a consequence of the executed action. However, |
| 243 | this protocol makes no assumption on the fact that a subsequent |
| 244 | invocation of an Autoremove action will actually remove the very same |
| 245 | packages indicated by Autoremove stanzas in the former solution. |
| 246 | |
| 247 | In terms of expressivity, install and remove stanzas can carry one |
| 248 | single field each, as APT-IDs are enough to pinpoint packages to be |
| 249 | installed/removed. Nonetheless, for protocol readability, it is |
| 250 | recommended that solvers either add unconditionally the fields Package, |
| 251 | Version, and Architecture to all install/remove stanzas or, |
| 252 | alternatively, that they support a `--verbose` command line flag that |
| 253 | explicitly enables the output of those fields in solutions. |
| 254 | |
| 255 | |
| 256 | #### Error |
| 257 | |
| 258 | An error is a single Deb 822 stanza, starting the field Error. The |
| 259 | following fields are supported in error stanzas: |
| 260 | |
| 261 | - **Error:** (mandatory). The value of this field is ignored, although |
| 262 | it should be a unique error identifier, such as a UUID. |
| 263 | |
| 264 | - **Message:** (mandatory). The value of this field is a text string, |
| 265 | meant to be read by humans, that explains the cause of the solver |
| 266 | error. Message fields might be multi-line, like the Description field |
| 267 | in the dpkg database. The first line conveys a short message, which |
| 268 | can be explained in more details using subsequent lines. |
| 269 | |
| 270 | |
| 271 | ### Progress |
| 272 | |
| 273 | During dependency solving, an external solver may send progress |
| 274 | information to APT using **progress stanzas**. A progress stanza starts |
| 275 | with the Progress field and might contain the following fields: |
| 276 | |
| 277 | - **Progress:** (mandatory). The value of this field is a date and time |
| 278 | timestamp, in RFC 2822 format. The timestamp provides a time |
| 279 | annotation for the progress report. |
| 280 | |
| 281 | - **Percentage:** (optional). An integer from 0 to 100, representing the |
| 282 | completion of the dependency solving process, as declared by the |
| 283 | solver. |
| 284 | |
| 285 | - **Message:** (optional). A textual message, meant to be read by the |
| 286 | APT user, telling what is going on within the dependency solving |
| 287 | (e.g. the current phase of dependency solving, as declared by the |
| 288 | solver). |
| 289 | |
| 290 | |
| 291 | # Future extensions |
| 292 | |
| 293 | Potential future extensions to this protocol, listed in no specific |
| 294 | order, include: |
| 295 | |
| 296 | - fixed error types to identify common failures across solvers and |
| 297 | enable APT to translate error messages |
| 298 | - structured error data to explain failures in terms of packages and |
| 299 | dependencies |