commit 975f0a194e6a86e93d635ec5d962fed4bfd6e8e4 Author: redxef Date: Fri Feb 17 02:35:13 2023 +0100 Initial implementation. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a061869 --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +PLUGINS := tarback/*.sh +SCRIPT := tarback.sh +PREFIX ?= /usr/local + +install: $(PLUGINS) + install -D -t $(PREFIX)/share/tarback -m 0644 -o root -g root $^ + install -D -m 0755 -o root -g root $(SCRIPT) $(PREFIX)/bin/ + +.PHONY: install diff --git a/tarback.sh b/tarback.sh new file mode 100755 index 0000000..6b12d1b --- /dev/null +++ b/tarback.sh @@ -0,0 +1,121 @@ +#!/bin/sh + +set -e + +XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}" +XDG_DATA_DIRS="${XDG_DATA_DIRS:-/usr/local/share:/usr/share}" + +# example: TARBACK_REMOTE="ssh myuser@myserver" ./tarback ... +TARBACK_REMOTE="${TARBACK_REMOTE:-}" +# maybe the command needs to be transformed before being passed to the +# remote command, see _transform_ssh_command for an example +TARBACK_TRANSFORM_REMOTE_COMMAND="${TARBACK_TRANSFORM_REMOTE_COMMAND:-}" +# shellcheck disable=SC2016 # disable variable not expanding hint +[ -z "$TARBACK_TAR_CREATE_COMMAND" ] \ + && TARBACK_TAR_CREATE_COMMAND='tar c -C "$(dirname "$1")" "$(basename "$1")"' +# shellcheck disable=SC2016 # disable variable not expanding hint +[ -z "$TARBACK_TAR_EXTRACT_COMMAND" ] \ + && TARBACK_TAR_EXTRACT_COMMAND='tar x -C "$(dirname "$1")"' +[ -z "$TARBACK_COMPRESSION" ] && TARBACK_COMPRESSION="xz" +[ -z "$TARBACK_SPLIT" ] && TARBACK_SPLIT="split -b $((128*1024*1024)) -" +[ -z "$TARBACK_MERGE" ] && TARBACK_MERGE='cat' +[ -z "$TARBACK_PLUGIN_SEARCH_PATH" ] \ + && TARBACK_PLUGIN_SEARCH_PATH="$(dirname "$0"):$XDG_DATA_HOME:$XDG_DATA_DIRS" + +TARBACK_PLUGIN_SEARCH_PATH="$(echo "$TARBACK_PLUGIN_SEARCH_PATH" | tr ':' '\n')" + +_transform_split_name() { + command_name="$(echo "$TARBACK_SPLIT" | awk '{print $1}')" + if echo "$command_name" | grep -q 'split'; then + echo "$1.part" + else + echo "$1" + fi +} + +_transform_ssh_command() { + command_name="$(echo "$TARBACK_REMOTE" | awk '{print $1}')" + if echo "$command_name" | grep -q 'ssh'; then + echo "'$1'" + else + echo "$1" + fi +} + +_transform_remote() { + r="$1" + # TODO add more transformers + for t in _transform_ssh_command "$TARBACK_TRANSFORM_REMOTE_COMMAND"; do + [ -z "$t" ] && continue # skip empty transformers + r="$("$t" "$r")" + done + echo "$r" +} + +create() { + # $1 ... src + # $2 ... dst + src="$1" + dst="$(_transform_split_name "$2")" + tarback_tar_create_command="$(_transform_remote "$TARBACK_TAR_CREATE_COMMAND")" + $TARBACK_REMOTE sh -c "$tarback_tar_create_command" - "$src" \ + | $TARBACK_COMPRESSION \ + | $TARBACK_SPLIT "$dst" +} + +restore() { + src="$(_transform_split_name "$1")" + dst="$2" + tarback_tar_extract_command="$(_transform_remote "$TARBACK_TAR_EXTRACT_COMMAND")" + $TARBACK_MERGE "$src"* \ + | $TARBACK_COMPRESSION --decompress --stdout \ + | $TARBACK_REMOTE sh -c "$tarback_tar_extract_command" - "$dst" +} + +short_options='p:' +while getopts "$short_options" arg; do + case "$arg" in + p) + # source plugin file + # shellcheck disable=SC1090 # disable cannot follow source + sourced=false + for loc in $TARBACK_PLUGIN_SEARCH_PATH; do + if [ -e "$loc/tarback/$OPTARG.sh" ]; then + . "$loc/tarback/$OPTARG.sh" + sourced=true + break + fi + done + if ! "$sourced"; then + echo "couldn't find plugin $OPTARG" >&2 + exit 1 + fi + shift 2 + ;; + *) + echo "unknown option $1" >&2 + exit 1 + ;; + esac +done + +case "$1" in + create) + shift + if [ "$#" -eq 2 ]; then + create "$@" + else + echo 'not enough arguments, expected 2: src dest' >&2 + exit 1 + fi + ;; + restore) + shift + if [ "$#" -eq 2 ]; then + restore "$@" + else + echo 'not enough arguments, expected 2: src dest' >&2 + exit 1 + fi + ;; +esac diff --git a/tarback/docker.sh b/tarback/docker.sh new file mode 100644 index 0000000..2d6a92b --- /dev/null +++ b/tarback/docker.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +TARBACK_TAR_CREATE_COMMAND='docker run -i --rm --workdir=/mnt --volume="$1":/mnt/"$1" alpine '"$TARBACK_TAR_CREATE_COMMAND" +TARBACK_TAR_EXTRACT_COMMAND='docker run -i --rm --workdir=/mnt --volume="$1":/mnt/"$1" alpine '"$TARBACK_TAR_EXTRACT_COMMAND"