Project:eselect/Developer guide

From Gentoo Wiki
Jump to:navigation Jump to:search

eselect is a framework for simplifying and introducing consistency to the various foo-config and blah-update tools. It is an option for developers who don’t like reinventing the wheel, not a mandatory tool.

Note
This document assumes some basic familiarity with eselect. Please read the User Guide in case you do not know the basics of eselect.

Getting started

Introduction

When porting your application to use the eselect framework, you will generally need to create a module. Often this can be heavily based upon an existing module, so check to see whether there is something that does almost what you need first (symlink handling is a good example of something that can be copied rather than reinvented).

A simple module

It’s easiest to illustrate by example. Here’s a simplified version of the kernel.eselect module. It has three actions, show, list, and set, plus the standard help, usage, and version actions, and is installed to $(datadir)/eselect/modules/.

CODE
# -*-eselect-*-  vim: ft=eselect
# Copyright 2005-2019 Gentoo Authors
# Distributed under the terms of the GNU GPL version 2 or later

DESCRIPTION="Manage the /usr/src/linux symlink"
MAINTAINER="eselect@gentoo.org"
VERSION="20180916"

# find a list of kernel symlink targets
find_targets() {
    local f
    for f in "${EROOT}"/usr/src/linux-[[:digit:]]*; do
        [[ -d ${f} ]] && basename "${f}"
    done
}

# remove the kernel symlink
remove_symlink() {
    rm "${EROOT}/usr/src/linux"
}

# set the kernel symlink
set_symlink() {
    local target=$1

    if is_number "${target}"; then
        local targets=( $(find_targets) )
        target=${targets[target-1]}
    fi

    [[ -z ${target} || ! -d ${EROOT}/usr/src/${target} ]] \
        && die -q "Target \"$1\" doesn't appear to be valid!"

    ln -s "${target}" "${EROOT}/usr/src/linux"
}

### show action ###

describe_show() {
    echo "Show the current kernel symlink"
}

do_show() {
    write_list_start "Current kernel symlink:"
    if [[ -L ${EROOT}/usr/src/linux ]]; then
        local kernel=$(canonicalise "${EROOT}/usr/src/linux")
        write_kv_list_entry "${kernel%/}" ""
    else
        write_kv_list_entry "(unset)" ""
    fi
}

### list action ###

describe_list() {
    echo "List available kernel symlink targets"
}

