#!/bin/sh # shellcheck source=conf/default.conf . "${0%/*}/../conf/default.conf" # TODO: read information from database # Create a lock file. if [ $# -eq 0 ]; then broken=$( # shellcheck disable=SC2016 { printf 'SELECT `package_sources`.`pkgbase`' printf ' FROM `package_sources`' mysql_join_package_sources_build_assignments printf ' WHERE `build_assignments`.`is_broken`' } | \ ${mysql_command} --raw --batch | \ sed '1d' | \ sort -u ) new_sum='x' sum='' tmp_dir=$(mktemp -d 'tmp.show-dependencies.0.XXXXXXXXXX' --tmpdir) trap 'rm -rf --one-file-system "${tmp_dir}"' EXIT # shellcheck disable=SC2016 { printf 'SELECT DISTINCT `package_sources`.`pkgbase`,`binary_packages`.`pkgname`' printf ' FROM `binary_packages`' mysql_join_binary_packages_build_assignments mysql_join_build_assignments_package_sources printf ' ORDER BY `binary_packages`.`pkgname`' # Why can't mysql order in the same way "sort" does! } | \ ${mysql_command} --raw --batch | \ sed ' 1d y/\t/ / ' | \ sort -k2,2 > \ "${tmp_dir}/builds" while ! [ "${new_sum}" = "${sum}" ]; do sum="${new_sum}" # shellcheck disable=SC2086 printf '%s\n' ${broken} | \ sort > \ "${tmp_dir}/broken" broken=$( { find "${work_dir}/package-infos" -maxdepth 1 -name '*.build-depends' | \ sed 's|^.*/\(.*\)\(\.[^.]\+\)\{4\}$|\1 \0|' | \ sort -k1,1 | \ join -1 1 -2 1 -o 1.2 - "${tmp_dir}/broken" | \ xargs -r cat } | \ sort -u | \ join -1 1 -2 2 -o 2.1 - "${tmp_dir}/builds" ) broken=$( { { # shellcheck disable=SC2086 printf '%s\n' ${broken} cat "${tmp_dir}/broken" } | \ sort -u cut -d' ' -f1 < \ "${work_dir}/build-list" | \ sort -u } | \ sort | \ uniq -d ) new_sum=$( # shellcheck disable=SC2086 printf '%s\n' ${broken} | \ sha512sum ) done rm -rf --one-file-system "${tmp_dir}" trap - EXIT broken=$( { # shellcheck disable=SC2086 printf '%s\n' ${broken} 'ALL' { find "${webserver_directory}/graphs" -maxdepth 1 -name '*.png' -printf '%f\n' | \ sed 's|\.png$||' { cut -d' ' -f1 < \ "${work_dir}/build-list" cat "${work_dir}/deletion-list" } | \ sort -u } | \ sort | \ uniq -d } | \ sort -u ) # shellcheck disable=SC2086 "$0" ${broken} { find "${webserver_directory}/graphs" -maxdepth 1 -name '*.png' # shellcheck disable=SC2086 printf "${webserver_directory}"'/graphs/%s.png\n' ${broken} ${broken} } | \ sort | \ uniq -u | \ xargs -r rm exit fi if pgrep -f '^\S+ '"$0"'.' | \ grep -vxF "$$" >&2; then >&2 echo $$ >&2 echo 'I was running already.' exit fi exec 9> "${work_dir}/${0##*/}.lock" if ! flock -n 9; then >&2 echo 'Cannot get show-dependencies lock.' exit fi exec 8> "${sanity_check_lock_file}" if ! flock -s -n 8; then >&2 echo 'Cannot get sanity-check lock.' exit fi tmp_dir=$(mktemp -d 'tmp.show-dependencies.1.XXXXXXXXXX' --tmpdir) trap 'rm -rf --one-file-system "${tmp_dir}"' EXIT sort -u "${work_dir}/build-order" | \ grep -v '^\(\S\+\) \1$' | \ grep '^\S\+ \S\+$' > \ "${tmp_dir}/original-build-order" sort -k1,1 "${work_dir}/build-list" > \ "${tmp_dir}/build-list.sorted-by-package" { sort -k1,1 "${tmp_dir}/original-build-order" | \ join -1 1 -2 1 -o 1.1,1.2 - "${tmp_dir}/build-list.sorted-by-package" sort -k2,2 "${tmp_dir}/original-build-order" | \ join -1 2 -2 1 -o 1.1,1.2 - "${tmp_dir}/build-list.sorted-by-package" } | \ sort -u | \ sponge "${tmp_dir}/original-build-order" find "${work_dir}/package-infos" -maxdepth 1 -printf '%f\n' | \ sed 's|\(\.[^.]\+\)\{4\}$||' | \ sort -u > \ "${tmp_dir}/known-packages" find "${work_dir}/package-infos" -maxdepth 1 -name '*.groups' -printf '%f %p\n' | \ while read -r name pf; do xargs -r printf "${name%.*.*.*.*}"' %s\n' < \ "${pf}" done > \ "${tmp_dir}/known-groups" find "${work_dir}/package-infos" -maxdepth 1 -name '*.packages' -printf '%f %p\n' | \ while read -r name pf; do grep -vxF "${name%.*.*.*.*}" "${pf}" | \ xargs -r printf "${name%.*.*.*.*}"' %s\n' done > \ "${tmp_dir}/known-split-packages" find "${work_dir}/package-infos" -maxdepth 1 -name '*.run-depends' -printf '%f %p\n' | \ while read -r name pf; do xargs -r printf '%s '"${name%.*.*.*.*}"'\n' < \ "${pf}" done > \ "${tmp_dir}/known-run-depends" for target_package in "$@"; do output="${webserver_directory}/graphs/${target_package}.png" if [ "${target_package}" = 'ALL' ]; then # groups and split packages built by jobs on the build list cat "${tmp_dir}/known-groups" "${tmp_dir}/known-split-packages" | \ sort -k1,1 | \ join -1 1 -2 1 -o 1.2 - "${tmp_dir}/build-list.sorted-by-package" | \ sort -u > \ "${tmp_dir}/relevant-stuff" { # groups and split packages built by jobs on the build list - which are also dependencies of packages on the build-list sort -k1,1 "${tmp_dir}/original-build-order" | \ join -1 1 -2 1 -o 2.1 - "${tmp_dir}/relevant-stuff" # build list jobs themself cut -d' ' -f1 < "${work_dir}/build-list" } | \ sort -u | \ sponge "${tmp_dir}/relevant-stuff" { sort -k1,1 "${tmp_dir}/original-build-order" | \ join -1 1 -2 1 -o 1.1,1.2 - "${tmp_dir}/relevant-stuff" | \ sort -k2,2 | \ join -1 2 -2 1 -o 1.1,1.2 - "${tmp_dir}/relevant-stuff" sed 's/.*/\0 \0/' "${tmp_dir}/relevant-stuff" } > \ "${tmp_dir}/build-order" rm "${tmp_dir}/relevant-stuff" find "${work_dir}/package-states" -name '*.done' -printf '%f\n' | \ sed 's|\(\.[^.]\+\)\{4\}$||' | \ sort -u | \ tee "${tmp_dir}/done-packages" | \ xargs -r printf '4 staging-package %s\n' > \ "${tmp_dir}/knots" { cat \ "${tmp_dir}/known-groups" \ "${tmp_dir}/known-run-depends" \ "${tmp_dir}/known-split-packages" awk '{print $1 " " $1}' < \ "${tmp_dir}/known-packages" } | \ sort -k1,1 > \ "${tmp_dir}/known-connections.sorted.1" sort -k2,2 \ "${tmp_dir}/known-connections.sorted.1" > \ "${tmp_dir}/known-connections.sorted.2" { # staging -> something -> build-list join -1 1 -2 1 -o 1.1,1.2 \ "${tmp_dir}/known-connections.sorted.1" \ "${tmp_dir}/done-packages" | \ sort -k2,2 | \ join -1 2 -2 1 -o 1.1,1.2,2.1,2.2 \ - \ "${tmp_dir}/known-connections.sorted.1" | \ sort -k4,4 | \ join -1 4 -2 1 -o 1.1,1.2,1.3,1.4 \ - \ "${tmp_dir}/build-list.sorted-by-package" | \ sed ' s|^\(\S\+ \S\+\) |\1\n| ' # staging -> something -> staging join -1 1 -2 1 -o 1.1,1.2 \ "${tmp_dir}/known-connections.sorted.1" \ "${tmp_dir}/done-packages" | \ sort -k2,2 | \ join -1 2 -2 1 -o 1.1,1.2,2.1,2.2 \ - \ "${tmp_dir}/known-connections.sorted.1" | \ sort -k4,4 | \ join -1 4 -2 1 -o 1.1,1.2,1.3,1.4 \ - \ "${tmp_dir}/done-packages" | \ sed ' s|^\(\S\+ \S\+\) |\1\n| ' # build-list -> something -> staging join -1 1 -2 1 -o 1.1,1.2 \ "${tmp_dir}/known-connections.sorted.1" \ "${tmp_dir}/build-list.sorted-by-package" | \ sort -k2,2 | \ join -1 2 -2 1 -o 1.1,1.2,2.1,2.2 \ - \ "${tmp_dir}/known-connections.sorted.1" | \ sort -k4,4 | \ join -1 4 -2 1 -o 1.1,1.2,1.3,1.4 \ - \ "${tmp_dir}/done-packages" | \ sed ' s|^\(\S\+ \S\+\) |\1\n| ' cat "${tmp_dir}/build-order" } | \ sort -u | \ sponge "${tmp_dir}/build-order" rm \ "${tmp_dir}/done-packages" \ "${tmp_dir}/known-connections.sorted.1" \ "${tmp_dir}/known-connections.sorted.2" else grep " $(str_to_regex "${target_package}")\$" "${tmp_dir}/original-build-order" | \ sort -u > \ "${tmp_dir}/build-order" printf '0 target-package %s\n' "${target_package}" > \ "${tmp_dir}/knots" last_sum='' current_sum=$(sha512sum "${tmp_dir}/build-order") while ! [ "${last_sum}" = "${current_sum}" ]; do last_sum="${current_sum}" awk '{print $1}' "${tmp_dir}/build-order" | \ sort -u > \ "${tmp_dir}/new" { cat \ "${tmp_dir}/original-build-order" \ "${tmp_dir}/known-split-packages" sed '/ base\(-devel\)\?$/d' "${tmp_dir}/known-groups" } | \ sort -k2,2 | \ join -1 2 -2 1 -o 1.1,1.2 - "${tmp_dir}/new" | \ sponge -a "${tmp_dir}/build-order" rm "${tmp_dir}/new" sort -u "${tmp_dir}/build-order" | \ sponge "${tmp_dir}/build-order" current_sum=$(sha512sum "${tmp_dir}/build-order") done fi # grep -v '^\(\S\+\) \1$' "${tmp_dir}/build-order" | \ # sponge "${tmp_dir}/build-order" # shellcheck disable=SC2129 tr ' ' '\n' < \ "${tmp_dir}/build-order" | \ sort -u | \ join -j 1 - "${tmp_dir}/build-list.sorted-by-package" | \ while read -r pkg rev mod_rev repo; do if [ -f "${work_dir}/package-states/${pkg}.${rev}.${mod_rev}.${repo}.broken" ]; then printf '1 broken-build-list-package %s\n' "${pkg}" elif [ -f "${work_dir}/package-states/${pkg}.${rev}.${mod_rev}.${repo}.blocked" ]; then printf '2 blocked-build-list-package %s\n' "${pkg}" else printf '3 build-list-package %s\n' "${pkg}" fi done >> \ "${tmp_dir}/knots" { sort -u "${work_dir}/deletion-list" tr ' ' '\n' < \ "${tmp_dir}/build-order" | \ sort -u } | \ sort | \ uniq -d | \ xargs -r printf '5 deletion-list-package %s\n' >> \ "${tmp_dir}/knots" { awk '{print $2}' "${tmp_dir}/known-split-packages" | \ sort -u tr ' ' '\n' < \ "${tmp_dir}/build-order" | \ sort -u } | \ sort | \ uniq -d | \ xargs -r printf '6 split-package %s\n' >> \ "${tmp_dir}/knots" { cat "${tmp_dir}/known-packages" tr ' ' '\n' < \ "${tmp_dir}/build-order" | \ sort -u } | \ sort | \ uniq -d | \ xargs -r printf '7 package %s\n' >> \ "${tmp_dir}/knots" { awk '{print $2}' "${tmp_dir}/known-groups" | \ sort -u tr ' ' '\n' < \ "${tmp_dir}/build-order" | \ sort -u } | \ sort | \ uniq -d | \ xargs -r printf '8 group %s\n' >> \ "${tmp_dir}/knots" tr ' ' '\n' < \ "${tmp_dir}/build-order" | \ sort -u | \ xargs -r printf '100 unknown %s\n' >> \ "${tmp_dir}/knots" sort -k3,3 -k1n,1 "${tmp_dir}/knots" | \ uniq -f2 | \ awk '{print $3 " " $1 " " $2}' | \ sort -k2,3 | \ sponge "${tmp_dir}/knots" mkdir "${tmp_dir}/neighbours" cat "${tmp_dir}/knots" "${tmp_dir}/build-order" | \ awk '{ print $1 " " $2 > "'"${tmp_dir}/neighbours/"'"$1; print $1 " " $2 > "'"${tmp_dir}/neighbours/"'"$2; }' find "${tmp_dir}/neighbours" -maxdepth 1 -type f | \ while read -r file; do sed ' s@\(^\| \)'"$(str_to_regex "${file##*/}")"'\( \|$\)@\1\2@ s@\(^\| \)'"$(str_to_regex "${file##*/}")"'\( \|$\)@\1\2@ ' "${file}" | \ sort -u | \ sponge "${file}" done find "${tmp_dir}/neighbours" -maxdepth 1 -type f -exec \ sha512sum {} \; | \ sed 's|^\(\S\+\) .*/\([^/]\+\)$|\2 \1|' | \ sort -k2,2 | \ uniq -f1 -D | \ awk '{print $2 " " $1}' > \ "${tmp_dir}/sums" rm -rf --one-file-system "${tmp_dir}/neighbours" sed ' :a $!N s|^\(\S\+\) \([^\n]\+\)\n\1 |\1 \2| ta P D ' "${tmp_dir}/sums" | \ join -1 1 -2 1 -o 2.2,1.2 - "${tmp_dir}/sums" | \ while read -r original replacement; do sed -i ' s@\( \|^\)'"$(str_to_regex "${original}")"'\( \|$\)@\1'"${replacement}"'\2@ s@\( \|^\)'"$(str_to_regex "${original}")"'\( \|$\)@\1'"${replacement}"'\2@ ' "${tmp_dir}/build-order" "${tmp_dir}/knots" done grep -v '^\(\S\+\) \1$' "${tmp_dir}/build-order" | \ sort -u | \ sponge "${tmp_dir}/build-order" sort -u "${tmp_dir}/knots" | \ sponge "${tmp_dir}/knots" { printf '%s\n' \ 'digraph dependencies {' \ ' fontname=dejavu;' cut -d' ' -f1,3 < \ "${tmp_dir}/knots" | \ while read -r who what; do if [ "${what}" = 'broken-build-list-package' ]; then color='#ff0000' elif [ "${what}" = 'blocked-build-list-package' ]; then color='#d00000' elif [ "${what}" = 'build-list-package' ]; then color='#800000' elif [ "${what}" = 'deletion-list-package' ]; then color='#808080' elif [ "${what}" = 'group' ]; then color='#0000ff' elif [ "${what}" = 'package' ]; then color='#000000' elif [ "${what}" = 'split-package' ]; then color='#8080ff' elif [ "${what}" = 'staging-package' ]; then color='#008000' elif [ "${what}" = 'target-package' ]; then color='#00ff00' else color='#ff80ff' fi printf ' "%s" [fontcolor="%s"];\n' "${who}" "${color}" done sed 's|\\|\\\\|g' "${tmp_dir}/build-order" | \ xargs -rn2 printf ' "%s" -> "%s";\n' | \ sort -u printf '%s\n' \ '}' } > \ "${tmp_dir}/input" sed -i ' s||,\\n|g s||, |g ' "${tmp_dir}/input" line_count=$(wc -l < "${tmp_dir}/input") if [ "${line_count}" -gt 500 ] && [ "${target_package}" != 'ALL' ]; then sed -i '/"base\(-devel\)\?"/d' "${tmp_dir}/input" line_count=$(wc -l < "${tmp_dir}/input") if [ "${line_count}" -gt 700 ]; then rm -f "${output}" >&2 printf 'Skipping graph for "%s" - would be too big (%d).\n' \ "${target_package}" \ "${line_count}" continue fi fi printf 'small enough (%s): %d\n' \ "${target_package}" \ "${line_count}" touch "${output}" chmod 644 "${output}" if ! dot -Tpng -o "${output}" "${tmp_dir}/input"; then rm -f "${output}" continue fi done rm "${work_dir}/${0##*/}.lock"