#!/bin/bash # receive one package to be built from the build-list whose dependencies # are already satisfied or which breaks a dependency cycle # 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 # 4: come back, when you've done your work - you hit the limit on # maximum allowed parallel jobs per ip # TODO: # respect build-manually-list ("blocked") # possibly hand out "broken" packages to different build slave . "${0%/*}/../conf/default.conf" mkdir -p "${work_dir}/package-states" hand_out_assignment() { # locked and broken packages won't be handed out if [ -f "${work_dir}/package-states/$1.$2.$3.$4.locked" ] || [ -f "${work_dir}/package-states/$1.$2.$3.$4.broken" ]; then return 0 fi echo "$1 $2 $3 $4" echo "${SSH_CLIENT%% *}" > "${work_dir}/package-states/$1.$2.$3.$4.locked" # lock every loop this package breaks grep "^${1//./\\.}\$" "${work_dir}/build-list.loops/"loop_* | \ cut -d: -f1 | \ tee -a "${work_dir}/package-states/$1.$2.$3.$4.locked" | \ sed 's|$|.locked|' | \ xargs -rn1 touch exit 0 } # 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 function clean_up { rm -f "${build_list_lock_file}" } trap clean_up EXIT # Check if there are any pending packages at all and if the requester # has already hit its max_parallel_build_per_client limit. num_jobs=0 pending_packages=false while read -r package git_revision mod_git_revision repository; do if [ -f "${work_dir}/package-states/${package}.${git_revision}.${mod_git_revision}.${repository}.locked" ]; then if [ "${SSH_CLIENT%% *}" = "$(head -n1 "${work_dir}/package-states/${package}.${git_revision}.${mod_git_revision}.${repository}.locked")" ]; then num_jobs=$[${num_jobs}+1]; fi else 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 if [ ${num_jobs} -ge ${max_parallel_build_per_client} ]; then >&2 echo "come back, when you've done your work - you hit the limit on maximum allowed parallel jobs per ip" exit 4 fi # Find first package of build-list whose dependencies are all met while read -r package git_revision mod_git_revision repository; do [ -z "$( ( cat "${work_dir}/package-infos/${package}."*".needs" awk '{print $1}' "${work_dir}/build-list" ) | \ sort | \ uniq -d )" ] || continue hand_out_assignment "${package}" "${git_revision}" "${mod_git_revision}" "${repository}" done < "${work_dir}/build-list" # Find package (of all packages which are not locked) # which breaks the most unlocked loops locked_packages="$( ls "${work_dir}/package-states/" | \ grep '\(\.[0-9a-f]\{40\}\)\{2\}\.[^\.\]\+\.locked$' | \ sed 's|\(\.[0-9a-f]\{40\}\)\{2\}\.[^\.\]\+\.locked$||' )" unlocked_loops="$( ls "${work_dir}/build-list.loops/" | \ grep '^loop_[0-9]\+$' | \ while read -r loop; do if [ -z "$( ( cat "${work_dir}/build-list.loops/${loop}" echo "${locked_packages}" ) | \ sort | \ uniq -d )" ]; then echo "${loop}" fi done )" for package in $( echo "${unlocked_loops}" | \ sed "s|^|${work_dir}/build-list.loops/|" | \ xargs cat | \ sort | \ uniq -c | \ sort -k1nr,1 | \ awk '{print $2}' ); do if assignment="$(grep "^${package//./\\.} " "${work_dir}/build-list")"; then hand_out_assignment ${assignment} fi 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