#! /bin/bash function main() { set -e set -u cd "$(dirname "${BASH_SOURCE[0]}")" export GOPATH="$PWD/restic-go" if [ -z "${PASSWORD:-""}" ]; then read -sp "Password: " PASSWORD echo "" fi install configure local action="$1" shift case "$action" in clean ) clean_remote "$@" ;; backup ) backup "$@" ;; restore ) restore "$@" ;; * ) RESTIC "$action" "$@" ;; esac } function install() { if ! go version; then echo "Must install go" >&2 exit 1 fi export GOFLAGS=""; export GO111MODULE=""; export GOPROXY="" export GOFLAGS="" mkdir -p "$GOPATH/bin/$(uname)" for i in ncw/rclone restic/restic; do local b="${i##*/}" if [ -e "$GOPATH/bin/$(uname)/$b" ]; then continue fi mkdir -p $GOPATH/src/github.com/${i%/*} #go get -u "github.com/$i" || true pushd "$GOPATH/src/github.com/${i%/*}" git clone --depth 1 --branch master https://github.com/$i cd ${i##*/} go get ./... case "$i" in restic* ) go run build.go mv "./$b" "$GOPATH/bin/$(uname)/$b" ;; * ) go install mv "$GOPATH/bin/$b" "$GOPATH/bin/$(uname)/$b" ;; esac popd done } function configure() { mkdir -p "$PWD/config" if [ ! -e "$PWD/config/rclone" ]; then configure_rclone fi if [ ! -e "$PWD/config/restic" ]; then configure_restic fi } function configure_rclone() { RCLONE config create remote drive #RCLONE config create remote-enc crypt \ # remote remote:cloudly/restic \ # filename_encryption obfuscate \ # directory_name_encryption true \ # password $PASSWORD \ # password2 "" } function configure_restic() { RESTIC init touch "$PWD/config/restic" } function backup() { local args=() for arg in "$@"; do local real="$(realpath "$arg")" if [ "$real" == "${real#$HOME}" ]; then log "Cowardly skipping $arg ($real) for not being under \$HOME ($HOME)" continue fi args+=("$real") done local extraTags=" " if [ -n "${TAGS:-""}" ]; then extraTags="--tag $TAGS" fi log "BACKUP ${args[@]}" RESTIC backup \ -e "**.sw*" \ --tag "${real#$HOME/}" \ $extraTags \ "${args[@]}" } function restore() { for arg in "$@"; do if [ -e "$arg" ] || [ -d "$arg" ]; then arg="$(realpath "$arg")" fi local latest="$(RESTIC snapshots --last --tag "${arg#$HOME/}" | sort -k 2 | grep '20[0-9][0-9].[0-9][0-9].[0-9][0-9]' | tail -n 1)" local id="$(echo "$latest" | awk '{print $1}')" local path="$(echo "$latest" | awk '{print $5}')" local rpath="$(echo "$latest" | awk '{print $6}')" log "RESTORE $id as $HOME/$path as $HOME/$path-restore" rm -rf "$HOME/$path-"{dump,restore} 2> /dev/null \ || sudo rm -rf "$HOME/$path-"{dump,restore} 2> /dev/null \ || true mkdir -p "$HOME/$path-dump" RESTIC restore $id --target "$HOME/$path-dump" mv "$HOME/$path-dump/${rpath#/}" "$HOME/$path-restore" rm -rf "$HOME/$path-"{dump,old} \ || sudo rm -rf "$HOME/$path-"{dump,old} \ || true if [ -d "$HOME/$path" ]; then mv "$HOME/$path" "$HOME/$path-old" fi mv "$HOME/$path-restore" "$HOME/$path" done if [ -z "${DIRTY:-}" ]; then clean_remote fi } function clean_remote() { RESTIC forget --prune --cleanup-cache --keep-last 2 --group-by host,tags "$@" RESTIC check } function RCLONE() { $GOPATH/bin/$(uname)/rclone --config=$PWD/config/rclone --ask-password=false "$@" } function RESTIC() { RESTIC_PASSWORD=$PASSWORD \ $GOPATH/bin/$(uname)/restic \ -r rclone:remote:cloudly/restic-plain/backup \ -o rclone.program=$GOPATH/bin/$(uname)/rclone \ -o rclone.args="serve restic --stdio --b2-hard-delete --drive-use-trash=false --config $PWD/config/rclone --bwlimit 26M --ask-password=false" \ "$@" #-r rclone:remote-enc:backup } function log() { echo "$(date +%H:%M:%S): $@" >&2 } function fatal() { log "$@" exit 1 } if [ "$0" == "${BASH_SOURCE[0]}" ]; then SECONDS=0 log "Start" main "$@" log "Stop ($?): $(python3 -c "print(int(10*$SECONDS/60)/10.0, 'minutes')")" fi