#!/bin/sh

short_options='ot:p:i:e:k:'
long_options='print-output,trigger:,pin-packages:,run-id:,extra-apt-source:,signing-key:'

usage() {
  cat <<EOF
usage: debci test [OPTIONS] srcpkg

Options:
  -o, --print-output
      print output directory after test finished
  -t TRIGGER, --trigger TRIGGER
      Records TRIGGER as being the trigger for this test run. The trigger will
      be written to a file in the output directory, so that it can be retrieved
      later
  -p RELEASE=pkgname,src:srcname,...
  --pin-packages RELEASE=pkgname,src:srcname,...
      Force specific packages to be installed from the given RELEASE. The
      format is the same as the --pin-packages option from autopkgtest. RELEASE
      will be automatically added to the testbed APT sources.
  -i ID, --run-id ID
      Use the specific ID as the run id for this test run, instead of
      generating one based on the current date.
  -e apt-source, --extra-apt-source apt-source
      Add the given apt-source to /etc/apt/sources.list.d and update it.
  -k KEY, --signing-key KEY
      KEY is copied to /etc/apt/trusted.gpg.d/ inside the testbed to authorize secure extra-apt-source.
$@
EOF
}

set -eu

debci_base_dir=$(readlink -f $(dirname $(readlink -f $0))/..)
. $debci_base_dir/lib/environment.sh
. $debci_base_dir/lib/functions.sh

process_package() {
  local pkgname
  case "$pkg" in
    .*|*/*)
      # a local pathname
      if [ -d "$pkg" ]; then
        pkgname="$(basename $(readlink -f "$pkg"))"
      else
        echo "E: $pkg is not a valid package"
        exit 1
      fi
      ;;
    *)
      pkgname="$pkg"
      ;;
  esac

  # output directory for test-package/autopkgtest
  local base_dir="$(autopkgtest_incoming_dir_for_package "$pkgname")"

  if [ -n "${run_id:-}" ]; then
    adt_out_dir="${base_dir}/${run_id}"
  else
    run_id=$(date +%Y%m%d_%H%M%S)
    adt_out_dir="${base_dir}/${run_id}"

    inc=0
    orig_run_id="$run_id"
    while [ -d "$adt_out_dir" ]; do
      # this in *very* unlikely to happen in production, but we need this for the
      # test suite
      run_id="${orig_run_id}.${inc}"
      adt_out_dir="${base_dir}/${run_id}"
    done
  fi

  mkdir -p "$(dirname $adt_out_dir)"
  start_timestamp=$(date +%s)


  # these variables can be considered as an API by backends/*/test-package and
  # debci-autopkgtest
  export debci_suite
  export debci_arch
  export debci_autopkgtest_args
  export debci_test_package="$pkgname"
  export debci_test_outputdir="$adt_out_dir"


  ########################################################################
  # XXX This is a hack to handle the fact that the --add-apt-source option
  # has spaces in it. $options is separated by | with a bogus first item
  # (to avoid an empty first argument; it is split on | into "$@", then
  # the first item is discarded. "$@" is then used when calling the backend
  # test-package command
  ########################################################################
  old_IFS="$IFS"
  IFS='|'
  set -- $options
  shift
  IFS="$old_IFS"
  ########################################################################


  if [ "$debci_quiet" = 'true' ]; then
    test-package "$@" --output-dir "$adt_out_dir" "$pkg" \
      >/dev/null 2>&1 || true
  else
    test-package "$@" --output-dir "$adt_out_dir" "$pkg" || true
  fi

  if [ ! -d "$adt_out_dir" ]; then
    return
  fi

  finish_timestamp=$(date +%s)

  # remove redundant logs
  rm -f "${adt_out_dir}"/*-stdout
  rm -f "${adt_out_dir}"/*-stderr

  # cap main log
  log=${adt_out_dir}/log
  if [ -f "${log}" ]; then
    limit=20 # in MB
    limit_bytes=$((limit*1024*1024))
    total_size="$(stat --format=%s "${log}")"
    if [ "${total_size}" -gt "$limit_bytes" ]; then
      mv "${log}" "${log}.orig"
      (
        # first 1MB
        dd bs=1024 if="${log}.orig" count=1024 # first 1 MB
        echo
        echo "----------------8<----------------8<----------------8<-----------------"
        echo ""
        echo "WARNING: log file truncated at ${limit} MB (before compression)"
        echo "         First 1MB is presented above, last $((limit-1)) MB below"
        echo ""
        echo "----------------8<----------------8<----------------8<-----------------"
        echo
        # last N-1 MB
        dd bs=1024 if="${log}.orig" skip=$((total_size/1024 - (limit-1)*1024))
      ) > "${log}" 2>/dev/null
      rm -f "${log}.orig"
    fi
    gzip "${log}"
  fi

  if [ -f "${adt_out_dir}/duration".in ]; then
    cp "${adt_out_dir}/duration".in "${adt_out_dir}/duration"
  else
    echo $(($finish_timestamp - $start_timestamp)) > "$adt_out_dir/duration"
  fi

  if [ -n "$trigger" ]; then
    echo "$trigger" > "$adt_out_dir/trigger"
  fi

  if [ -n "$print_output" ]; then
      echo "$adt_out_dir"
  fi
}

# defaults
index=''
print_output=''
trigger=''
options=':'

has_extra_apt_sources=false
for opt in $@; do
  case "$opt" in
    -e|--extra-apt-source)
      has_extra_apt_sources=true
      ;;
  esac
done

added_releases=
keydir=$(mktemp -d)

trap cleanup INT TERM EXIT
cleanup() {
  rm -rf "${keydir}"
}

key=0
while true; do
  opt="$1"
  shift
  case "$opt" in
    -o|--print-output)
      print_output=true
      ;;
    -t|--trigger)
      trigger="$1"
      shift
      ;;
    -p|--pin-packages)
      pin="$1"
      shift
      release=$(echo "$pin" | cut -d = -f 1)
      if [ "$has_extra_apt_sources" = false ]; then
        release_added=no
        for entry in $added_releases; do
          if [ "${entry}" = "${release}" ]; then
            release_added=yes
          fi
        done
        if [ "${release_added}" = no ]; then
          options="$options|--add-apt-release=$release"
          added_releases="${added_releases} ${release}"
        fi
      fi
      options="$options|--pin-packages=$pin"
      ;;
    -i|--run-id)
      run_id="$1"
      if echo "$run_id" | grep -q -e '^[0-9]\{8\}_[0-9]\{6\}$' -e '^[0-9]*$' ; then
        : ok
      else
        echo "E: invalid run-id: $run_id (format needs to be YYYYMMDD_HHMMSS)"
        exit 1
      fi
      shift
      ;;
    -e|--extra-apt-source)
      extra_apt_source=`echo -n "$1" | base64 -d`
      options="$options|--add-apt-source=$extra_apt_source"
      shift
      ;;
    -k|--signing-key)
      key=$((key+1))
      key_file="${keydir}/${key}.asc"
      echo -n "$1" | base64 -d > $key_file
      options="$options|--copy=${key_file}:/etc/apt/trusted.gpg.d/${key}.asc"
      shift
      ;;
    --)
      break
      ;;
  esac
done

if [ $# -eq 1 ]; then
  pkg="$1"
  process_package
else
  usage
  exit 1
fi
