#!/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 disable=SC2119,SC2120

# shellcheck source=../lib/load-configuration
. "${0%/*}/../lib/load-configuration"

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 ! verbose_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 ! verbose_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

  # shellcheck disable=SC2016
  infos=$(
    {
      printf 'SELECT DISTINCT `build_assignments`.`id`,IF(`build_assignments`.`is_broken`,"true","false") FROM `build_slaves`'
      mysql_join_build_slaves_build_assignments
      mysql_join_build_assignments_package_sources
      mysql_join_package_sources_upstream_repositories
      mysql_join_build_assignments_binary_packages
      mysql_join_binary_packages_binary_packages_in_repositories
      printf ' WHERE `build_slaves`.`id`=from_base64("%s")' \
        "$(
          # shellcheck disable=SC2154
          printf '%s' "${slave_id}" | \
            base64 -w0
        )"
      printf ' AND `package_sources`.`%s`=from_base64("%s")' \
        'pkgbase' "$(printf '%s' "$1" | base64 -w0)" \
        'git_revision' "$(printf '%s' "$2" | base64 -w0)" \
        'mod_git_revision' "$(printf '%s' "$3" | base64 -w0)"
      printf ' AND `upstream_repositories`.`name`=from_base64("%s")' \
        "$(printf '%s' "$4" | base64 -w0)"
      printf ' AND `binary_packages_in_repositories`.`repository`=%s;\n' \
        "${repository_ids__any_build_list}"
    } | \
      mysql_run_query | \
      tr '\t' ' '
  )
  if [ -z "${infos}" ]; then
    >&2 echo 'You do not build this package (anymore) - move on.'
    exit 2
  fi
  was_broken_before="${infos##* }"
  build_assignment_id="${infos%% *}"

  # save sent build logs
  saved_build_logs=$(
    tar -vx \
      -C "${build_log_directory}/error" \
      --wildcards \
      --no-wildcards-match-slash \
      --transform="s|^|$1.$2.$3.$4.|" \
      '*.build-log.gz'
  )

  # shellcheck disable=SC2016
  {
    if [ -n "${saved_build_logs}" ]; then
      printf 'CREATE TEMPORARY TABLE `failures` ('
      printf '`%s` %s,' \
        'date' 'TIMESTAMP' \
        'reason' 'SMALLINT' \
        'log_file' 'VARCHAR(512)' | \
        sed 's/,$//'
      printf ');\n'
      fail_reason_identifiers=$(
        {
          printf 'SELECT `fail_reasons`.`id`,replace(to_base64(`fail_reasons`.`identifier`),"\\n","")'
          printf ' FROM `fail_reasons` ORDER BY `fail_reasons`.`severity`'
        } | \
          mysql_run_query
      )
      for saved_build_log in ${saved_build_logs}; do
        printf '%s\n' "${fail_reason_identifiers}" | \
          while read -r reason_id identifier; do
            if zgrep -q "^$(
                printf '%s' "${identifier}" | \
                  base64 -d
              )\$" \
              "${build_log_directory}/error/$1.$2.$3.$4.${saved_build_log}"; then

              printf ' (from_base64("%s"),%s,from_base64("%s")),' \
                "$(
                  printf '%s' "${saved_build_log}" | \
                    sed 's|\.build-log\.gz$||;s|^.*\.||' | \
                    base64 -w0
                )" \
                "${reason_id}" \
                "$(
                  printf '%s' "$1.$2.$3.$4.${saved_build_log}" | \
                    base64 -w0
                )"
              break
            fi
          done
      done | \
        sed '
          1 s/^/INSERT INTO `failures` (`date`,`reason`,`log_file`) VALUES /
          s/,$/;\n/
        '
      printf 'INSERT INTO `failed_builds` (`build_slave`,`build_assignment`,`date`,`reason`,`log_file`,`log_file_exists`)'
      printf ' SELECT '
      printf 'from_base64("%s"),' \
        "$(printf '%s' "${slave_id}" | base64 -w0)" \
        "$(printf '%s' "${build_assignment_id}" | base64 -w0)"
      printf '`failures`.`%s`,' \
        'date' 'reason' 'log_file'
      printf '1'
      printf ' FROM `failures`;\n'
      printf 'DROP TEMPORARY TABLE `failures`;\n'
      printf 'COMMIT;\n'
    fi
    printf 'UPDATE `build_assignments`'
    printf ' SET `build_assignments`.`is_broken`=1,'
    printf '`build_assignments`.`priority`=0'
    printf ' WHERE `build_assignments`.`id`=from_base64("%s");\n' \
      "$(
        printf '%s' "${build_assignment_id}" | \
          base64 -w0
      )"
    printf 'COMMIT;\n'
    printf 'UPDATE `build_slaves`'
    printf ' SET `build_slaves`.`currently_building`=NULL,'
    printf ' `build_slaves`.`last_action`=NULL,'
    printf ' `build_slaves`.`logged_lines`=NULL,'
    printf ' `build_slaves`.`trials`=NULL'
    printf ' WHERE `build_slaves`.`id`=from_base64("%s");\n' \
      "$(
        printf '%s' "${slave_id}" | \
          base64 -w0
      )"
  } | \
    mysql_run_query

  # 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
    )

    # shellcheck disable=SC2119
    {
      # shellcheck disable=SC2154
      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'
    } | \
      irc_say
  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 ! verbose_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}"
}

