#!/bin/bash

# init variables
tmpDir="$(mktemp -d ~/tmp.archive.XXXXXX)"
trap 'rm -rf --one-file-system "${tmpDir}"' EXIT
pkgDir='/srv/http/vhosts/eckner.net/archlinuxewe/os'
pkgDir32Mount='/mnt/mirror.archlinux32.org'
pkgDir32="${pkgDir32Mount}/x86_64/releng"
pkgSrcDir=$(dirname $(readlink -f -n "$0"))
submoduleDir=$(readlink -f -n "${pkgSrcDir}/../submodules")
export SRCDEST="${HOME}/packageSources"
export PACKAGER='Erich Eckner <arch at eckner dot net>'
key='5FDCA472AB93292BC678FD59255A76DB9A12601A'
branch="HEAD"
force=false
upload=true
abortOnMakepkgError=true
cleanChroot=''
cleanUnsigned=false
checkDbSig='-v'
checkMakepkg='--check'
checkSanity=true
rmAddPkgs=false
log=''
logFile='-'
printOnly=false
myArch=$(
  pacman-conf Architecture
)

# print help screen
usage()
{
  >&2 echo ''
  >&2 echo 'Skript zum Updaten der selbsterstellten Archlinux-Pakete'
  >&2 echo ''
  >&2 echo 'Optionen:'
  >&2 echo '    --arch $arch:'
  >&2 echo '      only compile for $arch'
  >&2 echo '    -b|--branch [commitish]:'
  >&2 echo '      branch to check out - defaults to "HEAD"'
  >&2 echo '    -c|--cleanChroot:'
  >&2 echo '      clean chroot before building'
  >&2 echo '    --cleanUnsigned:'
  >&2 echo '      remove unsigned Packages first'
  >&2 echo '    -f|--force:'
  >&2 echo '      rebuild packages even if they look up to date'
  >&2 echo '    --ignore-wrong-db-signature:'
  >&2 echo '      do not verify old database signature'
  >&2 echo '    -L|--log file:'
  >&2 echo '      generate logfile of makepkg-runs ("-" as file autogenerates name)'
  >&2 echo '    --no-abortOnMakepkgError:'
  >&2 echo '      do not abort when makepkg returns non-zero'
  >&2 echo '    --no-check:'
  >&2 echo '      pass --nocheck to makepkg'
  >&2 echo '    --no-sanity-check:'
  >&2 echo '      skip check for sanity of packages'
  >&2 echo '    --no-upload:'
  >&2 echo '      do not upload built packages from rechenknecht to jeti100'
  >&2 echo '    --only $package:'
  >&2 echo '      only consider $package for build and update process'
  >&2 echo '    -p|--print-only:'
  >&2 echo '      only print what would be done'
  >&2 echo ''
  exit 1
}

