1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/.murdock
Kaspar Schleiser c704d4a274 murdock: make get_compile_jobs() return subjobs
This change allows callers to receive the job list of individual apps in
chunks (instead of all at once after all appdirs have been processed),
if run as dwq job itself.

E.g.,

    $ dwqc ./.murdock get_compile_jobs

would previously run "get_compile_jobs()" as one job, collecting all the
output from "get_app_board_toolchain_pairs()" subjobs, then return the
combined output as job result.

By using subjobs, the job returns right away, but has previously sent
the "get_app_board_toolchain_pairs" jobs as subjobs ti the initial
instance, which will also wait for all of them to complete, but
already print subjob output as it is received.
2019-07-02 22:06:33 +02:00

312 lines
8.5 KiB
Bash
Executable File

#!/bin/sh
: ${TEST_BOARDS_AVAILABLE:="nrf52dk samr21-xpro"}
: ${TEST_BOARDS_LLVM_COMPILE:="iotlab-m3 native nrf52dk mulle nucleo-f401re samr21-xpro slstk3402a"}
export RIOT_CI_BUILD=1
export STATIC_TESTS=${STATIC_TESTS:-1}
export CFLAGS_DBG=""
export DLCACHE_DIR=${DLCACHE_DIR:-~/.dlcache}
export ENABLE_TEST_CACHE=${ENABLE_TEST_CACHE:-1}
NIGHTLY=${NIGHTLY:-0}
RUN_TESTS=${RUN_TESTS:-${NIGHTLY}}
DWQ_ENV="-E BOARDS -E APPS -E NIGHTLY -E RUN_TESTS -E ENABLE_TEST_CACHE -E TEST_HASH"
check_label() {
local label="${1}"
[ -z "${CI_PULL_LABELS}" ] && return 1
echo "${CI_PULL_LABELS}" | grep -q "${label}"
return $?
}
[ "$RUN_TESTS" != "1" ] && {
check_label "CI: run tests" && RUN_TESTS=1
}
[ "$ENABLE_TEST_CACHE" = "1" ] && {
check_label "CI: disable test cache" && export ENABLE_TEST_CACHE=0
}
error() {
echo "$@"
exit 1
}
# if MURDOCK_HOOK is set, this function will execute it and pass on all it's
# parameters. should the hook script exit with negative exit code, hook() makes
# this script exit with error, too.
# hook() will be called from different locations of this script.
# currently, the only caller is "run_test", which calls "hook run_test_pre".
# More hooks will be added as needed.
hook() {
if [ -n "${MURDOCK_HOOK}" ]; then
echo "- executing hook $1"
"${MURDOCK_HOOK}" "$@" || {
error "$0: hook \"${MURDOCK_HOOK} $@\" failed!"
}
echo "- hook $1 finished"
fi
}
# true if word "$1" is in list of words "$2", false otherwise
# uses grep -w, thus only alphanum and "_" count as word bounderies
# (word "def" matches "abc-def")
is_in_list() {
[ $# -ne 2 ] && return 1
local needle="$1"
local haystack="$2"
echo "$haystack" | grep -q -w "$needle"
}
# grep that doesn't return error on empty input
_grep() {
grep "$@"
true
}
_greplist() {
if [ $# -eq 0 ]; then
echo cat
else
echo -n "_grep -E ($1"
shift
for i in $*; do
echo -n "|$i"
done
echo ")"
fi
}
# get list of all app directories
get_apps() {
make -f makefiles/app_dirs.inc.mk info-applications \
| $(_greplist $APPS) | sort
}
# take app dir as parameter, print all boards that are supported
# Only print for boards in $BOARDS.
get_supported_boards() {
local appdir=$1
local boards="$(make --no-print-directory -C$appdir info-boards-supported 2>/dev/null || echo broken)"
if [ "$boards" = broken ]; then
echo "makefile_broken"
return
fi
for board in $boards
do
echo $board
done | $(_greplist $BOARDS)
}
get_supported_toolchains() {
local appdir=$1
local board=$2
local toolchains="gnu"
if is_in_list "${board}" "${TEST_BOARDS_LLVM_COMPILE}"; then
toolchains="$(make -s --no-print-directory -C${appdir} BOARD=${board} \
info-toolchains-supported 2> /dev/null | grep -o -e "llvm" -e "gnu")"
fi
echo "${toolchains}"
}
# given an app dir as parameter, print "$appdir $board:$toolchain" for each
# supported board and toolchain. Only print for boards in $BOARDS.
# if extra args are given, they will be prepended to each output line.
get_app_board_toolchain_pairs() {
local appdir=$1
local boards="$(get_supported_boards $appdir)"
# collect extra arguments into prefix variable
shift
local prefix="$*"
if [ "$boards" = makefile_broken ]; then
echo "$appdir makefile_broken"
return
fi
for board in ${boards}
do
for toolchain in $(get_supported_toolchains $appdir $board)
do
echo $prefix $appdir $board:$toolchain
done
done | $(_greplist $BOARDS)
}
# use dwqc to create full "appdir board toolchain" compile job list
get_compile_jobs() {
get_apps | \
dwqc ${DWQ_ENV} -s \
${DWQ_JOBID:+--subjob} \
"$0 get_app_board_toolchain_pairs \${1} $0 compile"
}
print_worker() {
[ -n "$DWQ_WORKER" ] && \
echo "-- running on worker ${DWQ_WORKER} thread ${DWQ_WORKER_THREAD}, build number $DWQ_WORKER_BUILDNUM."
}
test_hash_calc() {
local bindir=$1
# Why two times cut?
# "test-input-hash.sha1" contains a list of lines containing
# "<hash> <filename>" on each line.
# We need to filter out the filename, as it contains the full path name,
# which differs depending on the build machine.
#
# After piping through sha1sum, we get "<hash> -". " -" has to go so we save the
# hassle of escaping the resulting hash.
cat ${bindir}/test-input-hash.sha1 | cut -f1 -d' ' | sha1sum | cut -f1 -d' '
}
test_cache_get() {
test "${ENABLE_TEST_CACHE}" = "1" || return 1
test -n "$(redis-cli get $1)" > /dev/null
}
test_cache_put() {
redis-cli set "$1" ok
}
# compile one app for one board with one toolchain. delete intermediates.
compile() {
local appdir=$1
local board=$(echo $2 | cut -f 1 -d':')
local toolchain=$(echo $2 | cut -f 2 -d':')
[ "$board" = "makefile_broken" ] && {
echo "$0: There seems to be a problem in \"$appdir\" while getting supported boards!"
echo "$0: testing \"make -C$appdir info-boards-supported\"..."
make -C$appdir info-boards-supported && echo "$0: success. no idea what's wrong." || echo "$0: failed!"
exit 1
}
# set build directory. CI ensures only one build at a time in $(pwd).
export BINDIR="$(pwd)/build"
export PKGDIRBASE="${BINDIR}/pkg"
# Pre-build cleanup
rm -rf ${BINDIR}
print_worker
# sanity checks
[ $# -ne 2 ] && error "$0: compile: invalid parameters (expected \$appdir \$board:\$toolchain)"
[ ! -d "$appdir" ] && error "$0: compile: error: application directory \"$appdir\" doesn't exist"
[ ! -d "boards/$board" ] && error "$0: compile: error: board directory \"boards/$board\" doesn't exist"
# compile
CCACHE_BASEDIR="$(pwd)" BOARD=$board TOOLCHAIN=$toolchain RIOT_CI_BUILD=1 \
make -C${appdir} clean all test-input-hash -j${JOBS:-4}
RES=$?
# run tests
if [ $RES -eq 0 ]; then
if [ $RUN_TESTS -eq 1 -o "$board" = "native" ]; then
if [ -f "${BINDIR}/.test" ]; then
if [ "$board" = "native" ]; then
BOARD=$board make -C${appdir} test
RES=$?
elif is_in_list "$board" "$TEST_BOARDS_AVAILABLE"; then
test_hash=$(test_hash_calc "$BINDIR")
echo "-- test_hash=$test_hash"
if test_cache_get $test_hash; then
echo "-- skipping test due to positive cache hit"
else
BOARD=$board TOOLCHAIN=$toolchain TEST_HASH=$test_hash \
make -C${appdir} test-murdock
RES=$?
fi
fi
fi
fi
fi
if [ -d ${BINDIR} ]
then
echo "-- build directory size: $(du -sh ${BINDIR} | cut -f1)"
# cleanup
rm -rf ${BINDIR}
fi
return $RES
}
test_job() {
local appdir=$1
local board=$(echo $2 | cut -f 1 -d':')
local toolchain=$(echo $2 | cut -f 2 -d':')
local flashfile="$3"
[ ! -f "$flashfile" ] && {
echo "$0: _test(): flashfile \"$flashfile\" doesn't exist!"
return 1
}
dwqc \
${DWQ_ENV} \
${DWQ_JOBID:+--subjob} \
--file $flashfile:$appdir/bin/${board}/$(basename $flashfile) \
--queue ${TEST_QUEUE:-$board} \
--maxfail 1 \
"./.murdock run_test $appdir $board:$toolchain"
}
run_test() {
local appdir=$1
local board=$(echo $2 | cut -f 1 -d':')
local toolchain=$(echo $2 | cut -f 2 -d':')
print_worker
echo "-- executing tests for $appdir on $board (compiled with $toolchain toolchain):"
hook run_test_pre
BOARD=$board TOOLCHAIN=${toolchain} make -C$appdir flash-only test
RES=$?
if [ $RES -eq 0 -a -n "$TEST_HASH" ]; then
echo -n "-- saving test result to cache: "
test_cache_put $TEST_HASH
fi
return $RES
}
# execute static tests
static_tests() {
local repo=${CI_BASE_REPO:-https://github.com/RIOT-OS/RIOT}
local branch=${CI_BASE_BRANCH:-master}
print_worker
OUT="$(git remote add upstream $repo 2>&1 && git fetch upstream ${branch}:${branch} 2>&1)"
RES=$?
if [ $RES -ne 0 ]; then
echo "$OUT"
exit 1
fi
BUILDTEST_MCU_GROUP=static-tests ./dist/tools/ci/build_and_test.sh
}
get_non_compile_jobs() {
[ "$STATIC_TESTS" = "1" ] && \
echo "$0 static_tests###{ \"jobdir\" : \"exclusive\" }"
}
get_jobs() {
get_non_compile_jobs
get_compile_jobs
}
$*