4.3. Epoch, Scriptlets and Triggers
This section covers Epoch
, Scriptlets
, and Triggers
, which represent advanced directives for RMP SPEC files.
All these directives influence not only the SPEC file, but also the end machine on which the resulting RPM is installed.
4.3.1. The Epoch directive
The Epoch
directive enables to define weighted dependencies based on version numbers.
If this directive is not listed in the RPM SPEC file, the Epoch
directive is not set at all. This is contrary to common belief that not setting Epoch
results in an Epoch
of 0. However, the dnf
utility treats an unset Epoch
as the same as an Epoch
of 0 for the purposes of depsolving.
However, listing Epoch
in a SPEC file is usually omitted because in majority of cases introducing an Epoch
value skews the expected RPM behavior when comparing versions of packages.
Exemple 4.2. Using Epoch
If you install the foobar
package with Epoch: 1
and Version: 1.0
, and someone else packages foobar
with Version: 2.0
but without the Epoch
directive, the new version will never be considered an update. The reason being that the Epoch
version is preferred over the traditional Name-Version-Release
marker that signifies versioning for RPM Packages.
Using of Epoch
is thus quite rare. However, Epoch
is typically used to resolve an upgrade ordering issue. The issue can appear as a side effect of upstream change in software version number schemes or versions incorporating alphabetical characters that cannot always be compared reliably based on encoding.
4.3.2. Scriptlets directives
Scriptlets are a series of RPM directives that are executed before or after packages are installed or deleted.
Use Scriptlets only for tasks that cannot be done at build time or in an start up script.
A set of common Scriptlet directives exists. They are similar to the SPEC file section headers, such as %build
or %install
. They are defined by multi-line segments of code, which are often written as a standard POSIX shell script. However, they can also be written in other programming languages that RPM for the target machine’s distribution accepts. RPM Documentation includes an exhaustive list of available languages.
The following table includes Scriptlet directives listed in their execution order. Note that a package containing the scripts is installed between the %pre
and %post
directive, and it is uninstalled between the %preun
and %postun
directive.
Directive | Définition |
---|---|
| Scriptlet that is executed just before installing or removing any package. |
| Scriptlet that is executed just before installing the package on the target system. |
| Scriptlet that is executed just after the package was installed on the target system. |
| Scriptlet that is executed just before uninstalling the package from the target system. |
| Scriptlet that is executed just after the package was uninstalled from the target system. |
| Scriptlet that is executed at the end of the transaction. |
4.3.3. Turning off a scriptlet execution
The following procedure describes how to turn off the execution of any scriptlet using the rpm
command together with the --no_scriptlet_name_
option.
Procédure
For example, to turn off the execution of the
%pretrans
scriptlets, run:# rpm --nopretrans
You can also use the
-- noscripts
option, which is equivalent to all of the following:-
--nopre
-
--nopost
-
--nopreun
-
--nopostun
-
--nopretrans
-
--noposttrans
-
Ressources supplémentaires
-
rpm(8)
man page.
4.3.4. Scriptlets macros
The Scriptlets directives also work with RPM macros.
The following example shows the use of systemd scriptlet macro, which ensures that systemd is notified about a new unit file.
$ rpm --showrc | grep systemd -14: __transaction_systemd_inhibit %{__plugindir}/systemd_inhibit.so -14: _journalcatalogdir /usr/lib/systemd/catalog -14: _presetdir /usr/lib/systemd/system-preset -14: _unitdir /usr/lib/systemd/system -14: _userunitdir /usr/lib/systemd/user /usr/lib/systemd/systemd-binfmt %{?*} >/dev/null 2>&1 || : /usr/lib/systemd/systemd-sysctl %{?*} >/dev/null 2>&1 || : -14: systemd_post -14: systemd_postun -14: systemd_postun_with_restart -14: systemd_preun -14: systemd_requires Requires(post): systemd Requires(preun): systemd Requires(postun): systemd -14: systemd_user_post %systemd_post --user --global %{?*} -14: systemd_user_postun %{nil} -14: systemd_user_postun_with_restart %{nil} -14: systemd_user_preun systemd-sysusers %{?*} >/dev/null 2>&1 || : echo %{?*} | systemd-sysusers - >/dev/null 2>&1 || : systemd-tmpfiles --create %{?*} >/dev/null 2>&1 || : $ rpm --eval %{systemd_post} if [ $1 -eq 1 ] ; then # Initial installation systemctl preset >/dev/null 2>&1 || : fi $ rpm --eval %{systemd_postun} systemctl daemon-reload >/dev/null 2>&1 || : $ rpm --eval %{systemd_preun} if [ $1 -eq 0 ] ; then # Package removal, not upgrade systemctl --no-reload disable > /dev/null 2>&1 || : systemctl stop > /dev/null 2>&1 || : fi
4.3.5. The Triggers directives
Triggers are RPM directives which provide a method for interaction during package installation and uninstallation.
Triggers may be executed at an unexpected time, for example on update of the containing package. Triggers are difficult to debug, therefore they need to be implemented in a robust way so that they do not break anything when executed unexpectedly. For these reasons, Red Hat recommends to minimize the use of Triggers.
The order of execution on a single package upgrade and the details for each existing Triggers are listed below:
all-%pretrans … any-%triggerprein (%triggerprein from other packages set off by new install) new-%triggerprein new-%pre for new version of package being installed … (all new files are installed) new-%post for new version of package being installed any-%triggerin (%triggerin from other packages set off by new install) new-%triggerin old-%triggerun any-%triggerun (%triggerun from other packages set off by old uninstall) old-%preun for old version of package being removed … (all old files are removed) old-%postun for old version of package being removed old-%triggerpostun any-%triggerpostun (%triggerpostun from other packages set off by old un install) … all-%posttrans
The above items are found in the /usr/share/doc/rpm-4.*/triggers
file.
4.3.6. Using non-shell scripts in a SPEC file
The -p
scriptlet option in a SPEC file enables the user to invoke a specific interpreter instead of the default shell scripts interpreter (-p /bin/sh
).
The following procedure describes how to create a script, which prints out a message after installation of the pello.py
program:
Procédure
-
Open the
pello.spec
file. Find the following line:
install -m 0644 %{name}.py* %{buildroot}/usr/lib/%{name}/
Under the above line, insert:
%post -p /usr/bin/python3 print("This is {} code".format("python"))
- Build your package as described in Building RPMs.
Install your package:
# dnf install /home/<username>/rpmbuild/RPMS/noarch/pello-0.1.2-1.el8.noarch.rpm
Check the output message after the installation:
Installing : pello-0.1.2-1.el8.noarch 1/1 Running scriptlet: pello-0.1.2-1.el8.noarch 1/1 This is python code
To use a Python 3 script, include the following line under install -m
in a SPEC file:
%post -p /usr/bin/python3
To use a Lua script, include the following line under install -m
in a SPEC file:
%post -p <lua>
This way, you can specify any interpreter in a SPEC file.