# 4 - Advanced Packaging with EPM

This chapter describes the advanced packaging features of EPM.

## Including Other List Files

The `%include` directive includes another list file:

    %include filename

Includes can usually be nested up to 250 levels depending on the host operating system and libraries.

## Dependencies

EPM supports four types of dependencies in list files: `%incompat`, `%provides`, `%replaces`, and `%requires`. Table 4.1 shows the level of support for each package format.

Table 4.1: Dependency Support
Format | %incompat | %provides | %replaces | %requires
--- | --- | --- | --- | ---
aix | No | No | Yes | Yes
bsd | Yes | No | No | Yes
deb | Yes | Yes1 | Yes | Yes
inst | Yes | No | Yes | Yes
osx | No | No | No | No
pkg | Yes | No | No | Yes
portable | Yes | Yes | Yes | Yes
rpm | Yes | Yes | No | Yes
setld | No | No | No | No
slackware | No | No | No | No
swinstall | No | No | Yes | Yes

1. Debian's package format does not currently support version numbers for `%provides` dependencies.

Software conflicts and requirements are specified using the `%incompat` and `%requires` directives.

If your software replaces another package, you can specify that using the `%replaces` directive. `%replaces` is silently mapped to `%incompat` when the package format does not support package replacement.

If your package provides certain functionality associated with a standard name, the `%provides` directive can be used.

Dependencies are specified using the package name and optionally the lower and upper version numbers:

    %requires foobar
    %requires foobar 1.0
    %incompat foobar 0.9
    %replaces foobar
    %replaces foobar 1.2 3.4
    %provides foobar

or the filename:

    %requires /usr/lib/libfoobar.so
    %incompat /usr/lib/libfoobar.so.1.2

Package dependencies are currently enforced only for the same package format, so a portable distribution that requires package "foobar" will only look for an installed "foobar" package in portable format.

Filename dependencies are only supported by the Debian, portable, and RPM distribution formats.

## Scripts

Bourne shell script commands can be executed before or after installation, patching, or removal of the software. Table 4.2 shows the support for scripts in each package format.

The `%preinstall` and `%postinstall` directives specify commands to be run before and after installation, respectively:

    %preinstall echo Command before installing
    %postinstall echo Command after installing

Similarly, the `%prepatch` and `%postpatch` directives specify commands to be executed before and after patching the software:

    %prepatch echo Command before patching
    %postpatch echo Command after patching

Finally, the `%preremove` and `%postremove` directives specify commands that are run before and after removal of the software:

    %preremove echo Command before removing
    %postremove echo Command after removing

Table 4.2: Scripts Support
Format | %preinstall | %postinstall | %prepatch | %postpatch | %preremove | %postremove
--- | --- | --- | --- | --- | --- | ---
aix | Yes | Yes | No | No | Yes | Yes
bsd | No | Yes | No | No | Yes | No
deb | Yes | Yes | No | No | Yes | Yes
inst | Yes | Yes | No | No | Yes | Yes
osx | Yes | Yes | No | No | No | No
pkg | Yes | Yes | No | No | Yes | Yes
portable | Yes | Yes | Yes | Yes | Yes | Yes
rpm | Yes | Yes | No | No | Yes | Yes
setld | Yes | Yes | No | No | Yes | Yes
slackware | No | Yes | No | No | No | No
swinstall | Yes | Yes | No | No | Yes | Yes

To include an external script file, use the `<filename` notation:

    %postinstall <filename

To include multiple lines directly, use the `<<string` notation (a.k.a. a "here" document):

    %postinstall <<EOF
    echo Command before installing
    /usr/bin/foo
    EOF

Note that all commands specified in the list file will use the variable expansion provided by EPM, so be sure to quote any dollar sign (`$`) characters in your commands. For example, "$foo" is replaced by the value of "foo", but "$$foo" becomes "$foo".

## Conditional Directives

The `%system` directive can match or not match specific operating system names or versions. The operating system name is the name reported by `uname` in lowercase, while the operating system version is the major and minor version number reported by `uname -r`:

`%system macos`
  Only include the following files when building a distribution for the macOS operating system.
`%system linux-2.0`
  Only include the following files when building a distribution for Linux 2.0.x.
`%system !macos !linux-2.0`
  Only include the following files when building a distribution for operating systems other than macOS and Linux 2.0.x.

The special name `all` is used to match all operating systems:

    %system all

For format-specific files, the `%format` directive can be used:

`%format rpm`
  Only include the following files when building an RPM distribution.
`%format !rpm`
  Only include the following files when not building an RPM distribution.x.
`%format all`
  Include the following files for all types of distributions.

The `%arch` directive can match or not match specific architectures. The architecture name is the name reported by `uname -m`; "arm" is a synonym for "armv6", "armv7", and "armv8", "intel" is a synonym for "i386", "i486", "i586", and "i686", and "powerpc" is a synonym for "ppc":