# shellcheck disable=SC2016
build_assignment_id=$(
  {
    printf 'SELECT DISTINCT `build_assignments`.`id` FROM `build_slaves`'
    mysql_join_build_slaves_build_assignments
    mysql_join_build_assignments_package_sources
    mysql_join_package_sources_upstream_repositories
    mysql_join_build_assignments_binary_packages
    mysql_join_binary_packages_binary_packages_in_repositories
    printf ' WHERE `build_slaves`.`id`=from_base64("%s")' \
      "$(
        # shellcheck disable=SC2154
        printf '%s' "${slave_id}" | \
          base64 -w0
      )"
    printf ' AND `package_sources`.`%s`=from_base64("%s")' \
      'pkgbase' "$(
        printf '%s' "$1" | \
          base64 -w0
      )" \
      'git_revision' "$(
        printf '%s' "$2" | \
          base64 -w0
      )" \
      'mod_git_revision' "$(
        printf '%s' "$3" | \
          base64 -w0
      )"
    printf ' AND `upstream_repositories`.`name`=from_base64("%s")' \
      "$(
        printf '%s' "$4" | \
          base64 -w0
      )"
    printf ' AND `binary_packages_in_repositories`.`repository`=%s' \
      "${repository_ids__any_build_list}"
    printf ' AND `binary_packages`.`sub_pkgrel`=from_base64("%s");\n' \
      "$(
        printf '%s' "$5" | \
          base64 -w0
      )"
  } | \
    mysql_run_query | \
    tr '\t' ' '
)

if [ -z "${build_assignment_id}" ]; then
  >&2 echo 'Sorry, the sent package is outdated.'
  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

export TMPDIR="${tmp_dir}"

# extract package(s)
tar -x \
  --wildcards \
  --no-wildcards-match-slash \
  '*.pkg.tar.xz' \
  '*.pkg.tar.xz.sig' \
  '*.pkg.tar.xz-namcap.log.gz' \
  '*.pkg.tar.xz.so.needs.gz' \
  '*.pkg.tar.xz.so.provides.gz'

# check if all packages come with:
#  - a package file
#  - a signature
#  - a namcap log
#  - a list of needed libraries
#  - a list of provided libraries
missing_files=$(
  find . -maxdepth 1 \( \
    \( \
      -name '*.pkg.tar.xz' \
      -printf '%f package\n' \
    \) -o \
    \( \
      -name '*.pkg.tar.xz.sig' \
      -printf '%f signature\n' \
    \) -o \
    \( \
      -name '*.pkg.tar.xz-namcap.log.gz' \
      -printf '%f namcap\n' \
    \) -o \
    \( \
      -name '*.pkg.tar.xz.so.needs.gz' \
      -printf '%f needed-libraries\n' \
    \) -o \
    \( \
      -name '*.pkg.tar.xz.so.provides.gz' \
      -printf '%f provided-libraries\n' \
    \) \
  \) | \
    sed '
      s/\(\.pkg\.tar\.xz\)\(\.sig\|\(-namcap\.log\|\.so\.\(provides\|needs\)\)\.gz\) /\1 /
    ' | \
    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
      }
      / needed-libraries /!{
        h
        s/^\(\S\+\) .*$/List of libraries needed by "\1" is missing./
        p
        g
      }
      / provided-libraries /!{
        h
        s/^\(\S\+\) .*$/List of libraries provided by "\1" is missing./
        p
        g
      }
    '
)

