#!/bin/bash

# This script requires SSHFS and Borg.
# It backs up data from a remote location to a local repository.

# =============
# CONFIGURATION
# =============

# Hostname, domain name, or IP address of the machine where the data to be backed up resides.
DATA_HOST="5ccppi"
# White-space-delimited list of absolute paths of directories on the remote machine to be backed up.
DATA_PATHS=( "/home/ccppi" "/var/lib" "/etc" )
PRENAMEARCHIVE="linode"

# Absolute local path where the remote system will be temporarily mounted locally.
# The directory will be created. Pick someplace to which you have write access.
SSHFS_MOUNTPOINT="/tmp/sshfs-tmp-borg_pull"
# The username for the account on the remote machine as which we’ll be loggin in via SSH.
SSHFS_USER="user"
SSHFS_PORT="0000"

# The absolute local path for the directory where the backups will be stored.
BACKUP_ROOT="/mnt/backup/borg-linode"
# A command to generate the date stamp that will appear in a backup’s title.
BACKUP_DATE=$(date +"%Y-%m-%d_%H:%M")

# Whether or not to compacts repositories after backing up. I haven’t tested this
# because I have an older version of Borg that doesn’t support compacting.
#COMPACT_REPOS="false"

DAILIES_TO_RETAIN="7"
WEEKLIES_TO_RETAIN="4"

# This script is intended to be run unattended. If this option is set to “true”,
# the script will pause for a few seconds before exiting if everything is successful,
# and wait for user input before exiting if anything goes wrong.
LINGER_ON_EXIT="true"

EMPHASIS_COLOR="\e[36m"
ERROR_COLOR="\e[91m"
SUCCESS_COLOR="\e[32m"
PROMPT_COLOR="\e[30;106m"

# =============
# Mise en place
# =============

NO_COLOR="\e[0m"
ERRORLEVEL=0
SUCCESSES="false"
PROBLEMS="false"
declare -A STATA

