Below you can find a short introduction (or primer) to the CUDF format: it should be enough to get you started in reading or writing CUDF documents. For a more in depth explaination of CUDF syntax and semantics, you would probably want to check the full specification of CUDF 2.0.

Concepts

CUDF (for Common Upgradeability Description Format) is a document format meant to describe upgrade scenarios as commonly faced by package managers in Free and Open Source Software distributions.

Typically, in an upgrade scenario, there exists:

  1. A current package universe describing all packages known to the package manager.

  2. A current package status denoting all currently installed packages; the package status is contained in the package universe.

  3. A user request representing the change that a user has asked the package manager to perform.

A CUDF document grasps all relevant details of the above entities, providing a common ground to describe the input of the dependency solver components found in most package managers.

File format

package: m4
version: 3
depends: libc6 >= 8

package: openssl
version: 11
depends: libc6 >= 18, libssl0.9.8 >= 8, zlib1g >= 1
conflicts: ssleay < 1

# and so on ...

CUDF is a simple plain text format, largely inspired by RFC 2822 (commonly known for being the basis of the mailbox format). Accordingly, a CUDF document is composed by several stanzas (or paragraphs), separated by an empty line.

Comments are allowed by using # on the first column, and newlines are in the Unix style (i.e. \n or ASCII 0x0A).

Each stanza consists of a set of key/value pairs, where keys are unique within a given stanza. A single key/value pair denotes a property and appears in the document as a single logical line obtained by concatenating: the key, the string ": " (without quotes, i.e. a colon and the ASCII space 0x0A), and the value.

Keys must match the regexp "^[a-z][a-z0-9-]*$" (without quotes).

Line continuations

package: wesnoth
version: 1
depends: libc6 >= 8, libfreetype6 >= 4, libfribidi0 >= 1, 
 libgcc1 >= 6, libsdl-image1.2 >= 2, libsdl-mixer1.2 >= 1, 
 libsdl-net1.2, libsdl1.2debian >= 3, libstdc++6 >= 5, 
 libx11-6 , zlib1g >= 5, wesnoth-data = 1

Each value is, in the most general case, a single line of text. Still, to make CUDF documents more readable, long values can be split over multiple lines using line continuations. Each key/value pair line can be continued by subsequent line(s) starting with a space. All such lines taken together (the first line with the key and all continuations) form a single key value pair: the key is as usual, whereas the value is obtaining by concatenating the value on the first line with all continuations, taking care of removing the leading space of each continuation.

Types

Each value in a stanza is in fact a typed value and you cannot generally write arbitrary strings as values, for instance writing "foo" as a package version will lead to a parse error. CUDF supports several types and also lets you define your own.

Generally you can ignore the gory details by just having a look at the examples below that highlight the most important types:

  • integers: ..., -2, -1, 0, 1, 2, ...
  • positive integers: 1, 2, 3, ...
  • booleans: true, false
  • package names, i.e. strings that match the (very liberal) regex "^[a-zA-Z0-9+./@()%-]+$" : libc6, libdb4.6, libc-dev, /bin/bash (as a virtual package in some distribution), ...
  • package formulae, boolean formulae over versioned package predicates:
    • python-minimal: any package called python-minimal
    • libedac1 = 1: version 1 of package libedac1
    • libxft2 > 1: any version of libxft2 greater than 1
    • haskell-doc <= 2: any version of haskell-doc less than or equal to 2
    • libz-dev != 3: any version of libz-dev other than 3
    • postfix > 2 | exim4-base: either a version of postfix greater than 2, or any version of exim4-base
    • ocaml-nox, libc6 >= 6: both (any version of) ocaml-nox and a version of libc6 greater than 6
    • php4, apache | httpd: both (any version of) php4 and one among: (any version of) apache and (any version of) httpd
    • ... you got the idea :-)
  • package lists, degenerate formulae where disjunctions (i.e. "|") are not allowed:
    • libc6: any version of libc6
    • f2c, cpp: any version of f2c and any version of cpp
    • python >= 10 , python-support >= 11: a version of python greater or equal to 10 and a version of python-support greater or equal to 11

For more details on available CUDF types, you should check Section 2.2.2 of the CUDF spec.

Stanzas

# sample CUDF document structure

preamble: 
# documents start with an optional preamble
# ...