if [ -n "${missing_files}" ]; then
  >&2 echo 'The following packages lack a signature, namcap log, package file or list of needed/provided libraries:'
  >&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 "$(
  printf '%s\n' "${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 printf '%s\n' "${signatures}"
  exit 3
fi

# check if the sent packages are the expected ones
find . -maxdepth 1 -name '*.pkg.tar.xz' -printf '%f\n' > \
  "${tmp_dir}/packages"

# shellcheck disable=SC2016
{
  printf 'SELECT'
  printf ' `binary_packages`.`id`,'
  mysql_package_name_query
  printf ' FROM `binary_packages`'
  mysql_join_binary_packages_architectures
  mysql_join_binary_packages_binary_packages_in_repositories
  printf ' WHERE `binary_packages`.`build_assignment`=from_base64("%s")' \
    "$(
      printf '%s' "${build_assignment_id}" | \
        base64 -w0
    )"
  printf ' AND `binary_packages_in_repositories`.`repository`=%s' \
    "${repository_ids__any_build_list}"
  printf ';\n'
} | \
  mysql_run_query | \
  tr '\t' ' ' | \
  sort -k2 > \
  "${tmp_dir}/package-ids"

package_errors=$(
  {
    sed '
      s|^|was_built: |
    ' "${tmp_dir}/packages"
    sed '
      s|^[0-9]\+ |expected: |
    ' "${tmp_dir}/package-ids"
  } | \
    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

if [ ! -s "${tmp_dir}/package-ids" ]; then
  >&2 echo 'No package was expected, no package was built.'
  >&2 echo 'That should not happen!'
  exit 4
fi

# shellcheck disable=SC2016
{
  printf 'SELECT `binary_packages`.`id`,'
  mysql_package_name_query
  printf ',`t`.`id`,`t_a`.`name`,`t`.`name`'
  printf ' FROM `build_assignments`'
  mysql_join_build_assignments_binary_packages
  mysql_join_binary_packages_architectures
  mysql_join_build_assignments_package_sources
  mysql_join_package_sources_upstream_repositories
  mysql_join_upstream_repositories_repository_moves
  printf ' JOIN `repositories` as `t` ON `t`.`id`=`repository_moves`.`to_repository`'
  mysql_join_repositories_architectures 't' 't_a'
  printf ' JOIN `architecture_compatibilities`'
  printf ' ON `architecture_compatibilities`.`built_for`=`binary_packages`.`architecture`'
  printf ' AND `architecture_compatibilities`.`runs_on`=`t`.`architecture`'
  printf ' AND `architecture_compatibilities`.`fully_compatible`'
  printf ' WHERE `repository_moves`.`from_repository`=%s' \
    "${repository_ids__any_build_list}"
  printf ' AND `build_assignments`.`id`=from_base64("%s");\n' \
    "$(
      printf '%s' "${build_assignment_id}" | \
        base64 -w0
    )"
} | \
  mysql_run_query | \
  tr '\t' ' ' | \
  sort -u > \
  "${tmp_dir}/repository-ids"

errors=$(
  {
    cut -d' ' -f2 < \
      "${tmp_dir}/repository-ids" | \
      sort -u | \
      sed 's/^/repository-was-found: /'
    cut -d' ' -f2 < \
      "${tmp_dir}/package-ids" | \
      sort -u | \
      sed 's/^/package-was-sent: /'
  } | \
    sort -k2 | \
    uniq -uf1
)

if [ -n "${errors}" ]; then
  >&2 echo 'I cannot determine, where this package (or some part of it)'
  >&2 echo 'should be published:'
  >&2 printf '%s\n' "${errors}"
  >&2 echo 'This is some internal error and not (necessarily) your fault.'
  # We give a temporary error (although resolving this needs manual
  # intervention), because there is nothing wrong with the sent package
  # whence it does not need to be built again, but can simply be sent again.
  exit 1
fi

while read -r package_id package_name; do
  # move namcap.logs
  mv \
    "${tmp_dir}/${package_name}-namcap.log.gz" \
    "${build_log_directory}/success/"
  # generate checksum
  sha512sum "${tmp_dir}/${package_name}" | \
    awk '{print "'"${package_id}"'\t" $1}' >> \
    "${tmp_dir}/sha512sums"
  # generate list of required/provided libraries
  for lib in 'provides' 'needs'; do
    zcat "${tmp_dir}/${package_name}.so.${lib}.gz" | \
      sed '
        s/^/'"${package_id}"'\t/
      ' >> "${tmp_dir}/so.${lib}"
  done
