snaprep

git mirror of https://ccx.te2000.cz/bzr/snaprep
git clone https://ccx.te2000.cz/git/snaprep
Log | Files | Refs

commit 92189fd599a89fab7bd33e3e9ec6408f77ebe494
parent 41e185c3a457d2b746b05ab601b9ce0c0a7b4e2b
Author: Jan Pobrislo <ccx@webprojekty.cz>
Date:   Fri, 21 Feb 2014 00:18:54 +0100

posixify
Diffstat:
Abin/snap.missing | 19+++++++++++++++++++
Mbin/snap.push | 52++++++++++++++++++++++++++++------------------------
Mbin/snap.push.single | 103++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Abin/snap.push.single.zsh | 39+++++++++++++++++++++++++++++++++++++++
Cbin/snap.push -> bin/snap.push.zsh | 0
5 files changed, 162 insertions(+), 51 deletions(-)

diff --git a/bin/snap.missing b/bin/snap.missing @@ -0,0 +1,19 @@ +#!/bin/awk -f +BEGIN { + if (ARGC != 2) { + print "usage: snap.missing source destination" + exit 2 + } + + while ("snap.list " ARGV[1] | getline) { + snapshots[$0] = 1 + } + + while ("snap.list " ARGV[2] | getline) { + snapshots[$0] = 0 + } + + for (ts in snapshots) { + if (snapshots[ts]) print ts + } +} diff --git a/bin/snap.push b/bin/snap.push @@ -1,33 +1,37 @@ -#!/bin/zsh +#!/bin/sh +: ${SNAP_SRCS:=.} + +usage() { + printf >&2 "Usage: %s: [-S SNAP_SRCS] [-D SNAP_DST] [-] [RSYNC_ARGS]\n" $(basenam "$0") + exit 2 +} + die() { - print -r - "$@" + printf "%s" "$*" exit 1 } -if [[ -z $SNAP_SRCS ]]; then - SNAP_SRCS=$1;shift -fi -SNAP_SRCS=${SNAP_SRCS%%/} +while getopts S:D: opt; do + case $opt in + (S) SNAP_SRCS=$OPTARG;; + (D) SNAP_DST=$OPTARG;; + (?) usage;; + (h) usage;; + esac +done -if [[ -z $SNAP_DST ]]; then - SNAP_DST=$1;shift -fi -SNAP_DST=${SNAP_DST%%/} +case $1 in + (-) shift;; + (--) shift;; +esac -typeset -A snapshots -for ts in ${(f)"$(snap.list $SNAP_SRCS/)"}; do - snapshots[$ts]=$SNAP_SRCS/$ts -done +if test -z "$SNAP_DST"; then + echo >&2 "SNAP_DST is required either as env var or argument" + usage +fi -for ts in ${(f)"$(snap.list $SNAP_DST/)"}; do - unset "snapshots[$ts]" -done +export SNAP_DST -export SNAP_SRC SNAP_DST -for SNAP_SRC in $snapshots; do - if [[ -o xtrace ]]; then - zsh -x $commands[snap.push.single] "$@" - else - snap.push.single "$@" - fi +snap.missing "$SNAP_SRCS" "$SNAP_DST" | while read ts; do + snap.push.single -S "$SNAP_SRCS/$ts" - "$@" done diff --git a/bin/snap.push.single b/bin/snap.push.single @@ -1,39 +1,88 @@ -#!/bin/zsh +#!/bin/sh +: ${SNAP_SRC:=.} + +usage() { + printf >&2 "Usage: %s: [-S SNAP_SRC] [-D SNAP_DST] [-] [RSYNC_ARGS]\n" $(basenam "$0") + exit 2 +} + die() { - print -r - "$@" + printf "%s" "$*" exit 1 } -if [[ -z $SNAP_SRC ]]; then - SNAP_SRC=$1;shift -fi -SNAP_SRC=${SNAP_SRC%%/} +while getopts S:D: opt; do + case $opt in + (S) SNAP_SRC=$OPTARG;; + (D) SNAP_DST=$OPTARG;; + (?) usage;; + (h) usage;; + esac +done -if [[ -z $SNAP_DST ]]; then - SNAP_DST=$1;shift +case $1 in + (-) shift;; + (--) shift;; +esac + +if test -z "$SNAP_DST"; then + echo >&2 "SNAP_DST is required either as env var or argument" + usage fi -SNAP_DST=${SNAP_DST%%/} -rsync=( rsync -aA --delete "$@" ) +check_local() { + for m in $SNAP_SRC/.snapshot.[0-9]*; do + test -f "$m" || continue + test -n "$mark" && die "duplicate snapshot mark" + mark=$m + done + + test -f "$mark" || die "snapshot mark not found" + ts=${mark##*.} +} + +check_remote() { + snap.list "$SNAP_SRC/" | while read m; do + test -n "$ts" && die "duplicate snapshot mark" + ts=$m + done + test -n "$ts" || die "snapshot mark not found" +} -marks=( $SNAP_SRC/.snapshot.[0-9]*(N) ) -(( $#marks != 1 )) && die invalid marks ${(qqq)marks} +rs() { + rsync -aA --delete +} -if [[ $SNAP_DST == *:* ]]; then +push_remote() { # remote - [[ $SNAP_DST == *.push ]] || $SNAP_DST=$SNAP_DST.push - $rsync --exclude=/.snapshot.\* $SNAP_SRC/ $SNAP_DST/ && \ - $rsync $SNAP_SRC/ $SNAP_DST/ -else - # local - [[ -d $SNAP_DST ]] || die destination not a directory: ${(qqq)SNAP_DST} - ts=${marks##*.} - snapshots=( ${SNAP_DST}/.snapshot.[1-9]*(N) ) - if (($#snapshots)); then - link=${SNAP_DST}/${${snapshots[-1]}##*.} - $rsync --link-dest=$link $SNAP_SRC/ $SNAP_DST/$ts/ || exit $? + case "$SNAP_DST" in + (*.push) ;; + (*) SNAP_DST=${SNAP_DST}.push;; + esac + rs "$@" --exclude=/.snapshot.\* "$SNAP_SRC/" "$SNAP_DST/" && \ + rs "$@" "$SNAP_SRC/" "$SNAP_DST/" +} + +push_local() { + test -d "$SNAP_DST" || die "destination not a directory: ${SNAP_DST}" + snapshot=$(snap.list "$SNAP_DST" | tail -1) + if test -n $snapshot; then + link=${SNAP_DST}/${snapshots} + rs "$@" "--link-dest=$link" "$SNAP_SRC/" "$SNAP_DST/$ts/" || exit $? else - $rsync $SNAP_SRC/ $SNAP_DST/$ts/ || exit $? + rs "$@" "$SNAP_SRC/" "$SNAP_DST/$ts/" || exit $? fi - touch ${SNAP_DST}/$marks:t -fi + touch "${SNAP_DST}/${marks##*/}" +} + +case "$SNAP_SRC" in + (*:*) check_remote;; + (*) check_local;; +esac + +case "$SNAP_DST" in + (rsync:*) push_remote;; + (*::*) push_remote;; + (*:*) die "pushing via remote shell directly not supported, use -e with rsync:// instead";; + (*) push_local;; +esac diff --git a/bin/snap.push.single.zsh b/bin/snap.push.single.zsh @@ -0,0 +1,39 @@ +#!/bin/zsh +die() { + print -r - "$@" + exit 1 +} + +if [[ -z $SNAP_SRC ]]; then + SNAP_SRC=$1;shift +fi +SNAP_SRC=${SNAP_SRC%%/} + +if [[ -z $SNAP_DST ]]; then + SNAP_DST=$1;shift +fi +SNAP_DST=${SNAP_DST%%/} + +rsync=( rsync -aA --delete "$@" ) + +marks=( $SNAP_SRC/.snapshot.[0-9]*(N) ) +(( $#marks != 1 )) && die invalid marks ${(qqq)marks} + +if [[ $SNAP_DST == *:* ]]; then + # remote + [[ $SNAP_DST == *.push ]] || SNAP_DST=$SNAP_DST.push + $rsync --exclude=/.snapshot.\* $SNAP_SRC/ $SNAP_DST/ && \ + $rsync $SNAP_SRC/ $SNAP_DST/ +else + # local + [[ -d $SNAP_DST ]] || die destination not a directory: ${(qqq)SNAP_DST} + ts=${marks##*.} + snapshots=( ${SNAP_DST}/.snapshot.[1-9]*(N) ) + if (($#snapshots)); then + link=${SNAP_DST}/${${snapshots[-1]}##*.} + $rsync --link-dest=$link $SNAP_SRC/ $SNAP_DST/$ts/ || exit $? + else + $rsync $SNAP_SRC/ $SNAP_DST/$ts/ || exit $? + fi + touch ${SNAP_DST}/$marks:t +fi diff --git a/bin/snap.push b/bin/snap.push.zsh