#!/usr/local/bin/bash
#/ Usage: ghe-backup-git-hooks-cluster
#/ Take an online, incremental snapshot of custom Git hooks configuration.
#/
#/ Note: This command typically isn't called directly. It's invoked by
#/ ghe-backup when the cluster strategy is used.
set -e

# Bring in the backup configuration
. $( dirname "${BASH_SOURCE[0]}" )/ghe-backup-config

bm_start "$(basename $0)"

# Verify rsync is available.
if ! rsync --version 1>/dev/null 2>&1; then
    echo "Error: rsync not found." 1>&2
    exit 1
fi

bm_start "$(basename $0)"

backup_dir="$GHE_SNAPSHOT_DIR/git-hooks"
# Location of last good backup for rsync --link-dest
backup_current="$GHE_DATA_DIR/current/git-hooks"

# Perform a host-check and establish GHE_REMOTE_XXX variables.
ghe_remote_version_required "$host"

# Split host:port into parts
port=$(ssh_port_part "$GHE_HOSTNAME")
host=$(ssh_host_part "$GHE_HOSTNAME")

# Add user / -l option
user="${host%@*}"
[ "$user" = "$host" ] && user="admin"

# Generate SSH config for forwarding
config=""

# git server hostnames
hostnames=$(ghe_cluster_online_nodes "git-server")
for hostname in $hostnames; do
  config="$config
Host $hostname
  ProxyCommand ssh -q $GHE_EXTRA_SSH_OPTS -p $port $user@$host nc.openbsd %h %p
  StrictHostKeyChecking=no
"
done

config_file=$(mktemp -t cluster-backup-restore-XXXXXX)
echo "$config" > "$config_file"

opts="$GHE_EXTRA_SSH_OPTS -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o PasswordAuthentication=no"

# Removes the remote sync-in-progress file on exit, re-enabling GC operations
# on the remote instance.
cleanup() {
  rm -f $config_file
}
trap 'cleanup' EXIT
trap 'exit $?' INT # ^C always terminate

# Transfer Git hooks data from a GitHub instance to the current snapshot
# directory, using a previous snapshot to avoid transferring files that have
# already been transferred. A set of rsync filter rules are provided on stdin
# for each invocation.
rsync_git_hooks_data () {
    port=$(ssh_port_part "$1")
    host=$(ssh_host_part "$1")

    subpath=$2
    shift 2

    # If we have a previous increment and it is not empty, avoid transferring existing files via rsync's
    # --link-dest support. This also decreases physical space usage considerably.
    if [ -d "$backup_current/$subpath" ] && [ "$(ls -A $backup_current/$subpath)" ]; then

      subdir="git-hooks/$subpath"
      link_path=".."
      while true; do
        if [ $(dirname $subdir) = "." ]; then
          break
        fi

        if [ $(dirname $subdir) = "/" ]; then
          break
        fi

        link_path="../$link_path"
        subdir=$(dirname $subdir)
      done

      local link_dest="--link-dest=../${link_path}/current/git-hooks/$subpath"
    fi

    # Ensure target directory exists, is needed with subdirectories
    mkdir -p "$backup_dir/$subpath"

    ghe-rsync -av \
        -e "ssh -q $opts -p $port -F $config_file -l $user" $link_dest \
        --rsync-path='sudo -u git rsync' \
        "$host:$GHE_REMOTE_DATA_USER_DIR/git-hooks/$subpath/" \
        "$backup_dir/$subpath" 1>&3
}

hostname=$(echo $hostnames | awk '{ print $1; }')
if ghe-ssh -F $config_file "$hostname:122" -- "sudo -u git [ -d '$GHE_REMOTE_DATA_USER_DIR/git-hooks/environments/tarballs' ]"; then
  rsync_git_hooks_data $hostname:122 environments/tarballs
else
  ghe_verbose "git-hooks environment tarballs not found. Skipping ..."
fi

if ghe-ssh -F $config_file "$hostname:122" -- "sudo -u git [ -d '$GHE_REMOTE_DATA_USER_DIR/git-hooks/repos' ]"; then
  rsync_git_hooks_data $hostname:122 repos
else
  ghe_verbose "git-hooks repositories not found. Skipping ..."
fi

bm_end "$(basename $0)"
