#!/bin/sh

# report back on a build assignment
# either on success via:
#   "$0 $package $revision $mod_revision $repository" and tar'ed packages (= a tar of
#   package(s) and signature(s)) on stdin
# or on failure via:
#   "$0 $package $revision $mod_revision $repository ERROR"

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

#  fix signing of database

. "${0%/*}/../conf/default.conf"

# 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

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

  if [ ! -f "${work_dir}/package-states/$1.$2.$3.$4.locked" ]; then
    # too late, package already outdated -> ignore error report
    exit 0
  fi

  cat \
    "${work_dir}/package-states/$1.$2.$3.$4.locked" >> \
    "${work_dir}/package-states/$1.$2.$3.$4.broken"

  rm "${work_dir}/package-states/$1.$2.$3.$4.locked"

  # unlock every loop this package would have broken and which is not
  # broken by another locked package
  locked_packages="$(
    ls "${work_dir}/package-states/" | \
      grep '\.locked$' | \
      sed 's@^.*/\([^/]\+\)\.\([0-9a-f]\{40\}\.\)\{2\}[^.]\+\.locked$@\1@'
  )"
  grep -xF "${1}" "${work_dir}/build-list.loops/loop_"* 2> /dev/null | \
    cut -d: -f1 | \
    while read -r loop; do
      if [ -z "$(
          (
            echo "${locked_packages}"
            cat "${loop}"
          ) | \
            sort | \
            uniq -d
        )" ]; then
        rm -f "${loop}.locked"
      fi
    done

  # move build order to end of build list

  sed -i \
    "/^$(str_to_regex "$1 $2 $3 $4")\$/d" \
    "${work_dir}/build-list"
  echo "$1 $2 $3 $4" >> \
    "${work_dir}/build-list"

  exit 0

fi

# the build was successful on the build slave

# so we also need a lock on the package database

exec 8> "${package_database_lock_file}"
if ! flock -n 8; 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}"
}

if ! grep -qxF "$1 $2 $3 $4" "${work_dir}/build-list" ||
  ! [ -f "${work_dir}/package-states/$1.$2.$3.$4.locked" ]; 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)"
cd "${tmp_dir}"
trap clean_up_tmp_dir EXIT

# extract package(s)
tar -x

# check if all packages are signed and all signatures belong to a package
signature_errors="$(
  ls -1 *.pkg.tar.xz{,.sig} | \
    sed 's|\.sig$||' | \
    sort | \
    uniq -c | \
    grep -v '^\s*2\s' | \
    awk '{print $2}'
)"

if [ -n "${signature_errors}" ]; then
  >&2 echo 'The following packages lack a signature or vice versa:'
  >&2 echo "${signature_errors}"
  exit 3
fi

# check if the sent packages are the expected ones
packages="$(
  ls -1 | \
    grep '\.pkg\.tar\.xz$'
)"
package_errors="$(
  (
    printf '%s\n' ${packages} | \
      sed '
        s@\(-[^-]\+\)\{2\}-\([^-]\+\)\.pkg\.tar\.xz$@ \2@
        / any$/{
          s|any$|i686|
        }
      '
    sed 's|$| i686|' "${work_dir}/package-infos/$1.$2.$3.packages"
  ) | \
    sort | \
    uniq -u
)"

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

# move packages
destination="$(official_or_community "$1.$2.$3.$4")staging"

${master_mirror_command} \
  "${master_mirror_directory}/i686/${destination}/${destination}.db."* \
  .
repo-add "${destination}.db.tar.gz" ${packages}
# repo-add -v -s -k "${repo_key}" "${destination}.db.tar.gz" ${packages}

${master_mirror_command} \
  "${destination}.db."* \
  ./*".pkg.tar.xz" \
  ./*".pkg.tar.xz.sig" \
  "${master_mirror_directory}/i686/${destination}/"

for package in ${packages}; do
  remove_old_package_versions "i686/${destination}" "${package}"
done

# remove old state files (these should be only "done" markers, but
# actually we don't care what it is) - as long as it's not "testing"
ls "${work_dir}/package-states" | \
  grep "^$(str_to_regex "$1")\(\.[^.]\+\)\{4\}\$" | \
  grep -v "^$(str_to_regex "$1.$2.$3.$4")\.[^.]\+\$" | \
  grep -v '\.testing$' | \
  sed "s|^|${work_dir}/package-states/|" | \
  xargs -rn1 rm -f

# remove all loops which are broken by this package
grep -xF "$1" "${work_dir}/build-list.loops/loop_"* 2> /dev/null | \
  cut -d: -f1 | \
  sed 'p;s|$|.locked|' | \
  xargs -rn1 rm -f

if ! ls "${work_dir}/build-list.loops" | \
  grep -q '^loop_[0-9]\+$'; then
  # no loops left
  sed -i '/^break_loops$/d' "${work_dir}/build-list"
fi

# remove package from build list
sed -i "/^$(str_to_regex "$1 $2 $3 $4")\$/d" "${work_dir}/build-list"

# remove package lock file
printf '%s\n' ${packages} > \
  "${work_dir}/package-states/$1.$2.$3.$4.done"
rm -f \
  "${work_dir}/package-states/$1.$2.$3.$4.locked" \
  "${work_dir}/package-states/$1.$2.$3.$4.broken"