# clean up before exit
cleanUp () {
  if [ -n "${log}" ]; then
    [ "a${logFile}" == 'a-' ] && logFile="/tmp/$(date '+%F-%H-%M-%S')"
    [[ "${logFile}" == *".tar.gz" ]] || logFile="${logFile}.tar.gz"
    cd "${tmpDir}"
    logFiles=$(
      for s in */*.log; do
        [ -r "${s}" ] && echo "${s}"
      done
    )
    if [ -n "${logFiles}" ]; then
      tar -czf "${logFile}" ${logFiles}
      echo 'Logfiles saved to "'"${logFile}"'".'
    fi
  fi
}

send_build_status() {
  if [ $1 -eq 0 ]; then
    curl -X DELETE -Ss "https://arch.eckner.net/buildreport.php?arch=$2&paket=$3&result=success"
  else
    if [ -n "$4" ]; then
      zcat "$4"
    else
      tar -cf - *.log
    fi \
    | xz \
    | curl -Ss -T - "https://arch.eckner.net/buildreport.php?arch=$2&paket=$3&result=error"
  fi
}

echo 'parse arguments ...'
eval set -- "$(
  getopt -o b:cfL:pr \
    --long arch: \
    --long branch: \
    --long cleanChroot \
    --long cleanUnsigned \
    --long force \
    --long ignore-wrong-db-signature \
    --long log: \
    --long no-abortOnMakepkgError \
    --long no-check \
    --long no-sanity-check \
    --long no-upload \
    --long only: \
    --long print-only \
    --long removeAdditionalPackages \
    -n "$(basename "$0")" \
    -- "$@" \
    || echo "usage"
)"
args=("$@")

while true; do
  case $1 in
    --arch)
      shift
      echo '"arch '"$1"'" erkannt'
      onlyArchs[${#onlyArchs[@]}]="$1"
    ;;
    -b|--branch)
      shift
      branch="$1"
      echo '"branch '"${branch}"'" erkannt'
    ;;
    -c|--cleanChroot)
      echo '"cleanChroot" erkannt'
      cleanChroot='-c'
    ;;
    --cleanUnsigned)
      echo '"cleanUnsigned" erkannt'
      cleanUnsigned=true
    ;;
    -f|--force)
      echo '"force" erkannt'
      force=true
    ;;
    --ignore-wrong-db-signature)
      echo '"ignore-wrong-db-signature" erkannt'
      checkDbSig=''
    ;;
    -L|--log)
      shift
      log='-L'
      logFile="$1"
      echo '"log '"${logFile}"'" erkannt'
    ;;
    --no-abortOnMakepkgError)
      echo '"no-abortOnMakepkgError" erkannt'
      abortOnMakepkgError=false
    ;;
    --no-check)
      echo '"no-check" erkannt'
      checkMakepkg='--nocheck'
    ;;
    --no-sanity-check)
      echo '"no-sanity-check" erkannt'
      checkSanity=false
    ;;
    --no-upload)
      echo '"no-upload" erkannt'
      upload=false
    ;;
    --only)
      shift
      echo '"only '"$1"'" erkannt'
      onlyPackages[${#onlyPackages[@]}]="${1%/}"
    ;;
    -p|--print-only)
      echo '"print-only" erkannt'
      printOnly=true
    ;;
    -r|--removeAdditionalPackages)
      echo '"removeAdditionalPackages" erkannt'
      rmAddPkgs=true
    ;;
    --)
      shift
      break
    ;;
    *)
      >&2 echo "FEHLER: Verstehe Option \"$1\" doch nicht! Ich beende."
      exit 1
  esac
  shift
done

if [ ! $# -eq 0 ]; then
  >&2 printf 'FEHLER: Zu viele (%s) Argumente:\n' "$#"
  >&2 printf '"%s"\n' "$@"
  >&2 echo 'Ich beende.'
  usage
fi

if ! ${checkSanity}; then
  if ${upload} && ! ${printOnly}; then
    >&2 echo 'FEHLER: "--no-sanity-check" geht nur zusammen mit "--no-upload" oder "--print-only"! Ich beende.'
    exit 1
  fi
fi

echo '... done'

# extract git ${branch}
git -C "${pkgSrcDir}" archive --format tar "${branch}" | \
  tar -x -C "${tmpDir}" -f -
git -C "${pkgSrcDir}" diff '6dc373759d940181bcb2a742f1f37548a7c1cacc' "${branch}" -- $(
  sed '
    s/^\[submodule "\([^"[:space:]]\+\)"\]$/\1/
    t
    d
  ' "${tmpDir}/.gitmodules"
) \
| sed '
  /^+++ b/ {
    N
    N
    s#^+++ b/\(\S\+\)\n@@ -0,0 +1 @@\n+Subproject commit \([0-9a-f]\{40\}\)$#\1 \2#
    t
  }
  d
' \
| while read -r module commit; do
  rmdir "${tmpDir}/${module}"
  echo "${commit}" >"${tmpDir}/${module}"
done

cd "${tmpDir}"

# clean unsigned packages
if ${cleanUnsigned}; then
  ssh archlinuxewe@eckner.net "$(
    printf '
      rmPaket() {
        if [ "$(basename "$(pwd)")" != "any" ]; then
          if [ "$(basename "$(pwd)")" == "releng" ]; then
            repo-remove releng.db.tar.gz "${1%%-*-*-*.pkg.tar.*}"
          else
            repo-remove %s -s -k 0x3CFB0AD8F60030F8 archlinuxewe.db.tar.gz "${1%%-*-*-*.pkg.tar.*}"' \
      "${checkDbSig}"
    printf '
          fi
        fi
        rm "$1"
        [ -e "$1.sig" ] && rm "$1.sig"
        [ -h "$1.sig" ] && rm "$1.sig"
      }'

    printf '
      mount "%s"' "${pkgDir32Mount}"

    printf '
      for arch in %s/* %s; do' \
      "${pkgDir}" "${pkgDir32}"
    printf '
        [ -d "${arch}" ] || continue
        cd "${arch}"
        for paket in *.pkg.tar.xz *.pkg.tar.zst; do
          [ ! -e "${paket}" ] && [ ! -h "${paket}" ] && continue
          [ -e "${paket}.sig" ] && continue
          [ -h "${paket}.sig" ] && continue
          rmPaket "${paket}"
        done
      done
      date +%%s > %s/../lastupdate' \
      "${pkgDir}"
    printf '
      fusermount3 -u "%s"' "${pkgDir32Mount}"
  )"
fi

unset pakete
unset pakete_teile_und_archs
unset archs
unset verss
unset repos

if [ -f '.gitmodules' ]; then
  >&2 printf 'updating submodules ...'
  sed -n '
    /^\s*path = /{
      N
      s, gitolite@eckner\.net:aur/, https://git.eckner.net/aur/,
      Tkein_aur
      s/\.git$//
      :kein_aur
      s/^\s*path = //
      s/\n\s*url = / /
      p
    }
  ' '.gitmodules' \
  | parallel -j0 "${tmpDir}/update-submodule" "${pkgSrcDir}" "${submoduleDir}"
  >&2 printf ' done.\n'
fi

# check packages
if ${checkSanity}; then

  err=false

  namcap */PKGBUILD || err=true

  for paket in *; do
    [ -r "${paket}/PKGBUILD" ] || continue

    if ! grep -q "^# Maintainer\s*:\s\+Erich Eckner\s\+<arch at eckner dot net>\$" "${paket}/PKGBUILD" || \
      grep "^# Maintainer\s*:" "${paket}/PKGBUILD" | \
        grep -vq "^# Maintainer\s*:\s\+Erich Eckner\s\+<arch at eckner dot net>\$"; then
      >&2 echo "${paket}/PKGBUILD hat falsche(n) Maintainer"
      if grep -qxF '[submodule "'"${paket}"'"]' '.gitmodules'; then
        continue
      fi
      err=true
    fi

  done
  if ${err}; then
    exit 1
  fi

fi

if ${force}; then
  available_packages=''
else
  available_packages=$(
    {
      curl -Ss 'https://arch.eckner.net/os/' \
      | sed '
        s@^.*<a href="\([^/"]\+\)/">\1/</a>.*$@\1@
        /^\.\.$/d
        /^any$/d
        t
        d
      ' \
      | while read -r arch; do
        curl -Ss 'https://arch.eckner.net/os/'"${arch}"'/archlinuxewe.db.tar.gz' \
        | tar -Oxzf - \
        | sed -n '
          /^%FILENAME%$/ {
            N
            s@^%FILENAME%\n@archlinuxewe/'"${arch}"'/@
            T
            p
          }
        '
      done
      curl -Ss 'https://mirror.archlinux32.org/x86_64/releng/releng.db.tar.gz' \
      | tar -Oxzf - \
      | sed '
        /^%FILENAME%$/ {
          N
          s@^%FILENAME%\n@releng/x86_64/@
          t
        }
        d
      '
    } \
    | sed '
      s@^\([^/]\+/\)[^/]\+\(/[^/]\+-any\.pkg\.tar\.\(xz\|zst\)\)$@\0\n\1any\2@
    ' \
    | sed '
      s@^\(\S\+\)-\([^-]\+-[^-]\+\)-\([^-]\+\)$@\2 \1-\3@
    ' \
    | sort -k2,2 -u
  )
