#!/usr/bin/env bash

SCRIPT="$(cd "${0%/*}" && echo "$PWD")/${0##*/}"
SCRIPT="$(readlink -f "$SCRIPT")"
SCRIPT_DIR="$(dirname "$SCRIPT")"
if [ -z ${SOURCE_DIR+x} ] ; then
  SOURCE_DIR="/srv/www/htdocs/opensuse"
fi
if [ -z ${SNAPSHOT_DIR+x} ] ; then
  SNAPSHOT_DIR="/srv/www/htdocs/snapshot"
fi
if [ -z ${RSYNC_INCLUDE+x} ] ; then
  RSYNC_INCLUDE="$SCRIPT_DIR/rsync/include-tumbleweed.txt"
fi
if [ -z ${SNAPSHOT_AGE_MAX+x} ] ; then
  SNAPSHOT_AGE_MAX="-60 days"
fi
SNAPSHOT_OLDEST=$(date -d "$SNAPSHOT_AGE_MAX" +%Y%m%d)
LOCKFILE_NAME="$SNAPSHOT_DIR/.lock"

snapshot_list_raw()
{
  local ISO_DIR="$SOURCE_DIR/tumbleweed/iso"
  find "$ISO_DIR" -maxdepth 1 -name "Changes.*.txt" | grep -oP "\d+" | sort -r
}

snapshot_list()
{
  snapshots=()

  for snapshot in $(snapshot_list_raw) ; do
    # Changes files are sorted largest to smallest so once a snapshot is
    # encountered that is older than OLDEST stop looping.
    if [ $snapshot -lt $SNAPSHOT_OLDEST ] ; then
      break
    fi
    snapshots+=($snapshot)
  done

  # Remove ignored snapshots.
  for ignore in $(cat "$SNAPSHOT_DIR/ignore") ; do
    local ignore=($ignore)
    snapshots=(${snapshots[@]/$ignore})
  done

  echo "${#snapshots[@]} snapshots of interest"
}

snapshot_process()
{
  snapshots_available=(${snapshots[@]})

  # Remove latest snapshot since handled below and process existing snapshots.
  # Missing snapshots will be removed ensuring that if snapshots are missed or
  # ignored that the new snapshot will be hardlinked againsts the next available
  # snapshot instead of none in the case the previous was missed.
  local snapshots=(${snapshots[@]:1})
  local i=0
  for snapshot in ${snapshots[@]} ; do
    echo -n "$snapshot: "

    local dir="$SNAPSHOT_DIR/$snapshot"
    if [ -f "$dir/.htaccess" ] ; then
      # Indicates directory represented the latest snapshot.
      rm "$dir/.htaccess"
      echo "redirect removed"
    elif [ -d "$dir" ] ; then
      echo "exists"
    else
      local missing=($snapshot)
      snapshots_available=(${snapshots_available[@]/$missing})
      echo "missing"
    fi

    ((i++))
  done

  # Snapshot latest (assumes source are fully updated).
  local snapshot_latest="$SNAPSHOT_DIR/${snapshots_available[0]}"
  if [ ! -e "$snapshot_latest" ] ; then
    local snapshot_older="$SNAPSHOT_DIR/${snapshots_available[1]}"
    if [ -d "$snapshot_older" ] ; then
      # Hardlink against previous snapshot.
      rsync --include-from "$RSYNC_INCLUDE" -a --delete --link-dest="$(realpath $snapshot_older)" "$SOURCE_DIR/" "$snapshot_latest"
    else
      # First snapshot, with no previous base (ie make full copy).
      rsync --include-from "$RSYNC_INCLUDE" -a --delete "$SOURCE_DIR/" "$snapshot_latest"
    fi

    # Redirect to main mirrors until next snapshot.
    cp "$SCRIPT_DIR/.htaccess" "$snapshot_latest"

    echo "${snapshots_available[0]}: snapshot created and redirect set"
  fi

  # Remove expired snapshots.
  for f in $(find "$SNAPSHOT_DIR" -mindepth 1 -maxdepth 1 -type d | sort -r) ; do
    local snapshot="$(basename "$f")"
    if [ -d "$f" ] && [ $snapshot -lt $SNAPSHOT_OLDEST ] ; then
      rm -rf "$f"
      local removed=($snapshot)
      snapshots_available=(${snapshots_available[@]/$removed})
      echo "$(basename "$f"): removed"
    fi
  done
}

snapshot_dir_init()
{
  mkdir "$SNAPSHOT_DIR"
  echo 0 > "$SNAPSHOT_DIR/latest"
  echo -n > "$SNAPSHOT_DIR/list"
  echo -n > "$SNAPSHOT_DIR/ignore"
}

snapshot_check()
{
  # Check the changes entries to determine current release.
  local release=$(snapshot_list_raw | head -n 1)
  local snapshot_latest=$(cat "$SNAPSHOT_DIR/latest")

  # Only process if new release which may mean multiple snapshots can expire if
  # no new snapshots are published.
  if [ "$release" != "" ] && [ "$release" -gt "$snapshot_latest" ] ; then
    echo "new snapshot $release published"
    snapshot_latest="$release"
    snapshot_list
    snapshot_process
    echo "$release" > "$SNAPSHOT_DIR/latest"
    printf '%s\n' "${snapshots_available[@]}" > "$SNAPSHOT_DIR/list"
  fi
}


if [ ! -d "$SNAPSHOT_DIR" ] || [ ! -f "$SNAPSHOT_DIR/latest" ] ; then
  snapshot_dir_init
fi

lockfile -r 0 "$LOCKFILE_NAME" || exit 1
trap "rm -f \"$LOCKFILE_NAME\"; exit" 0 1 2 3 9 15

snapshot_check
