#!{{ shell_binary }}
LC_ALL=C
export LC_ALL
umask 077

# Exit on any error, to prevent inconsistent backup
# Error on unset variable expansion
set -eu

# Redirect output to log
exec > >(tee -ai '{{ output_log_file }}')
exec 2>&1

echo -e "\n\n$0 run at : $(date)"

srv_directory='{{ directory["srv"] }}'
backup_directory='{{ directory["backup"] }}'
etc_directory='{{ directory["etc"] }}'
tmp_directory='{{ directory["tmp"] }}'

rsync () {
  set -x
  '{{ rsync_binary }}' -rlptgov --stats --safe-links --delete --delete-excluded "$@"
  set +x
}

relativise () {
  while IFS= read -r line; do
    if [ ! -z "$line" ]; then
      '{{ parameter_dict["coreutils-location"] }}/bin/realpath' --quiet --canonicalize-missing --no-symlinks --relative-to="$1" "$line"
    fi
  done
}

(
  path=$srv_directory/runner
  backup_path=$backup_directory/runner/
  cd "$path"

  if [ -d instance ]; then
    # Concatenate the exclude file of each partition of webrunner
    # to create a global exclude file.
    # Also, ignore all buildout-managed files.
    (
      echo "*.sock"
      echo "*.socket"
      echo "*.pid"
      echo ".installed*.cfg"
      for partition in "$path"/instance/slappart*; do
        # So "relativise" can handle relative paths (which are expected to be relative to partition).
        cd "$partition"
        exclude_file=srv/exporter.exclude
        if [ -r "$exclude_file" ]; then
          relativise "$path" < "$exclude_file"
        fi
        for installed in .installed*.cfg; do
          if [ -r "$installed" ]; then
            # Print every line from each __buildout_installed__ found.
            '{{ parameter_dict["gawk-location"] }}/bin/gawk' '
              BEGIN { do_print = 0 }
              match($0, /^__buildout_installed__\s*=\s*(\S.*)/, ary) { do_print = 1; print ary[1]; next }
              /^\S/ { do_print = 0; next }
              match($0, /^\s+(\S.*)/, ary) { if (do_print) print ary[1] }
            ' "$installed" | relativise "$path"
          fi
        done
      done
    ) | rsync --exclude-from=- instance "$backup_path"
  fi

  test -d project  && rsync project "$backup_path"
  test -f proxy.db && rsync proxy.db "$backup_path"
)
# We sync .* appart
(
  cd "$etc_directory"
  date +%s -u > .resilient-timestamp
  rsync config.json "$backup_directory"/etc/
  # Hidden files are related to the webrunner's internals
  cp -r .??* "$backup_directory/etc/"
)
if [ -d "$backup_directory"/runner/software ]; then
  rm "$backup_directory"/runner/software/*
fi

(
  cd "$backup_directory"
  find -type f ! -name backup.signature -print0 | xargs -0 sha256sum | sort -k 66 > backup.signature
)

# Check that export didn't happen during backup of instances
tmp_backup_sum=$(mktemp -p "$tmp_directory")
tmp_filtered_signature=$(mktemp -p "$tmp_directory")

remove_tmp_files () {
  rm "$tmp_backup_sum" "$tmp_filtered_signature"
}
trap remove_tmp_files EXIT

# Getting files from runner backup directory, as instance backup files may be
# explicitely excluded from the backup, using the srv/exporter.exclude
cd {{ directory['backup'] }}
backup_directory_path=$(find . -path "./runner/instance/slappart*/srv/backup/*" -type f)

# If no backup found, it's over
if [ -z "$backup_directory_path" ]; then
  exit 0
fi

sleep 5
sha256sum $backup_directory_path | sort -k 66 > "$tmp_backup_sum"
egrep "instance/slappart.*/srv/backup/" "$backup_directory/backup.signature" > "$tmp_filtered_signature"

# If the diff fails, then the notifier will restart this script
if diff "$tmp_backup_sum" "$tmp_filtered_signature"; then
  exit 0
fi
echo "ERROR: Some backups are not consistent, exporter should be re-run."
echo "Let's sleep {{ parameter_dict['backup_wait_time'] }} minutes, to let the backup end..."
sleep {{ parameter_dict["backup_wait_time"] }}m
exit 1
