#!/bin/sh

# seed the build list from differences between an x86_64 and our master mirror

# shellcheck source=conf/default.conf
. "${0%/*}/../conf/default.conf"

# shellcheck disable=SC2016
usage() {
  >&2 echo ''
  >&2 echo 'seed-build-list [options]:'
  >&2 echo '  seed the build list from'
  >&2 echo '    - differences between an x86_64 and our master mirror'
  >&2 echo '    - a list of packages which need to be rebuilt'
  >&2 echo ''
  >&2 echo 'possible options:'
  >&2 echo '  -h|--help:'
  >&2 echo '    Show this help and exit.'
  >&2 echo '  -i|--ignore $package:'
  >&2 echo '    Do not update $package.'
  >&2 echo '  -m|--mirror $url:'
  >&2 echo '    Get x86_64 packages from mirror at $url.'
  >&2 echo '  -n|--no-action:'
  >&2 echo '    Do not actually update build-list, just print it.'
  >&2 echo '  -p|--package $pkg_regex:'
  >&2 echo '    Update packages matching $pkg_regex.'
  [ -z "$1" ] && exit 1 || exit "$1"
}

tmp_dir=$(mktemp -d 'tmp.seed-build-list.XXXXXXXXXX' --tmpdir)
# shellcheck disable=SC2064
trap "rm -rf --one-file-system '${tmp_dir:?}'" EXIT

eval set -- "$(
  getopt -o hi:m:np: \
    --long help \
    --long ignore: \
    --long mirror: \
    --long no-action \
    --long package: \
    -n "$(basename "$0")" -- "$@" || \
    echo usage
  )"

touch "${tmp_dir}/mirrors"
touch "${tmp_dir}/package-regexes"
touch "${tmp_dir}/ignore-packages"

update=true

while true
do
  case "$1" in
    -h|--help)
      usage 0
    ;;
    -i|--ignore)
      shift
      echo "$1" >> \
        "${tmp_dir}/ignore-packages"
    ;;
    -m|--mirror)
      shift
      echo "$1" >> \
        "${tmp_dir}/mirrors"
    ;;
    -n|--no-action)
      update=false
    ;;
    -p|--package)
      shift
      echo "$1" >> \
        "${tmp_dir}/package-regexes"
    ;;
    --)
      shift
      break
    ;;
    *)
      >&2 echo 'Whoops, forgot to implement option "'"$1"'" internally.'
      exit 42
    ;;
  esac
  shift
done