done < \
  "${tmp_dir}/package-ids"

# move packages

cut -d' ' -f4,5 "${tmp_dir}/repository-ids" | \
  sort -u | \
  while read -r arch repo; do

    mkdir -p "${arch}/${repo}"
    ${master_mirror_rsync_command} \
      "${master_mirror_rsync_directory}/${arch}/${repo}/${repo}.db."* \
      "${master_mirror_rsync_directory}/${arch}/${repo}/${repo}.files."* \
      "${arch}/${repo}/"

    grep " $(str_to_regex "${arch} ${repo}")\$" "${tmp_dir}/repository-ids" | \
      cut -d' ' -f2 | \
      xargs -r repo-add "${arch}/${repo}/${repo}.db.tar.gz"
    # xargs -r repo-add -v -s -k "${repo_key}" "${destination}.db.tar.gz"

  done

# upload the packages into /pool
${master_mirror_rsync_command} -c --copy-dest=/.transfer \
  ./*".pkg.tar.xz" \
  ./*".pkg.tar.xz.sig" \
  "${master_mirror_rsync_directory}/pool/"

# create symlinks
find . \( -name '*.pkg.tar.xz' -o -name '*.pkg.tar.xz.sig' \) -printf '%f\n' | \
  while read -r file; do
    rm "${file}"
    ln -s "../../pool/${file}" "${file}"
  done

# upload the database and the symlinks into /$arch/$repo

cut -d' ' -f4,5 "${tmp_dir}/repository-ids" | \
  sort -u | \
  while read -r arch repo; do
    recompress_gz \
      "${tmp_dir}" \
      "${arch}/${repo}/${repo}."*".tar.gz" \
      "${arch}/${repo}/${repo}."*".tar.gz.old"
    # shellcheck disable=SC2046
    ${master_mirror_rsync_command} \
      "${arch}/${repo}/${repo}.db."* \
      "${arch}/${repo}/${repo}.files."* \
      $(
        grep " $(str_to_regex "${arch} ${repo}")\$" "${tmp_dir}/repository-ids" | \
          cut -d' ' -f2 | \
          sed '
            s,^,./,
            p
            s/$/.sig/
          '
      ) \
      "${master_mirror_rsync_directory}/${arch}/${repo}/"
  done

trigger_mirror_refreshs

# shellcheck disable=SC2016
{
  # insert checksums into database
  printf 'CREATE TEMPORARY TABLE `pkg_hashes` (`pkgid` BIGINT, `sha512sum` VARCHAR(128));\n'
  printf 'LOAD DATA LOCAL INFILE "%s" INTO TABLE `pkg_hashes`;\n' \
    "${tmp_dir}/sha512sums"
  printf 'UPDATE `binary_packages`'
  printf ' JOIN `pkg_hashes` ON `pkg_hashes`.`pkgid`=`binary_packages`.`id`'
  printf ' SET `binary_packages`.`sha512sum`=`pkg_hashes`.`sha512sum`;\n'
  printf 'COMMIT;\n'

  # insert provided/needed libraries into database
  for lib_link in 'pl:provides' 'nl:needs'; do
    printf 'CREATE TEMPORARY TABLE `%s` (`pkgid` BIGINT, `lib` VARCHAR(128));\n' \
      "${lib_link%:*}"
    printf 'LOAD DATA LOCAL INFILE "%s" INTO TABLE `%s`;\n' \
      "${tmp_dir}/so.${lib_link#*:}" "${lib_link%:*}"

    printf 'INSERT IGNORE INTO `install_targets` (`name`)'
    printf ' SELECT DISTINCT `%s`.`lib` FROM `%s`;\n' \
      "${lib_link%:*}" "${lib_link%:*}"
    printf 'COMMIT;\n'

    if [ "${lib_link%:*}" = 'pl' ]; then
      printf 'INSERT IGNORE INTO `install_target_providers` (`package`,`install_target`)'
    else
      printf 'INSERT IGNORE INTO `dependencies` (`dependent`,`depending_on`,`dependency_type`)'
    fi
    printf ' SELECT `%s`.`pkgid`,`install_targets`.`id`' \
      "${lib_link%:*}"
    if [ "${lib_link%:*}" = 'nl' ]; then
      printf ',`dependency_types`.`id`'
    fi
    printf ' FROM `install_targets`'
    if [ "${lib_link%:*}" = 'nl' ]; then
      printf ' JOIN `dependency_types` ON `dependency_types`.`name`="link"'
    fi
    printf ' JOIN `%s` ON `%s`.`lib`=`install_targets`.`name`' \
      "${lib_link%:*}" "${lib_link%:*}"
    printf ';\n'
    printf 'COMMIT;\n'
  done

  # remove build_assignment's markers
  printf 'UPDATE `build_assignments`'
  printf ' SET'
  printf ' `build_assignments`.`is_broken`=0,'
  printf ' `build_assignments`.`priority`=0,'
  printf ' `build_assignments`.`return_date`=NOW()'
  printf ' WHERE `build_assignments`.`id`=from_base64("%s");\n' \
    "$(
      printf '%s' "${build_assignment_id}" | \
        base64 -w0
    )"
  printf 'COMMIT;\n'

  # insert into appropriate repositories and retrieve ids
  while read -r package_id _ repository_id _; do
    printf 'INSERT INTO `binary_packages_in_repositories` (`package`,`repository`,`is_to_be_deleted`) VALUES '
    printf '(%s,%s,0);\n' \
      "${package_id}" "${repository_id}"
    printf 'SELECT LAST_INSERT_ID();\n'
  done < \
    "${tmp_dir}/repository-ids"
  printf 'COMMIT;\n'

  # remove from build-list
  printf 'DELETE FROM `binary_packages_in_repositories`'
  printf ' WHERE `binary_packages_in_repositories`.`package` IN ('
  cut -d' ' -f1 < \
    "${tmp_dir}/package-ids" | \
    base64_encode_each | \
    sed '
      s/^/from_base64("/
      s/$/"),/
      $ s/,$//
    '
  printf ') AND `binary_packages_in_repositories`.`repository`=%s;\n' \
    "${repository_ids__any_build_list}"
  printf 'COMMIT;\n'

  # update package information
  printf 'UPDATE `binary_packages`'
  printf ' SET'
  printf ' `binary_packages`.`has_issues`=0,'
  printf ' `binary_packages`.`is_tested`=0'
  printf ' WHERE `binary_packages`.`id` IN ('
  cut -d' ' -f1 < \
    "${tmp_dir}/package-ids" | \
    base64_encode_each | \
    sed '
      s/^/from_base64("/
      s/$/"),/
      $ s/,$//
    '
  printf ');\n'
  printf 'COMMIT;\n'

  # remove from build slave's `currently_building`
  printf 'UPDATE `build_slaves`'
  printf ' SET `build_slaves`.`currently_building`=NULL,'
  printf ' `build_slaves`.`last_action`=NULL,'
  printf ' `build_slaves`.`logged_lines`=NULL,'
  printf ' `build_slaves`.`trials`=NULL'
  printf ' WHERE `build_slaves`.`currently_building`=from_base64("%s");\n' \
    "$(
      printf '%s' "${build_assignment_id}" | \
        base64 -w0
    )"
  printf 'COMMIT;\n'

  # remove broken loops
  printf 'CREATE TEMPORARY TABLE `loops_to_delete` (`loop` MEDIUMINT);\n'
  printf 'INSERT INTO `loops_to_delete`'
  printf ' SELECT `build_dependency_loops`.`loop` FROM `build_dependency_loops`'
  mysql_join_build_dependency_loops_binary_packages
  mysql_join_binary_packages_binary_packages_in_repositories
  printf ' WHERE NOT `binary_packages_in_repositories`.`repository`=%s;\n' \
    "${repository_ids__any_build_list}"
  printf 'COMMIT;\n'
  printf 'DELETE FROM `build_dependency_loops` WHERE EXISTS ('
    printf 'SELECT 1 FROM `loops_to_delete`'
    printf ' WHERE `loops_to_delete`.`loop`=`build_dependency_loops`.`loop`'
  printf ');\n'
  printf 'DROP TEMPORARY TABLE `loops_to_delete`;\n'
} | \
  mysql_run_query | \
  sort -u | \
  remove_old_package_versions