Exheres for Smarties

Overview

exheres-0 is an experimental, fluid EAPI and tree layout (in theory, the two concepts are independent, but the only place using one without the other is the Paludis test suite). When we stop breaking things we’ll make an EAPI exheres-1 and carry on using exheres-0 for experiments.

Tree Layout

metadata/
    about.conf (mandatory)
    accounts/
        groups/
            *.conf
        users/
            *.conf
    categories.conf (mandatory)
    layout.conf (mandatory)
    options/
        descriptions/
            options.conf
            *.conf
    repository_mask.conf
licences/
    BSD-3
    GPL-2
    GPL-3
profiles/
    repo_name (mandatory)
packages/
    cat-foo/
        exlibs/
            per-category.exlib
        pkg-foo/
            pkg-foo-1.23.exheres-0
            per-package.exlib
exlibs/
    foo.exlib
sets/
    stages.conf

Profiles

A self-contained repository (a repository that doesn’t have any masters) must define a set of profiles. The tree layout for those profiles looks like this:

profiles/
    system.conf
    options.conf
    amd64/
        parents.conf
        make.defaults
        options.conf
        desktop/
            parents.conf
    desktop/
        options.conf

The special system set is defined by these top-level files. An exheres repository cannot have a different system set depending upon which profile is selected.

For any particular profiles directory the following files are all optional.

Repository Metadata

Repositories expose optional and required metadata to package managers. The metadata is stored in the metadata sub-directory.

Additionally, the name of the repository needs to be included in the profiles sub-directory. The profiles sub-directory also contains other information relating to the repository. This information must either be provided explicitly here or by specifying a master repository that does provide this information, such as ::arbor.

Some packages need to depend on a specific group or user. This can be achieved by adding group/<group's name> or user/<user's name> to DEPENDENCIES (Note: in “build:” or “build+run:” if it’s needed by the exheres!). For both groups and users, a corresponding config file needs to be added, <group's name>.conf or <user's name>.conf respectively.

If the primary_group contains a group which is also tracked via accounts, user/<user's name> will have a dependency on that group.

To mask more than one package use *annotations:

(
    sys-devel/gcc[~scm]
    sys-devel/gcc[~4.5-scm]
) [[
    *author = [ Ingmar Vanhassel <ingmar@exherbo.org> ]
    *date = [ 02 Oct 2009 ]
    *token = scm
    *description = [ Mask live GCC versions ]
]]

The token key can contain any of the following values:

There is also a second category of tokens; these are allocated for groups where packages are tightly coupled. Or, in other words, where unmasking one package in the group typically means having to unmask all the others.

Other values can be added to these lists if needed. The user token is reserved for user masks.

Repository Masters

A master repository which is listed in metadata/layout.conf in your repository allows you to:

Master repositories are not inherited from masters. So if you need an exlib from ::foo which needs another exlib from ::bar then you need to list both foo and bar in masters. Since foo needs bar as a master, bar needs to be listed before foo.

Keep in mind that you should not specify masters if you just depend on a package in that repository. The unavailable repositories track that and will tell users to add the repository if they need the package.

Concept Renames

What Gentoo calls use flags we call options. We may support non-Boolean options at some point if there are good use cases demonstrated. USE_EXPAND is called SUBOPTIONS, and uses a colon (e.g. video_drivers:intel).

Keywords have become platforms. We’re still using arch and ~arch, for now. We don’t automatically inject PLATFORM into MYOPTIONS; platforms are regular SUBOPTIONS and should be managed as such.

General Strictness

Various things that were merely QA notices for ebuilds are strict errors.

Sometimes packages install to invalid directories. To prevent this exheres-0 comes with a whitelist of directories legal to install to. The default whitelisted directories are:

/etc
/usr
/var

Additionally the following directories are explicitly forbidden to install to:

/run
/run/lock
/var/run
/var/lock

To add additional directories to these lists use exdirectory.

Supported environment

Exheres packages may use all features of GNU bash 4.0, and may assume that the extglob and the globstar shell options are set. The locale is preset to C.

Packages should assume the existence of GNU sed 4.0, GNU grep, coreutils, or a highly compatible implementation of sed, grep, and coreutils that supports many extensions that the GNU implementations support.

Users should avoid adding workarounds for certain implementations, and instead add a dependency on the GNU implementation of the tool if it is required.

If the logic that requires GNU coreutils is part of the exheres/exlib, consider doing it in a more compatible way, but don’t bend over backwards for it; If it can be done portably with a single change in arguments used, or it can be done in an extra line or so, that’s fine, but if it requires recreating the intended functionality entirely, that’s when you need to add a dependency on GNU coreutils.