`%arch intel`
  Only include the following files when building a package for 32-bit Intel processors.
`%arch armv6`
  Only include the following files when building a package for ARMv6 processors.
`%system !powerpc`
  Only include the following files when building a package for processors other than PowerPC.

The special name `all` is used to match all architectures:

    %arch all

Finally, EPM can conditionally include lines using the `%if`, `%elseif`, `%ifdef`, `%elseifdef`, `%else`, and `%endif` directives.

`%if` directives include the text that follows if the named variable(s) are defined to a non-empty string:

    %if FOO
    f 755 root sys /usr/bin/foo foo
    %elseif BAR
    f 755 root sys /usr/bin/bar bar
    %endif

`%ifdef` directives only include the text if the named variable(s) are defined to any value:

    %ifdef OSTYPE
    f 755 root sys /usr/bin/program program-$OSTYPE
    %else
    f 755 root sys /usr/bin/program program.sh
    %endif

## Protecting Object Files from Stripping

The `nostrip()` option can be included at the end of a file line to prevent EPM from stripping the symbols and debugging information from a file:

    f 755 root sys /usr/lib/libfoo.so libfoo.so nostrip()

## Software Patches

EPM supports portable software patch distributions which contain only the differences between the original and patch release. Patch files are specified using uppercase letters for the affected files. In the following example, the files /usr/bin/bar and /etc/foo.conf are marked as changed since the original release:

    f 755 root sys /usr/bin/foo foo
    F 755 root sys /usr/bin/bar bar
    f 755 root sys /usr/share/man/man1/foo.1 foo.man
    f 755 root sys /usr/share/man/man1/bar.1 bar.man
    C 644 root sys /etc/foo.conf foo.conf

## Variables

EPM imports the current environment variables for use in your list file. You can also define new variable in the list file or on the command-line when running EPM.

Variables are defined by starting the line with the dollar sign (`$`) followed by the name and value:

    $name=value
    $prefix=/usr
    $exec_prefix=${prefix}
    $bindir=$exec_prefix/bin

Variable substitution is performed when the variable is defined, so be careful with the ordering of your variable definitions.

Also, any variables you specify in your list file will be overridden by variables defined on the command-line or in your environment, just like with `make`. This can be a useful feature or a curse, depending on your choice of variable names.

As you can see, variables are referenced using the dollar sign (`$`). As with most shells, variable names can be surrounded by curly braces (`${variable}`) to explicitly delimit the name.

If you need to insert a `$` in a filename or a script, use `$$`:

    %install echo Enter your name:
    %install read $$name
    %install echo Your name is $$name.

## Init Scripts

Initialization scripts are generally portable between platforms, however the location of initialization scripts varies greatly.

The `i` file type can be used to specify and init script that is to be installed on the system. EPM will then determine the appropriate init file directories to use and create any required symbolic links to support the init script:

    i 755 root sys foo foo.sh

The previous example creates an init script named foo on the end-user system and will create symbolic links to run levels 0, 2, 3, and 5 as needed, using a sequence number of 00 (or 000) for the shutdown script and 99 (or 999) for the startup script.

To specify run levels and sequence numbers, use the `runlevel()`, `start()`, and `stop()` options:

    i 755 root sys foo foo.sh "runlevel(02) start(50) stop(30)"

## Literal Package Data

Sometimes you need to include format-specific package data such as keywords, signing keys, and response data. The `%literal(section)` directive adds format-specific data to the packages you create. Literal data is currently only supported for DEB, RPM and PKG packages.

### Debian Literal Data

Debian packages have control files that provide metadata for each package. The `%literal(control)` directive can be used to provide this metadata:

    %literal(control) <<EOF
    Section: misc
    Priority: extra
    EOF

Debian packages support template files to define the metadata associated with configuration variables. The `%literal(templates)` directive can be used to provide this metadata:

    %literal(templates) <<EOF
    Template: canpi-server/reboot
    Type: boolean
    Description: Would you like to reboot to complete the package installation ?
     The package installation updates the device table overlay definition.
     For these changes to take effect the system must be restarted.
     The canpi daemon is not started by the package installation as the lack of /dev/can0
     will cause it to fail immediately.

    EOF

### PKG Literal Data

PKG packages support request files that are used to do batch installations when installation commands require user input. The `%literal(request)` directive can be used to provide this user input:

    %literal(request) <<EOF
    John Doe
    1 Any Lane
    Forest Lawn, OH 12345
    EOF

### RPM Literal Data

RPM packages support numerous attributes in the "spec" file that control how the package is created and what metadata is included with the package. The `%literal(spec)` directive can be used to provide attributes for the spec file:

    %literal(spec) <<EOF
    %changelog
    * Tue Aug 26 2008 John Doe <johndoe@domain.com>

    - Added new feature "bar"

    * Fri Aug 1 2008 John Doe <johndoe@domain.com>

    - Added new feature "foo"
    EOF