Error handling
Importance of error handling
Decent error handling is important because:
- Errors must be detected before Portage tries to install a broken or incomplete package onto the live filesystem. If build failures aren't caught, a working package could be unmerged and replaced with nothing.
-
When receiving bug reports, it is a lot easier to figure out what went wrong
if you know exactly which call caused the error, rather than just knowing
that, say, something somewhere in
src_compilebroke. - Good error handling and notification can help cut down on the number of bug reports received for a package.
The die function
The die function should be used to indicate a fatal error and abort the
build. Its parameters should be the message to display.
Although die will work with no parameters, a short message should always be
provided to ease error identification. This is especially important when a
function can die in multiple places.
Ebuild helpers automatically die on failure. Some eclass-provided functions will automatically die upon failure, others will not. Developers should check the eclass reference when in doubt.
Sometimes displaying additional error information beforehand can be useful. Use
eerror to do this. See Messages.
die on almost all external commands in ebuilds.
die and subshells
die may be called from a subshell. It aborts the build as if it had
been called from the main process, so constructs like the following behave as
expected:
[[ -f foorc ]] && ( update_foorc || die "Couldn't update foorc!" )
Note that this only covers the exit status that die itself acts upon.
A command that fails anywhere but at the end of a pipeline is still not
detected, as described in the next section.
Checking the exit status of a pipeline
When using pipes, simple conditionals and tests upon $? will not
correctly detect errors occurring in anything except the final command in
the chain. To get around this, bash provides the PIPESTATUS variable,
and the pipestatus command checks it for you:
bzip2 -dc "${DISTDIR}/${VIM_RUNTIME_SNAP}" | tar -xf -
pipestatus || die "unpacking ${VIM_RUNTIME_SNAP} failed"
The pipestatus command is only provided by the package manager in
EAPI 9 and later. In earlier EAPIs, inherit
eapi9-pipestatus.eclass to get it.
assert function for this purpose. It has been
banned in EAPI 9 and should not be used in new code.
If you need the gory details of PIPESTATUS, see the bash manpage.
The nonfatal command
If a non-zero exit status from an ebuild helper function is expected, you may
call it under the nonfatal function. Instead of dying on failure,
the command will then return non-zero exit status, as in the following example:
src_test() {
if ! nonfatal emake check ; then
local a
eerror "Tests failed. Looking for files to add to your bug report..."
while IFS='' read -r -d $'\0' a ; do
eerror " ${a}"
done < <(find "${S}" -type f -name '*.log' -print0)
die "Make check failed"
fi
}
nonfatal is available both as a shell function and as an external
command. The former allows it to be used with other shell functions, such as
those provided by eclasses, and the latter allows it to be used from commands
like find and xargs.
die also accepts the -n option. When called with it under
nonfatal, it will not abort the build but return with an error status
instead. This is mostly useful in eclass functions that want to let their
caller decide how a failure is handled:
my_helper() {
some_command || die -n "some_command failed" || return
einfo "some_command succeeded"
}
Outside of nonfatal, the -n option has no effect and die
aborts the build as usual.