#!/bin/sh # receive one package to be built from the build-list whose dependencies # are already satisfied or which breaks a dependency cycle # accepts a comma separated list of prefered packages as the first argument # exit code shows state of success: # 0: ok, I gave you an assignment # 1: come back (shortly) later - I was running already # 2: come back later - there are still packages to be built, # but currently none has all its dependencies ready # 3: come back after the next run of get-package-updates - currently # there are no pending packages # shellcheck source=conf/default.conf . "${0%/*}/../conf/default.conf" mkdir -p "${work_dir}/package-states" hand_out_assignment() { # find out the sub_pkgrel sub_pkgrel=$( next_sub_pkgrel "$1" "$2" "$3" "$4" ) # we don't care anymore if an older version of this package was # "locked" or "broken" find "${work_dir}/package-states" -maxdepth 1 -regextype grep \ -regex '.*/'"$(str_to_regex "$1")"'\(\.[^.]\+\)\{3\}\.\(locked\|broken\)' \ -not -regex '.*/'"$(str_to_regex "$1.$2.$3.$4.")"'[^.]\+' \ -delete # 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" echo "$1 $2 $3 $4 ${sub_pkgrel}" { # shellcheck disable=SC2154 echo "${slave}" if [ -r "${work_dir}/package-states/$1.$2.$3.$4.locked" ]; then cat "${work_dir}/package-states/$1.$2.$3.$4.locked" fi } | \ sort -u | \ sponge "${work_dir}/package-states/$1.$2.$3.$4.locked" # shellcheck disable=SC2016 { printf 'UPDATE `build_slaves`' printf ' SET `currently_building` = (' printf ' SELECT `build_assignments`.`id`' printf ' FROM `build_assignments`' printf ' JOIN `package_sources` ON `build_assignments`.`package_source`=`package_sources`.`id`' printf ' JOIN `upstream_repositories` ON `package_sources`.`upstream_package_repository`=`upstream_repositories`.`id`' printf ' WHERE' printf ' `package_sources`.`%s` = from_base64("%s") AND' \ 'pkgbase' "$(printf '%s' "$1" | base64 -w0)" \ 'git_revision' "$(printf '%s' "$2" | base64 -w0)" \ 'mod_git_revision' "$(printf '%s' "$3" | base64 -w0)" printf ' `upstream_repositories`.`name` = from_base64("%s")' \ "$(printf '%s' "$4" | base64 -w0)" printf ')' printf ' WHERE `build_slaves`.`name`=from_base64("%s");' \ "$(printf '%s' "${slave}" | base64 -w0)" } | \ ${mysql_command} # lock every loop this package breaks find "${work_dir}/build-list.loops" -maxdepth 1 -regextype grep \ -regex '.*/loop_[0-9]\+' \ -exec grep -qxF "$1" '{}' \; \ -exec touch '{}.locked' \; exit 0 } 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() { rm -f "${build_list_lock_file}" rm -rf --one-file-system "${tmp_dir}" } tmp_dir=$(mktemp -d 'tmp.get-assignment.XXXXXXXXXX' --tmpdir) trap clean_up EXIT # Check if there are any pending packages at all and if the requester # has already got an assignment. pending_packages=false while read -r package git_revision mod_git_revision repository; do generate_package_metadata "${package}.${git_revision}.${mod_git_revision}.${repository}" if [ -f "${work_dir}/package-states/${package}.${git_revision}.${mod_git_revision}.${repository}.locked" ]; then # has this slave already got or does he prefer this assignment? # note, that the dependencies are met, because this package is already locked if grep -qxF "${slave}" "${work_dir}/package-states/${package}.${git_revision}.${mod_git_revision}.${repository}.locked" || \ printf ',%s,' "$1" | \ grep -qF ",${package},"; then hand_out_assignment "${package}" "${git_revision}" "${mod_git_revision}" "${repository}" fi elif [ ! -f "${work_dir}/package-states/${package}.${git_revision}.${mod_git_revision}.${repository}.blocked" ]; then pending_packages=true fi done < "${work_dir}/build-list" if ! ${pending_packages}; then >&2 echo 'come back after the next run of get-package-updates - currently there are no pending packages' exit 3 fi # Find first package of build-list whose "dependencies" are all met # 1st: prefered packages on the build list which have all dependencies met # 2nd: unbroken packages on the build list which have all dependencies met # 3rd: unbroken packages breaking a loop # 4th: broken packages which have all dependencies met or break a loop for iteration in 'prefered' 'fresh' 'loops' 'broken'; do case "${iteration}" in 'prefered') hand_out_blocked=true hand_out_broken=true hand_out_loop=false echo "$1" | \ tr ',' '\n' | \ sort -u > \ "${tmp_dir}/hand-out-only-these-packages" ;; 'fresh') hand_out_blocked=false hand_out_broken=false hand_out_loop=false { cat "${work_dir}/build-list" find "${work_dir}/package-states" -name '*.broken' -printf '%f\n' | \ sed ' s|\.\([^.]\+\)\.\([^.]\+\)\.\([^.]\+\)\.[^.]\+$| \1 \2 \3| p ' } | \ sort -k1,1 -k2 | \ uniq -u | \ cut -d' ' -f1 | \ uniq > \ "${tmp_dir}/hand-out-only-these-packages" ;; 'loops') hand_out_blocked=false hand_out_broken=false hand_out_loop=true find "${work_dir}/build-list.loops" -maxdepth 1 -regextype grep \ -regex '.*/loop_[0-9]\+' \ -exec cat {} \; | \ sort -u > \ "${tmp_dir}/hand-out-only-these-packages" ;; 'broken') hand_out_blocked=false hand_out_broken=true hand_out_loop=true cut -d' ' -f1 < \ "${work_dir}/build-list" | \ sort -u > \ "${tmp_dir}/hand-out-only-these-packages" ;; esac cat -n "${work_dir}/build-list" | \ sort -k2,2 | \ join -1 1 -2 2 -o 2.1,2.2,2.3,2.4,2.5 "${tmp_dir}/hand-out-only-these-packages" - | \ sort -k1,1 | \ sed 's|^\s*\S\+\s\+||' > \ "${tmp_dir}/try-to-hand-out-these-packages" while read -r package git_revision mod_git_revision repository; do # package locked? (we have taken care of those in the previous loop) if [ -f "${work_dir}/package-states/${package}.${git_revision}.${mod_git_revision}.${repository}.locked" ]; then continue fi # package blocked? if ! ${hand_out_blocked} && [ -f "${work_dir}/package-states/${package}.${git_revision}.${mod_git_revision}.${repository}.blocked" ]; then continue fi # package broken? if ! ${hand_out_broken} && \ [ -f "${work_dir}/package-states/${package}.${git_revision}.${mod_git_revision}.${repository}.broken" ]; then continue fi # dependencies met? if [ -n "$(find_dependencies_on_build_list "${package}" "${git_revision}" "${mod_git_revision}" "${repository}")" ]; then # do we hand out looped packages? if ! ${hand_out_loop}; then continue fi # is it a looped package? if ! find "${work_dir}/build-list.loops" -maxdepth 1 -regextype grep \ -regex '.*/loop_[0-9]\+' \ -exec cat {} \; | \ grep -qxF "${package}"; then continue fi fi hand_out_assignment "${package}" "${git_revision}" "${mod_git_revision}" "${repository}" done < \ "${tmp_dir}/try-to-hand-out-these-packages" done # Remove the lock file >&2 echo 'come back later - there are still packages to be built, but currently none has all its dependencies ready' exit 2