if [ $# -ne 0 ]; then
  usage 1
fi

if [ ! -s "${tmp_dir}/mirrors" ] && \
  [ ! -s "${tmp_dir}/package-regexes" ]; then
  # nothing to do
  exit 0
fi

repos="${stable_package_repositories}"

# genereate must-haves query from mirror delta
if [ -s "${tmp_dir}/mirrors" ]; then
  {
    # theirs
    while read -r mirror; do
      if [ -z "${mirror}" ]; then
        continue
      fi
      for repo in ${repos}; do
        curl -sS "${mirror}/${repo}/os/x86_64/${repo}.db.tar.gz" | \
          tar -Oxz --wildcards '*/desc' | \
          sed '
            /^%FILENAME%$/!d
            N
            s/^.*\n//
            s/-x86_64\(\.pkg\.tar\.xz\)$/-i686\1/
            s/^\(.*\)-\([^-]\+-[^-]\+\)-\([^-]\+\)/theirs \2 \3 \1/
          '
      done
    done < \
      "${tmp_dir}/mirrors"
    # ours
    # shellcheck disable=SC2016
    {
      printf 'SELECT '
      mysql_package_name_query
      printf ' FROM `binary_packages`'
      mysql_join_binary_packages_architectures
    } | \
      mysql_run_query | \
      sed '
        s/^\(.*\)-\([^-]\+-[^-]\+\)-\([^-]\+\)/ours \2 \3 \1/
      '
  } | \
    expand_version 2 | \
    sort -k3,4 -k2Vr,2 -k1,1 | \
    shrink_version 2 | \
    uniq -f2 | \
    sed -n '
      s/^theirs \(\S\+ \)\{2\}//
      T
      p
    ' | \
    sort -u > \
    "${tmp_dir}/must-haves"
fi

# shellcheck disable=SC2016
{
  printf 'CREATE TEMPORARY TABLE `ignore_packages` (`pkgname` VARCHAR(64));\n'
  if [ -s "${tmp_dir}/ignore-packages" ]; then
    grep -vxF '' "${tmp_dir}/ignore-packages" | \
      base64_encode_each | \
      sed '
        s/^/(from_base64("/
        s/$/")),/
        $s/,$/;/
        1 s/^/INSERT INTO `ignore_packages` (`pkgname`) VALUES \n/
      '
  fi
  # packages on the build-list or deletion-list should be ignored
  printf 'INSERT IGNORE INTO `ignore_packages` (`pkgname`)'
  printf ' SELECT DISTINCT `ignore_bin`.`pkgname`'
  printf ' FROM `binary_packages` AS `ignore_bin`'
  mysql_join_binary_packages_repositories 'ignore_bin'
  printf ' WHERE `repositories`.`name` IN ("build-list","deletion-list")'
  # packages with no not-to-be-deleted and at least on to-be-deleted version should be ignored
  printf ' OR ('
  printf '`ignore_bin`.`is_to_be_deleted`'
  printf ' AND NOT EXISTS ('
    printf 'SELECT * FROM `binary_packages` AS `other_bin`'
    printf ' WHERE NOT `other_bin`.`is_to_be_deleted`'
    printf ' AND `other_bin`.`pkgname`=`ignore_bin`.`pkgname`'
  printf '));\n'
} | \
  sponge "${tmp_dir}/ignore-packages"

# shellcheck disable=SC2016
{
  printf 'CREATE TEMPORARY TABLE `must_haves` (`pkgname` VARCHAR(64));\n'
  if [ -s "${tmp_dir}/must-haves" ]; then
    grep -vxF '' "${tmp_dir}/must-haves" | \
      base64_encode_each | \
      sed '
        s/^/(from_base64("/
        s/$/")),/
        $s/,$/;/
        1 s/^/INSERT INTO `must_haves` (`pkgname`) VALUES \n/
      '
  fi
} | \
  sponge "${tmp_dir}/must-haves"

# fetch unknown must-haves from upstream
# shellcheck disable=SC2016
printf 'CREATE TEMPORARY TABLE `pkgbases` (`pkgbase` VARCHAR(64), `repository` VARCHAR(64));\n' > \
  "${tmp_dir}/pkgbases"
# shellcheck disable=SC2016
{
  cat "${tmp_dir}/must-haves" "${tmp_dir}/ignore-packages"
  printf 'SELECT `must_haves`.`pkgname` FROM `must_haves`'
  printf ' WHERE NOT EXISTS ('
    printf 'SELECT * FROM `binary_packages`'
    printf ' WHERE `binary_packages`.`pkgname`=`must_haves`.`pkgname`'
  printf ') AND NOT EXISTS ('
    printf 'SELECT * FROM `ignore_packages`'
    printf ' WHERE `ignore_packages`.`pkgname`=`must_haves`.`pkgname`'
  printf ') AND NOT `must_haves`.`pkgname` LIKE "lib32-%%";\n'
} | \
  mysql_run_query | \
  while read -r pkgname; do
    content=$(
      curl -Ss 'https://www.archlinux.org/packages/search/json/?name='"${pkgname}" | \
        tr ',' '\n'
    )
    repo=$(
      printf '%s\n' "${content}" | \
        sed -n '
          s/^\s*"repo"\s*:\s*"//
          T
          s/".*$//
          T
          p
        '
    )
    pkgbase=$(
      printf '%s\n' "${content}" | \
        sed -n '
          s/^\s*"pkgbase"\s*:\s*"//
          T
          s/".*$//
          T
          p
        '
    )
    if [ -z "${pkgbase}" ] || [ -z "${repo}" ]; then
      >&2 printf 'Could not find "%s" which is newer on x86_64!?\n' "${pkgname}"
      exit 2
    fi
    printf '(from_base64("%s"),from_base64("%s")),\n' \
      "$(printf '%s' "${pkgbase}" | base64 -w0)" \
      "$(printf '%s' "${repo}" | base64 -w0)"
  done | \
  sort -u | \
  sed '
    1 s/^/INSERT IGNORE INTO `pkgbases` (`pkgbase`,`repository`) VALUES \n/
    $s/,$/;/
  ' >> \
  "${tmp_dir}/pkgbases"

# shellcheck disable=SC2016
{
  cat "${tmp_dir}/must-haves" "${tmp_dir}/ignore-packages" "${tmp_dir}/pkgbases"
  printf 'SELECT '
  printf '`pkgbases`.`pkgbase`,'
  printf '`git_repositories`.`head`,'
  printf '('
    printf 'SELECT `al32`.`head` FROM `git_repositories` AS `al32`'
    printf ' WHERE `al32`.`name`="archlinux32"'
  printf '),'
  printf '`pkgbases`.`repository`'
  printf ' FROM `pkgbases`'
  printf ' JOIN `upstream_repositories` ON `upstream_repositories`.`name`=`pkgbases`.`repository`'
  mysql_join_upstream_repositories_git_repositories
  printf ';\n'
  printf 'SELECT '
  printf '`package_sources`.`pkgbase`,'
  printf '`git_repositories`.`head`,'
  printf '('
    printf 'SELECT `al32`.`head` FROM `git_repositories` AS `al32`'
    printf ' WHERE `al32`.`name`="archlinux32"'
  printf '),'
  printf '`upstream_repositories`.`name`'
  printf ' FROM `binary_packages`'
  mysql_join_binary_packages_build_assignments
  mysql_join_build_assignments_package_sources
  mysql_join_package_sources_upstream_repositories
  mysql_join_upstream_repositories_git_repositories
  printf ' WHERE ('
  if [ -s "${tmp_dir}/package-regexes" ]; then
    grep -vxF '' "${tmp_dir}/package-regexes" | \
      base64_encode_each | \
      sed '
        s/^/`binary_packages`.`pkgname` REGEXP from_base64("/
        s/$/") OR /
      ' | \
      tr -d '\n'
  fi
  printf 'EXISTS ('
    printf 'SELECT * FROM `must_haves`'
    printf ' WHERE `must_haves`.`pkgname`=`binary_packages`.`pkgname`'
  printf ')) AND NOT EXISTS ('
    printf 'SELECT * FROM `ignore_packages`'
    printf ' WHERE `ignore_packages`.`pkgname`=`binary_packages`.`pkgname`'
  printf ');\n'
} | \
  mysql_run_query | \
  sort -u | \
  tr '\t' ' ' | \
  if ${update}; then
    # always block if locked
    exec 9> "${build_list_lock_file}"
    flock 9

    exec 8> "${sanity_check_lock_file}"
    flock -s 8

    while read -r pkgbase git_rev mod_git_rev repo; do
      printf '%s %s %s %s\n' "${pkgbase}" "${git_rev}" "${mod_git_rev}" "${repo}" >> \
        "${work_dir}/build-list"
      printf '%s ' "${pkgbase}" "${git_rev}" "${mod_git_rev}" "${repo}" >&2
      generate_package_metadata "${pkgbase}" "${git_rev}" "${mod_git_rev}" "${repo}"
      mysql_generate_package_metadata 'build-list' "${pkgbase}" "${git_rev}" "${mod_git_rev}" "${repo}"
      printf '\n' >&2
    done

    rm -f "${build_list_lock_file}"
  else
    cat
  fi