blob: 799672c00017e0267a570cd0da99474b31460ca1 [file] [log] [blame]
#!/bin/sh -efu
# Copyright 2011-2012 Intel Corporation
# Author: Artem Bityutskiy
# License: GPLv2
. shell-error
if [ -z "${__included_aiaiai_sh_functions-}" ]; then
__included_aiaiai_sh_functions=1
# Print an error message and exit
# Usage: die <message>
die()
{
fatal "Fatal error: $1"
}
# Print a separator line to stdout
print_separator()
{
local i=0
while [ $i -lt 80 ]; do
i="$(($i+1))";
printf "-";
done
echo
}
# Check if dash is available and we are not running in dash
can_switch_to_dash()
{
if command -v "dash" >/dev/null 2>&1; then
if [ -n "${BASH_VERSION:-}" ]; then
return 0
fi
fi
return 1
}
# Die if a program is not in PATH
# Usage: program_required <program_name>
program_required()
{
local prg="$1"; shift
local msg="$1"; shift
if ! command -v "$prg" >/dev/null 2>&1; then
message "Program \"$prg\" is required but not found in PATH"
if [ -n "$msg" ]; then
die "$msg"
else
exit 1
fi
fi
}
# Some tools in the "helpers" subdirectory have to be compiled before they can
# be sued. When Aiaiai is used from the source tree (as opposed to being
# installed from an RPM package), the user may froget to compile the tools.
# This function tries to compile them.
#
# Usage: compile_helpers <srcdir>
#
# where <srcdir> is the directory where the helper tools are supposed to live.
compile_helpers()
{
local srcdir="$1"
local tools="remap-log aiaiai-locker"
for tool in $tools; do
if command -v "$tool" >/dev/null 2>&1; then
continue
fi
if [ -f "$srcdir/${tool}.c" ]; then
make -C "$srcdir" "$tool" >/dev/null 2>&1 ||:
fi
done
}
# Fetch the first occurrence of header "$1" from the mbox file
# Usage: fetch_header <header_name> < <mbox_file>
fetch_header()
{
local hdr="$1"
program_required "formail" ""
# Take only the first occurrence of the header
formail -z -c -x "$hdr:" | head -n1 | aiaiai-decode-rfc-2047
}
# Fetch all occurrences of header "$1" from the first e-mail in the mbox file
# Usage: fetch_header <header_name> < <mbox_file>
fetch_all_headers()
{
local hdr="$1"
program_required "formail" ""
# Take every occurrence of the header. This will only take occurrences
# from the first of a combined mbox.
formail -z -c -x "$hdr:" | aiaiai-decode-rfc-2047
}
# Similar to fetch_header, but exits with code 1 if the header hasn't been
# found, and has a little bit different interface (the result is stored in
# "<var>").
#
# Usage: fetch_header_or_die <var> <header_name> < <mbox_file>
fetch_header_or_die()
{
local var="$1"; shift
local hdr="$1"; shift
local res="$(fetch_header "$hdr")"
[ -n "$res" ] || die "Cannot find the \"$hdr:\" header"
eval "$var=\"\$res\""
}
fetch_header_per_patch()
{
local hdr="$1"
program_required "formail" ""
# Take only the first occurrence of the header per message
formail -s sh -c "formail -z -c -x \"$hdr:\" | head -n1" | aiaiai-decode-rfc-2047
}
# Insert a header into the given mbox file
# Usage: insert_header <mbox_file> <header>
insert_header()
{
local mbox="$1"; shift
local header="$1"; shift
# The below trick allows us to avoid creating a separate temporary
# file; open the "$mbox" file, unlink, use the open file descriptor for
# reading and redirect the output to the new version of the "$mbox"
# file. We could instead use the "sponge" tool, however.
exec 3<$mbox
rm $verbose "$mbox" >&2
verbose "Adding \"$header\""
formail -s formail -I "$header" <&3 > "$mbox"
exec 3<&-
}
git_dir()
{
local path="$1"
local dotgit="$path/.git"
if [ -d "$dotgit" ]; then
printf "%s" "$dotgit"
elif [ -d "$path" ]; then
printf "%s" "$path"
else
die "not a git repository: $path"
fi
}
# Apply a patch. In case of error, print user-friendly diagnostic messages to
# stdin.
# Usage: apply_patch < <mbox_file>
apply_patch()
{
local am cmt
program_required "patch" ""
cmt="$(git rev-parse "HEAD^{commit}")"
am="$(formail -s aiaiai-extract-patches | git am --3way 2>&1)" || {
cat <<EOF
Failed to apply patch(es) with git am on top of:
$(git log -1 --oneline "$cmt")
$am
Results of "patch --merge=diff3 -p1 < .git/rebase-apply/patch":
$(patch --merge=diff3 -p1 < .git/rebase-apply/patch 2>&1)
$(print_separator)
$(git diff --no-color | sed 's/^/> /')
EOF
return 1
}
}
# A helper function for 'build_failure()'. This function expects the properly
# formatted build log a stdin and outputs user-readable failure report to
# stdout.
__print_build_log()
{
local config="$(leave_first "$1")";
local arch="$(leave_second "$1")"; shift
local commit_id="$1"; shift
local commit_info="$(git log -1 --oneline "$commit_id")"
local commit_nickname="${1:-""}"
cat <<EOF
Failed to build $commit_nickname: $commit_info
Configuration: "$config${arch:+", architecture $arch"}".
$(cat)
EOF
}
# Format a build failure report.
# Usage: build_failure <defconfig> <commit_id> <commit_nickname> < <build_log>
build_failure()
{
# The build log might have been generated with multiple jobs which
# means it is probably messy and the error message is probably not at
# the very end. To make it more probable that we actually print the
# build error message within 24 lines we do the following:
# * filter sparse/smatch/cppcheck/coccinelle output
# * filter out 'CHECK drivers/blah.c' Kbuild lines
# * print 24 lines preceding the 'make[]: *** [] blah' pattern which
# make generates after an error
sed -n '# Filter out useless stuff
/\[sparse\]$/d
/\[smatch\]$/d
/\[cppcheck\]$/d
/\[coccinelle\]$/d
/^ CHECK /d
# Add the line to the hold buffer
H
# If the line is the error marker, print out the entire hold
# buffer and quit
/^make\[.*\]: \*\*\* \[.*\]/ { g; p; q; }
# Do the same if the last line is reached
$ { g; p; q; }' | tail -n24 |
__print_build_log "$@"
}
# Check if the build failed.
# Usage: build_failed <build_log>
build_failed()
{
local build_log="$1"
local failed
failed="$(tail -n1 -- "$build_log")"
test "$failed" = "FAILURE"
}
# Filter out the first element from a comma-separated list of elements.
# Usage: strip_first <list>
strip_first()
{
printf "%s" "$1" | sed -e 's/^[^,]*,\{0,1\}//g'
}
# Filter out all but the first element from a comma-separated list of elements.
# Usage: leave_first <list>
leave_first()
{
printf "%s" "$1" | sed -e 's/,.*$//g'
}
# Filter out all but the second element from a comma-separated list of elements.
# Usage: leave_second <list>
leave_second()
{
leave_first "$(strip_first "$1")"
}
# Filter out all but the third element from a comma-separated list of elements.
# Usage: leave_third <list>
leave_third()
{
leave_second "$(strip_first "$1")"
}
fi #__included_aiaiai_sh_functions