Metadata Variables

All metadata variables must be defined independently of any system, profile or tree dependent data, and must not vary depending upon exheres phase. Metadata may be generated on a different system from that upon which the exheres will be used, and the exheres must generate identical metadata every time it is used.

Environment Variables

Name and Version Variables

Dependencies

Look like this.

DEPENDENCIES="
    build+run:
        foo/bar
    run:
        foo/baz
    post:
        foo/monkey
"

Labels affect all following atoms inside the current ( ) block, but not any higher level blocks. The default is build+run but you should always specify it. So:

DEPENDENCIES="
    blah? ( cat/build-and-run )
    foo? (
        cat/build-and-run
        build:
            cat/build-only
        run:
            cat/run-only
            bar? (
                cat/run-only
                post:
                    cat/post-only
            )
            cat/run-only-again
    )
    cat/build-and-run
"

The full list of labels is:

Not all labels are fully implemented. For example install is currently identical to build. Optional dependencies (recommendations and suggestions) should always be accompanied by a description annotation that explains why you would want to take or ignore them.

Package Dependencies

category/package_name:slot[version][option]

Above is the basic syntax of a package dependency for easy reference. Note that a package dependency can be as simple as foo/bar, however most packages require specific versions.

Slot dependencies:

Version dependencies:

Option dependencies:

Operators:

Additionally there are =, >, >=, < and <= operators.

Blockers:

Adding a blocker to a package will prevent that the package and the blocked package are installed together. The reason for blockers must be explained using a description annotation so that users can find out easily why they block. Sometimes it is useful to specify a resolution annotation as well.

For further documentation of annotations for blockers see Annotations.

DEPENDENCIES="
    build+run:
        !foo/bar [[
            description = [ foo/bar and this package both install /usr/bin/quux ]
            resolution = uninstall-blocked-after
        ]]
"

In general, blockers should be used sparsely because they’re annoying for users to deal with. For example, instead of making all packages that install /usr/bin/sendmail block, we handle these using alternatives.

Do not use blockers for package moves / renaming a package either. See how to rename a package

DOWNLOADS

DOWNLOADS has two new things. First, labels:

DOWNLOADS="
    like-primaryuri.tar.bz2
    manual: fetch-restricted-stuff.tar.bz2
    listed-only: will-not-look-on-mirrors.tar.bz2
    local-only: only-on-local-mirrors.tar.bz2
"

Supported values are:

Second, arrows:

DOWNLOADS="http://sucky-upstream/download/foo/1.2/foo.tar.bz2 -> foo-1.2.tar.bz2"

