#!/bin/sh

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

# shellcheck disable=SC2016
usage() {
  >&2 echo 'usage:'
  >&2 echo '  create-build-support-package [options] --from $pkgname-$epoch:$pkgver-$pkgrel.$sub_pkgrel [--] $file1 $file2 $file3 ...'
  >&2 echo '    create $pkgname-shim containing'
  >&2 echo '    $file1, $file2, ... from the original package'
  >&2 echo '  create-build-support-package [options] --shim $pkgfile'
  >&2 echo '    insert $pkgfile into $repo_arch/build-support/$pkgname-shim'
  >&2 echo ''
  >&2 echo 'possible options:'
  >&2 echo '  -a|--arch $repo_arch: (required)'
  >&2 echo '    Operate on repository of given architecture.'
  >&2 echo '  -h|--help:'
  >&2 echo '    Show this help and exit.'
  >&2 echo '  --only-versioned-so-provides:'
  >&2 echo '    Remove all but versioned *.so provide entries. (only with --from)'
  >&2 echo '  -w|--wait:'
  >&2 echo '    Wait for lock if necessary.'
  [ -z "$1" ] && exit 1 || exit "$1"
}

eval set -- "$(
  getopt -o a:hw \
    --long arch: \
    --long from: \
    --long help \
    --long only-versioned-so-provides \
    --long shim: \
    --long wait \
    -n "$(basename "$0")" -- "$@" || \
    echo usage
  )"

only_versioned_so_provides=false
repo_arch=''
shim_package=''
source_package=''
wait_for_lock='-n'
while true; do
  case "$1" in
    -a|--arch)
      if [ -n "${repo_arch}" ]; then
        >&2 prinf -- '-a|--arch given more than once.\n'
        usage
      fi
      shift
      repo_arch="$1"
    ;;
    --from)
      if [ -n "${source_package}" ]; then
        >&2 prinf -- '--from given more than once.\n'
        usage
      fi
      shift
      source_package="$1"
    ;;
    -h|--help)
      usage 0
    ;;
    --only-versioned-so-provides)
      only_versioned_so_provides=true
    ;;
    --shim)
      if [ -n "${shim_package}" ]; then
        >&2 prinf -- '--shim given more than once.\n'
        usage
      fi
      shift
      shim_package="$1"
    ;;
    -w|--wait)
      wait_for_lock=''
    ;;
    --)
      shift
      break
    ;;
    *)
      >&2 printf 'Whoops, forgot to implement option "%s" internally.\n' \
        "$1"
      exit 42
    ;;
  esac
  shift
done

if [ -n "${source_package}" ] \
  && [ -n "${shim_package}" ]; then
  >&2 echo 'Conflicting parameters: --from and --shim'
  usage
fi

if ${only_versioned_so_provides} \
  && [ -n "${shim_package}" ]; then
  >&2 echo 'Conflicting parameters: --shim and --only-versioned-so-provides'
  usage
fi

exec 9> "${sanity_check_lock_file}"
verbose_flock -s ${wait_for_lock} 9

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