_backup() {
    DATA_PATH=$1
    FULL_REPO_PATH="${BACKUP_ROOT}"
    #/${DATA_HOST}${DATA_PATH}"
    printf "Backing up ${EMPHASIS_COLOR}%s%s${NO_COLOR}\nto %s%s...\n" "$DATA_HOST" "$DATA_PATH" "$BACKUP_ROOT"
    if borg create --stats --progress --exclude /*/lost+found "$FULL_REPO_PATH"::"$PRENAMEARCHIVE""-""${DATA_PATH////-}""$BACKUP_DATE" "$SSHFS_MOUNTPOINT""$DATA_PATH"
        then printf "%bSuccess.%b\n\n" "$SUCCESS_COLOR" "$NO_COLOR"
        STATA["${DATA_PATH}"]="SUCCESS"
        SUCCESSES="true"
        if [[ $COMPACT_REPOS == "true" ]]
            then borg --progress compact "$FULL_REPO_PATH"
        fi
        printf "Pruning %s...\n" "$FULL_REPO_PATH"
        if ! borg prune --keep-daily="$DAILIES_TO_RETAIN" --keep-weekly="$WEEKLIES_TO_RETAIN" "$FULL_REPO_PATH"
            then ERRORLEVEL=1
            PROBLEMS="true"
        fi
        printf "\n"

        else STATA["${DATA_PATH}"]="$?"
        ERRORLEVEL=1
        PROBLEMS="true"
        printf "\n"
    fi
}

_delete_mountpoint() {
    if [[ ! "$(ls -A $SSHFS_MOUNTPOINT)" ]]
        then printf "Deleting mountpoint %s...\n" "$SSHFS_MOUNTPOINT"
        if rmdir "$SSHFS_MOUNTPOINT"
            then printf "Deleted.\n\n"
            else printf "%bFailed to delete the mountpoint.%b\n\n" "$ERROR_COLOR" "$NO_COLOR"
            ERRORLEVEL=1
        fi
        else printf "%bNot deleting the mountpoint at %s\nbecause it looks like there’s still something in it. Weird.%b\n\n" "$ERROR_COLOR" "$SSHFS_MOUNTPOINT" "$NO_COLOR"
        ERRORLEVEL=1
    fi
}

_exit() {
    if [[ $ERRORLEVEL -eq 0 ]]
        then if [[ $LINGER_ON_EXIT == "true" ]]
            then printf "%bThis message will self-destruct.%b\n\n" "$PROMPT_COLOR" "$NO_COLOR"
            sleep 5
        exit 0
        fi
        elif [[ $LINGER_ON_EXIT == "true" ]]
            then printf "%b" "$PROMPT_COLOR"
            read -n1 -r -p "Press Enter to dismiss." input
            printf "%b\n" "$NO_COLOR"
            if [[ $input = "" ]]
            then exit 1
            else _exit
        fi
        exit 1
    fi
}

# ====
# Prep
# ====

printf "\nWe’re about to back up the following remote directories from %b%s%b:\n" "$EMPHASIS_COLOR" "${DATA_HOST}" "$NO_COLOR"
for i in "${DATA_PATHS[@]}"
do
    printf "• %b%s%b\n" "$EMPHASIS_COLOR" "${i}" "$NO_COLOR"
done
printf "\n"

if [[ ! -d "$SSHFS_MOUNTPOINT" ]]
    then printf "Creating mountpoint %s...\n" "$SSHFS_MOUNTPOINT"
    if mkdir "$SSHFS_MOUNTPOINT"
        then printf "Success.\n\n"
        else printf "%bWe seem to be having trouble creating the SSHFS mountpoint. Aborting!%b\n\n" "$ERROR_COLOR" "$NO_COLOR"
        ERRORLEVEL=1
        _exit
    fi
fi

printf "Mounting %s at %s...\n" "$DATA_HOST" "$SSHFS_MOUNTPOINT"
if sshfs -o ro,port="$SSHFS_PORT" "$SSHFS_USER"@"$DATA_HOST":/ "$SSHFS_MOUNTPOINT"
    then printf "Success.\n\n"
    else printf "%bWe seem to be having trouble mounting the remote remote file system.%b\n\n" "$ERROR_COLOR" "$NO_COLOR"
    ERRORLEVEL=1
    _delete_mountpoint
    _exit
fi

# =================
# Backup operations
# =================

for i in "${DATA_PATHS[@]}"
do
    _backup "$i"
done

# ==========
# Denouement
# ==========

printf "Unmounting %s from %s...\n" "$DATA_HOST" "$SSHFS_MOUNTPOINT"
if fusermount -u "$SSHFS_MOUNTPOINT"
    then printf "Success.\n\n"
    _delete_mountpoint
    else printf "%bWe’re having trouble unmounting the remote file system at %s.\n" "$ERROR_COLOR" "$SSHFS_MOUNTPOINT"
    printf "You’ll probably want to have a look at it.%b\n\n" "$NO_COLOR"
    ERRORLEVEL=1
fi

printf "%b==========\nCONCLUSION\n==========%b\n\n" "${EMPHASIS_COLOR}" "$NO_COLOR"
if [[ $SUCCESSES == "true" ]]
    then printf "The following locations backed up successfully:\n"
    for i in "${DATA_PATHS[@]}"
    do
        if [[ ${STATA[${i}]} == "SUCCESS" ]]
            then printf "• %b%s%b\n" "$EMPHASIS_COLOR" "$i" "$NO_COLOR"
        fi
    done
    printf "\n"
fi
if [[ $PROBLEMS == "true" ]]
    then printf "The following locations experienced issues:\n"
    for i in "${DATA_PATHS[@]}"
    do
        if [[ ! ${STATA[${i}]} == "SUCCESS" ]]
            then printf "• %b%s%b\n" "$ERROR_COLOR" "$i" "$NO_COLOR"
        fi
    done
    printf "\n"
fi

_exit