Platform Team/Guide/Sweets Packaging

Writing spec files

Package names

Within spec files, Zero packages might be identified by several methods:

  • current package (instead of a direct slug value, to make the spec file more robust, move the slug option to the [DEFAULT] section and use %(slug)s interpolation),
<current-slug>[/<sub-package>]
<package-slug>[/<sub-package>]
  • direct 0install link.
<0install-feed-url>

At the end, all links will be transfered to 0install feed urls. For default repository, the final 0install url will be composed by concatenating http://packages.sugarlabs.org/ prefix and package slug.

Versioning

The versioning scheme for Zero packages can be arbitrary, since the version spec option supports 0install version format. But in some cases, e.g., libraries, stricter versioning could be useful. In that case, the age spec option should be used.

The spec option age is intended to support, mostly, API breakages of library packages. But not ABI, because tracking an ABI is not trivial within the Sugar ecosystem (due to the enormous potential code base of varying quality) and of little utility, since packages may at any time rebuild from sources and multiple library versions may be installed (thanks to 0install).

Using the age option is simple, on every API breakage for the library package, increment the age value. Final package version will be:

<age-option>.<version-option>

Glob patterns

A pattern could be of two types:

  • doesn't contain / or ** substrings, will be applied only to file names
  • contains / or ** substring, will be applied to the full file path (relative to the root), thus could affect several directory levels

Only these pattern symbols are allowed:

  • * matches everything, except directory separator
  • ? matches any single character, except directory separator
  • ** matches everything, including directory separator

Sub packages

By default, package is the singular and will be composed using [Package] or/and [Activity] sections. But if the package contains several logical components, it might have sub packages. In that case, the spec file should contain additional sections (per sub package) in the form:

 [Package/<sub-package>]

Format of sub sections is identical to [Package] section. Sub packages could make sense, e.g., for packaging additional content, or to separate library and its script language binding.

Other packages can mention sub packages by the format:

<package>/<sub-package>

Good practise is using the following names for sub packages:

  • python for Python binding,
  • standalone if package might be used not only as Sugar activity but also as regular application (also, Application preset could be used for such sub packages).

Recipes

In some cases, e.g., to save storage space or bandwidth, it is useful to split a packaged application into several tarballs when some tarballs will contain any-arch data, that are common for all platforms, and other will contain binaries for particular platform. Thus, if an application supports several platforms and any-arch data is big (various media, text, etc. files), there will not be duplicate tarballs.

The key differences between recipes and sub packages:

  • Sub packages are logically independent parts of the package;
  • Each sub package is identified by unique 0install url, all recipe components are identified by recipe url;
  • Tarballs for different sub packages will be extracted to different directories, recipe component tarballs, within the same recipe, will be extracted to the same directory.

Use the recipe option to declare a (sub)package(s) as a recipe:

 [Package]
 recipe = <component-name> [; ...]

and declare sections that contain components:

 [<component-name>]
 ...

Being a recipe, the package section cannot contain files-related options (since package itself does not contain any tarballs directly, only via recipe components), these options could be set only in components:

  • langs
  • arch
  • include
  • exclude
  • exec
  • slots

The same component could be a part of different recipes. In that case, different package implementations will contain the same recipe component tarball.

Slots

Slots make sense only for binary services when they could be built against several compatibility ranges for their dependencies and these dependencies could be installed from native packages.

Assume that a service requires cairo, and that the source code uses a cairo feature that appeared only in v1.8, but the source code can fallback to previous cairo versions, as well. If cairo can be installed from 0install feeds, then there is no need for slots, since the service can declared as a "cairo >= 1.8" dependency, and so cairo will be installed from 0install feeds. But if cairo could be installed from native packages, there is no way to know in advance which cairo version will be present, and the service should have two implementations, one for cairo < 1.8 and one for cairo >= 1.8. In this case, slots will be useful.

To declare slots for a package dependency, slots and appropriate requires options should be placed in the [Service] section that uses the dependency:

 requires = <dependency>
 slots[<dependency>] = <versions-range>

Option slots will declare compatibility ranges for a particular dependency. Only one, closed from both sides, range can be used. For example, in the cairo case, it could be:

 1.0, 1.8, 2.0

The 1.0 (it could be 0.0 as well) restricts the version range from the left and the 2.0 (most likely v2.0 will not be backwards compatible with v1.x) from the right; so only two ranges can be chosen, 1.0 >= x < 1.8, 1.8 >= x < 2.0. While building binaries for the 0sugar build command, 0sugar will detect what the current cairo version is (the service that it is building/linking against), and will choose the proper slot or fail, otherwise.

Pitfalls

Devel packages

It is common practice in binary-based GNU/Linux distributions to use satellite devel packages to collect various build-time files like C headers or pkg-config files. In the 0install environment, this doesn't work, because every package is stored in a separate directory hierarchy, e.g., *.so symlinks, from devel package, will point to nothing, since all *.so.* files from the library package live in a separate directory.

Keep all build-time files in the runtime package.