summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xalt-prune-rclone-rm.sh73
-rwxr-xr-xbackomp13
2 files changed, 86 insertions, 0 deletions
diff --git a/alt-prune-rclone-rm.sh b/alt-prune-rclone-rm.sh
new file mode 100755
index 0000000..6e3eeb2
--- /dev/null
+++ b/alt-prune-rclone-rm.sh
@@ -0,0 +1,73 @@
+#!/usr/bin/env bash
+#
+# Copyright 2023 David Vazgenovich Shakaryan
+
+qargs() {
+ local arg str
+
+ for arg; do
+ [[ "${arg:-*}" =~ [^A-Za-z0-9%+./:=@_-] ]] && arg="${arg@Q}"
+ str+=" ${arg}"
+ done
+ printf '%s\n' "${str:1}"
+}
+
+target="${1}"
+
+[[ "${target}" =~ ^(rclone://([^:]+):)(.+) ]] || exit 1
+prefix="${BASH_REMATCH[1]}"
+remote="${BASH_REMATCH[2]}"
+path="${BASH_REMATCH[3]}"
+
+conf="$(rclone config dump)" || exit 1
+read -rd '' JQ <<'EOF'
+.[$k]
+| select(.type == "crypt" or .type == "sftp") // error("not crypt or sftp")
+| [.type, .remote]
+| @tsv
+EOF
+IFS=$'\t' read -r r_type r_remote < <(
+ jq -rc --arg k "${remote}" "${JQ}" <<<"${conf}") || exit 1
+
+if [[ "${r_type}" == 'crypt' ]]; then
+ crypt="${remote}"
+
+ [[ "${r_remote}" =~ ^([^:]+):(.*) ]] || exit 1
+ remote="${BASH_REMATCH[1]}"
+ base="${BASH_REMATCH[2]:+${BASH_REMATCH[2]}/}"
+
+ upath=0
+ while IFS=$'\t' read -r k v; do
+ [[ "${k% }" == "${path}" ]] && path="${base}${v# }" && upath=1
+ done < <(rclone cryptdecode --reverse "${crypt}:" "${path}")
+ wait "$!" || exit 1
+ ((upath)) || exit 1
+fi
+
+read -rd '' JQ <<'EOF'
+.[$k]
+| select(.type == "sftp") // error("not sftp")
+| select(.key_file_pass | not) // error("key uses passphrase")
+| [
+ (.key_file | select(.) // error("missing key")
+ | "-i", (sub("^~"; env.HOME) | @sh)),
+ (.known_hosts_file | select(.)
+ | "-o", ("UserKnownHostsFile=\(sub("^~"; env.HOME))" | @sh)),
+ (.port | select(.) | "-p", @sh),
+ ("\(.user // error("missing user"))@\(.host // error("missing host"))"
+ | @sh)
+]
+| join(" ")
+EOF
+mapfile -td '' args < <(
+ jq -rc --arg k "${remote}" "${JQ}" <<<"${conf}" | \
+ xargs -r printf '%s\0'
+ [[ "${PIPESTATUS[0]}" -eq 0 && "${PIPESTATUS[1]}" -eq 0 ]])
+wait "$!" || exit 1
+
+ssh_cmd=(ssh -o BatchMode=yes "${args[@]}")
+cmd=("${ssh_cmd[@]}"
+ "rm -rf $(printf '%q' "${path}")")
+echo "* $(qargs "${cmd[@]}")"
+"${cmd[@]}" || exit 1
+exit 0
diff --git a/backomp b/backomp
index af44f77..8d90b8c 100755
--- a/backomp
+++ b/backomp
@@ -348,6 +348,18 @@ prune() {
else
if ((DRY)); then
echo "* DRY: prune ${__snaps[__i]}"
+ elif [[ -n "${opts['alt_prune']}" ]]; then
+ echo "* alt-prune ${__snaps[__i]}"
+ bash -c "$(declare -p opts \
+ ); target=$(printf '%q' \
+ "${__snaps[__i]}" \
+ ); ${opts['alt_prune']}" < /dev/null
+ res="$?"
+ if [[ "${res}" -ne 0 ]]; then
+ err 'alt-prune command failed' \
+ "(${res}):" \
+ "${opts['alt_prune']}"
+ fi
elif [[ "${__snaps[__i]}" == rclone://* ]]; then
run rclone purge -- "${__snaps[__i]#*//}"
elif [[ "${__snaps[__i]}" =~ ^([^:/]*):(.*) ]]; then
@@ -419,6 +431,7 @@ declare -A def_opts=(
['rclone_copy_command']='copy'
['rclone_use_copy_dest']=1
['pre_copy']=
+ ['alt_prune']=
)
declare -A opts tainted_opts
reset_opts() {