#!/usr/local/bin/bash
#/ Usage: ghe-restore-repositories-gist <host>
#/ Restore repositories fron an rsync snapshot of all Git repository data to a GitHub cluster.
#/
#/ Note: This script typically isn't called directly. It's invoked by the
#/ ghe-restore command when restoring into a cluster.
set -e

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

# Show usage and bail with no arguments
[ -z "$*" ] && print_usage

bm_start "$(basename $0)"

# Grab host arg
GHE_HOSTNAME="$1"

# The snapshot to restore should be set by the ghe-restore command but this lets
# us run this script directly.
: ${GHE_RESTORE_SNAPSHOT:=current}

# Find the gists to restore
gist_paths=$(cd $GHE_DATA_DIR/$GHE_RESTORE_SNAPSHOT/  && find repositories -mindepth 6 -maxdepth 7 -name \*.git | grep gist | cut -d / -f2-)

# No need to restore anything, early exit
if [ -z "$gist_paths" ]; then
  echo "Warning: Gist backup missing. Skipping ..."
  exit 0
fi

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

# Generate SSH config for forwarding

config=""

# 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"

hostnames=$(ghe_cluster_online_nodes "git-server")
for hostname in $hostnames; do
  config="$config
Host $hostname
  ServerAliveInterval 60
  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"

cleanup() {
  for pid in $(jobs -p); do
    kill -KILL $pid > /dev/null 2>&1 || true
  done
  # Enable remote GC operations
  for hostname in $hostnames; do
    ghe-gc-enable -F $config_file $hostname:$port
  done
  rm -rf $config_file ssh_routes_in ssh_routes_out ssh_finalize_in ssh_finalize_out
}

trap 'cleanup' INT TERM EXIT

# Disable remote GC operations
for hostname in $hostnames; do
  ghe-gc-disable -F $config_file $hostname:$port
done

rm -rf ssh_routes_in ssh_routes_out ssh_finalize_in ssh_finalize_out
mkfifo ssh_routes_in
mkfifo ssh_routes_out
mkfifo ssh_finalize_in
mkfifo ssh_finalize_out

ghe-ssh "$GHE_HOSTNAME" github-env ./bin/gist-cluster-import-routes - < ssh_routes_out > ssh_routes_in &
ssh_routes_pid=$!
ghe-ssh "$GHE_HOSTNAME" github-env ./bin/gist-cluster-import-finalize - < ssh_finalize_out > ssh_finalize_in &
ssh_finalize_pid=$!

exec 4> ssh_routes_out
exec 5> ssh_finalize_out

for gist_path in $gist_paths; do
  gist_id=$(basename $(echo $gist_path | awk -F/ '{print $(NF)}') .git)
  echo "$gist_id" >&4
  read routes < ssh_routes_in

  if [ "$routes" = 'gist-not-found' ]; then
    echo "  Warning: gist ID $gist_id not found in the database, ignoring."
    continue
  fi

  for route in $routes; do
    ghe-rsync -aHR --delete \
      --exclude ".sync_in_progress" \
      -e "ssh -q $opts -p $port -F $config_file -l $user" \
      --rsync-path="sudo -u git rsync" \
      "$GHE_DATA_DIR/$GHE_RESTORE_SNAPSHOT/repositories/./$gist_path" \
      "$route:$GHE_REMOTE_DATA_USER_DIR/repositories" &
  done

  for pid in $(jobs -p); do
    if [ $pid = $ssh_routes_pid -o $pid = $ssh_finalize_pid ]; then
      continue
    fi
    wait $pid
    ret_code=$?
    if [ "$ret_code" != "0" ]; then
      echo "$pid exited $ret_code"
      exit $ret_code
    fi
  done

  echo "$gist_id /data/repositories/$gist_path $routes" >&5
  read output < ssh_finalize_in
done

exec 4>&-
exec 5>&-

# Ensure to flush these and close the pipes
cat ssh_routes_in > /dev/null &
cat ssh_finalize_in > /dev/null &

wait $ssh_routes_pid > /dev/null 2>&1 || true
wait $ssh_finalize_pid > /dev/null 2>&1 || true

bm_start "$(basename $0)"