if [ -n "${source_package}" ]; then
  # create shim_package from source_package

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

  pkg=$(
    # shellcheck disable=SC2016
    {
      printf 'SELECT DISTINCT '
      mysql_package_name_query
      printf ' FROM `binary_packages`'
      mysql_join_binary_packages_binary_packages_in_repositories
      mysql_join_binary_packages_in_repositories_repositories
      mysql_join_repositories_architectures '' 'r_a'
      mysql_join_binary_packages_architectures
      printf ' WHERE `repositories`.`is_on_master_mirror`'
      printf ' AND `r_a`.`name`=from_base64("%s")' \
        "$(
          printf '%s' "${repo_arch}" \
            | base64 -w0
        )"
      printf ' AND '
      mysql_package_name_query '' 'XX' \
        | sed '
          s/,"-",`XX.*\.pkg\.tar\.xz"//
        '
      printf '=from_base64("%s")' \
        "$(
          printf '%s' "${source_package}" \
            | base64 -w0
        )"
    } \
      | mysql_run_query \
      | tr '\t' ' '
  )

  if [ -z "${pkg}" ]; then
    >&2 printf 'Could not find %s/%s in the database.\n' \
      "${repo_arch}" "${source_package}"
    exit 1
  fi

  if printf '%s\n' "${pkg}" \
    | wc -l \
    | grep -vqxF '1'; then
    >&2 printf 'Package %s/%s was found multiple times:\n' \
      "${repo_arch}" "${source_package}"
    >&2 printf '%s\n' "${pkg}"
    exit 1
  fi

  new_pkg="${pkg%-*-*-*}"
  new_pkg="${new_pkg}-shim${pkg#${new_pkg}}"

  failsafe_rsync \
    "${master_mirror_rsync_directory}/pool/${pkg}" \
    "${tmp_dir}/"

  mkdir "${tmp_dir}/content"
  bsdtar -C "${tmp_dir}/content" -xf "${tmp_dir}/${pkg}" \
    '.BUILDINFO' \
    '.PKGINFO' \
    "$@"

  # TODO: mangle customizable meta-infos here (new provides, keep some
  # depends)
  sed -i '
    /^pkgname = / s/ \S\+$/\0-shim\nprovides =\0/
    /^depend = /d
  ' "${tmp_dir}/content/.PKGINFO"
  if ${only_versioned_so_provides}; then
    sed -i '
      /^provides = / {
        / = \S\+\.so=/ ! d
      }
      /^replaces = / d
      /^conflict = / d
    ' "${tmp_dir}/content/.PKGINFO"
  fi

  # from /usr/bin/makepkg
  list_package_files() {
    (
      cd "${tmp_dir}/content"
      find . -path './.*' \! -name '.'; find . \! -path './.*' \! -name '.' \
        | LC_ALL=C sort
    ) \
      | sed -e 's|^\./||' \
      | tr '\n' '\0'
  }

  list_package_files \
    | LANG=C bsdtar -C "${tmp_dir}/content" -cnf - --format=mtree \
      --options='!all,use-set,type,uid,gid,mode,time,size,md5,sha256,link' \
      --null --files-from - --exclude .MTREE \
    | gzip -c -f -n \
    > "${tmp_dir}/content/.MTREE"

  list_package_files \
    | LANG=C bsdtar -C "${tmp_dir}/content" -cnf - --null --files-from - \
    | xz -c -z - \
    > "${tmp_dir}/${new_pkg}"

  rm -rf --one-file-system "${tmp_dir:?}/content"
  mv "${tmp_dir}/${new_pkg}" "${work_dir}/"
  >&2 printf 'Please sign %s with a build slave key and run\n' \
    "${work_dir}/${new_pkg}"
  # shellcheck disable=SC2016
  >&2 printf 'create-build-support-package --arch %s --shim %s\n' \
    "${repo_arch}" \
    "${work_dir}/${new_pkg}"

elif [ -n "${shim_package}" ]; then
  # insert shim_package into [build-support]

  if [ $# -ne 0 ]; then
    >&2 echo 'Too many arguments'
    usage
  fi

  if [ ! -r "${shim_package}" ]; then
    >&2 printf 'Cannot open file %s\n' \
      "${shim_package}"
    exit 1
  fi

  if ! gpg --batch --status-fd 1 -q --homedir /etc/pacman.d/gnupg --verify \
    "${shim_package}.sig" \
    "${shim_package}" \
    2> /dev/null \
    | cut -d' ' -f2 \
    | grep -qxF TRUST_FULLY; then
    >&2 printf '%s has invalid signature\n' \
      "${shim_package}"
    exit 1
  fi

  exec 8> "${package_database_lock_file}"
  verbose_flock ${wait_for_lock} 8

  original_pkg_id=$(
    # shellcheck disable=SC2016
    {
      printf 'SELECT DISTINCT `binary_packages`.`id`'
      printf ' FROM `binary_packages`'
      mysql_join_binary_packages_architectures
      printf ' WHERE '
      mysql_package_name_query \
        | sed 's/pkgname`,"/\0-shim/'
      printf '=from_base64("%s")' \
        "$(
          printf '%s' "${shim_package##*/}" \
            | base64 -w0
        )"
    } | \
      mysql_run_query
  )
  if [ -z "${original_pkg_id}" ]; then
    >&2 printf 'could not find the original package to %s.\n' \
      "${shim_package##*/}"
    exit 1
  fi

  cp "${shim_package}" "${shim_package}.sig" "${tmp_dir}/"
  failsafe_rsync \
    "${master_mirror_rsync_directory}/${repo_arch}/build-support/build-support.db."* \
    "${master_mirror_rsync_directory}/${repo_arch}/build-support/build-support.files."* \
    "${tmp_dir}/"

  repo-add \
    "${tmp_dir}/build-support.db.tar.gz" \
    "${tmp_dir}/${shim_package##*/}"

  # shellcheck disable=SC2016
  {
    printf 'INSERT INTO `binary_packages`('
      printf '`build_assignment`,'
      printf '`epoch`,'
      printf '`pkgver`,'
      printf '`pkgrel`,'
      printf '`sub_pkgrel`,'
      printf '`architecture`,'
      printf '`sub_pkgrel_omitted`,'
      printf '`pkgname`,'
      printf '`has_issues`,'
      printf '`is_tested`,'
      printf '`sha512sum`'
    printf ')'
    printf ' SELECT '
    printf '`binary_packages`.`%s`,' \
      'build_assignment' \
      'epoch' \
      'pkgver' \
      'pkgrel' \
      'sub_pkgrel' \
      'architecture' \
      'sub_pkgrel_omitted'
    printf 'CONCAT(`binary_packages`.`pkgname`,"-shim"),'
    printf '0,0,"%s"' \
      "$(
        sha512sum "${tmp_dir}/${shim_package##*/}" \
          | awk '{print $1}'
      )"
    printf ' FROM `binary_packages`'
    printf ' WHERE `binary_packages`.`id`=%s' \
      "${original_pkg_id}"
    printf ' LIMIT 1;\n'
    printf 'SET @`new_package_id`=LAST_INSERT_ID();\n'
    printf 'INSERT INTO `binary_packages_in_repositories` (`package`,`repository`,`is_to_be_deleted`)'
    printf ' SELECT @`new_package_id`,`repositories`.`id`,0'
    printf ' FROM `repositories`'
    mysql_join_repositories_architectures
    printf ' WHERE `repositories`.`name`="build-support"'
    printf ' AND `architectures`.`name`=from_base64("%s");\n' \
      "$(
        printf '%s' "${repo_arch}" \
          | base64 -w0
      )"
    printf 'INSERT INTO `install_target_providers` (`package`,`install_target`,`version`,`install_target_is_group`)'
    printf ' SELECT @`new_package_id`'
    printf ',`install_target_providers`.`%s`' \
      'install_target' \
      'version' \
      'install_target_is_group'
    printf ' FROM `install_target_providers`'
    printf ' WHERE `install_target_providers`.`package`=%s;\n' \
      "${original_pkg_id}"
    # TODO: maybe add (some?) depends here, too?
  } | \
    mysql_run_query

  failsafe_rsync \
    "${tmp_dir}/${shim_package##*/}" \
    "${tmp_dir}/${shim_package##*/}.sig" \
    "${master_mirror_rsync_directory}/pool/"

  rm \
    "${tmp_dir}/${shim_package##*/}" \
    "${tmp_dir}/${shim_package##*/}.sig"
  ln -s "../../pool/${shim_package##*/}" "${tmp_dir}/${shim_package##*/}"
  ln -s "../../pool/${shim_package##*/}.sig" "${tmp_dir}/${shim_package##*/}.sig"

  failsafe_rsync \
    "${tmp_dir}/${shim_package##*/}" \
    "${tmp_dir}/${shim_package##*/}.sig" \
    "${tmp_dir}/build-support.db."* \
    "${tmp_dir}/build-support.files."* \
    "${master_mirror_rsync_directory}/${repo_arch}/build-support/"

  rm\
    "${shim_package}" \
    "${shim_package}.sig"

else
  >&2 echo 'Need either --from or --shim.'
  usage
fi