#!/bin/sh # shellcheck source=../conf/default.conf . "${0%/*}/../conf/default.conf" # TODO: can this be faster? # Create a lock file. if [ $# -eq 0 ]; then broken=$( printf 'CALL show_broken_packages_and_dependencies;\n' | \ mysql_run_query | \ sed ' s/\s.*$// ' | \ sort -u printf 'ALL\n' ) # 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 for target_package in "$@"; do output="${webserver_directory}/graphs/${target_package}.png" # shellcheck disable=SC2016 { printf 'CREATE TEMPORARY TABLE `relevant_binary_packages` (`id` BIGINT, UNIQUE KEY (`id`));\n' printf 'CREATE TEMPORARY TABLE `relevant_binary_packages_copy` (`id` BIGINT, UNIQUE KEY (`id`));\n' printf 'CREATE TEMPORARY TABLE `relevant_install_targets` (`id` BIGINT, UNIQUE KEY (`id`));\n' if [ "${target_package}" = 'ALL' ]; then printf 'INSERT IGNORE INTO `relevant_binary_packages` (`id`)' printf ' SELECT DISTINCT `binary_packages`.`id`' printf ' FROM `repositories`' mysql_join_repositories_repository_stabilities printf ' AND `repository_stabilities`.`name` IN ("unbuilt","staging")' mysql_join_repositories_binary_packages printf ';\n' else printf 'CALL calculate_dependencies_of_package_upto_first_built_one(from_base64("%s"));\n' \ "$( printf '%s' "${target_package}" | \ base64 -w0 )" fi printf 'INSERT IGNORE INTO `relevant_binary_packages_copy` (`id`)' printf ' SELECT `relevant_binary_packages`.`id` FROM `relevant_binary_packages`' printf ';\n' printf 'INSERT IGNORE INTO `relevant_install_targets` (`id`)' printf ' SELECT DISTINCT `install_target_providers`.`install_target`' printf ' FROM `relevant_binary_packages`' mysql_join_binary_packages_install_target_providers 'relevant_binary_packages' mysql_join_install_target_providers_dependencies mysql_join_dependencies_dependency_types printf ' AND `dependency_types`.`relevant_for_building`' printf ' JOIN `relevant_binary_packages_copy` ON `relevant_binary_packages_copy`.`id`=`dependencies`.`dependent`' printf ';\n' # we return lines with either: # "knot" $type $identifier $label # or # "edge" $type $from_knot $to_knot printf 'SELECT DISTINCT' printf ' "knot",' printf 'IF(`build_assignments`.`is_%s`,"%s-build-list-pkgbase",' \ 'blocked' 'broken' \ 'broken' 'broken' printf '"build-list-pkgbase"' printf ')),' printf 'CONCAT("pkgbase:",`package_sources`.`id`),' printf '`package_sources`.`pkgbase`' printf ' FROM `relevant_binary_packages`' printf ' JOIN `binary_packages` ON `relevant_binary_packages`.`id`=`binary_packages`.`id`' mysql_join_binary_packages_repositories mysql_join_repositories_repository_stabilities printf ' AND `repository_stabilities`.`name`="unbuilt"' mysql_join_binary_packages_build_assignments mysql_join_build_assignments_package_sources printf ';\n' printf 'SELECT DISTINCT' printf ' "knot",' printf 'CONCAT("pkgname-",`repository_stabilities`.`name`),' printf 'CONCAT("pkgname:",`binary_packages`.`id`),' printf '`binary_packages`.`pkgname`' printf ' FROM `relevant_binary_packages`' printf ' JOIN `binary_packages` ON `relevant_binary_packages`.`id`=`binary_packages`.`id`' mysql_join_binary_packages_repositories mysql_join_repositories_repository_stabilities printf ';\n' printf 'SELECT DISTINCT' printf ' "knot","install-target",' printf 'CONCAT("install-target:",`install_targets`.`id`),' printf '`install_targets`.`name`' printf ' FROM `relevant_install_targets`' printf ' JOIN `install_targets` ON `install_targets`.`id`=`relevant_install_targets`.`id`' printf ';\n' printf 'SELECT DISTINCT' printf ' "edge","builds"' printf ',CONCAT("%s:",`%s`.`id`)' \ 'pkgbase' 'package_sources' \ 'pkgname' 'binary_packages' printf ' FROM `relevant_binary_packages`' printf ' JOIN `binary_packages` ON `relevant_binary_packages`.`id`=`binary_packages`.`id`' mysql_join_binary_packages_repositories mysql_join_repositories_repository_stabilities printf ' AND `repository_stabilities`.`name`="unbuilt"' mysql_join_binary_packages_build_assignments mysql_join_build_assignments_package_sources printf ';\n' printf 'SELECT DISTINCT' printf ' "edge","provides"' printf ',CONCAT("%s:",`%s`.`id`)' \ 'pkgname' 'binary_packages' \ 'install-target' 'install_targets' printf ' FROM `relevant_binary_packages`' printf ' JOIN `binary_packages` ON `relevant_binary_packages`.`id`=`binary_packages`.`id`' mysql_join_binary_packages_install_target_providers printf ' JOIN `relevant_install_targets` ON `relevant_install_targets`.`id`=`install_target_providers`.`install_target`' mysql_join_install_target_providers_install_targets printf ';\n' printf 'SELECT DISTINCT' printf ' "edge",CONCAT("depends:",`dependency_types`.`name`)' printf ',CONCAT("%s:",`%s`.`id`)' \ 'install-target' 'install_targets' \ 'pkgname' 'binary_packages' printf ' FROM `relevant_binary_packages`' printf ' JOIN `binary_packages` ON `relevant_binary_packages`.`id`=`binary_packages`.`id`' mysql_join_binary_packages_dependencies printf ' JOIN `relevant_install_targets` ON `relevant_install_targets`.`id`=`dependencies`.`depending_on`' mysql_join_dependencies_dependency_types printf ' AND `dependency_types`.`relevant_for_building`' mysql_join_dependencies_install_targets printf ';\n' } | \ mysql_run_query | \ sed ' y/\t/ / /^knot /{ s/^\S\+ // w '"${tmp_dir}"'/knots d } /^edge /{ s/^\S\+ // w '"${tmp_dir}"'/edges d } ' >&2 mkdir "${tmp_dir}/find-identical" awk '{ print $1 >> "'"${tmp_dir}"'/find-identical/characteristics-"$2 }' < \ "${tmp_dir}/knots" awk '{ print $1 " X " $3 >> "'"${tmp_dir}"'/find-identical/characteristics-"$2 print $1 " " $2 " X" >> "'"${tmp_dir}"'/find-identical/characteristics-"$3 }' < \ "${tmp_dir}/edges" modifier=$( find "${tmp_dir}/find-identical" -maxdepth 1 \ -type f \ -name 'characteristics-*' | \ while read -r file; do printf '%s ' "${file##*/}" sort -u "${file}" | \ sha512sum | \ awk '{print $1}' done | \ sort -k2,2 | \ uniq -Df1 | \ sed 's,^characteristics-,,' | \ sed ' :a $!N s/^\(\S\+\) \(\S\+\)\n\(\S\+ \)\2$/\1+\3\2/ ta P D ' | \ cut -d' ' -f1 | \ sed ' s/^/s,\\(/ s/+\([^+[:space:]]\+\)$/\\)\\(\\s\\|$\\),\1\\2,g;/ s/+/\\|/g ' ) rm -rf --one-file-system "${tmp_dir}/find-identical" sed "${modifier}" "${tmp_dir}/knots" | \ sort -k2,2 -k1,1 | \ sed ' :a $!N s/^\(\S\+ \S\+ \)\(\S\+\)\n\1\(\S\+\)$/\1\2\3/ ta P D ' | \ sponge "${tmp_dir}/knots" sed "${modifier}" "${tmp_dir}/edges" | \ sort -u | \ sponge "${tmp_dir}/edges" { printf '%s\n' \ 'digraph dependencies {' \ ' fontname=dejavu;' # knots: $type $identifier $label # edges: $type $from_knot $to_knot while read -r type id label; do case "${type}" in 'broken-build-list-pkgbase') color='#ff0000' ;; 'blocked-build-list-pkgbase') color='#d00000' ;; 'build-list-pkgbase') color='#800000' ;; 'pkgname-unbuilt') color='#800000' ;; 'pkgname-staging') color='#008000' ;; 'pkgname-stable'|'pkgname-testing'|'pkgname-standalone') color='#000000' ;; 'install-target') color='#000080' ;; *) color='#ff80ff' label="${label} (${type})" ;; esac printf ' "%s" [label="%s", fontcolor="%s"];\n' "${id}" "${label}" "${color}" done < \ "${tmp_dir}/knots" while read -r type from_knot to_knot; do printf '"%s" -> "%s";\n' \ "${from_knot}" "${to_knot}" done < \ "${tmp_dir}/edges" printf '%s\n' \ '}' } > \ "${tmp_dir}/input" sed -i ' s||,\\n|g s||, |g ' "${tmp_dir}/input" line_count=$(wc -l < "${tmp_dir}/input") if [ "${target_package}" != 'ALL' ] && [ "${line_count}" -gt 1000 ]; then rm -f "${output}" >&2 printf 'Skipping graph for "%s" - would be too big (%d).\n' \ "${target_package}" \ "${line_count}" continue 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"