A => Makefile +21 -0
@@ 1,21 @@
+BIN_DIR?=/usr/local/bin
+LIB_DIR?=/usr/local/lib
+COMP_DIR?=/usr/local/etc/bash_completion.d
+
+.PHONY: install uninstall test
+
+install:
+ install -m755 backup $(BIN_DIR)/backup
+ install -m755 backup-files $(BIN_DIR)/backup-files
+ install -m755 backup-legal $(BIN_DIR)/backup-legal
+ install -m755 backup-music $(BIN_DIR)/backup-music
+
+uninstall:
+ rm $(BIN_DIR)/backup
+ rm $(BIN_DIR)/backup-files
+ rm $(BIN_DIR)/backup-legal
+ rm $(BIN_DIR)/backup-music
+
+test:
+ #shellcheck *.bash *.sh $(LIB_DIR)/mylib.bash $(LIB_DIR)/myparse.bash $(LIB_DIR)/myminiparse.sh
+
A => backup +41 -0
@@ 1,41 @@
+#!/bin/sh
+
+if [ $# -eq 0 ]; then
+ /usr/bin/printf "USAGE: backup COMMAND\n"
+ exit 1
+fi
+
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ -h|--help|help)
+ /usr/bin/printf "backup COMMAND\n"
+ /usr/bin/printf "Commands:\n"
+ /usr/bin/printf " help show help text\n"
+ /usr/bin/printf " files backup local files\n"
+ /usr/bin/printf " legal backup a legal documents directory\n"
+ /usr/bin/printf " music backup a music media directory\n"
+ exit 0
+ ;;
+
+ files)
+ shift
+ exec /usr/local/bin/backup-files $@
+ ;;
+
+ legal)
+ shift
+ exec /usr/local/bin/backup-legal $@
+ ;;
+
+ music)
+ shift
+ exec /usr/local/bin/backup-music $@
+ ;;
+
+ *)
+ /usr/bin/printf "Unknown command '%s'\n" "$1"
+ exit 1
+ ;;
+ esac
+done
+
A => backup-files +85 -0
@@ 1,85 @@
+#!/bin/bash
+
+TEMP_DIR=~
+
+if [[ $# -eq 0 ]]; then
+ /usr/bin/printf "USAGE: backup files --bucket=BUCKET --name=remote/archive/name [OPTIONS] FILES\n"
+ exit 1
+fi
+
+source /usr/local/lib/mylib.bash
+
+bucket=""
+remote_archive_name=""
+remote_checksum_name=""
+local_archive_name=""
+local_checksum_name=""
+positional=()
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ -h|--help)
+ /usr/bin/printf "backup files [OPTIONS]\n"
+ /usr/bin/printf "Options:\n"
+ /usr/bin/printf " -h, --help Show help text\n"
+ /usr/bin/printf " -b=BUCKET, --bucket=BUCKET Push files to remote bucket [docs|media|work]\n"
+ /usr/bin/printf " -n NAME, --name NAME Name of archive\n"
+ exit 0
+ ;;
+
+ -b=docs|--bucket=docs)
+ bucket="dominic-docs"
+ shift
+ ;;
+
+ -b=media|--bucket=media)
+ bucket="dominic-media"
+ shift
+ ;;
+
+ -b=work|--bucket=work)
+ bucket="dominic-work"
+ shift
+ ;;
+
+ -b=*|--bucket=*)
+ /usr/bin/printf "Invalid bucket '%s'\n" "$1";
+ exit 1
+ ;;
+
+ -n|--name)
+ base_name="$(fn_basename "$2")"
+ safe_name="$(fn_basename "$2" | sed -e 's/\//_/g')"
+
+ remote_archive_name="${base_name}.tar.zstd"
+ remote_checksum_name="${base_name}.sha256"
+ local_archive_name=${TEMP_DIR}/"${safe_name}.tar.zstd"
+ local_checksum_name=${TEMP_DIR}/"${safe_name}.sha256"
+ shift; shift
+ ;;
+
+ *)
+ positional+=("$1")
+ shift
+ ;;
+ esac
+done
+
+# error if no filenames given, or if no bucket given, or if no remote name given
+if [[ "${#positional[@]}" -lt 1 ]]; then
+ /usr/bin/printf "No input filenames given\n"
+ exit 1
+elif [[ -z "$bucket" ]]; then
+ /usr/bin/printf "No remote bucket given\n"
+ exit 1
+elif [[ -z "$remote_archive_name" ]]; then
+ /usr/bin/printf "No remote filename given\n"
+ exit 1
+fi
+
+# main routine
+/usr/local/bin/mktar --compress=zstd --checksum=sha256 --name "$local_archive_name" "${positional[@]}" \
+ && ~/.local/bin/b2 upload-file "$bucket" "$local_archive_name" "$remote_archive_name" >/dev/null\
+ && ~/.local/bin/b2 upload-file "$bucket" "$local_checksum_name" "$remote_checksum_name" >/dev/null\
+ && /usr/bin/rm --force "$local_archive_name" \
+ && /usr/bin/rm --force "$local_checksum_name"
+
A => backup-legal +84 -0
@@ 1,84 @@
+#!/bin/bash
+
+CACHE_DIR=~/.cache/backup-legal
+LEGAL_DIR=/hdd/documents/legal
+TEMP_DIR=~
+
+if [[ $# -eq 0 ]]; then
+ /usr/bin/printf "USAGE: backup legal [OPTIONS]\n"
+ exit 1
+fi
+
+source /usr/local/lib/mylib.bash
+
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ -h|--help)
+ /usr/bin/printf "backup legal [OPTIONS]\n"
+ /usr/bin/printf "Options:\n"
+ /usr/bin/printf " -h, --help Show help text\n"
+ /usr/bin/printf " -p, --push Push new documents to backups\n"
+ /usr/bin/printf " -u, --update Update cache of backups\n"
+ exit 0
+ ;;
+
+ -u|--update)
+ /usr/bin/printf "Updating local cache of legal documents on backup server...\n"
+
+ /usr/bin/mkdir -p "$CACHE_DIR"
+ cd "$CACHE_DIR"
+ /usr/bin/rm *
+ ~/.local/bin/b2 ls --recursive dominic-docs legal \
+ | /usr/bin/grep -e '\.tar\.zstd\.age$' \
+ | /usr/bin/sed -e 's/\.tar\.zstd\.age//' -e 's/^legal\///' -e 's/\//-/' \
+ | /usr/bin/uniq \
+ | /usr/bin/xargs /usr/bin/touch
+ exit 0
+ ;;
+
+ -p|--push)
+ /usr/bin/printf "Pushing new legal documents to the backup server...\n"
+
+ /usr/bin/mkdir -p "$CACHE_DIR"
+
+ skipped=0
+
+ /usr/bin/printf "Enter a passphrase: "
+ read -s passphrase
+ /usr/bin/printf "\n"
+
+ for doc_name in $(/usr/bin/find "${LEGAL_DIR}" -mindepth 1 -maxdepth 1); do
+ doc_name="$(/usr/bin/basename "$doc_name")"
+ base_name="$(fn_basename "$doc_name")"
+
+ if [ -f "$CACHE_DIR/${base_name}" ]; then
+ #/usr/bin/printf "Skipping %s...\n" "$base_name"
+
+ skipped=$((skipped+1))
+ else
+ #/usr/bin/printf "Pushing %s...\n" "$base_name"
+
+ cd "${LEGAL_DIR}" \
+ && /usr/local/bin/mktar-batch --compress=zstd --checksum=sha256 --encrypt=age --passphrase "$passphrase" --name ${TEMP_DIR}/${base_name}.tar.zstd.age ${doc_name} \
+ && ~/.local/bin/b2 upload-file dominic-docs ${TEMP_DIR}/${base_name}.tar.zstd.age legal/${base_name}.tar.zstd.age >/dev/null \
+ && ~/.local/bin/b2 upload-file dominic-docs ${TEMP_DIR}/${base_name}.sha256 legal/${base_name}.sha256 >/dev/null \
+ && /usr/bin/touch "${CACHE_DIR}/${base_name}"
+
+ /usr/bin/rm --force ${TEMP_DIR}/${base_name}.tar.zstd.age
+ /usr/bin/rm --force ${TEMP_DIR}/${base_name}.sha256
+ fi
+ done
+
+ if [[ $skipped -ne 0 ]]; then
+ /usr/bin/printf "Skipped %s documents\n" "$skipped"
+ fi
+ exit 0
+ ;;
+
+ *)
+ /usr/bin/printf "Unknown option '%s'\n" "$1"
+ exit 1
+ ;;
+ esac
+done
+
A => backup-music +85 -0
@@ 1,85 @@
+#!/bin/bash
+
+CACHE_DIR=~/.cache/backup-music
+MUSIC_DIR=/hdd/media/music
+TEMP_DIR=~
+
+if [[ $# -eq 0 ]]; then
+ /usr/bin/printf "USAGE: backup music [OPTIONS]\n"
+ exit 1
+fi
+
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ -h|--help)
+ /usr/bin/printf "backup music [OPTIONS]\n"
+ /usr/bin/printf "Options:\n"
+ /usr/bin/printf " -h, --help Show help text\n"
+ /usr/bin/printf " -p, --push Push new music to backups\n"
+ /usr/bin/printf " -u, --update Update cache of backups\n"
+ exit 0
+ ;;
+
+ -u|--update)
+ /usr/bin/printf "Updating local cache of music on backup server...\n"
+
+ /usr/bin/mkdir -p "$CACHE_DIR"
+ cd "$CACHE_DIR"
+ /usr/bin/rm *
+ ~/.local/bin/b2 ls --recursive dominic-media music \
+ | /usr/bin/grep -e '\.tar\.gz\.gpg$' \
+ | /usr/bin/sed -e 's/\.tar\.gz\.gpg//' -e 's/^music\///' -e 's/\//-/' \
+ | /usr/bin/uniq \
+ | /usr/bin/xargs /usr/bin/touch
+ exit 0
+ ;;
+
+ -p|--push)
+ /usr/bin/printf "Pushing new music to the backup server...\n"
+
+ /usr/bin/mkdir -p "$CACHE_DIR"
+
+ skipped=0
+
+ /usr/bin/printf "Enter a passphrase: "
+ read -s passphrase
+ /usr/bin/printf "\n"
+
+ for artist in $(/usr/bin/find "${MUSIC_DIR}" -mindepth 1 -maxdepth 1 -type d); do
+ artist=$(/usr/bin/basename "$artist")
+
+ for album in $(/usr/bin/find "${MUSIC_DIR}/${artist}" -mindepth 1 -maxdepth 1 -type d); do
+ album=$(/usr/bin/basename "$album")
+ name="${artist}-${album}"
+ if [ -f "$CACHE_DIR/${name}" ]; then
+ #/usr/bin/printf "Skipping %s...\n" "$name"
+
+ skipped=$((skipped+1))
+ else
+ #/usr/bin/printf "Pushing %s...\n" "$name"
+
+ cd "${MUSIC_DIR}" \
+ && /usr/local/bin/mktar-batch --compress=gzip --checksum=sha1 --encrypt=gpg --passphrase "$passphrase" --name ${TEMP_DIR}/${name}.tar.gz.gpg ${artist}/${album} \
+ && ~/.local/bin/b2 upload-file dominic-media ${TEMP_DIR}/${name}.tar.gz.gpg music/${artist}/${album}.tar.gz.gpg >/dev/null \
+ && ~/.local/bin/b2 upload-file dominic-media ${TEMP_DIR}/${name}.sha1 music/${artist}/${album}.sha1 >/dev/null \
+ && /usr/bin/touch "${CACHE_DIR}/${name}"
+
+ /usr/bin/rm --force ${TEMP_DIR}/${name}.tar.gz.gpg
+ /usr/bin/rm --force ${TEMP_DIR}/${name}.sha1
+ fi
+ done
+ done
+
+ if [[ $skipped -ne 0 ]]; then
+ /usr/bin/printf "Skipped %s albums\n" "$skipped"
+ fi
+ exit 0
+ ;;
+
+ *)
+ /usr/bin/printf "Unknown option '%s'\n" "$1"
+ exit 1
+ ;;
+ esac
+done
+