Feed file format specification
This document is a formal description of the XML feed file format. An interface describes a program, library or other component. A feed provides a list of known implementations of the interface (versions of the program) and details about how to get them, how to check that they are authentic, how to run them and what other components they depend on.
This class diagram shows how the different concepts are related. Each feed file contributes information to this model:
Each Feed lists a number of Implementations. An Identity is a way to recognise an Implementation (e.g. a cryptographic digest). A Retrieval method is a way to get an Implementation (e.g. by downloading from an FTP site). A Binding says how to let the program locate the Implementations when run. A Dependency indicates that one component depends on another (e.g. Gimp requires the GTK library). A Constraint limits the choice of a dependency (e.g. Gimp requires a version of GTK >= 2.6).
Note on terminology: originally the word 'interface' was used to mean both 'interface' and 'feed', so don't be confused if you see it used this way.
Changes to this document (and to the rest of the web-site) are tracked using subversion. To view the change log:
$ svn log https://zero-install.svn.sourceforge.net/svnroot/zero-install/trunk/htdocs/interface-spec.xml
Contents
- Introduction
- Groups
- Implementations
- Package implementations
- Retrieval methods
- Dependencies
- Constraints
- Bindings
- Versions
- Stability
- Metadata
- Digital signatures
- Future plans
Introduction
Feed files are introduced in the packager's guide. They have the following syntax (? follows optional items, * means zero-or-more, order of elements is not important, and extension elements can appear anywhere as long as they use a different namespace):
<?xml version='1.0'?> <interface xmlns='http://zero-install.sourceforge.net/2004/injector/interface' min-injector-version='...' ? uri='...' ? > <name>...</name> <summary>...</summary> <description>...</description> ? <homepage>...</homepage> ? <category type='...' ? >...</category> * <needs-terminal/> ? <icon type='...' href='...'/> * <feed src='...' langs='...' ? arch='...' ?/> * <feed-for interface='...'/> * [group] * [implementation] * </interface>
- min-injector-version
- This attribute gives the oldest version of the injector that can read this file. Older versions will tell the user to upgrade if they are asked to read the file. Versions prior to 0.20 do not perform this check, however. If the attribute is not present, the file can be read by all versions.
- uri
- This attribute is only needed for remote feeds (fetched via HTTP). The value must exactly match the expected URL, to prevent an attacker replacing one correctly-signed feed with another (e.g., returning a feed for the shred program when the user asked for the backup program).
- <name>
- a short name to identify the interface (e.g. "Foo")
- <summary>
- a short one-line description; the first word should not be upper-case unless it is a proper noun (e.g. "cures all ills")
- <description>
- a full description, which can be several paragraphs long (optional since 0.32, but recommended)
- <homepage>
- the URL of a web-page describing this interface in more detail
- <category>
- a classification for the interface. If no type is given, then the category is one of the 'Main' categories defined by the freedesktop.org menu specification. Otherwise, it is a URI giving the namespace for the category.
- <needs-terminal>
- if present, this element indicates that the program requires a terminal in order to run. Graphical launchers should therefore run this program in a suitable terminal emulator.
- <icon>
- an icon to use for the program; this is used by programs such as AddApp.
- <feed>
- the linked feed contains more implementations of this feed's interface. The "langs" and "arch" attributes, if present, indicate that all implementations will fall within these limits (e.g. arch='*-src' means that there is no point fetching this feed unless you are looking for source code). See the <implementation> element for a description of the values of these attributes.
- <feed-for>
- the implementations in this feed are implementations of the given interface. This is used when adding a third-party feed.
Groups
A group has this syntax:
<group
version='...' ?
released='...' ?
main='...' ?
self-test='...' ?
doc-dir='...' ?
license='...' ?
stability='...' ?
langs='...' ?
arch='...' ? >
[requires] *
[group] *
[binding] *
[implementation] *
[package-implementation] *
</group>
All attributes of the group are inherited by any child groups and implementations as defaults, but can be overridden there. All dependencies ("requires") and bindings are inherited (sub-groups may add more dependencies and bindings to the list, but cannot remove anything).
Implementations
An implementation has this syntax (an unspecified argument is inherited from the closest ancestor <group> which defines it):
<implementation
id='...'
version='...' ?
version-modifier='...' ?
main='...' ?
self-test='...' ?
doc-dir='...' ?
released='...' ?
stability='...' ?
langs='...' ?
arch='...' ? >
<manifest-digest [digest] * /> *
[ retrieval-method ] *
[binding] *
</implementation>
- id
- The digest of the implementation's manifest, in the form alg=value. See the manifest specification for details about manifests. If the feed file is a local file (the interface 'uri' starts with /) then the id may instead contain the pathname of a local directory (either an absolute path or a path relative to the directory containing the feed file).
- version
- The version number. See the version numbers section below for more details.
- version-modifier
- A string to be appended to the version. The purpose of this is to allow complex version numbers (such as "1.0-rc2") without breaking older versions of the injector (before 0.24), which only support dot-separated lists of integers.
- main
- The relative path of an executable inside the implementation that should be executed by default when the interface is run. If an implementation has no main setting, then it cannot be executed without specifying one manually (with 0launch --main=MAIN). This typically means that the interface is for a library.
- self-test
- The relative path of an executable inside the implementation that can be executed to test the program. The program must be non-interactive (e.g. it can't open any windows or prompt for input). It should return with an exit status of zero if the tests pass. Any other status indicates failure.
- doc-dir
- The relative path of a directory inside the implementation that contains the package's documentation. This is the directory that would end up inside /usr/share/doc on a traditional Linux system.
- released
- The date this implementation was made available, in the format YYYY-MM-DD. For development versions checked out from version control this attribute should not be present.
- stability
- The default stability rating for this implementation. If not present, testing is used. See the stability section below for more details.
- langs
- The natural language(s) which this package supports, as a space-separated list of languages codes (in the same format as used by the $LANG environment variable). For example, the value "en_GB fr" would be used for a package supporting British English and French. This attribute is currently ignored by 0launch.
- arch
- For platform-specific binaries, the platform for which this implementation was compiled, in the form os-cpu. The injector knows that certain platforms are backwards-compatible with others, so binaries with arch="Linux-i486" will still be available on Linux-i686 machines, for example. Either the os or cpu part may be *, which will make it available on any OS or CPU. If missing, the default is *-*.
- license
- License terms (typically a Trove category, as used on freshmeat.net).
For non-local implementations (those where the id doesn't start with /), the element contains a set of retrieval methods, each of which gives a different way of getting the implementation (i.e., of getting a directory structure whose digest matches the one in the id).
The manifest-digest element can be used to give the digest using other algorithms (in addition to the one used in the id attribute). It is currently ignored. This is to allow a smooth upgrade to newer digest algorithms without breaking old clients. Each non-namespaced attribute gives a digest, with the attribute name being the algorithm. For example:
<manifest-digest sha256="4f078f9080bd9b3b87e8360f014268886ec653ed077bb3cb6725185c0a07473a"/>
Unrecognised elements inside an implementation are ignored. Currently, the injector always chooses the first of the methods it understands, but in future it may use other strategies (such as choosing the closest mirror, or letting the user select one manually). It may also use other methods which aren't listed, such as searching for the implementation on a peer-to-peer network.
Package implementations
This element names a distribution-provided package which, if present, is a valid implementation of this interface. The syntax is:
<package-implementation
package='...'
main='...' ? >
If the named package is available then it will be considered as a possible implementation of the interface. If main is given then it must be an absolute path.
Note that, unlike a normal implementation, a distribution package does not resolve to a directory. Any bindings inside <requires> elements for the interface will be ignored; it is assumed that the requiring component knows how to use the packaged version without further help. Therefore, adding distribution packages to your interface considerably weakens the guarantees you are making about what the requestor may get.
Package implementations still inherit attributes and dependencies from their parent group. The doc-dir and license attributes may be given, but version and released are read from the native packaging system.
Support for distribution packages was added in version 0.28 of the injector. Earlier versions ignore this element. Future versions may provide a way to specify which distributions the element applies to.
Retrieval methods
A retrieval method is a way of getting an implementation.
The simplest retrieval method is the <archive> element:
<archive
href='...'
size='...'
extract='...' ?
type='...' ?
start-offset='...' ? />
This states that an archive may be downloaded from the address given in the href attribute. The archive must have the given size or it will be rejected. When unpacked (either the subdirectory named in the extract attribute, or the whole archive if it is not present), the resulting tree will generate a manifest with the secure hash value given as the implementation's id.
The type of the archive is given as a MIME type in the type attribute (since 0launch version 0.21). If missing, the type is guessed from the extension on the href attribute (all versions). Known types and extensions (case insensitive) are:
- application/x-rpm (.rpm)
- application/x-deb (.deb)
- application/x-tar (.tar)
- application/x-bzip-compressed-tar (.tar.bz2)
- application/x-lzma-compressed-tar (.tar.lzma)
- application/x-compressed-tar (.tar.gz or .tgz)
- application/zip (.zip)
- application/vnd.ms-cab-compressed (.cab)
The start-offset attribute (since version 0.21) gives the number of bytes at the beginning of the file which should be ignored. This is useful for some self-extracting archives which are made up of a shell script followed by a normal archive in a single file. If missing, it defaults to 0. The value in the size attribute does not include the skipped bytes.
An implementation can also be created by following a <recipe>:
<recipe>
<archive ...> +
</recipe>
In this case, each child element of the recipe represents a step. To get an implementation by following a recipe, a new empty directory is created and then all of the steps are performed in sequence. The resulting directory must have the digest given in the implementation's id. A recipe containing only a single archive is equivalent to just specifying the archive on its own (except that recipes aren't supported prior to version 0.20 of the injector). If a recipe contains an unrecognised element then the whole recipe must be ignored.
The only type of step supported is an <archive>, which causes the named archive to be fetched and unpacked over the top of whatever is currently in the temporary directory.
Note: A recipe is generally only useful for patching existing archives without having to host the complete result yourself. Normally, if your program requires files from several different packages then it is better to use the <requires> element instead. This allows libraries to be shared between different programs, and lets the user choose the versions and upgrade them individually.
Dependencies
A <requires> element means that every implementation within the same group (including nested sub-groups) requires an implementation of the specified interface when run. The injector will choose a suitable implementation, downloading one if required.
<requires
interface='...' >
[ constraints ] *
[ bindings ] *
</requires>
The constraint elements (if any) limit the set of acceptable versions. The bindings specify how the injector should make its choice known (typically, by setting environment variables).
Constraints
Constraints appear inside <requires> elements. They restrict the set of versions from which the injector may choose an implementation.
<version
not-before='...' ?
before='...' ? >
- not-before
- This is the lowest-numbered version that can be chosen.
- before
- This version and all later versions are unsuitable.
For example, <version not-before='2.4' before='2.6'> allows any of these versions: 2.4, 2.4.0, and 2.4.8. It will not select 2.3.9 or 2.6.
Bindings
Bindings specify how the chosen implementation is made known to the running program. Bindings can appear in a <requires> element, in which case they tell a component how to find its dependency, or in an <implementation> (or group), where they tell a component how to find itself.
Note: Bindings outside of <requires> elements require 0launch >= 0.31. However, the same effect can be achieved with earlier versions of 0launch by adding an explicit <requires> from a component to itself and putting the binding in that.
Environment bindings
<environment
name='...'
insert='...'
mode='prepend|append|replace' ?
default='...' ? /> *
The location of the chosen implementation is passed to the program by setting environment variables, as specified by the <environment> elements (typically, there will be exactly one of these in each <requires> element). Each environment element gives the name of the variable and the relative path of the item within the implementation to insert into the variable's value.
If mode is prepend (or not set), then the absolute path of the item is prepended to the current value of the variable, separated by a colon character. If the environment variable is not currently set then the path is prepended to the value of the default attribute. If no default value is given either then the default for that environment variable is used, or the environment variable's value is set to the absolute path directly if there is no default.
If mode is append then the same thing happens, except that the new value is added at the end instead of the beginning. If the mode is replace then the old value is overwritten, and the default attribute is ignored.
For example, <environment name='PATH' insert='bin'/> would perform something similar to the bash shell statement export PATH=/path/to/impl/bin:$PATH.
The following environment variables have known defaults and therefore the default attribute is not needed with them:
- PATH
- /bin:/usr/bin
- XDG_CONFIG_DIRS
- /etc/xdg
- XDG_DATA_DIRS
- /usr/local/share:/usr/share
The mode argument is ignored by versions of the injector prior to 0.28, which act as if prepend was given.
Overlay bindings
Note: This feature is not yet supported by any version of Zero Install, but is proposed for Klik 2.
<overlay
src='...' ?
mount-point='...' ? />
An overlay binding specifies that the chosen implementation should be made available at the given location in the filesystem (typically, by using some kind of per-process union mount).
- src
- The relative path of the directory in the implementation to publish. The default is '.', to publish everything.
- mount-point
- The mount point on which src is to appear in the filesystem. If missing, '/' is assumed.
For example, if the implementation contains the file usr/games/foo then <overlay /> means that the running process should be able to access this file using the absolute path /usr/games/foo.
Versions
A version number string has the following form:
Version := DottedList ("-" Modifier? DottedList?)*
DottedList := (Integer ("." Integer)*)
Modifier := "pre" | "rc" | "post"
Numerically, the modifiers come in the order "-pre" (pre-release), "-rc" (release candidate), "-" (no modifier name), "-post" (post-release or patch level). Versions are ordered like this:
- 0.1
- 1
- 1.0
- 1.1
- 1.2-pre
- 1.2-pre1
- 1.2-rc1
- 1.2
- 1.2-0
- 1.2-post
- 1.2-post1-pre
- 1.2-post1
- 1.2.1-pre
- 1.2.1.4
- 1.2.2
- 1.2.10
- 3
The injector doesn't care about anything other than the sort order (i.e., whether one version comes before or after another). It is expected that an implementation can be safely replaced by one with a later version number, but not necessarily with an earlier one. So, if an application works with version "1.2.1" of a library then it should also work with version "1.2.2" or "1.3" or even "5.7", but not "1.2.0". This is a little different to some other systems, where numbers in different places have different meanings.
For example, if the latest version of a library you use is version 5.1, then you shouldn't add the restriction before='5.2', because when 5.2 comes out it should still work with your program. Of course, this might not always work, and hopefully the problem will be reported while the new library version is marked as testing (before most users hit the problem). Once you know that 5.2 is a problem, you can add the before='5.2' restriction to the implementation then.
Incompatible changes (where a newer version cannot be used in place of an older version) to an interface should be handled by creating a new interface URI. Eg:
- http://gtk.org/2005/interfaces/GTK-1.2.x (contains 1.2.0, 1.2.1, 1.2.2, ...)
- http://gtk.org/2005/interfaces/GTK-2.x (contains 2.0.0, 2.0.1, 2.2.0, 2.4.0, 2.4.1, ...)
Note that version numbers containing dash characters are not supported before version 0.24 of the injector. To create feeds that still work with older versions, you can use the version-modifier attribute. E.g., use version='1' version-modifier='-pre' instead of version='1-pre'. Older versions will silently ignore this attribute.
Stability
The feed file also gives a stability rating for each implementation. The following levels are allowed (must be lowercase in the feed files):
- stable
- testing
- developer
- buggy
- insecure
Stability ratings are expected to change over time. When any new release is made, its stability should be set to testing. Users who have selected Help test new versions will then start using it. Other users will continue with the previous stable release. After a while (days, weeks or months, depending on the project) with no serious problems found, the implementation's stability can be changed to stable so that everyone will use it.
If problems are found, it can instead be marked as buggy, or insecure. The injector won't select either by default, but it is useful to users to see the reason (users may opt to continue using a buggy version if it seems to work for them, but they should never use an insecure one). developer is like a more extreme version of testing, where the program is expected to have bugs.
When to use 'buggy'
Don't mark old releases as buggy every time you do a new release, just because a few bugs have been fixed. People who have selected Network use: Full will automatically upgrade to the new version anyway, so marking an older version as buggy only affects people who have explicitly stated that they don't want to use the latest version, but would prefer to use an older release to save network use.
Metadata
All elements can contain extension elements, provided they are not in the Zero Install namespace used by the elements defined here. The injector does not currently make use of these elements itself, but other programs may find them useful. In future, some of these may be used (for example, the GUI may display the license terms).
The use of Dublin Core is suggested for the following concepts, which have the following meanings when found as a direct child of a <group> or <implementation> element:
- dc:creator
- The primary author of the program.
- dc:publisher
- The person who created this implementation. For a binary, this is the person who compiled it.
Other Dublin Core terms that may be useful include contributor, dateCopyrighted, language, rights and rightsHolder.
These terms are not required as they are duplicated by the core Zero Install terms: identifier (id), available (released) and requires (requires).
The source element may be used in future to record the source used to build this implementation.
Digital signatures
When an interface is downloaded from the web, it must contain a digital signature. Two signature formats are supported:
GPG plain signatures
A plain signature is generated from an unsigned interface using the command gpg --clearsign. The resulting file is a plain text file but is not valid XML. This format is supported by all versions of the injector.
GPG XML signatures
An interface can also be signed by appending an XML comment block of the form:
<!-- Base64 Signature iD8DBQBEXM/qrgeCgFmlPMERArNSAKDBuNz5SQMZ8rwJmW2fhNHJwor6KwCgwx7XEfY+6gUC90rJ b5eCY+I8HNA= -->
This block must go at the end of the file, and contains a Base64-encoded version of the file that would be created by using gpg --detach-sign on the original interface. The signature block must start on a new line, may not contain anything except valid base64 characters, and nothing may follow the signature block. XML signature blocks are supported from version 0.18 of the injector and may be generated easily using the 0publish command. They have the advantage that the result is still valid XML and can therefore be processed and styled using standard tools.
Local interfaces are plain XML, although having an XML signature block is no problem as it will be ignored as a normal comment.
Future plans
- The extra meta-data elements need to be better specified.
- In addition to <version>, it should be possible to specifically exclude certain versions or ranges of versions so you can say, for example: "2.0 <= version < 3 and version != 2.57".
- As well as before and not-before, we should support after and not-after.
- Additional <recipe> step types should be supported, such as <apply-patch>.
- It should be possible to state that a <requires> is actually optional (or only needed if some local library isn't available).
- It should be possible to give a delta (binary patch) against a previous version, to make upgrading quicker.
- It should be possible to scope bindings. For example, when a DTP package requires a clipart package, the clipart package should not be allowed to affect the DTP package's environment.