fi

# collect packages
for paket in $( \
  echo */PKGBUILD | \
    sed "s|/PKGBUILD||g" \
  ); do
  [ -d "${paket}" ] || continue
  [ ${#onlyPackages[@]} -eq 0 ] && consider=true || consider=false
  for ((i=0; i<${#onlyPackages[@]}; i++)); do
    [[ "${paket}" == "${onlyPackages[${i}]%:*}" ]] && consider=true
  done
  ${consider} || continue

  unset epoch
  unset pkgname
  unset arch
  . "${paket}/PKGBUILD"
  if grep -q '#\s*repo:\s*releng\s*\(#.*\)\?$' "${paket}/PKGBUILD"; then
    repo='releng'
  else
    repo='archlinuxewe'
  fi

  missing_archs=$(
    for pkgnam in "${pkgname[@]}"; do
      archs=$(
        declare -f package_${pkgnam} | \
          sed -n '
            s/^\s*arch=(\(.\+\));$/\1/
            T
            s/["'"'"']//g
            y/ /\n/
            p
          ' | \
          grep -xF 'any' || \
          printf '%s\n' "${arch[@]}"
      )

      for singleArch in ${archs}; do

        [ "${singleArch}" == "x86_64" ] || \
          [ "${singleArch}" == "pentium4" ] || \
          [ "${singleArch}" == "i486" ] || \
          [ "${singleArch}" == "i686" ] || \
          [ "${singleArch}" == "armv6h" ] || \
          [ "${singleArch}" == "armv7h" ] || \
          [ "${singleArch}" == "aarch64" ] || \
          [ "${singleArch}" == "any" ] || \
          continue

        pkgFile_a="${epoch:+${epoch}:}${pkgver}-${pkgrel}"
        pkgFile_b="${repo}/${singleArch}/${pkgnam}-${singleArch}.pkg.tar.zst"
        if printf '%s\n' \
            "${available_packages}" \
          | cut -d' ' -f2 \
          | grep -qxF "${pkgFile_b}" \
          && printf '%s\n' \
            "${available_packages}" \
            "${pkgFile_a} ${pkgFile_b}" \
          | sort -k2,2 -k1V,1 \
          | uniq -df1 \
          | grep -qxF "${pkgFile_a} ${pkgFile_b}" \
          && ! ${force}; then
          continue
        fi
        printf '%s\n' "${singleArch}"

      done

    done | \
      sort -u
  )
  if [ ${#onlyArchs[@]} -ne 0 ]; then
    missing_archs=$(
      printf '%s\n' "${missing_archs}" | \
        grep -xF "$(printf '%s\n' "${onlyArchs[@]}")"
    )
  fi
  if [ ${#onlyPackages[@]} -ne 0 ]; then
    unset tmpOnlyArchs
    for ((i=0; i<${#onlyPackages[@]}; i++)); do
      [[ "${paket}" == "${onlyPackages[${i}]%:*}" ]] || continue
      [ -z "${onlyPackages[${i}]%%*:*}" ] || continue
      tmpOnlyArchs[${#tmpOnlyArchs[@]}]="${onlyPackages[${i}]##*:}"
    done
    if [ ${#tmpOnlyArchs[@]} -ne 0 ]; then
      missing_archs=$(
        printf '%s\n' "${missing_archs}" 2>/dev/null | \
          grep -xF "$(printf '%s\n' "${tmpOnlyArchs[@]}")"
      )
    fi
  fi

  if [ -n "${missing_archs}" ]; then
    for singleArch in ${missing_archs}; do
      if ! printf '%s\n' "${arch[@]}" | \
        grep -qxF "${singleArch}"; then
        continue
      fi
      pakete[${#pakete[@]}]="${paket}"
      pakete_teile_und_archs[${#pakete_teile_und_archs[@]}]=$(
        for pn in "${pkgname[@]}"; do
          printf '%s:%s\n' \
            "$(
              declare -f package_${pn} | \
                sed -n '
                  s/^\s*arch=(\(.\+\));$/\1/
                  T
                  s/["'"'"']//g
                  y/ /\n/
                  p
                ' | \
                grep -xF 'any' || \
                printf '%s' "${singleArch}"
            )" \
            "${pn}" \
          | if [ "${singleArch}" != 'any' ] \
            && [ "${singleArch}" != 'x86_64' ]; then
            sed '/^any:/d'
          else
            cat
          fi
        done
      )
      archs[${#archs[@]}]="${singleArch}"
      verss[${#verss[@]}]="${epoch:+${epoch}:}${pkgver}-${pkgrel}"
      if [ "${repo}" != 'archlinuxewe' ]; then
        repos[${#repos[@]}]="${repo} archlinuxewe"
      else
        repos[${#repos[@]}]="${repo}"
      fi
    done
  fi
done

# only print packages to be built?
if ${printOnly}; then
  printf '%d scheduled builds:\n' "${#pakete[@]}"
  for ((i=0; i<${#pakete[@]}; i++)); do
    echo " ${pakete[${i}]} ${verss[${i}]} ${archs[${i}]}"
    printf '   %s\n' ${pakete_teile_und_archs[${i}]}
  done
  exit 0
fi

maxErr=0

# build packages
for ((i=0; i<${#pakete[@]}; i++)); do
  paket="${pakete[${i}]}"
  paket_teile_und_archs=(${pakete_teile_und_archs[${i}]})
  arch="${archs[${i}]}"
  vers="${verss[${i}]}"
  repo="${repos[${i}]}"

  cd "${tmpDir}/${paket}"
  rm -rf --one-file-system src pkg

  if ! grep -qwF _patch_PKGBUILD PKGBUILD; then

    # add PKGBUILD-patches to the PKGBUILD
    if grep -q '^\s*pkgbase=' PKGBUILD; then
      (
        eval "$(
          sed -n '/^\s*pkgname=(/,/)/ p' PKGBUILD
        )"
        printf 'package_%s\n' "${pkgname[@]}"
      )
    else
      printf 'package\n'
    fi \
    | sponge \
    | while read -r function; do
      sed -i '
        /^'"${function}"'() {$/,/^}$/ {
          /^}$/ i _patch_PKGBUILD
        }
      ' PKGBUILD
    done
    {
      echo '_patch_PKGBUILD() {'
      ls -1 "${tmpDir}/"*".PKGBUILDpatch" \
      | grep -vxF "$(
        sed '
          s,^# skip \(\S\+\)\(\s\|$\).*$,'"${tmpDir}"'/\1.PKGBUILDpatch,
          t
          d
        ' PKGBUILD
      )" \
      | xargs -r cat
      echo ':'
      echo '}'
    } \
    >> PKGBUILD
  fi

  case "${arch}" in
    'any'|'i486'|'i686'|'pentium4'|'x86_64'|"${myArch}")
      if [ -n "${cleanChroot}" ]; then
        build_mode='archbuild'
      elif sed -n '
        /^conflicts=(/ {
          :a
          /)/ ! {
            N
            $! ba
          }
          p
        }
      ' PKGBUILD \
      | grep -qwF "$(
        pacman -Qqg base-devel
        pacman -Qi base \
        | sed -n '
          /^Depends On\s*:/,/^\S/ {
            s/^Depends On\s*:/ /
            /^\S/d
            p
          }
        ' \
        | tr ' ' '\n' \
        | sort -u \
        | grep -vxF ''
      )"; then
        build_mode='makechrootpkg'
      else
        build_mode='archbuild'
      fi
      if [ "${build_mode}" = 'archbuild' ]; then
        archlinuxewe-${arch/any/${myArch}}-build ${cleanChroot} -- -- ${log} ${checkMakepkg} --holdver
      else
        makechrootpkg -r "/var/lib/archbuild/archlinuxewe-${arch/any/${myArch}}" -- ${log} ${checkMakepkg} --holdver -f
      fi
      send_build_status "$?" "${arch}" "${paket}"
      find . -mindepth 1 -maxdepth 1 -type f -name '*.pkg.tar' -exec zstd --rm {} \;
      err[${i}]=$?
      if [ ${err[${i}]} -eq 0 ]; then
        if [ "${arch}" = 'i486' ] \
        || [ "${arch}" = 'i686' ] \
        || [ "${arch}" = 'pentium4' ]; then
          {
            printf '%s\n' \
              "From: plasmapaule@gmail.com" \
              "To: buildmaster@archlinux32.org" \
              "Subject: $(uname -n) - report about installed ${arch} packages" \
              ""
            find . \
              -mindepth 1 \
              -maxdepth 1 \
              -name '*.pkg.tar.zst' \
              -exec bsdtar -Oxf {} .BUILDINFO \; \
            | sed '
              s@^installed = \(.*\)$@/var/cache/archbuild32/\1.pkg.tar.zst@
              t
              d
            ' \
            | xargs -r sha512sum \
            2>/dev/null \
            | sed '
              s@\s\+.*/@ @
              s/^/stabilize: /
            '
          } | \
            sendmailadvanced -t
        fi
      fi
    ;;
    'armv6h'|'armv7h'|'aarch64')
      # armv6h & armv7h & aarch64 is built on the raspberry pis
      PKGEXT=".pkg.tar.zst" SRCPKGDEST="${tmpDir}" makepkg --allsource -f
      err[${i}]=$?
      if [ ${err[${i}]} -eq 0 ]; then
        ssh makepkg@${arch}.builder "$(
          printf 'set -e\n'
          printf 'rm -rf --one-file-system build/*\n'
          printf 'cd build\n'
          printf 'tar -xzf -\n'
          printf 'cd "%s"\n' "${paket}"
          printf 'export %s="%s"\n' \
            'SRCDEST' '${HOME}/packageSources' \
            'PACKAGER' "${PACKAGER}"
          printf 'archlinuxewe-%s-build %s -- -- -- %s >&2 || {\n' \
            "${arch}" \
            "${cleanChroot}" \
            "${log} ${checkMakepkg}"
          printf 'err=$?\n'
          printf 'tar -czf - *.log\n'
          printf 'exit ${err}\n'
          printf '}\n'
          printf 'tar -czf - *.pkg.tar'
          [ -n "${log}" ] && \
            printf ' *.pkg.tar-*.log'
          printf '\n'
        )" \
        < "${tmpDir}/${paket}-${vers}.src.tar.gz" \
        > "paket.tar.gz"
        err[${i}]=$?
        send_build_status "${err[${i}]}" "${arch}" "${paket}" "paket.tar.gz"
        if [ ${err[${i}]} -eq 0 ]; then
          tar -xzvf paket.tar.gz \
          | sed '
            s/^.*\.pkg\.tar$/\0 \0.zst/
            t
            s/^\(.*\.pkg\.tar\)\(-.*\.log\)$/\0 \1.zst\2/
            t
            s/^.*$/unknown file "\0" in packages tar cannot be compressed/
            w /dev/stderr
            d
          ' \
          | while read -r file cfile; do
            zstd "${file}" -o "${cfile}"
            rm "${file}"
          done
        fi
      fi
    ;;
    *)
      printf 'unbekannte Architektur "%s"\n' "${arch}"
      err[${i}]=128
    ;;
  esac
  for teil_und_arch in "${paket_teile_und_archs[@]}"; do
    if [ ${err[${i}]} -ne 0 ]; then
      break
    fi
    teil="${teil_und_arch#*:}"
    teil_arch="${teil_und_arch%%:*}"
    namcap "${tmpDir}/${paket}/${teil}-${vers}-${teil_arch}.pkg.tar.zst" > \
      "${tmpDir}/namcap"
    err[${i}]=$?
    if [ -n "${log}" ]; then
      cat "${tmpDir}/namcap" > \
        "${tmpDir}/${paket}/${teil}-namcap-${arch}.log"
    fi
    if [ ${err[${i}]} -ne 0 ]; then
      sed 's/^/namcap: /' "${tmpDir}/namcap"
      find "${tmpDir}/${paket}" \
      | sed 's/^/files:  /'
      break
    fi
    if grep "$(
      {
        printf '%s\\|' \
          "E: ELF file (.*) found in an ['\"]any['\"] package"
        if ! grep -qF " ${teil} ist absichtlich nicht any ohne ELF Dateien" PKGBUILD \
        && ! grep -qF " ist alles absichtlich nicht any ohne ELF Dateien" PKGBUILD; then
          printf '%s\\|' \
            "W: No ELF files and not an ['\"]any['\"] package"
        fi
      } | \
        sed 's@\\|$@@'
      )" "${tmpDir}/namcap"; then
      err[${i}]=64
    fi
  done
  rm -f "${tmpDir}/namcap"
  if ${abortOnMakepkgError} && [ ${err[${i}]} -ne 0 ]; then
    cleanUp
    exit ${err[${i}]}
  fi
  [ ${err[${i}]} -gt ${maxErr} ] && maxErr=${err[${i}]}

  for teil_und_arch in "${paket_teile_und_archs[@]}"; do
    teil="${teil_und_arch#*:}"
    teil_arch="${teil_und_arch%%:*}"
    gpg --detach-sign -u "${key}" --no-armor ${teil}-${vers}-${teil_arch}.pkg.tar.zst
  done

  # upload package and update db
  if ${upload} && [ ${err[${i}]} -eq 0 ]; then

    cd "${tmpDir}/${paket}"
    printf '%s\n' "${paket_teile_und_archs[@]%%:*}" | \
      sort -u | \
      while read -r arch; do
        if [ "${paket}" = 'pacman-static' ] && \
          [ "${arch}" = 'i686' ] && \
          false; then
          tar -OxJf "${paket_teile_und_archs[0]#*:}" usr/bin/pacman-static 2>/dev/null > /srv/arch-mirror/sources.archlinux32/sources/pacman-static
          gpg --detach-sign -u "${key}" --yes --no-armor /srv/arch-mirror/sources.archlinux32/sources/pacman-static
        fi

        paket_teile=(
          $(
            printf '%s\n' "${paket_teile_und_archs[@]}" | \
              sed -n '
                s/^'"${arch}"'://
                T
                p
              '
          )
        )
        tar -cf - $(
          printf " %s-${vers}-${arch}.pkg.tar.zst"     "${paket_teile[@]}"
          printf " %s-${vers}-${arch}.pkg.tar.zst.sig" "${paket_teile[@]}"
        ) | \
          ssh archlinuxewe@eckner.net "$(

            printf 'tmp_archive=$(mktemp)\n'
            printf 'mount "%s"\n' \
              "${pkgDir32Mount}"
            printf 'cat > "${tmp_archive}"\n'
            printf 'trap "rm ${tmp_archive}; fusermount3 -u %s" EXIT\n' \
              "${pkgDir32Mount}"

            printf '
              entferneAltePakete() {
                altePakete=$(
                  ls -1 | \
                    grep "^$1-[^-]\+-[^-]\+-$2\.pkg\.tar\.\(xz\|zst\)\$"
                )
                if [ -n "${altePakete}" ]; then
                  if [ "$(basename "$(pwd)")" != "any" ]; then
                    if [ "$(basename "$(pwd)")" == "releng" ]; then
                      repo-remove releng.db.tar.gz "$1"
                    else
                      repo-remove %s -s -k 0x3CFB0AD8F60030F8 archlinuxewe.db.tar.gz "$1"' \
              "${checkDbSig}"
            printf '
                    fi
                  fi
                  for altesPaket in ${altePakete}; do
                    rm "${altesPaket}"
                    if [ -e "${altesPaket}.sig" ] || [ -h "${altesPaket}.sig" ]; then
                      rm "${altesPaket}.sig"
                    fi
                  done
                fi
              }'

            printf '
              addPaket() {
                if [ "$(basename "$(pwd)")" == "releng" ]; then
                  repo-add releng.db.tar.gz "$1"
                else
                  repo-add %s -s -k 0x3CFB0AD8F60030F8 archlinuxewe.db.tar.gz "$1"
                fi
              }' \
              "${checkDbSig}"

            for r in ${repo}; do
              if [ "${r}" = 'releng' ]; then
                printf '
                cd "%s"' \
                  "${pkgDir32}"
              else
                printf '
                cd "%s/%s"' \
                  "${pkgDir}" "${arch}"
              fi
              printf '
                for teil in %s; do' \
                "${paket_teile[*]}"
              printf '
                  entferneAltePakete "${teil}" "%s"' \
                "${arch}"
              printf '
                done'

              printf '
                tar -xf "${tmp_archive}"
                for teil in %s; do' \
                "${paket_teile[*]}"

              if [ "${arch}" == "any" ] && [ "${r}" != 'releng' ]; then
                printf '
                  for lArch in $(ls ..); do
                    [ ! -d "../${lArch}" ] && continue
                    [ "${lArch}" == "any" ] && continue
                    cd "../${lArch}"

                    entferneAltePakete "${teil}" "any"'
                printf '
                    ln -s "../any/${teil}-%s-%s.pkg.tar.zst" "${teil}-%s-%s.pkg.tar.zst"' \
                  "${vers}" "${arch}" "${vers}" "${arch}"
                printf '
                    if [ -e "%s/any/${teil}-%s-%s.pkg.tar.zst.sig" ]' \
                  "${pkgDir}" "${vers}" "${arch}"
                printf '; then
                      ln -s "../any/${teil}-%s-%s.pkg.tar.zst.sig" "${teil}-%s-%s.pkg.tar.zst.sig"' \
                  "${vers}" "${arch}" "${vers}" "${arch}"
                printf '
                    fi
                    addPaket "${teil}-%s-%s.pkg.tar.zst"' \
                  "${vers}" "${arch}"
                printf '
                  done'
              else
                printf '
                  addPaket "${teil}-%s-%s.pkg.tar.zst"' \
                  "${vers}" "${arch}"
              fi
              printf '
                done'
            done
            printf '
              date +%%s > "%s/../lastupdate"' \
              "${pkgDir}"
          )"
      done
  fi
done

# check db
if ${upload}; then
  ssh archlinuxewe@eckner.net "$(
    printf '
      err=0

      mount "%s"' \
      "${pkgDir32Mount}"
    printf '

      for arch in %s/* %s' \
      "${pkgDir}" "${pkgDir32}"
    printf '; do
        [ ! -d "${arch}" ] && continue
        [ "${arch##*/}" == "any" ] && continue

        for paketFehler in $( \
          (
            if [ "$(basename "${arch}")" == 'releng' ]; then
              tar -Oxzf "${arch}/releng.db.tar.gz"
            else
              tar -Oxzf "${arch}/archlinuxewe.db.tar.gz"
            fi | \
              grep -A1 "^%%FILENAME%%\$" | \
              grep -v "^%%FILENAME%%\$" | \
              grep -v -- "^--\$"
            ls "${arch}" | \
              grep "^.*\.pkg\.tar\.\(xz\|zst\)\$"
          ) | \
            sort | \
            uniq -u
        ); do

          err=1
          if [ -e "${arch}/${paketFehler}" ]; then
            >&2 echo "FEHLER: Paket ${arch}/${paketFehler} ist nur im Verzeichnisbaum vorhanden."
          else
            >&2 echo "FEHLER: Paket ${arch}/${paketFehler} ist nur in der Datenbank vorhanden."
          fi

        done

        for signaturWarnungen in $( \
          ls "${arch}" | \
            grep "^.*\.pkg\.tar\.\(xz\|zst\)\(\.sig\)\?\$" | \
            sed "s|\.sig\$||" | \
            sort | \
            uniq -u
        ); do

          if [ -e "${arch}/${signaturWarnungen}" ]; then
            >&2 echo "WARNUNG: Paket ${arch}/${signaturWarnungen} hat keine Signatur."
          else
            err=1
            >&2 echo "FEHLER: Zur Signatur ${arch}/${signaturWarnungen}.sig gibt es kein Paket."
          fi

        done

      done

      fusermount3 -u "%s"' \
      "${pkgDir32Mount}"
    printf '

      exit ${err}'
  )"
fi

cleanUp
exit ${maxErr}