When consulting the listed URI (which can be a mirror://) the filename is used. When consulting mirrors and for the saved download location, the value on the right of the arrow is used.

Options can be used to make a download conditional:

DOWNLOADS="platform:amd64? ( amd64-only.tar.xz )"

Annotations

Annotations are another new dep-like toy. They don’t convey any critical information for DEPENDENCIES (as in, a compliant package manager need do nothing more than parse the contents, and an annotation-using package manager can ignore any particular key it wants). They look like this:

DEPENDENCIES="
    build+run:
        zoo/monkey [[
            description = [ it needs a monkey ]
            url = [ http://explain.exherbo.org/?zoo-monkey ]
        ]]

        !zoo/clown [[
            description = [ clowns will murder us in our sleep ]
            url = [ http://explain.exherbo.org/?clowns-are-evil ]
            resolution = uninstall-blocked-after
        ]]

    suggestion:
        zoo/snake [[
            description = [ otherwise we can't strangle things ]
        ]]
"

Annotations start with [[ and end with ]]. Inside, they’re key = value or key = [ value that can contain spaces ]. Note that whitespace is mandatory everywhere. Also note that currently the only ‘quote’ we allow is [ ] and you can’t use things that look like use? flags, ( dependencies ) etc., but if this proves too restrictive we might change it.

Annotation keys we recognise currently are:

Annotations are not limited to package and block dep specs. You can put them after other things too:

DEPENDENCIES="
    build+run: [[ here = [ would apply to the labels ] ]]
        foo? (
            (
                cat/one
                cat/two
            ) [[ here = [ would apply to the () block ] ]]
            cat/three
        ) [[ here = [ would apply to the foo? block ] ]]
"

DOWNLOADS="
    mirror://foo/${PNV}.tar.bz2 [[ here = [ would apply to the URI ] ]]
"

If you need an annotation to apply to each leaf element in a ( ) block you can prefix it with an *. The following two snippets are equivalent:

DEPENDENCIES="
    build+run:
        (
            cat/one
            cat/two
        ) [[
            foo = [ would apply just to the block ]
           *bar = [ would apply to each leaf node in this block ]
        ]]
"

DEPENDENCIES="
    build+run:
        (
            cat/one [[ bar = [ would apply to each leaf node in this block ] ]]
            cat/two [[ bar = [ would apply to each leaf node in this block ] ]]
        ) [[ foo = [ would apply just to the block ] ]]
"

Sometimes one feature causes multiple dependencies to be suggestions. Providing group-name annotations allows the feature to be taken with e.g. --take git-svn rather than having to list each dependency separately.

DEPENDENCIES="
    suggestion:
        (
            dev-scm/subversion[perl]
            dev-perl/libwww-perl
            dev-perl/TermReadKey
        ) [[ *description = [ Dependency for 'git svn' ] *group-name = [ git-svn ] ]]
        dev-perl/TermReadKey [[ description = [ Dependency for 'git add --interactive' ] ]]
"

Don’t overdo annotations. Blockers almost always benefit from having them. So do suggestions and recommendations. Normal deps, not so much, although sometimes a little [[ note = [ configure.ac says 2.0, but we get runtime terminal corruption unless we use at least 2.3 ] ]] might not go amiss.

LICENCES

LICENCES supports annotations, too, as shown in the following example:

LICENCES="
    GPL-3 [[ note = [ readline module ] ]]
    LGPL-3
"

The only recognized annotation key for a licence is note. Blocks of licences can also be annotated with the last-checked key.

LICENCES="( GPL-3 LGPL-3 ) [[ last-checked = 3.1.4 ]]"

The purpose of LICENCES is to determine what type of licence you have to accept in order to install a package, not to show exactly which attributions you might need to use or other details. For this reason there are a number of generic licences available with placeholders for the attribution. If the licence of the software you are packaging matches one of these you should use it. The definition of a match is not set in stone so apply common sense and as always ask if you are in doubt.

Every licence of an exheres has to match a file in the licences directory of the repository or one of its masters.

For packages that have different parts under different licences, list each one separated by a whitespace:

LICENCES="
    GPL-3 [[ note = [ readline module ] ]]
    LGPL-3
"

For packages with a dual licensing, use the syntax below:

LICENCES="|| (
    GPL-3 [[ note = [ readline module ] ]]
    LGPL-3
)"

MYOPTIONS

MYOPTIONS is a bit like IUSE, except more powerful. All flags have to be listed in MYOPTIONS, even SUBOPTIONS flags, and there is no special ARCH handling. Labels are used to select the active suboption. For example:

MYOPTIONS="
    foo
    bar
    baz
    linguas:
        en
        fr
    platform:
        x86
"

You need to list any platforms that will be used in dependencies or queried in any way; there is no need to list a platform simply because a package is keyworded on that platform.

Local flag descriptions, and more detailed descriptions for flags with a global meaning, are specified via annotations:

MYOPTIONS="imlib2 [[ description = [ Use imlib2 to render icons ] ]]"

Do not start your description with “enables support for”. This is superfluous. Do not describe foo as “Support for foo” unless even Wulf’s dead grandmother knows what foo is; you can at least manage “Support for the foo image format”.

Flags can also have requirements:

MYOPTIONS="
    foo
    bar
    baz [[ requires = [ foo -bar ] ]]
    linguas:
        en
        en_GB [[ requires = [ linguas: en ] ]]
"

These are checked just before pkg_pretend is called (and even if they fail, pkg_pretend will still be called). Theoretically you can override pkg_bad_options (being sure to call default to get the standard description displayed) to get improved error messages, but this may not be a good idea.

To have a requires annotation applied to an all-of block you can use *requires. This is a shortcut for applying the requirement to each child:

MYOPTIONS="
    X
    python
    (
        gtk [[ requires = python ]]
        qt
        motif
    ) [[ *requires = X ]]
"

Here, gtk requires both X and python (but we discourage this style – see below).

All-of blocks also support a number-selected annotation, which can have the value at-least-one, at-most-one or exactly-one:

MYOPTIONS="
    X
    python
    (
        gtk [[ requires = python ]]
        qt
        motif
    ) [[
        number-selected = at-most-one
        *requires = X
    ]]
"

Since number-selected is always applied to a group of options it should never be prefixed with an *. ( gtk qt motif ) [[ *number-selected = at-least-one ]] is wrong and would be equivalent to:

MYOPTIONS="
    gtk [[ number-selected = at-least-one ]]
    qt [[ number-selected = at-least-one ]]
    motif [[ number-selected = at-least-one ]]
"

which does not make any sense.

MYOPTIONS annotations can be done conditionally. Make sure you apply the annotations to an all-of block, not the conditional block. Any requirements inside a conditional block are tested only if the condition is met; any flags listed inside a conditional block are always considered part of MYOPTIONS, but the conditional flag itself must be explicitly listed beforehand.

MYOPTIONS="
    X
    python
    (
        gtk [[ requires = python ]]
        qt
        motif
    ) [[ *requires = X ]]
    X? ( ( gtk qt motif ) [[ number-selected = exactly-one ]] )
"

Negative flags are allowed, both as a requires value and inside an all-of block. Use sparingly.

In terms of style, it’s clearest to list all relevant flags first, along with any descriptions, and then go through and apply any requirements, avoiding grouping requirements together. So:

MYOPTIONS="
    X [[ description = [ Build a graphical user interface ] ]]
    python [[ description = [ Generate bindings for the Python programming language ] ]]
    gtk
    qt
    motif

    gtk [[ requires = python ]]
    ( gtk qt motif ) [[ *requires = X ]]
    X? ( ( gtk qt motif ) [[ number-selected = exactly-one ]] )
"

Presumed options are required by default. Any package that depends on this package without explicitly saying something about this option will require this option enabled.

MYOPTIONS="
    X [[ presumed = true ]]
"

If any package does not need the option enabled they need to state so explicitly using a cat/foo[?X] dependency or any other form that mentions X in the dependency.

REMOTE_IDS

The REMOTE_IDS function provides a pointer to this package in a remote database. It is specified as a list of database:index tokens:

REMOTE_IDS="freecode:blah vim:1234"

A non-definitive list of remote databases:

When adding new remote databases, it is important that given the database name and index, a client can find the information being pointed to without any searching.

UPSTREAM_*

UPSTREAM_CHANGELOG contains URLs for upstream changelogs:

UPSTREAM_CHANGELOG="http://blah/changelog.txt [[ lang = en ]]"
UPSTREAM_DOCUMENTATION="
    ${HOMEPAGE}/doc/admin/ [[ lang = en description = [ Administration guide ] ]]
    ${HOMEPAGE}/doc/user/  [[ lang = en description = [ User manual ] ]]
"

Likewise, UPSTREAM_DOCUMENTATION contains documentation URLs and UPSTREAM_RELEASE_NOTES contains release notes (e.g. NEWS files). These are all for user use.

REPLACING_IDS and REPLACED_BY_ID

REPLACING_IDS is a whitespace-separated list of ids (e.g. cat/pkg-1:0::installed) that are being replaced (uninstalled or overwritten) as a result of this install. REPLACING_IDS is defined in pkg_preinst and pkg_postinst. In addition it may be defined in pkg_pretend and pkg_setup, but you should take care to handle binary package creation and installation correctly if you need to use it in these phases.

REPLACED_BY_ID is a single id that is replacing this package, if it is being replaced as part of an install, or empty otherwise. REPLACED_BY_ID is defined in pkg_prerm and pkg_postrm.

Phases

The default phase functions are named default_src_blah, and you’re allowed to (and encouraged to) call them if you’re just adding functionality. But rather than calling default_src_blah, you can just call the special default function that’ll look at what phase we’re in and act accordingly.

Do not use the default functions if it involves doing something weird. Especially do not use the default functions if it means screwing around with the DEFAULT_ variables. If you are not simply setting the DEFAULT_ variables statically in global scope, you should write your own functions instead.

Phases are listed in running order. The pkg_config and pkg_info phases are separate user invoked phases.

pkg_pretend

Run in the sandbox and with userpriv. Called for every package after a cave resolve or cave resolve -x (but not currently for binaries – not sure how we’ll handle those yet). You can die in here to tell the user to change config things etc. (but use option deps and the like if possible instead).

pkg_pretend is not part of the normal call sequence. Variables set in this phase will not be available in other phases. pkg_pretend must not alter the file system.

default_pkg_pretend()
{
    :
}

pkg_nofetch

Run in the sandbox and with userpriv if RESTRICT=fetch is enabled.

default_pkg_nofetch()
{
    [[ -z "${ARCHIVES}" ]] && return

    local f g=
    for f in ${ARCHIVES} ; do
        [[ -f "${FETCHEDDIR}/${ARCHIVES}" ]] && continue
        if [[ -z "${g}" ]] ; then
            echo "The following files could not be fetched automatically for ${PN}:"
            g=no
        fi
        echo "* ${f}"
    done
}

src_fetch_extra

Run in the sandbox and with userpriv.

default_src_fetch_extra()
{
    :
}

pkg_setup

Run in the sandbox.

default_pkg_setup()
{
    :
}

src_unpack

Run in the sandbox and with userpriv.

default_src_unpack()
{
    [[ -n "${ARCHIVES}" ]] && unpack --if-compressed ${ARCHIVES}
}

src_prepare

Run in the sandbox and with userpriv. The DEFAULT_SRC_PREPARE_PATCHES array, if set, should be set in global scope and mustn’t be set dynamically. If you’re doing anything complicated, write your own src_prepare. The variable is just for the easy cases.

default_src_prepare()
{
    if [[ -n "${DEFAULT_SRC_PREPARE_PATCHES[@]}" ]]; then
        expatch "${DEFAULT_SRC_PREPARE_PATCHES[@]}"
    fi
}

src_configure

Run in the sandbox and with userpriv. Again, DEFAULT_SRC_CONFIGURE_* is just for the easy cases.

default_src_configure()
{
    if [[ -x ${ECONF_SOURCE:-.}/configure ]] ; then
        econf \
            "${DEFAULT_SRC_CONFIGURE_PARAMS[@]}" \
            $(for s in "${DEFAULT_SRC_CONFIGURE_OPTIONS[@]}" ; do \
                option ${s} ; \
            done ) \
            $(for s in "${DEFAULT_SRC_CONFIGURE_OPTION_ENABLES[@]}" ; do \
                option_enable ${s} ; \
            done ) \
            $(for s in "${DEFAULT_SRC_CONFIGURE_OPTION_WITHS[@]}" ; do \
                option_with ${s} ; \
            done ) \
            $(for s in "${DEFAULT_SRC_CONFIGURE_TESTS[@]}" ; do \
                expecting_tests ${s} ; \
            done )
    fi
}

src_compile

Run in the sandbox and with userpriv. DEFAULT_SRC_COMPILE_PARAMS is passed on to emake.

default_src_compile()
{
    if [[ -f Makefile ]] || [[ -f makefile ]] || [[ -f GNUmakefile ]] ; then
        emake "${DEFAULT_SRC_COMPILE_PARAMS[@]}"
    fi
}

src_test

Run in the sandbox and with userpriv. Should be considered mandatory.

default_src_test()
{
    if [[ -f Makefile ]] || [[ -f GNUmakefile ]] || [[ -f makefile ]] ; then
        echo "Makefile found, looking for potential test targets"
        if make -j1 -n "${DEFAULT_SRC_TEST_PARAMS[@]}" check ; then
            echo "Found check target"
            emake "${DEFAULT_SRC_TEST_PARAMS[@]}" check
        elif make -j1 -n "${DEFAULT_SRC_TEST_PARAMS[@]}" test ; then
            echo "Found test target"
            emake "${DEFAULT_SRC_TEST_PARAMS[@]}" test
        else
            echo "No check or test target, skipping tests"
        fi
    else
        echo "No Makefile, skipping tests"
    fi
}

src_test_expensive

Run in the sandbox and with userpriv. Used to run testsuites that take a very long time or are otherwise expensive using a huge amount of diskspace, memory or other resource.

default_src_test_expensive()
{
    :
}

src_install

Run in the sandbox.

This default function is fairly complex so it deserves a longer explanation. The first part simply looks for a Makefile and, if one is found, uses the install target with DESTDIR="${IMAGE}. It dies if an existing Makefile is missing an install target and it supports one variable for adding extra parameters for emake install. The emagicdocs function, however, tries to identify (case-insensitively) documents that are common in lots of packages and installs them by means of dodoc. It supports three variables for adding extra docs and one variable for excluding undesired docs.

The code for emagicdocs is listed under Helper functions.

pkg_preinst

Run in the sandbox.

default_pkg_preinst()
{
    :
}

pkg_prerm

Run in the sandbox.

default_pkg_prerm()
{
    :
}

pkg_postrm

Run in the sandbox.

default_pkg_postrm()
{
    :
}

pkg_postinst

Run in the sandbox.

default_pkg_postinst()
{
    :
}

pkg_config

Run in the sandbox.

default_pkg_config()
{
    eerror "No configuration function is defined"
}

pkg_info

Run in the sandbox and with userpriv. Can be run for both installed and uninstalled packages.

default_pkg_info()
{
    :
}

Helper Functions

Organised by where they’re implemented in Paludis, to make it easy to keep this up to date.

We have the nonfatal function which modifies how a function that usually dies on its own works: If a function, e.g. emake, dies on its own, it means that any code beyond that function (e.g. a || die "blah") won’t ever be reached and, thus, a default error message is displayed. If you want to display a custom error message, you can add the prefix nonfatal to the function call, e.g. nonfatal emake blah. This will cause emake to just emit a non-zero return code which you can use with a regular || die "blah" function, i.e. emake will signal things went wrong but won’t die by itself.

die_functions.bash

echo_functions.bash

ever_functions.bash

Some commands optionally take a version argument – this is indicated as ever command [version]. Whenever a version is optional and omitted, ever functions default to the PV for the current id, unless stated otherwise.

Rather than being a number, the index parameter can be a separator character such as ‘-’, ‘.’ or ‘_’. In this case, the first separator of this kind is selected.

install_functions.bash

kernel_functions.bash

We probably want to ban these at some point.

sydbox.bash

See Magic Commands under Sandboxing.

exheres-0/build_functions.bash

exheres-0/conditional_functions.bash

exheres-0/exlib_functions.bash

exheres-0/list_functions.bash

exheres-0/output_functions.bash

exheres-0/portage_stubs.bash

utils/

All of the following scripts die by default upon failure. If this isn’t desired call them via nonfatal:

utils/exheres-0/

Exlibs

Not that different to eclasses yet. Can be per-category and per-package rather than global. Loaded using require.

Functions are exported using export_exlib_phases. It can be called more than once; a phase is exported if it is given as an argument to export_exlib_phases at least once. If it is called, it must be after any exlib that exports the same phases is included with require.

Incremental metadata variables

The metadata variables DEPENDENCIES and MYOPTIONS are incremental across exlibs. The values set in all required exlibs and the value set in the exheres get encapsulated in parentheses and concatenated by the package manager. The encapsulation is necessary to ensure labels in one exlib do not affect what labels apply in another exlib or the exheres.

Exlib Parameters

Exlibs can take parameters.

require foo [ bar=baz blah=bleh ] monkey [ in=space ]

This requires foo.exlib with bar=baz and blah=bleh parameters, and monkey.exlib with the in=space parameter. Exlib parameters need to be declared as early as possible in the exlib using the myexparam function. The following three examples declare the bar variable as a required parameter, blah as an optional parameter that is set to bloh if not provided and baz as an optional parameter that is set to an empty string if not provided:

myexparam bar
myexparam blah=bloh
myexparam baz=

To access the value of an exlib parameter use the exparam function. This takes one argument, the name of the exlib parameter, and outputs the value. It must be used only in the exlib that declares the parameter and only after it has been declared.

exparam bar

Unfortunately due to a limitation in bash and the way this functionality is implemented, using exparam in a subshell from a function that is called outside global scope will not work. So for instance this code will result in the error message “exparam is banned outside exlibs”:

foo_pkg_setup() {
    var=$(exparam bar)
}

Therefore exparam has optional support for specifying a variable name to assign the value of the exlib parameter to:

foo_pkg_setup() {
    exparam -v var bar
}

Exlib parameters can also be arrays. The following two examples are equivalent:

require foo [ bar=[ 1 2 "3 3" ] ]
require foo [[ bar=[[ 1 2 "3 3" ]] ]]

Allowing the latter notation makes it possible to have a regular variable with the value “[”:

require foo [[ bar=[ ]]

Arrays must be declared via myexparam. The following three examples declare an exlib array as required, optional with an empty default value and optional with three default elements respectively:

myexparam bar[]
myexparam bar=[ ]
myexparam bar=[ 1 2 "3 3" ]

To empty an array with a non-empty default value:

require foo [ bar=[ ] ]

With exparam you can access either the number of elements, any individual element using an index or the full array:

exparam bar[#]
exparam bar[0]
exparam bar[1]
exparam bar[*]
exparam bar[@]

exparam bar is equivalent to exparam bar[0]. And again the value of the array can be assigned to a new array with exparam -v array bar[@] or of any individual element with e.g. exparam -v v3 bar[3].

For exlib parameters that specify a Boolean option, the standard convention is to use the values true and false. To support this, myexparam takes a -b option to specify that only those two values are permitted, and exparam takes a -b option to return a true or false exit status instead of outputting to stdout. exparam -b is only permitted for parameters that were declared with myexparam -b. For example:

myexparam -b foo
myexparam -b bar=true

if exparam -b foo; then
    DEPENDENCIES+=" dev-libs/libfoo"
fi

Sandboxing

There are three types of sandboxing:

execve() calls are sandboxed only in metadata phase. In this phase no external calls are allowed.

Path sandboxing and network sandboxing are enabled in the phases listed below:

Here’s a list of path prefixes that are allowed by default: Note: Environment variables are expanded.

prefix.write:
        ${CCACHE_DIR}
        ${PALUDIS_TMPDIR}
        /var/cache
        /var/tmp
        /tmp
        /proc/self/task
        /proc/self/attr
        /selinux/context
        /dev/shm
        /dev/pts
        /dev/ptmx
        /dev/tts
        /dev/pty
        /dev/tty
        /dev/random
        /dev/console
        /dev/full
        /dev/null
        /dev/zero
        /dev/stderr
        /dev/stdout
        /proc/self/fd
        /dev/fd

Network sandboxing has two whitelists, one for bind and one for connect, sendto etc. By default network sandboxing allows bind to address 127.0.0.1/8 on ports 0 and 1024-65535. If a bind call is successful the address is automatically added to the connect whitelist.

Magic Commands

The behaviour of sandboxing may be altered by using magic commands. These commands provide a simple way to interact with sydbox. Check sydbox manual page for the list of magic commands. Previously we used a simple wrapper function called sydboxcmd around sydbox’ magic stat() function. This function is now deprecated in favour of the higher level wrapper esandbox.

Here’s a list of esandbox commands:

Querying sandbox status

Turning sandboxing on/off

Whitelisting

Filtering

Miscellaneous commands

Specifying Network Addresses

Network addresses may be specified in the following forms:

where /NETMASK can be omitted and PORT_RANGE can either be a number or two numbers in the form BEGIN-END. In addition, there are a few network aliases that are expanded to network addresses. They are listed below:

So you may use LOOPBACK@0 instead of inet:127.0.0.0/8@0

Deprecated Commands

Formatting

Copyright goes to you, but you need to GPL v2 it if it goes in the tree. For stuff you wrote from scratch:

# Copyright 2008 Ciaran McCreesh
# Distributed under the terms of the GNU General Public License v2

If you make large changes to an exheres:

# Copyright 2007, 2008 Ciaran McCreesh
# Copyright 2008 Ivan Toby Rich
# Distributed under the terms of the GNU General Public License v2

If you rip off another non-trivial exheres:

# Copyright 2008 Ivan Toby Rich
# Distributed under the terms of the GNU General Public License v2
# Based in part upon 'foo-1.23.exheres-0', which is:
#     Copyright 2008 Ciaran McCreesh

Basing your work upon ebuilds is fine, but if you did, make sure you include the Gentoo copyright notice. This applies even if you read the ebuilds for inspiration – unless you have a lawyer handy to tell you exactly what does or does not count as a derived work, it’s easiest to assume that if you looked at the ebuilds then it’s derived (not because it necessarily is, but because doing so imposes no additional restrictions, whereas not doing so gives certain Gentoo people with nothing better to do an opportunity to make nuisances of themselves). So then you need do this:

# Copyright 2008 Ciaran McCreesh
# Distributed under the terms of the GNU General Public License v2
# Based in part upon 'foo-1.23.ebuild' from Gentoo, which is:
#     Copyright 1999-2007 Gentoo Foundation

Applying Patches

All attempts should be made to keep the package as close to the upstream version as possible. In general, patches for compilation and runtime errors are okay. However, patches that introduce new features are discouraged, unless they are part of the upstream release cycle. Patches that alter external interfaces are particularly problematic. It is unacceptable to believe that it is sufficient to patch packages in our repository for such a change as this makes life harder for users who want to use packages that are not in our repositories. In the case that a patch is needed it must contain a header with the following information:

Source: written by, from distribution, etc
Upstream: patch status, bug number, etc
Reason: reason for the patch

This allows for others (or yourself), who may work with the package in the future, to be able to determine why a specific patch was applied. In the case that a patch no longer applies, the header aids in determining what to do with the patch (port it, discard it, etc.).

If there is active upstream development, it is highly recommended that patches be passed along to them so that they may incorporate the fix in the next release. This is beneficial for both parties. Bugs in the upstream project are caught and fixed, and it reduces the effort required downstream to track and fix the bug with every release. Note: Contributed patches are often rejected if they are not reported upstream for that reason. Please note in the upstream line if the patch is applied by upstream. In the case of several branches it could also be helpful to note the branch in which the patch is applied.

In the case of git format-patch-style patches, the Source: and Reason: lines may be left out if the commit message is expressive enough and if it is obvious where the patch originated. If that is not the case, the relevant parts have to be included in the patch header.

On Providing Choices

Packages should provide user options where reasonable and useful, but it is not necessary to spend excessive effort to support every obscure little tweak. Users can write their own custom exheres if they want these, although this should not require them to alter packages other than the ones they want to customise. In other words, if you make a definite decision instead of providing an option, avoid making other packages rely on that decision whenever reasonably possible.

Providers

providers is a suboption for the specific case when the same feature is provided by two or more similar packages.

Here is a example package (dvd+rw-tools) using providers:

# Copyright 2008 Ingmar Vanhassel <ingmar@exherbo.org>
# Distributed under the terms of the GNU General Public License v2

SUMMARY="A frontend to mkisofs to facilitate mastering Blu-ray Disc and DVD media, both +RW/+R and -R[W]"
HOMEPAGE="http://fy.chalmers.se/~appro/linux/DVD+RW/"
DOWNLOADS="${HOMEPAGE}/tools/${PNV}.tar.gz"

LICENCES="GPL-2"
SLOT="0"
PLATFORMS="~amd64 ~x86"
MYOPTIONS="
    ( providers:
        cdrtools
        cdrkit
    ) [[
        *description = [ ISOfs manipulation tools provider ]
        number-selected = at-least-one
    ]]
"

DEPENDENCIES="
    build:
        sys-devel/m4
    run:
        providers:cdrtools? ( app-cdr/cdrtools )
        providers:cdrkit? ( app-cdr/cdrkit )
"
[...]

More in-depth documentation on providers, their relationship with virtuals, and criteria for what constitutes a package being virtual can be found on the Providers and Virtuals doc.

Virtuals

Virtuals are packages without contents. Their sole purpose is to list providers of the exact same feature to ease specifying dependencies in packages requiring said feature. They rely entirely on the providers suboption.

Organisational rules for adding new virtuals:

Some specific packaging rules apply to virtuals:

Here is an example virtual (notification-daemon) for Freedesktop notifications providers:

# Copyright 2009 Mike Kelly
# Copyright 2014 Quentin "Sardem FF7" Glidic <sardemff7@exherbo.org>
# Distributed under the terms of the GNU General Public License v2

SUMMARY="Virtual: Freedesktop notifications providers"
HOMEPAGE=""

SLOT="0"
PLATFORMS="~amd64 ~x86"
MYOPTIONS="
    ( providers:
        notification-daemon
        notify-osd
        dunst
        eventd
        awesome
        notification-daemon-xfce
        gnome-shell
        kde-runtime
    ) [[
        *description = [ Freedesktop notifications provider ]
        number-selected = at-least-one
    ]]
"

DEPENDENCIES="
    providers:notification-daemon? ( x11-apps/notification-daemon )
    providers:notify-osd? ( x11-apps/notify-osd )
    providers:dunst? ( x11-apps/dunst )
    providers:eventd? ( net/eventd[dbus] )
    providers:awesome? ( x11-wm/awesome[>=3.1] [[ description = [ with the naughty library ] ]] )
    providers:notification-daemon-xfce? ( xfce-extra/notification-daemon-xfce )
    providers:gnome-shell? ( gnome-desktop/gnome-shell )
    providers:kde-runtime? ( kde/kde-runtime [[ description = [ with knotify ] ]] )
"

Alternatives

Organisational rules for adding new alternatives:

Rename a package

Sometimes, a package needs to be renamed (most likely because upstream changed its name). Here is what you should do:

Move packages between repositories

If a package should be moved from one repository to another, it’s important to also import any prior package related git actions (history) of that package. This is because commit messages often explain why certain changes have been made. Also, the history itself is of interest. To do this you have to first extract the history in patch format and import those patches via the usual procedure by using git-am.

cd /path/to/current_repository
git log --pretty=email --patch-with-stat --reverse -- path/to/package | (cd /path/to/new_repository && git am)

Resurrect a package

If you want to mantain a previously buried package you should in order:


Copyright 2008, 2009 Ciaran McCreesh

Copyright 2008-2015 Bo Ørsted Andresen

Copyright 2011 Ali Polatel

Copyright 2015 Saleem Abdulrasool