#!/bin/bash

# init variables
tmpDir="$(mktemp -d /tmp/archive.XXXXXX)"
pkgDir="/srv/arch-mirror/arch/arch/archlinuxewe/os"
pkgSrcDir="$(dirname $(readlink -f -n "$0"))"
[ "$(hostname)" == "rechenknecht" ] && \
  [ "${pkgSrcDir}" == "${HOME}" ] && \
    aufRechenknecht=true || \
    aufRechenknecht=false
force=false
upload=true
updateMe=true
abortOnMakepkgError=true
cleanUnsigned=false

# print help screen
usage()
{
  >&2 echo ''
  >&2 echo 'Skript zum Updaten der selbsterstellten Archlinux-Pakete'
  >&2 echo ''
  >&2 echo 'Verwendung:'
  >&2 echo '  '"$0"' [ -f|--force ] [ --no-upload ] [ --no-selfUpdate ] [ --no-abortOnMakepkgError ] [ -c|--cleanUnsigned ]'
  >&2 echo '    -f|--force:                rebuild packages even if they look up to date'
  >&2 echo '    --no-upload:               do not upload built packages from rechenknecht to jeti100'
  >&2 echo '    --no-selfUpdate:           do not update this script from git'
  >&2 echo '    --no-abortOnMakepkgError:  do not abort when makepkg returns non-zero'
  >&2 echo '    -c|--cleanUnsigned:        remove unsigned Packages first'
  >&2 echo ''
  rm -rf "${tmpDir}"
  exit 1
}

echo 'parse arguments ...'
eval set -- "$(getopt -o fc --long force,no-upload,no-selfUpdate,no-abortOnMakepkgError,cleanUnsigned -n "$(basename "$0")" -- "$@" || echo "usage")"
args=("$@")

while true
do
  case $1 in
    -f|--force)
      echo '"force" erkannt'
      force=true
      shift
    ;;
    -c|--cleanUnsigned)
      echo '"cleanUnsigned" erkannt'
      cleanUnsigned=true
      shift
    ;;
    --no-upload)
      echo '"no-upload" erkannt'
      upload=false
      shift
    ;;
    --no-selfUpdate)
      echo '"no-selfUpdate" erkannt'
      updateMe=false
      shift
    ;;
    --no-abortOnMakepkgError)
      echo '"no-abortOnMakepkgError" erkannt'
      abortOnMakepkgError=false
      shift
    ;;
    --)
      shift
      break
    ;;
    *)
      >&2 echo "FEHLER: Verstehe Option \"$1\" doch nicht! Ich beende."
      rm -rf "${tmpDir}"
      exit 1
  esac
done