package: foo
# then come several packages
# ...

package: bar
# ...

request: 
# and finally a mandatory request stanza
# ...

The various stanzas that compose a CUDF document belong to 3 different kinds of stanzas, recognizable by the name of their first property.

  1. A single preamble stanza (starting with the preamble property) may appear at the beginning of the document; it is forbidden to have such a stanza elsewhere.

  2. Then come several consecutive package stanzas (starting with the package property).

  3. Finally, there must be a single and mandatory request stanza (starting with the request property) which concludes the document.

Each kind of stanza has a property scheme that defines the set of properties allowed therein, their types, and whether they are mandatory or optional (in the latter case, a default value is specified too).

Below you can find an overview of property schemata highlighting the most important properties; further details can be found in Section 2.2.3 of the CUDF spec.

Package stanzas

A package stanza describes a single package known to the package manager; all package stanzas in a CUDF document describe the package universe as a whole.

package: ...   (mandatory; type: package name; must be the first property)
version: ...   (mandatory; type: positive integer)
installed: ... (optional; default: false; type: boolean)
depends: ...   (optional; type: package formula)
conflicts: ... (optional; type: package list)
provides: ...  (optional; type: package list)

A few important remarks on the above properties:

  • versions are positive integers, usual version strings like "1.2.3-4" are not accepted (as they have no clear cross-distribution semantics). Ideally, each set of versions in a given distribution has a total order and can then be easily mapped to positive integers.

  • provides account for features (or virtual packages): packages can depend on features, such dependencies will be considered satisfied if at least one package providing the features is installed.

    CUDF features are versioned, you can provides: httpd > 2 ; an unversioned feature stands for providing all possible versions of that feature.

  • conflicts are not implicit among different versions of the same package: multiple versions of the same package can be installed at the same time.
    Self-conflicts are ignored. This means that you can achieve Debian-like implicit conflicts (i.e. only one version of each package can be installed at any given time) as follows:

package: bash
version: 5
conflicts: bash
# i.e. conflict with all other versions of foo
  • Self-conflicts are ignored for virtual packages too, so you can achieve mutual-exclusion among a set of packages providing the same feature as follows:

package: postfix
version: 2
provides: mail-transport-agent
conflicts: mail-transport-agent

package: exim
version: 3
provides: mail-transport-agent
conflicts: mail-transport-agent

Request stanza

The trailing request stanza describes the user request, that is which change the user wants to be performed to the set of installed packages (i.e. the package status).

request: ...   (mandatory; type: string; value is ignored)
install: ...   (optional; type: package list)
remove: ...    (optional; type: package list)
upgrade: ...   (optional; type: package list)
  • install, remove, upgrade are similar: they tell the solver which packages must be, respectively, installed, removed, and upgraded. In all cases version requirements can be specified, e.g. install: bash > 3 means that the user want to install a version of bash greater than 3.

  • upgrade poses additional requirements: all packages request to be upgraded:

    1. must have a single version installed in the solution proposed by the solver
    2. cannot be downgraded to a version strictly smaller to the one that was previously installed

Preamble stanza

The optional leading preamble can be used to provide document meta-information.

preamble: ...      (mandatory; type: string; value is ignored)
property: ...      (optional; type: property declaration)
univ-checksum: ... (optional; type: string)
  • property is used to declare extra properties that should be allowed in package stanzas (by default they are forbidden). The actual syntax and semantics it's a bit tricky and should be checked for in Section 2.2.2 of the CUDF spec. Here we simply give a representative example that:

    • allows an optional suite property whose value must be one of: stable, testing, unstable
    • allows an optional bugs property of integer type with a default value of 0
    • requires a mandatory installed-size of positive integer type
    • allows an optional description property of string type with default value of no description
preamble:
property: suite: enum [ stable , testing , unstable ] = [ stable ] ,
 bugs: int = [0] ,
 installed-size: posint ,
 description: string = ["no description"]
univ-checksum: 8c6d8b4d0cf7027cd523ad095d6408b4901ac31c
  • univ-checksum provides a checksum of the universe: a solver receiving two CUDF documents with the same checksum is allowed to avoid parsing / internalizing all packages again, in case it has a cache hit for that

Note that the description of all stanzas above is not complete, more properties and details are available, but you should really refer to the CUDF spec for that.