#!/bin/sh # report back on a build assignment # either on success via: # "$0 $package $revision $mod_revision $repository" and tar'ed packages and logs # (= a tar of package(s), signature(s) and log(s)) on stdin # or on failure via: # "$0 $package $revision $mod_revision $repository ERROR" and tar'ed logs # exit codes: # 0: ok # 1: another instance was already running # 2: outdated package # 3: signature error # 4: package error (e.g. wrong packages sent) # TODO: sign database # shellcheck source=conf/default.conf . "${0%/*}/../conf/default.conf" if [ -s "${work_dir}/build-master-sanity" ]; then >&2 echo 'Build master is not sane.' exit 1 fi # Create a lock file and a trap. exec 9> "${build_list_lock_file}" if ! flock -n 9; then >&2 echo 'come back (shortly) later - I cannot lock build list.' exit 1 fi exec 8> "${sanity_check_lock_file}" if ! flock -s -n 8; then >&2 echo 'come back (shortly) later - sanity-check running.' exit 1 fi clean_up_lock_file() { rm -f "${build_list_lock_file}" } trap clean_up_lock_file EXIT if [ "$5" = 'ERROR' ]; then # the build failed on the build slave if ! grep -qxF "$1 $2 $3 $4" "${work_dir}/build-list" || ! [ -f "${work_dir}/package-states/$1.$2.$3.$4.locked" ]; then >&2 echo 'Too late, package already outdated, I ignore this error report.' exit 2 fi # shellcheck disable=SC2154 if ! grep -qxF "${slave}" "${work_dir}/package-states/$1.$2.$3.$4.locked"; then >&2 echo 'You do not build this package - move on.' exit 2 fi # save sent build logs tar -x \ -C "${build_log_directory}/error" \ --wildcards \ --no-wildcards-match-slash \ --transform="s|^|$1.$2.$3.$4.|" \ '*.build-log.gz' if [ -f "${work_dir}/package-states/$1.$2.$3.$4.broken" ]; then was_broken_before=true else was_broken_before=false fi # shellcheck disable=SC2154 echo "${slave}" >> \ "${work_dir}/package-states/$1.$2.$3.$4.broken" # shellcheck disable=SC2016 { printf 'UPDATE `build_assignments`' printf ' JOIN `build_slaves` ON `build_slaves`.`currently_building`=`build_assignments`.`id`' printf ' SET `build_assignments`.`is_broken`=1, `build_slaves`.`currently_building`=NULL' printf ' WHERE `build_slaves`.`name`=from_base64("%s");\n' \ "$( printf '%s' "${slave}" | \ base64 -w0 )" } | \ ${mysql_command} # shellcheck disable=SC2154 sed -i ' /^'"$(str_to_regex "${slave}")"'$/d ' "${work_dir}/package-states/$1.$2.$3.$4.locked" if [ ! -s "${work_dir}/package-states/$1.$2.$3.$4.locked" ]; then rm "${work_dir}/package-states/$1.$2.$3.$4.locked" # unlock every loop this package would have broken and which is not # broken by another locked package locked_packages=$( find "${work_dir}/package-states/" -maxdepth 1 -name '*.locked' -printf '%f\n' | \ sed 's@^\(.\+\)\.\([0-9a-f]\{40\}\.\)\{2\}[^.]\+\.locked$@\1@' ) find "${work_dir}/build-list.loops" -maxdepth 1 -regextype grep \ -regex '.*/loop_[0-9]\+' \ -exec grep -qxF "$1" '{}' \; \ -not -exec grep -qxF "${locked_packages}" '{}' \; \ -exec rm '{}.locked' \; # move that build order to the end of the build-list sed -i ' /^'"$(str_to_regex "$1 $2 $3 $4")"'$/ { $ b d } $ a '"$1 $2 $3 $4" \ "${work_dir}/build-list" fi # release lock on build-list - otherwise seed-build-list won't run flock -u 9 if ! ${was_broken_before}; then haskell_rebuild_packages=$( find "${build_log_directory}/error" -type f \ -name "$1.$2.$3.$4.*.build-log.gz" \ -exec zgrep -qFx ' The following packages are broken because other packages they depend on are missing. These broken packages must be rebuilt before they can be used.' {} \; \ -exec zcat {} \; | \ sed -n ' s/^installed package \(.*\) is broken due to missing package .*$/\1/ T p ' | \ tr ' ' '\n' | \ sed ' s/^/-p ^haskell-/ s/-[0-9.]\+$/\$/ ' | \ sort -u ) rescheduled_packages=$( if [ -n "${haskell_rebuild_packages}" ]; then # shellcheck disable=SC2086 "${base_dir}/bin/seed-build-list" ${haskell_rebuild_packages} | \ sed 's/ .*$//' fi ) if [ -p "${irc_dir}/#archlinux-ports/in" ]; then { printf '%s is broken (says %s).' \ "$1" \ "${slave}" if [ -n "${rescheduled_packages}" ]; then printf -- ' - I rescheduled:' # shellcheck disable=SC2086 printf ' %s,' ${rescheduled_packages} | \ sed 's/,$/./' fi printf '\n' } | tee /dev/stderr > \ "${irc_dir}/#archlinux-ports/in" # why do we need tee there in order for the redirection to work??? fi fi exit 0 fi # the build was successful on the build slave # so we also need a lock on the package database exec 7> "${package_database_lock_file}" if ! flock -n 7; then >&2 echo 'come back (shortly) later - I cannot lock package database.' exit 1 fi clean_up_lock_file() { rm -f "${build_list_lock_file}" rm -f "${package_database_lock_file}" } if ! grep -qxF "$1 $2 $3 $4" "${work_dir}/build-list" || ! [ -f "${work_dir}/package-states/$1.$2.$3.$4.locked" ] || ! [ "$5" = "$(next_sub_pkgrel "$1" "$2" "$3" "$4")" ]; then >&2 echo 'Sorry, the sent package is outdated.' exit 2 fi # shellcheck disable=SC2154 if ! grep -qxF "${slave}" "${work_dir}/package-states/$1.$2.$3.$4.locked"; then >&2 echo 'Whoops, this package is not built by this slave.' exit 2 fi clean_up_tmp_dir() { cd "${base_dir}" rm -rf --one-file-system "${tmp_dir}" clean_up_lock_file } tmp_dir=$(mktemp -d "${work_dir}/tmp.return-assignment.XXXXXXXXXX") cd "${tmp_dir}" trap clean_up_tmp_dir EXIT # extract package(s) tar -x \ --wildcards \ --no-wildcards-match-slash \ '*.pkg.tar.xz' \ '*.pkg.tar.xz.sig' \ '*.pkg.tar.xz-namcap.log.gz' # check if all packages are signed and all signatures belong to a package missing_files=$( find . -maxdepth 1 -name '*.pkg.tar.xz' -o -name '*.pkg.tar.xz.sig' -o -name '*.pkg.tar.xz-namcap.log.gz' | \ sed ' s@\.sig$@ signature@ t s@-namcap\.log\.gz$@ namcap@ t s@$@ package@ ' | \ sort -k1,1 -k2,2 | \ sed ' :a $!N s/^\(\(\S\+\) [^\n]\+\)\n\2 /\1 / ta P D ' | \ sed -n ' s/$/ / / package /!{ h s/^\(\S\+\) .*$/Package "\1" is missing./ p g } / signature /!{ h s/^\(\S\+\) .*$/Signature of "\1" is missing./ p g } / namcap /!{ h s/^\(\S\+\) .*$/Namcap log of "\1" is missing./ p g } ' ) if [ -n "${missing_files}" ]; then >&2 echo 'The following packages lack a signature, namcap log or package file:' >&2 echo "${missing_files}" exit 3 fi # check if the signatures are valid signatures=$( find . -maxdepth 1 -name '*.pkg.tar.xz' \ -printf 'package file %f\n' \ -exec gpg --batch --status-fd 1 -q --homedir /etc/pacman.d/gnupg --verify '{}.sig' '{}' \; 2> /dev/null ) if [ -z "$( echo "${signatures}" | \ cut -d' ' -f2 | \ grep -x 'file\|TRUST_FULLY' | \ sort | \ uniq -c | \ awk '{print $1}' | \ uniq -d )" ]; then >&2 echo 'Signature(s) is/are not fully trusted:' >&2 echo "${signatures}" exit 3 fi # check if the sent packages are the expected ones packages=$( find . -maxdepth 1 -name '*.pkg.tar.xz' -printf '%f\n' ) package_errors=$( { # shellcheck disable=SC2086 printf '%s\n' ${packages} | \ sed ' s@\(-[^-]\+\)\{2\}-\([^-]\+\)\.pkg\.tar\.xz$@ \2@ / any$/{ s|any$|i686| } s|^|was_built: | ' sed ' s|$| i686| s|^|expected: | ' "${work_dir}/package-infos/$1.$2.$3.$4.packages" } | \ sort -k2 | \ uniq -u -f1 ) if [ -n "${package_errors}" ]; then >&2 echo 'The following packages should have been built but are missing or vice versa:' >&2 echo "${package_errors}" exit 4 fi # move namcap.logs find . -maxdepth 1 -name '*.pkg.tar.xz-namcap.log.gz' -execdir mv '{}' "${build_log_directory}/success/" \; # move packages destination=$(official_or_community "$1.$2.$3.$4" 'staging') ${master_mirror_rsync_command} \ "${master_mirror_rsync_directory}/i686/${destination}/${destination}.db."* \ "${master_mirror_rsync_directory}/i686/${destination}/${destination}.files."* \ . # shellcheck disable=SC2086 repo-add "${destination}.db.tar.gz" ${packages} # repo-add -v -s -k "${repo_key}" "${destination}.db.tar.gz" ${packages} ${master_mirror_rsync_command} \ "${destination}.db."* \ "${destination}.files."* \ ./*".pkg.tar.xz" \ ./*".pkg.tar.xz.sig" \ "${master_mirror_rsync_directory}/i686/${destination}/" trigger_mirror_refreshs for package in ${packages}; do remove_old_package_versions 'i686' "${destination}" "${package}" done # remove old state files (these should be only "done" markers, but # actually we don't care what it is) - as long as it's not "testing" or "tested" find "${work_dir}/package-states" -maxdepth 1 -regextype grep \ -not -name '*.testing' \ -not -name '*.tested' \ -regex '.*/'"$(str_to_regex "$1")"'\(\.[^.]\+\)\{4\}' \ -not -regex '.*/'"$(str_to_regex "$1.$2.$3.$4")"'\.[^.]\+' \ -exec rm '{}' \; # remove all loops which are broken by this package find "${work_dir}/build-list.loops" -maxdepth 1 -regextype grep \ -regex '.*/loop_[0-9]\+' \ -exec grep -qxF "$1" '{}' \; \ -exec rm '{}.locked' \; # remove package from build list sed -i "/^$(str_to_regex "$1 $2 $3 $4")\$/d" "${work_dir}/build-list" # remove package lock file if ! [ "${destination}" = 'build-support' ]; then # shellcheck disable=SC2086 printf '%s\n' ${packages} > \ "${work_dir}/package-states/$1.$2.$3.$4.done" fi # shellcheck disable=SC2016 { printf 'UPDATE `build_assignments`' printf ' JOIN `build_slaves` ON `build_slaves`.`currently_building`=`build_assignments`.`id`' printf ' JOIN `binary_packages` ON `binary_packages`.`build_assignment`=`build_assignments`.`id`' printf ' SET' printf ' `build_assignments`.`is_broken`=0,' printf ' `build_slaves`.`currently_building`=NULL,' printf ' `binary_packages`.`repository`=(SELECT `repositories`.`id` FROM `repositories` WHERE `repositories`.`name`=from_base64("%s")),' \ "$( printf '%s' "${destination}" | \ base64 -w0 )" printf ' `binary_packages`.`has_issues`=0,' printf ' `binary_packages`.`is_tested`=0' printf ' WHERE `build_slaves`.`name`=from_base64("%s");\n' \ "$( printf '%s' "${slave}" | \ base64 -w0 )" } | \ ${mysql_command} rm -f \ "${work_dir}/package-states/$1.$2.$3.$4.locked" \ "${work_dir}/package-states/$1.$2.$3.$4.broken"