if [ ! $# -eq 0 ]
then
  >&2 echo 'FEHLER: Zu viele Argumente! Ich beende.'
  usage
fi

echo '... done'

$aufRechenknecht && pkgSrcDir="${pkgSrcDir}/archPackages"
cd "${pkgSrcDir}"

# extract git HEAD
git archive --format tar HEAD | \
  tar -x -C "${tmpDir}" -f -

cd "${tmpDir}"

# update $0
if ${updateMe} && ${aufRechenknecht} && [ -e "$(basename $0)" ] && ! diff -q "$(basename $0)" "$0" &> /dev/null
then
  cp "$(basename $0)" "$0"
  $0 "${args}"
  err=$?
  rm -rf "${tmpDir}"
  exit ${err}
fi

# clean unsigned packages
if ${cleanUnsigned} && ${aufRechenknecht}
then
  ssh paule@127.0.0.1 '
    rmPaket() {
      [ "$(basename "$(pwd)")" == "any" ] && return
      repo-remove -v -s -k 0x20194BA1 archlinuxewe.db.tar.gz "${1%-*-*-*.pkg.tar.xz}"
      rm "$1"
      [ -e "$1.sig" ] && rm "$1.sig"
    }

    cd "'${pkgDir}'"
    for arch in *
    do
      [ -d "${arch}" ] || continue
      cd "${arch}"
      for paket in *.pkg.tar.xz
      do
        [ -e "${paket}.sig" ] && continue
        rmPaket ${paket}
      done
      cd ..
    done
  '
fi

unset pakete
unset archs
unset verss

# collect packages
for paket in $( \
  echo */PKGBUILD | \
    sed "s|/PKGBUILD||g" \
  )
do
  [ -d "${paket}" ] || continue
  . ${paket}/PKGBUILD

  for singleArch in "${arch[@]}"
  do

    [ "${singleArch}" == "x86_64" ] || \
      [ "${singleArch}" == "i686" ] || \
      [ "${singleArch}" == "any" ] || \
      continue

    pkgFile="${paket}-${pkgver}-${pkgrel}-${singleArch}.pkg.tar.xz"

    allExist=true
    [ "${singleArch}" == "any" ] && \
      for dir in ${pkgDir}/*
      do
        [ "${dir}" == "any" ] && continue
        [ ! -d "${dir}" ] && continue
        [ ! -e "${dir}/${pkgFile}" ] && allExist=false
      done

    if ${force} || \
      ! ${aufRechenknecht} || \
      [ ! -e "${pkgDir}/${singleArch}/${pkgFile}" ] || \
      ! ${allExist}
    then
      pakete[${#pakete[@]}]="${paket}"
      archs[${#archs[@]}]="${singleArch}"
      verss[${#verss[@]}]="${pkgver}-${pkgrel}"
    fi
  done
done

if ${aufRechenknecht}
then
  maxErr=0

# generate current makepkg.conf and makepkg32.conf
  cd "${tmpDir}"
  cp /etc/makepkg.conf .
  patch -p0 -i makepkgSystem.patch
  cp makepkg{,32}.conf
  patch -p0 -i makepkg32.patch

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

    cd "${tmpDir}/${paket}"
    rm -f ${paket}-*-${arch}.pkg.tar.xz

    if [ "${arch}" == "i686" ]
    then
      # 32-bit is built in chroot
      echo '\
        sudo pacman -Sy && \
        cd "'"${tmpDir}/${paket}"'" && \
        _targetHost='\''--host=i686-pc-linux-gnu'\'' makepkg --config "'"${tmpDir}"'/makepkg32.conf" --sign -fcsr --noconfirm && \
        exit\
      ' | \
        chrootUnpriv
      err[${i}]=$?
    else
      # everything else is built directly
      sudo pacman -Sy
      makepkg --config "${tmpDir}/makepkg.conf" --sign -fcsr --noconfirm
      err[${i}]=$?
    fi
    if ${abortOnMakepkgError} && [ ${err[${i}]} -ne 0 ]
    then
      rm -rf "${tmpDir}"
      exit ${err[${i}]}
    fi
    [ ${err[${i}]} -gt ${maxErr} ] && maxErr=${err[${i}]}

    if ${upload} && [ ${err[${i}]} -eq 0 ]
    then

# upload package and update db
      cd "${tmpDir}/${paket}"
      tar -cf - ${paket}-${vers}-${arch}.pkg.tar.xz{,.sig} |
        ssh paule@127.0.0.1 '

          rmPaket() {
            [ "$(basename "$(pwd)")" == "any" ] && return
            repo-remove -v -s -k 0x20194BA1 archlinuxewe.db.tar.gz "${1%-*-*-*.pkg.tar.xz}"
            rm "$1"
            [ -e "$1.sig" ] && rm "$1.sig"
          }

          addPaket() {
            [ "$(basename "$(pwd)")" == "any" ] && return
            neu="$1"
            for alt in $(ls ${neu%-*-*-*.pkg.tar.xz}-*.pkg.tar.xz)
            do
              [ "${alt}" == "${neu}" ] && continue
              rmPaket "${alt}"
            done
            repo-add -v -s -k 0x20194BA1 archlinuxewe.db.tar.gz "${neu}"
          }

          cd '${pkgDir}/${arch}/'
          if [ -e "'${paket}-${vers}-${arch}.pkg.tar.xz'" ]
          then
            rmPaket "'${paket}-${vers}-${arch}.pkg.tar.xz'"
          fi
          tar -xf -
          addPaket "'${paket}-${vers}-${arch}.pkg.tar.xz'"

          if [ "'${arch}'" == "any" ]
          then
            cd ..
            for lArch in *
            do
              [ ! -d "${lArch}" ] && continue
              [ "${lArch}" == "any" ] && continue
              cd "${lArch}"

              if [ -e "'${paket}-${vers}-${arch}.pkg.tar.xz'" ]
              then
                rmPaket "'${paket}-${vers}-${arch}.pkg.tar.xz'"
              fi
              ln -s "'${pkgDir}/any/${paket}-${vers}-${arch}.pkg.tar.xz'" "'${paket}-${vers}-${arch}.pkg.tar.xz'"
              if [ -e "'${pkgDir}/any/${paket}-${vers}-${arch}.pkg.tar.xz.sig'" ]
              then
                ln -s "'${pkgDir}/any/${paket}-${vers}-${arch}.pkg.tar.xz.sig'" "'${paket}-${vers}-${arch}.pkg.tar.xz.sig'"
              fi
              addPaket "'${paket}-${vers}-${arch}.pkg.tar.xz'"

              cd ..
            done
          fi
        '
    fi
  done

# check db
  if ${upload}
  then
    ssh paule@127.0.0.1 '
      cd '${pkgDir}'
      err=0

      for arch in *
      do
        [ ! -d "${arch}" ] && continue
        [ "${arch}" == "any" ] && continue

        for paketFehler in $( \
          (
            tar -Oxzf '${pkgDir}'/${arch}/archlinuxewe.db.tar.gz | \
              grep -A1 "^%FILENAME%\$" | \
              grep -v "^%FILENAME%\$" | \
              grep -v -- "^--\$"
            ls '${pkgDir}'/${arch} | \
              grep "^.*\.pkg\.tar\.xz\$"
          ) | \
            sort | \
            uniq -u
        )
        do

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

        done

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

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

        done

      done

      exit ${err}
    '
  fi

  if [ ${maxErr} -ne 0 ]
  then
    rm -rf "${tmpDir}"
    exit ${maxErr}
  fi

else

  namcap */PKGBUILD

# check packages
  err=false
  for ((i=0; i<${#pakete[@]}; i++))
  do
    paket="${pakete[${i}]}"

    . ${paket}/PKGBUILD

    if echo "${source}" | grep -q "://opensources\.eckner\.net/"
    then

# one of Erich's packages

      remSum="$(curl -o - "${source#*::}&post=sha256sum" 2> /dev/null)"
      if [ ! "${remSum}" == "${sha256sums}" ]
      then
        >&2 echo "sha256sum von ${pkgname} stimmt nicht: ${remSum} vs. ${sha256sums}."
        err=true
      fi

    elif echo "${source}" | grep -q "://arch\.eckner\.net/"
    then

# a modified official package

      offVer="$( \
        ssh paule@jeti100 'ls '"${pkgDir}"'/*/'"${paket}"'-*.pkg.tar.xz' | \
          xargs -n1 basename | \
          sort -V | \
          tail -n1 \
        )"
      if [ ! "${offVer}" == "${pkgname}-${pkgver}-${pkgrel}-${arch}.pkg.tar.xz" ]
      then
        >&2 echo "${pkgname} ist in den offiziellen Quellen aktueller: ${offVer}."
        err=true
      fi

    fi

  done
  if ${err}
  then
    rm -rf "${tmpDir}"
    exit 1
  fi

  cd "${pkgSrcDir}"
  git push
  err=$?
  if [ ${err} -ne 0 ]
  then
    rm -rf "${tmpDir}"
    exit ${err}
  fi

  ssh -p 22222 141.35.51.219 "~/archPackagesUpdate" "${args}"
  err=$?
  if [ ${err} -ne 0 ]
  then
    rm -rf "${tmpDir}"
    exit ${err}
  fi
fi

# clean up
rm -rf "${tmpDir}"