do_list() {
    local i targets=( $(find_targets) )

    write_list_start "Available kernel symlink targets:"
    for (( i = 0; i < ${#targets[@]}; i++ )); do
        # highlight the target where the symlink is pointing to
        [[ ${targets[i]} = \
            $(basename "$(canonicalise "${EROOT}/usr/src/linux")") ]] \
            && targets[i]=$(highlight_marker "${targets[i]}")
    done
    write_numbered_list -m "(none found)" "${targets[@]}"
}

### set action ###

describe_set() {
    echo "Set a new kernel symlink target"
}

describe_set_parameters() {
    echo "<target>"
}

describe_set_options() {
    echo "target : Target name or number (from 'list' action)"
}

do_set() {
    [[ -z $1 ]] && die -q "You didn't tell me what to set the symlink to"
    [[ $# -gt 1 ]] && die -q "Too many parameters"

    if [[ -L ${EROOT}/usr/src/linux ]]; then
        # existing symlink
        remove_symlink || die -q "Couldn't remove existing symlink"
        set_symlink "$1" || die -q "Couldn't set a new symlink"
    elif [[ -e ${EROOT}/usr/src/linux ]]; then
        # we have something strange
        die -q "${EROOT}/usr/src/linux exists but is not a symlink"
    else
        set_symlink "$1" || die -q "Couldn't set a new symlink"
    fi
}

As you can see, the format is fairly similar to that of an ebuild – it is a bash script which is run in a special environment. This is intentional. There are DESCRIPTION and VERSION variables globally which are used by eselect and some of the default action handlers, and a series of functions.

Warning
In ebuilds, global scope code can cause problems. In eselect modules, global scope code is absolutely forbidden. Your module will be sourced for tasks other than running your actions. For example, if eselect modules list is executed, your module will be sourced to obtain the description. Any code being run here would be a very bad thing.

Unlike ebuilds, the function names are not fixed. Any function whose name starts with do_ is considered to be an action implementation. It is conventional to have a describe_ function for every do_ function that gives a short description of the function – this is used for eselect modulename help, for example. The describe_actions_options and describe_action_parameters functions are optional.

All eselect modules are required to support the ROOT variable. For prefix support, variables EPREFIX and EROOT are also defined and have the same meaning as in ebuilds.

Note
If eselect is invoked as foo-config or foo-update (for example, via a symlink), it will automatically execute the foo module.

All modules contributed to eselect should have a header indicating copyright. This must be an exact copy of the header in the above example (except for the years, of course).

Adding modules for testing

eselect modules can be manually added to the system. This is specially useful when an eselect module is being developed and needs testing. Copying (or symlinking) the eselect module to ~/.eselect/modules/ will make eselect aware of it.

Standard action names

The following list contains suggested allowed names for actions. If there is no suitable name on the list for your task, it is best to ask for the list to be updated – for consistency, it would be nice to have a standardised list of action names.

help
Display a help message. Automatic.
usage
Display a usage message. Automatic.
version
Display the current version. Automatic.
list
Used to display all available providers of a symlink, or all available modules.
show
Used to display the current provider of a symlink, or the currently installed module, or the current status.
set
Used to set a new provider or a symlink.
unset
Used to unset the current provider, or to remove a symlink.
update
Used to automatically select a new provider for a symlink (as opposed to set, which generally takes a parameter manually selecting the provider) or to gather system information that is vital to further actions.
enable
Used to enable an optional feature.
disable
Used to disable an optional feature.
scan
Read information off the current filesystem.
Note
You can override the help, usage and version actions. They are provided by default by lib/default.eselect. You should only do this with a good reason. Removing them is not a good idea, eselect assumes that they exist.

Utility functions

eselect provides many utility functions. These are useful for standardised output formatting. Where possible, these should be used, especially for output. If a standard function is not available for the output format required, consider implementing one.

The following categories of function are available by default:

To use any of the other functions, you have to first inherit the corresponding library file.

General utility functions

These are implemented in libs/core.bash.

die
The die function (which, unlike its ebuild counterpart, can be called from within subshells) is used to exit with a fatal error. It should be invoked as die -q "Message to display". If the -q is not provided, a stacktrace will be displayed – this should never happen because of user input error, only abnormal conditions.
check_do
The check_do utility function checks that the first parameter is a function, and then calls it with any additional parameters as its arguments. If the function does not exist, die is called. Again, this is mostly internal.
do_action
The do_action utility function is the correct way to call a utility function which is defined in another module. The first parameter is the action, additional parameters are passed as arguments.
inherit
The inherit function sources eselect library files based on their name. In order to source the file libs/foo.bash you have to add inherit foo in global scope of your module.
sed
The sed function is a wrapper around GNU sed.

Output utility functions

These are implemented in libs/output.bash.

write_error_msg
The write_error_msg function displays an error message in the standard format. It is similar to eerror.
write_warning_msg
The write_warning_msg function displays a warning message in the standard format. It is similar to ewarn.
The write_list_ family of functions
To display a list, the write_list_ family of functions should be used. If -p is passed as the first argument to these functions, plain highlighting is used.
write_list_start
Lists should always start with a header, which can be displayed using write_list_start The Header.
write_numbered_list_entry
To display a numbered list, the write_numbered_list_entry function should be used for each item. The first parameter is the list item number, the second is the list item text (remember to quote this).
write_kv_list_entry
To display a keyword/value list, the write_kv_list_entry function should be used. The first parameter is the key, the second the value.
write_numbered_list
The write_numbered_list function is a wrapper around write_numbered_list_entry that handles the numbering automatically. Each parameter passed is displayed as a numbered list item, the first with index 1, the second with index 2 and so on. The -m option can be used to specify a negative report message that is output for an empty list.
highlight
The highlight utility function can be used to emphasise some text which is to be displayed by any of the above functions. A typical invocation might look like:
CODE
write_list_start "This is $(highlight list) example"
write_kv_list_entry "First" "This is the first entry"
write_kv_list_entry "$(highlight Second)" "This is the $(highlight second) entry"
write_kv_list_entry "Third" "$(highlight The end)"
highlight_warning
The highlight_warning function is like highlight, but for warnings. It displays the text in question in red.
highlight_marker
To mark a list entry as active/selected, the highlight_marker function should be used. First argument is the list entry. The function places a highlighted star (or its second argument instead, if set) behind the entry. A typical invocation might look like:
CODE
for (( i = 0; i < ${#targets[@]}; i++ )); do
    [[ test_if_target_is_active ]] \
        && targets[i]=$(highlight_marker "${targets[i]}")
done
is_output_mode
The is_output_mode function returns true if and only if its parameter is equal to eselect’s output mode. Currently, only the default and brief output modes are defined, the latter corresponding to the --brief option. (This function appeared in eselect-1.2.6.)
space
The space utility function takes a single integer parameter. It displays that many space characters.

Test functions

These are implemented in libs/tests.bash.

has
The has utility function is like its Portage equivalent. It returns true if and only if the first parameter is equal to any of the remaining parameters.
is_function
The is_function utility function returns true if and only if its parameter exists and is a function. This is mostly used internally, but may have some use for modules.
is_number
Returns true if and only if the parameter is a positive whole number.

Path-manipulation functions

These are implemented in libs/path-manipulation.

basename
The basename function is a transparent bash-only replacement for the external basename application.
dirname
The dirname function is a transparent bash-only replacement for the external dirname application.
canonicalise
The canonicalise function is a wrapper to either GNU readlink -f or realpath.
relative_name
The relative_name function converts a path name (passed as its first argument) to be relative to a directory (second argument). This can be used to generate a relative symlink from absolute paths. (This function appeared in eselect-1.2.4.)

Manipulation functions

These are implemented in libs/manip.bash.

svn_date_to_version
If your module is kept in a CVS or subversion repository, then the svn_date_to_version function can be used instead of manually keeping track of VERSION. It is safe to use in global scope. The canonical usage is as follows:
CODE
SVN_DATE='$Date: $'
VERSION=$(svn_date_to_version "${SVN_DATE}")

Then turn on SVN keyword expansion for the module:

user $svn propset svn:keywords "Date" modules/foo.eselect

Configuration functions

These are implemented in libs/config.bash.

store_config
The store_config function saves a key/value pair in a given configuration file which is passed as first argument. This file is a bash script consisting only of key/value pairs and should not be altered manually. Comments in the file will be deleted each time store_config is called. The function is invoked as store_config filename key value.
load_config
The load_config function loads a stored value from the module’s configuration file. It is invoked as load_config filename key and prints the associated value.
append_config
The append_config function adds an item to an already stored value in the module’s configuration file. It uses load_config / store_config internally and should be invoked as append_config filename key item. Note that the item will not be appended if it occurs in the key’s value already.

Multilib functions

These are implemented in libs/multilib.bash.

list_libdirs
The list_libdirs function returns a set of valid libdirs for the used architecture. By default it uses /etc/ld.so.conf to obtain all the valid libdirs. If this fails due to a missing or broken file, this function uses uname to determine the architecture.
get_libdir
The get_libdir function prints the basename of the libdir path that was passed to eselect's configure.

Package-manager functions

These are implemented in libs/package-manager.bash.

arch
The arch function returns the correct value of the ARCH variable for the current system. If the package manager cannot provide this information, arch falls back to a lookup-table based on the HOSTTYPE and OSTYPE bash variables.
envvar
The envvar function retrieves the contents of a configuration-environment variable for a given package. The syntax is envvar ${package-name} ${var-name}.
best_version
The best_version function returns the highest available version for a given package dependency specification.
has_version
The has_version function checks whether a package matching a given dependency specification is installed.
get_repositories
The get_repositories function returns a list of repositories known to the package manager.
get_repo_news_dir
The get_repo_news_dir function returns the directory where to find GLEP 42 news items for a given repository.

This page was converted from and is kept in sync with the eselect Developer Reference by Ciaran McCreesh, Danny van Dyk, Ulrich Müller, and Shyam Mani. It is dual-licensed under GPL-2+ or CC-BY-SA-4.0.