Conary:Recipe
From rPath Wiki
|
Recipes provide the instructions needed to create package for Conary package management. Recipes are to Conary what spec files are to RPM package management.
Recipes are written in Conary's domain-specific language, which itself is written in Python.
Use the following resources when writing recipes for Conary packages and groups:
- Recipe conventions and structure covered in the sections that follow here
- Recipe Templates: Linked list of templates for recipes to package various types of source, to package binaries, and to create Conary groups
- Package Recipe: Recipe writing specifically for packages, including resources for Package Recipe Classes
- Group Recipe: Recipe writing specifically for groups, including resources for Group Recipe Classes
- Info Recipe: Instructions and reference for creating info recipes, used to create system users or groups prior to the installation of any packages which require those users or groups
Recipe Syntax
Use the following syntax guidelines to keep Conary recipes consistent in form. Many of these overlap with typically recommended Python syntax:
- Use 4 space indentation, not tabs
NOTE: In the vi text editor, packages can set the tab key to enter four spaces with each use: set expandtab softabstop=4 sw=4 - Keep line lengths to 78 characters, exceeding this for strings without natural breaks
- When breaking up a function, indent the next line of the function to the open parenthesis ( ( ) opening the function, or (if more lines are needed) increase indentation one level
- Avoid excessive ( \ ) in strings when possible
- Use grouped single quotes ( '' ) instead of multiple-line triple-double quotes ( """ ... """ ) for function arguments, such as in the following example:
r.Configure('options here' ' --more-option=here' ' --still-more-options')
If you are using \n at the end of each line, use """ ... """ instead.
Recipe Naming Conventions
The actual class name in a recipe does not matter, but rPath recommends that it is a CamelCase version of the name string provided, removing any characters that are not allowed in Python identifiers. Also, the current class instance, which is typically self in standard Python code, is called r in Conary recipes.
Other naming conventions recommended by rPath are as follows:
- Use extraConfig for config options that are based on Use/Arch flags
- Use r.macros.x for values that are used in strings
- Use a local variable when branching on that value; this is useful when branching can be useful for features that do not deserve a Use flag but may need to be turned on or off by individual packagers
- In URLs that change directories with versions, do not use %(version)s in the filename
Parts of a Recipe
Each recipe is a subclass of a parent recipe classes defined in the Conary application programming interface (API). Packages can be subclassed further as needed, but this is rare. Classes provide recipe code reuseability, taking advantage of calling methods inherited from the parent class.
The Python code for recipes is referred to by its different sections. Recipes include class variables and macros plus processing actions. The processing actions include source preparation, build, and policy actions. See the following sections for descriptions of each section. Consider the following example recipe while referencing the descriptions:
class Tmpwatch(CPackageRecipe): name = 'tmpwatch' version = '2.9.0' buildRequires = [] def setup(r): r.addArchive('http://url/to/tmpwatch-%(version)s.tar.gz') r.addSource('crond-tmpwatch', dest='/etc/cron.daily/tmpwatch', mode=0755) r.MakeInstall(rootVar='ROOT')
Class Variables and Macros
Conary uses class variables and macros to describe various aspects of a package. Conary leverages its pre-defined class variables and macros in specific ways, and packagers can define and use additional variables and macros as needed for a specific package or group.
Class Variables
The following class variables are currently pre-defined in Conary:
- name - a string containing the name part of the source, as provided in one or more filenames
- version - a string containing the version part of the source, often provided in one or more filenames; this becomes the upstream version part of the revision, which is part of a Conary version string for the package; if the version format does not fit accepted revision number format, additional macros can be defined to convert the version to an acceptable format
- buildRequires - a list of components required to build this package (see Conary Collection Taxonomy)
Class variables from the tmpwatch example are:
name = 'tmpwatch' version = '2.9.0'
The buildRequires code has several inherited components required to build the package. For the example, the default inherited buildRequires is as follows:
buildRequires = [
'binutils:devellib',
'binutils:lib',
'binutils:runtime',
'bzip2:runtime',
'conary:lib',
'conary:python',
'conary:runtime',
'coreutils:runtime',
'cpio:runtime',
'debugedit:runtime',
'diffutils:runtime',
'elfutils:runtime',
'filesystem:runtime',
'findutils:runtime',
'gawk:runtime',
'gcc:devellib',
'gcc:lib',
'gcc:runtime',
'glibc:devel',
'glibc:devellib',
'glibc:lib',
'glibc:runtime',
'grep:runtime',
'gzip:runtime',
'make:runtime',
'mktemp:runtime',
'patch:runtime',
'python:lib',
'python:runtime',
'sed:runtime',
'setup:runtime',
'sqlite:lib',
'tar:runtime',
]
A recipe can remove build requirements that have been inherited by using the clearBuildRequires() function. For example:
class Example(PacakgeRecipe): name = 'example' version = '1.0' clearBuildRequires('tar:runtime', 'sed:runtime')
This removes tar:runtime and sed:runtime from the set of package components required to build the example package. Calling clearBuildRequires() with no argument clears all of the build requirements for the package recipe. Note: Until Conary 1.2.11, this function was called clearBuildReqs().
When the package is cooked, Conary indicates if additional build requirements are needed. Conary looks at the shared libraries and at config.log files (if any) to determine these additional requirements. The packager can add those to the recipe by recreating the buildRequires code above, but only with the indicated requirements not already in the inherited list. Conary combines the lists from the recipe classes and parent classes to make a complete build requirements list.
Additional pre-defined class variables include extraConfig which can be manually passed to r.Configure as options to a configure script. The main reason to include this is if it is shared between packages by inheritance. Packagers can also define new class variables such as local flags to enable or disable certain package features, as in the following code:
Flags.sample = False Flags.example = True Flags.example.setShortDoc('Support the drinking feature')
Macros
Macros provided by Conary include installation paths, compiler and linker flags, and the previously mentioned pre-defined class variables. Conary defines r.macros which are substituted into most arguments to methods invoked from recipes.
Packagers can use and modify Conary macros or define new macros for a recipe. See the Conary Macros page for detailed information on the macros provided by Conary.
In the example, class variables name and source can be used as macros:
r.addSource('%(name)s-%(version)s.tar.gz')
When Conary makes the substitution as specified by the class variable assignments in the recipe, it expands the argument to tmpwatch-2.9.0.tar.gz.
Processing Actions
The source preparation, build, and policy actions are all contained in a method (function) that defines the processing actions of the recipe. The name of the method, often setup or unpack, corresponds to the parent class from which the recipe inherits and typically reflects the method defined in the recipe template or example recipe initially used. In the example C package recipe, setup() starts this processing portion of the recipe. Since Conary 1.2.6, Conary will print out the full name of each of the methods it invokes, in the order in which it invokes them. The full name includes the name of the class. This makes it easy to see which methods were inherited and which were defined within the recipe.
Source Actions
Recipe processing starts with one or more source preparation actions. These are "add" actions, including addArchive, addSource, addPatch, addAction, addGitSnapshot, addMercurialSnapshot, addCvsSnapshot, addSvnSnapshot, addBzrSnapshot, addPostInstallScript, addPreRollbackScript, addPostUpdateScript, and addPreUpdateScript. The action should correspond with the type of source and the way the source is provided to the recipe. These actions include unpacking the added archives and applying the added patches. They do not, however, include compiling any of the source.
Note that setup() does not actually build software, it only populates the recipe object with information about how to cook the recipe. This results in a "to-do" list for Conary to perform during the cook, which actually builds the software.
If necessary, add additional methods to the recipe class (outside of the recipe processing method) and call them as part of the source setup actions. This can be useful when creating a recipe as a new parent class for other recipes.
In the example C package recipe, addArchive is used to retrieve a compressed tar file, then an addSource is used to contribute a source file in the same directory with the recipe. Each of these classes are described in the package recipe classes and group recipe classes pages, where they also link to the appropriate Conary API pages.
By default, the recipe system assumes that the source archives will have a top-level directory %(name)s-%(version)s, also accessible as the %(maindir)s macro. In most cases, Conary can automatically determine what to do in cases where they do not have this structure. If Conary cannot determine the correct structure, explicitly specify an alternate main directory explicitly at the beginning of the recipe within the recipe processing method:
r.mainDir('somepackage_20040505')
Source actions must never be called from within a conditional. This is because source actions do two separate things. First, they cause the source artifact to be stored as part of the Conary :source component. Second, they apply the source artifact to the filesystem at build time. Any source action that is not executed at the time that the :source component is checked in will not have its source artifact available when building into the repository, which will cause builds in other configurations to fail (see CNY-3221 for details).
All source actions have a use= keyword argument that is used in lieu of conditionally invoking the source action. For example, instead of:
if Flags.debug: r.addSource('http://example.com/download/foo-debug.tar.gz')
use
r.addSource('http://example.com/download/foo-debug.tar.gz', use=Flags.debug)
For more information about source preparation, see the source actions part of the Conary API.
Build Actions
In a Conary recipe, all processing actions that do not start with add are build or policy actions. Build actions take place after source preparation actions and control the compiling and installing of the packaged software. The building occurs in a build directory (%(builddir)s) and files are installed into a destination directory (%(destdir)s). Relative paths provided in the recipe calls are interpreted relative to the build directory.
Build actions that perform installation tasks (such as Install, Move, and MakeDirs) automatically create and necessary directories. The MakeDirs should only be necessary to overcome any invalid install targets in makefiles or to explicitly create and set the mode for directories the package should own. Note that directory paths specified must include a trailing slash within these build actions (such as in r.Move('../example/data/*', '/example/data/')).
Packages rarely need to own directories. Conary creates supporting directories for packages with mode 0755 and ownership root:root. Conary also removes supporting directories if they are empty. Possible reasons to package a directory are because the directory must exist even if empty and because special permissions or ownership are required. If a package needs to own a directory, the packager can use the setModes build action to change its mode to something other than 0755, or the packager can pass an exception with the policy action ExcludeDirectories.
Though packagers can use the Run build action to run arbitrary shell scripts to control the compile and install processes, rPath recommends using Conary build actions provided by its parent classes (see the package recipe classes and group recipe classes).
Build actions from the tmpwatch example are:
r.MakeInstall([[Conary:root Var|root Var]]="ROOT")
Note that rootVar for MakeInstall defaults to the GNU standard DESTDIR so that most packages need no more than r.MakeInstall() (no options set when called).
For more information about build actions, see the source actions part of the Conary API.
Policy Actions
Policy actions can be used when it is necessary modify the behavior of Conary policy. Conary provides methods specifically for the modification of particular Conary actions. See Conary policy documentation in the API pages and note that Conary internal policy is implemented in two files:
Policy actions that can be specified in a package recipe are listed in Conary:Package Recipe Classes, and each is linked to a corresponding reference in the Conary API pages.
One possible modification could be in Conary's automatic creation of components for a package. Conary packages all files in the %(destdir)s and separates the package into components. Conary determines which files to assign to which components for software management on a Conary system. For instance, shared libraries are put into :lib components, allowing them to be used by other packages and managed such to ensure dependencies remain intact. Other common assignments are header files and development documentation in :devel, user documentation in :doc, and miscellaneous files in :runtime. The policy action ComponentSpec can be used to override the automatic component assignment:
r.ComponentSpec('data', '%(sysconfdir)s/mylibrary.conf')
As with any policy action, packagers should be aware of how the native Conary policy works and why it works as it does. In this specific case, for example, the packager should consider that the :lib component for any package should be multilib capable.
Another modification was mentioned earlier in the form of ExcludeDirectories, which can be used as follows to force the creation of an empty directory, an action otherwise avoided by Conary packages:
r.ExcludeDirectories(exceptions='/var/log/telnetd/')
Use Flags and Flavoring
Various aspects of an installed Conary system are specified by Use flags. These flags determine which optional features are enabled, such as OpenSSL, LDAP support, Gnome, and SASL. These flags can be used to automatically enable or disable support in a source package for these features. Implementing these flags in a package or group recipe ensure the package adheres to specific conditions when cooked for specific Conary flavors.
The following example shows the leveraging of the Gnome use flag:
if Use.gnome: extraConfig += '--enable-gnome' buildRequires.append('libgnome:devel')
If support for an optional feature can be disabled when building a source package, packagers should add logic to your recipe to respect the appropriate Use flag, including adding necessary build requirements and passing the correct flags to the configure script.
Conary's use flags are defined by files in /etc/conary/use/.
Ordering
There are no restrictions to the ordering of lines in a recipe provided that the setup function and macro settings are executed prior to other actions. No matter where you place your actions in your recipe method, Conary will perform those actions in this order:
- Source actions
- Build actions
- Policy actions
Best practice is to write your recipe to reflect this processing order. See the following skeleton as an example:
class PackageName(PackageRecipe): name = 'name' version = '4.5' buildRequires = [] def setup(r): r.addArchive r.addPatch r.addSource #if the source code is one-off files that do not interact with patches r.addAction <setting cflags, mflags macros; they last throughout build> r.Configure r.Make r.MakeDirs r.MakeInstall r.Install r.Symlink r.Doc r.Remove, other cleanup r.Ownership/SetModes r.PackageSpec r.ComponentSpec
Some packagers may prefer a logical order while others prefer a chronological order. Additionally, some packagers need more blank lines than others to help organize the code. Note the types of methods called to plan recipe structure, and ensure that the structure facilitates efficient code update work.
