#!/bin/sh # build packages one by one, then upload the binary package to the repository server # shellcheck disable=SC2119,SC2120 # shellcheck source=../lib/load-configuration . "${0%/*}/../lib/load-configuration" # TODO: distinguish between "pentium4" and "i686" # TODO: report back memory and hdd stats to the build master on successful build # shellcheck disable=SC2016 usage() { >&2 echo '' >&2 echo 'build-packages: build package(s) on the build-list' >&2 echo '' >&2 echo 'possible options:' >&2 echo ' -d|--diff source-directory:' >&2 echo ' Apply the diff between $source-directory/PKGBUILD and' >&2 echo ' $source-directory/../../trunk/PKGBUILD before building.' >&2 echo ' This option is intended for building from trunk where minor' >&2 echo ' fixes did not get released yet. Hence, it conflicts intentionally' >&2 echo ' with -n, -l, -t or -x and it requires -p.' >&2 echo ' -h|--help: Show this help and exit.' >&2 echo ' -l|--local pkgname.git-revision.git-mod-revision.repository:' >&2 echo ' Build the given package without asking / reporting to the' >&2 echo ' build master. Cannot be combined with -n, -p, -t or -x.' >&2 echo ' where:' >&2 echo ' - git-revision: packages-HEAD or community-HEAD or a valid commit' >&2 echo ' - git-mod-revision: work-tree or a valid commit' >&2 echo ' example:' >&2 echo ' build-package -l which.packages-HEAD.work-tree.core' >&2 echo ' -n count: Build $count packages (if available), then exit.' >&2 echo ' $count=0 is interpreted as infinity.' >&2 echo ' The default is $count=1 or 0 iff -t or -x is given.' >&2 echo ' Cannot be combined with -l.' >&2 echo ' -p|--prefer pkgname:' >&2 echo ' Ask the build master to get an assignment for the given' >&2 echo ' package but built what is offered anyway. Cannot be combined' >&2 echo ' with -l.' >&2 echo ' -s|--straw $straw:' >&2 echo ' Use this straw instead of the preconfigured ones. -- May be' >&2 echo ' given multiple times to allow using multiple straws.' >&2 echo ' -t seconds: Do not request new assignment(s) $seconds seconds after start.' >&2 echo ' Cannot be combined with -l.' >&2 echo ' -x: If package build fails, do not request new assignment(s).' >&2 echo ' Cannot be combined with -l.' >&2 echo '' >&2 echo 'known straws (separated by and enclosed in ":", sets of straws separated by " "):' >&2 echo ' :clean_chroot:' >&2 echo ' clean the chroot before building' >&2 echo ' :mirrored_source:' >&2 echo ' compile from source tarbal from sources.archlinux.org if possible' >&2 echo ' :mirrored_source_by_hash:' >&2 echo ' download sources from sources.archlinux32.org by hash if possible' >&2 echo ' :without_check:' >&2 echo ' run makepkg with "--no-check"' >&2 echo ' :without_systemd_nspawn:' >&2 echo ' do not invoke archbuild'"'"'s systemd-nspawn fanciness [RISKY]' >&2 echo ' :with_build_support:' >&2 echo ' allow using [build-support]' >&2 echo ' :with_/dev/fuse:' >&2 echo ' mount /dev/fuse into the chroot' [ -z "$1" ] && exit 1 || exit "$1" } eval set -- "$( getopt -o d:hl:n:p:s:t:ux \ --long diff: \ --long help \ --long local: \ --long prefer: \ --long straw: \ --long upload \ -n "$(basename "$0")" -- "$@" || \ echo usage )" unset count unset diff_source_dir unset forced_package unset forced_straws unset prefered_package exit_after_failure=false timeout=0 while true do case "$1" in -d|--diff) shift if [ -n "${diff_source_dir}" ]; then >&2 echo 'Option -d, --diff can be given only once.' usage fi diff_source_dir="$1" ;; -h|--help) usage 0 ;; -l|--local) shift if [ -n "${forced_package}" ]; then >&2 echo 'Option -l, --local can be given only once.' usage fi forced_package="$1" ;; -n) shift count="$1" [ "${count}" -eq 0 ] && \ count=-1 ;; -p|--prefer) shift if [ -n "${prefered_package}" ]; then >&2 echo 'Option -p, --prefer can be given only once.' usage fi prefered_package="$1" ;; -s|--straw) shift forced_straws="${forced_straws} $1" ;; -t) shift timeout="$1" ;; -x) exit_after_failure=true ;; --) shift break ;; *) >&2 echo 'Whoops, forgot to implement option "'"$1"'" internally.' exit 42 ;; esac shift done if [ $# -ne 0 ]; then >&2 echo 'Too many arguments.' usage fi if [ -n "${diff_source_dir}" ]; then if [ -n "${count}" ] || \ [ -n "${forced_package}" ] || \ [ "${timeout}" -ne 0 ] || \ ${exit_after_failure} || \ [ -z "${prefered_package}" ]; then >&2 echo 'Conflicting flags.' usage fi fi if [ -n "${forced_package}" ]; then if [ -n "${count}" ] || \ [ "${timeout}" -ne 0 ] || \ [ -n "${prefered_package}" ] || \ ${exit_after_failure}; then >&2 echo 'Conflicting flags.' usage fi upload_to_build_master=false else upload_to_build_master=true fi if [ -z "${count}" ]; then if [ "${timeout}" -ne 0 ] || ${exit_after_failure}; then count=-1 else count=1 fi fi if [ -n "${forced_straws}" ]; then straws_that_might_repair_failing_builds="${forced_straws# }" fi if [ "${timeout}" -ne 0 ]; then timeout=$((timeout+$(date +%s))) fi checksum=$( calculate_script_checksum ) # When this script or a script in lib/ got updated, we do not request # any new assignments. This script should rather exit and be restarted. while [ "${count}" -ne 0 ] && \ [ "$(calculate_script_checksum)" = "${checksum}" ]; do if [ "${timeout}" -ne 0 ] && [ "${timeout}" -lt "$(date +%s)" ]; then break fi err=0 case "$(uname -m)" in 'i486') my_arch='i486' ;; 'i686'|'x86_64') if grep '^flags\s*:' '/proc/cpuinfo' | \ grep -qwF 'sse2'; then my_arch='pentium4' else my_arch='i686' fi ;; *) >&2 printf 'Sorry, architecture %s does not work (yet) as a build slave.\n' \ "$(uname -m)" exit 2 ;; esac # TODO: we might get a build assignment of a different architecture # (e.g. a pentium4 slave might get an i686 assignment - we must take # that into account for the build_command if [ -z "${forced_package}" ]; then package=$( # shellcheck disable=SC2029 ssh \ -i "${master_build_server_identity}" \ -p "${master_build_server_port}" \ "${master_build_server_user}@${master_build_server}" \ 'get-assignment' "${my_arch}" "${prefered_package}" ) || err=$? expected_packages=$( printf '%s\n' "${package}" | \ sed '1d' ) package=$( printf '%s\n' "${package}" | \ sed -n '1p' ) else package=$( echo "${forced_package}" | \ sed ' s|\.\([^.]\+\)\.\([^.]\+\)\.\([^.]\+\)\.\([^.]\+\)$| \1 \2 \3 \4| ' ) expected_packages='' fi case ${err} in # 0: ok, I gave you an assignment 0) [ ${count} -gt 0 ] && \ count=$((count-1)) arch="${package##* }" package="${package% *}" sub_pkgrel="${package##* }" package="${package% *}" repository="${package##* }" package="${package% *}" mod_git_revision="${package##* }" package="${package% *}" git_revision="${package##* }" if [ "${git_revision}" = "${package}" ]; then # build master did not tell us an architecture git_revision="${mod_git_revision}" mod_git_revision="${repository}" repository="${sub_pkgrel}" sub_pkgrel="${arch}" arch="${my_arch}" else package="${package% *}" fi if [ "${arch}" = 'any' ]; then arch="${my_arch}" fi if [ -z "${forced_straws}" ] && \ printf '%s\n' "${package}" | \ grep -q '^\(haskell\|python2\?\)-'; then haskell_straws=':without_check:' else haskell_straws='' fi if [ "${git_revision##*-}" = 'HEAD' ]; then git_revision=$( repo_name="${git_revision%-*}" eval repo_path='"${repo_paths__'"${repo_name}"'}"' if [ -z "${repo_path}" ]; then >&2 printf 'Unknown git repository "%s".\n' "${repo_name}" exit 2 fi git -C "${repo_path}" rev-parse HEAD ) fi if [ "${mod_git_revision}" = 'work-tree' ]; then mod_git_revision=$( # we can't just create an empty index-file with mktemp, because git doesn't like it find . \ -mindepth 1 \ -maxdepth 1 \ -name 'tmp.build-packages.git.*' \ -exec rm -rf --one-file-system {} \; tmp_subdir=$(mktemp -d 'tmp.build-packages.git.XXXXXXXXXX' --tmpdir) trap 'rm -rf --one-file-system "${tmp_subdir}"' EXIT export GIT_INDEX_FILE="${tmp_subdir}/index.new" git -C "${repo_paths__archlinux32}" add -A git -C "${repo_paths__archlinux32}" write-tree ) fi # Update git repositories (official packages, community packages and the repository of package customizations). for repo_name in ${repo_names}; do eval repo_path='"${repo_paths__'"${repo_name}"'}"' if [ -d "${repo_path}/.git" ]; then git -C "${repo_path}" remote update else git -C "${repo_path}" fetch origin master:master fi || \ true done # trigger update of mirror (if configured) if [ -n "${mirror_update_command}" ]; then ${mirror_update_command} fi bail_out() { err=$? if [ -n "$1" ]; then err="$1" fi cd "${base_dir}" recursively_umount_and_rm "${tmp_dir}" if [ -z "${forced_package}" ]; then flock -u 9 || true fi exit "${err}" } find "${work_dir}" \ -mindepth 1 \ -maxdepth 1 \ -name 'tmp.build-packages.??????' \ -printf '%p\n' | \ while read -r old_tmp_dir; do find "${old_tmp_dir}" -xdev -not -type l -exec chmod 777 {} \; rm -rf --one-file-system "${old_tmp_dir}" done tmp_dir=$(mktemp -d "${work_dir}/tmp.build-packages.XXXXXX") trap bail_out EXIT if ! git_repo=$(find_repository_with_commit "${git_revision}") || \ [ -z "${git_repo}" ] || \ ! find_pkgbuilds "${package}" "${repository}" "${git_repo}" "${git_revision}" "${mod_git_revision}" || \ ! extract_source_directory "${git_repo}" "${git_revision}" "${mod_git_revision}" "${tmp_dir}" "${sub_pkgrel}" || \ ! apply_trunk_patch "${tmp_dir}" "${diff_source_dir}"; then # report local failure (probably a missing commit) to build-master # shellcheck disable=SC2029 ssh \ -i "${master_build_server_identity}" \ -p "${master_build_server_port}" \ "${master_build_server_user}@${master_build_server}" \ 'return-assignment' 'ABORT' recursively_umount_and_rm "${tmp_dir}" if [ -z "${forced_package}" ]; then flock -u 9 || true fi trap - EXIT continue fi cd "${tmp_dir}" echo 'nothing' > "${tmp_dir}/.ping-build-master" if [ -z "${forced_package}" ]; then # we get a lock on "${work_dir}/ping-build-master.lock", # if we release that lock, ping-to-master should stop _immediately_ exec 9> "${work_dir}/ping-build-master.lock" if ! verbose_flock -n 9; then >&2 echo 'ERROR: Cannot lock ping-to-master - this should not happen.' exit 2 fi "${base_dir}/bin/ping-to-master" "$$" "${tmp_dir}" & fi success=false for straw in ${straws_that_might_repair_failing_builds} ${haskell_straws}; do echo 'preparing' > "${tmp_dir}/.ping-build-master" if echo "${straw}" | \ grep -qF ':mirrored_source:'; then # maybe a missing source is/was the problem? if makepkg --verifysource 2>/dev/null; then # nope, sources are fine continue fi # try to download them from sources.archlinux.org/sources/$repo/$source source_name=$( makepkg --printsrcinfo | \ sed -n ' /^\s*\(epoch\|pkg\(base\|ver\|rel\)\) = /{s|^\s\+||;p} /^pkgname = /q ' | \ sed ' s|^pkgbase = \(.*\)$|0 \1-| s|^epoch = \(.*\)$|1 \1:| s|^pkgver = \(.*\)$|2 \1-| s|^pkgrel = \([^.]*\)\(\..*\)\?$|3 \1.src.tar.gz| ' | \ sort -k1n,1 | \ sed ' s|^[0-9] || :a N s|\n[0-9] \(\S\+\)$|\1| ta ' ) if ! wget -q --timeout=15 -nc -nd "https://sources.archlinux.org/sources/${git_repo}/${source_name}"; then # we can't improve anything continue fi # shellcheck disable=SC2046 tar -xz --overwrite \ -f "${source_name}" \ --exclude PKGBUILD \ $( if [ -n "${PKGBUILD_mod}" ]; then git -C "${repo_paths__archlinux32}/${PKGBUILD_mod%/*}" archive "${mod_git_revision}" -- . | \ tar -t | \ sed 's/^/--exclude /' fi ) \ --strip-components=1 \ || true fi if echo "${straw}" | \ grep -qF ':mirrored_source_by_hash:'; then # maybe a missing source is/was the problem? if makepkg --verifysource 2>/dev/null; then # nope, sources are fine continue fi # download it from sources.archlinux32.org by its hash if ! download_sources_by_hash; then # we can't improve anything, if no source was downloadable continue fi fi if echo "${straw}" | \ grep -qF ':clean_chroot:'; then outerParameters='-c' else outerParameters='' fi if echo "${straw}" | \ grep -qF ':without_check:'; then innerParameters='--nocheck' else innerParameters='' fi if echo "${straw}" | \ grep -qF ':with_/dev/fuse:'; then middleParameters='-d /dev/fuse' else middleParameters='' fi if echo "${straw}" | \ grep -qF ':with_build_support:'; then build_command='staging-with-build-support-'"${arch}"'-build' elif echo "${straw}" | \ grep -qF ':without_systemd_nspawn:'; then if [ -z "${prefered_package}" ]; then >&2 echo 'straw :without_systemd_nspawn: only allowed with -p' exit 2 fi if [ "${prefered_package}" != "${package}" ]; then >&2 echo 'The prefered package was not handed out.' >&2 echo 'Because straw :without_systemd_nspawn: is active, I will abort.' exit 2 fi if uname -m | \ grep -qxF 'x86_64'; then >&2 echo 'straw :without_systemd_nspawn: requires running build-packages on the' >&2 echo 'architecture for which the package should be built.' >&2 printf '"%s" != "%s"\n' \ "$(uname -m)" \ "${arch}" exit 2 fi build_command='makepkg' outerParameters="${innerParameters} -fcrs --asdeps --noconfirm --holdver" else build_command='staging-'"${arch}"'-build' fi find . -maxdepth 1 -type f \( -name '*.pkg.tar.xz' -o -name '*.pkg.tar.xz.sig' \) -exec \ rm {} \; echo 'building' > "${tmp_dir}/.ping-build-master" >&2 printf '%s: building package "%s" (revisions %s %s, repository %s, straw %s) ...' \ "$(date +'%Y-%m-%d %T')" \ "${package}" \ "${git_revision}" \ "${mod_git_revision}" \ "${repository}" \ "${straw}" # by piping the log, we don't see anything in the terminal, # but all ways to duplicate the logs seem pretty elaborate # shellcheck disable=SC2024,SC2086 if "${build_command}" ${outerParameters} -- ${middleParameters} -- ${innerParameters} > \ "$( date -u --iso-8601=seconds | \ cut -d+ -f1 ).build-log" 2>&1; then # build successful >&2 printf ' ok.\n' if [ "${build_command}" = 'makepkg' ]; then find . -maxdepth 1 -type f -name '*.pkg.tar.xz' \ -exec sh -c 'namcap "$1" > "$1-namcap.log"' '_' '{}' \; fi tar_content_dir=$(mktemp -d "${tmp_dir}/tar-content.XXXXXX") echo 'post-build' > "${tmp_dir}/.ping-build-master" # remove unexpected packages if [ -n "${expected_packages}" ]; then { find . -maxdepth 1 -type f -name '*.pkg.tar.xz' -printf '%f\n' printf '%s\n' "${expected_packages}" | \ sed 'p' } | \ sort | \ uniq -u | \ while read -r unexpected_package; do rm "${unexpected_package}"* done fi >&2 printf 'signing package(s)\n' find . -maxdepth 1 -type f -name '*.pkg.tar.xz' \ -execdir gpg --local-user="${package_key}" --detach-sign '{}' \; \ -execdir mv '{}' '{}.sig' '{}-namcap.log' "${tar_content_dir}/" \; \ -printf '%f\n' | \ sponge | \ while read -r pkg_file; do { pacman -Spdd --print-format '%l' --noconfirm "${pkg_file%-*-*-*}" 2>/dev/null | \ sed ' s|/[^/]\+\.pkg\.tar\.xz$|| ' # shellcheck disable=SC2016 curl -Ss 'https://www.archlinux.org/mirrorlist/?country=all&protocol=https&tier=1&use_mirror_status=on' | \ sed -n ' s/^#Server = // T s/\$repo/'"${repository}"'/g s/\$arch/x86_64/g p ' | \ shuf } | \ sed ' s|$|/'"${pkg_file}"'| s/\.[0-9]\+\(-[^-]\+\)$/\1/ s/-'"${arch}"'\+\(\.pkg\.tar\.xz\)$/-x86_64\1/ ' | \ while read -r url; do >&2 printf 'downloading "%s" ...' "${url}" if wget -q --timeout=15 -nd "${url}"; then >&2 printf ' ok.\n' break; fi >&2 printf ' failed. Next ...\n' done done >&2 printf 'searching for provided libraries\n' find "${tar_content_dir}" -maxdepth 1 \ -name '*.pkg.tar.xz' \ -printf '%p\n' | \ while read -r pkgfile; do pacman -Qqlp "${pkgfile}" | \ sed -n ' s,^.*/,, /\.so\(\..\+\)\?$/ { :a p s/\(\.so\(\..\+\)\?\)\.[^.]\+$/\1/ t a } ' | \ sort -u > \ "${pkgfile}.so.provides" done >&2 printf 'searching for required and more provided libraries\n' package_content_dir=$(mktemp -d "${tmp_dir}/package-content.XXXXXX") find "${tar_content_dir}" -maxdepth 1 \ -name '*.pkg.tar.xz' | \ while read -r pkgfile; do if printf '%s\n' "${pkgfile}" | \ grep -vq -- '-any\.pkg\.tar\.xz$'; then # we do not check "any" packages for linked libraries # (why do they have them in the first place?) mkdir "${package_content_dir}/${pkgfile##*/}" tar -C "${package_content_dir}/${pkgfile##*/}" -xJf "${pkgfile}" 2>/dev/null # we rely on "${checksum}" not appearing in any objdump output : ${checksum?umm, checksum is unset - this will break below sed-fu} # TODO: symbols may be in object files _inside_archives_ # In that case, we're interested in the object file's name, # not the archive's file name find "${package_content_dir}/${pkgfile##*/}" \ -name 'opt' -prune , \ -type f \ -exec objdump -x '{}' \; 2>/dev/null | \ sed ' /^architecture:.* i386:x86-64, /,/^architecture:.* i386:x86-32, / d /\sNEEDED\s/ { s/^\s*\S\+\s\+\(\S\+\)\(\s.*\)\?$/\1/ /\.c32$/d s,^.*/,, t } /^Version References:$/,/^$/ { /^\s*required from / { s/^\s*required from \(\S\+\):\s*$/'"${checksum}"'\1/ T end h d } s/^\s*\(0x[0-9a-fA-F]\+\)\s\+0x[0-9a-fA-F]\+\s\+[0-9]\+\s\+\(\S\+\)$/\2-\1/ T end G s/^\(\S\+\)\n'"${checksum}"'\(\S\+\)$/\2-\1/ t } :end d ' | \ sort -u > \ "${pkgfile}.so.needs" sed -i ' /^\(libav.*\.so\)\.[0-9]\+$/ { :a N s/^\(libav.*\.so\)\(\.[0-9]\+\)\?\n\1\.[0-9]\+$/\1/ t a P D } ' "${pkgfile}.so.needs" find "${package_content_dir}/${pkgfile##*/}" \ -name 'opt' -prune , \ \( -type f -o -type l \) \ -printf "${checksum}"'%f\n' \ -exec objdump -x '{}' \; 2>/dev/null | \ sed ' /^architecture:.* i386:x86-64, /,/^architecture:.* i386:x86-32, / d /^'"${checksum}"'/ { h d } /\sSONAME\s/ { s/^\s*\S\+\s\+\(\S\+\)\s.*$/\1/ t } /^Version definitions:$/,/^$/ { s/^[0-9]\+\s\+0x[0-9a-fA-F]\+\s\+\(0x[0-9a-fA-F]\+\)\s\+\(\S\+\)$/\2-\1/ T end G s/^\(\S\+\)\n'"${checksum}"'\(\S\+\)$/\2-\1/ t } :end d ' | \ sort -u >> \ "${pkgfile}.so.provides" find "${package_content_dir:?}/${pkgfile##*/}" -xdev -not -type l -exec chmod 777 '{}' \; rm -rf --one-file-system "${package_content_dir:?}/${pkgfile##*/}" fi tar -tJf "${pkgfile}" 2>/dev/null | \ sed -n ' s,^usr/lib/python\([^/]\+\)/$,python \1, t print s,^usr/lib/perl[^/]\+/\([^/]\+\)/$,perl \1, t print s,^usr/lib/ruby/\([^/]\+\)/$,ruby \1, b :print s/\./ / p ' | \ while read -r name major_version minor_version; do printf '%s>=%s.%s\n%s<%s.%s\n' \ "${name}" \ "${major_version}" \ "${minor_version}" \ "${name}" \ "${major_version}" \ "$((minor_version+1))" done >> \ "${pkgfile}.so.needs" done >&2 printf 'running namcap ...' if [ "${repository}" = 'multilib' ]; then x86_64_build_command='multilib-build' else x86_64_build_command='extra-x86_64-build' fi # this is a little hack: makepkg receives '--version', but namcap is run nevertheless # (and it only works with devtools32, because they are running namcap on *.pkg.tar.xz in the base directory, too) sudo "${x86_64_build_command}" -- -- --version > /dev/null 2>&1 || \ sudo "${x86_64_build_command}" -c -- -- --version > /dev/null 2>&1 || \ true >&2 printf ' ok.\n' >&2 printf 'smoothen namcap log ...' # now we generate diffs from the namcap.logs find . "${tar_content_dir}/" -maxdepth 1 -type f -name '*.pkg.tar.xz-namcap.log' -printf '%p\n' | \ while read -r log; do smoothen_namcap_log "${log}" done find "${tar_content_dir}/" -maxdepth 1 -type f -name '*.pkg.tar.xz-namcap.log' -printf '%f\n' | \ sed ' s|\(^.*\)-'"${arch}"'\(\.pkg\.tar\.xz-namcap\.log\)$|\0 \1-x86_64\2| s|^.*-any\.pkg\.tar\.xz-namcap\.log$|\0 \0| ' | \ while read -r log x86_64_log; do if [ -f "${x86_64_log}" ]; then diff -u "${x86_64_log}" "${tar_content_dir}/${log}" | \ sed ' 1,3d /^[^+-]/d ' | \ sponge "${tar_content_dir}/${log}" else sed -i 's|^|*|' "${tar_content_dir}/${log}" fi done >&2 printf ' ok.\n' echo 'uploading' > "${tmp_dir}/.ping-build-master" if ${upload_to_build_master}; then find "${tar_content_dir}/" -maxdepth 1 \ \( \ -name '*.pkg.tar.xz-namcap.log' -o \ -name '*.pkg.tar.xz.so.needs' -o \ -name '*.pkg.tar.xz.so.provides' \ \) \ -execdir gzip '{}' \; else find "${tar_content_dir}/" -maxdepth 1 \ -name '*.pkg.tar.xz-namcap.log' \ -execdir grep -HF '' '{}' \; fi # shellcheck disable=SC2046 tar -cf 'package.tar' -C "${tar_content_dir}" -- $( find "${tar_content_dir}/" -maxdepth 1 \ \( \ -name '*.pkg.tar.xz' -o \ -name '*.pkg.tar.xz.sig' -o \ -name '*.pkg.tar.xz-namcap.log.gz' -o \ -name '*.pkg.tar.xz.so.needs.gz' -o \ -name '*.pkg.tar.xz.so.provides.gz' \ \) \ -printf '%f\n' ) || \ tar -cf 'package.tar' -T /dev/null if ${upload_to_build_master}; then # shellcheck disable=SC2046 rsync $( find "${tar_content_dir}/" -maxdepth 1 \ \( \ -name '*.pkg.tar.xz' -o \ -name '*.pkg.tar.xz.sig' \ \) \ -printf '%p\n' ) "rsync://mirror.archlinux32.org/transfer32/" || true fi while ${upload_to_build_master}; do err=0 # shellcheck disable=SC2029 ssh \ -i "${master_build_server_identity}" \ -p "${master_build_server_port}" \ "${master_build_server_user}@${master_build_server}" \ 'return-assignment' "${package}" "${git_revision}" "${mod_git_revision}" "${repository}" "${arch}" "${sub_pkgrel}" \ < 'package.tar' || \ err=$? case ${err} in 0) # upload successful break ;; 1) >&2 echo '"return-assignment" was running already.' wait_some_time 15 ;; 2) >&2 echo 'I was too slow, the package is outdated. I will continue ...' break ;; 3) >&2 echo "'return-assignment' reports a signature error." exit 1 ;; 4) >&2 echo "'return-assignment' reports too many or missing packages." exit 1 ;; 5) >&2 echo "'return-assignment' was called with wrong arguments." exit 1 ;; *) >&2 echo "unknown return code ${err} from 'return-assignment'" exit ${err} esac done success=true break fi echo 'failure' > "${tmp_dir}/.ping-build-master" >&2 printf ' failed.\n' # receive missing keys # shellcheck disable=SC2038 find . -maxdepth 1 -type f -name '*.build-log' -exec \ sed -n ' s/^.* FAILED (unknown public key \([0-9A-F]\{16\}\)).*$/0x\1/ T p ' {} \; | \ xargs -rn1 gpg --recv-keys || \ true # TODO: maybe, we want to auto-receive keys from github here, too? done if ! ${success}; then for log in *'.build-log'; do if [ -f "${log}" ]; then if ${upload_to_build_master}; then gzip "${log}" else grep -HF '' "${log}" fi fi done if ${upload_to_build_master} && \ tar -cf 'build-logs.gz.tar' \ -- *'.build-log.gz'; then while true; do err=0 # shellcheck disable=SC2029 ssh \ -i "${master_build_server_identity}" \ -p "${master_build_server_port}" \ "${master_build_server_user}@${master_build_server}" \ 'return-assignment' "${package}" "${git_revision}" "${mod_git_revision}" "${repository}" "${arch}" 'ERROR' \ < 'build-logs.gz.tar' || \ err=$? case ${err} in 0) # upload successful break ;; 1) >&2 echo '"return-assignment" was running already.' wait_some_time 15 ;; 2) >&2 echo 'I was too slow, the package is outdated. I will continue ...' break ;; 5) >&2 echo '"return-assignment" was called with wrong arguments.' exit 1 ;; *) >&2 echo "unknown return code ${err} from 'return-assignment'" exit ${err} esac done fi if ${exit_after_failure}; then >&2 echo 'Build failed, exiting now' exit 0 fi fi # clean up tmp_dir cd "${base_dir}" recursively_umount_and_rm "${tmp_dir}" if [ -z "${forced_package}" ]; then flock -u 9 || true fi trap - EXIT continue ;; 1) >&2 echo 'get-assignment told me:' >&2 echo ' come back (shortly) later - I was running already' wait_some_time 15 continue ;; 2) >&2 echo 'get-assignment told me:' >&2 echo ' 2: come back later - there are still packages to be built,' >&2 echo ' but currently none has all its dependencies ready' wait_some_time 60 continue ;; 3) >&2 echo 'get-assignment told me:' >&2 echo ' 3: come back after the next run of get-package-updates - currently' >&2 echo ' there are no pending packages' exit 0 ;; 4) >&2 echo 'get-assignment told me:' >&2 echo ' 4: wrong number of arguments' exit 5 ;; *) >&2 echo "ERROR: Unknown exit code ${err} from 'get-assignment'." exit ${err} ;; esac done >&2 echo 'Done.'