Import patchsync version 1
authorMatt McCutchen <matt@mattmccutchen.net>
Wed, 2 Sep 2020 20:42:51 +0000 (16:42 -0400)
committerMatt McCutchen <matt@mattmccutchen.net>
Wed, 2 Sep 2020 20:42:51 +0000 (16:42 -0400)
Modification time: 2006-09-03 13:39:32 -0400

patchsync [new file with mode: 0755]

diff --git a/patchsync b/patchsync
new file mode 100755 (executable)
index 0000000..8c20a1d
--- /dev/null
+++ b/patchsync
@@ -0,0 +1,93 @@
+#!/bin/bash
+# patchsync: Synchronize a branch with a patch (e.g., acls.diff and rsync-acl).
+# usage: patchsync <staging> {'' | --dry-run} [branch | patch]
+# <staging>: the staging directory, containing a shell script "settings" and an optional rsync filter file "filter"
+#     "settings" must contain:
+#         - $trunk, $patch, $branch paths interpreted relative to the staging dir
+#         - shell function do_diff: trunk, branch => patch
+#             e.g., for rsync: diff -uprN trunk branch | sed -re 's/^(\+\+\+|---) ([^\t]+).*$/\1 \2/' | grep -v '^diff' >patch
+#         - shell function do_patch: branch copied from trunk, patch => branch
+#             e.g., for rsync: patch --no-backup-if-mismatch -d branch/ -p1 <patch
+# --dry-run: don't note anything
+# branch | patch: overwrite the specified thing in case of a conflict (e.g., on the first run)
+
+set -e
+
+staging="$1"
+if ! [ -r "$staging/settings" ]; then
+       echo "Specify a staging directory containing a settings file!" 1>&2
+       exit 1
+fi
+cd "$staging"
+
+dryrun="$2"
+whichtochange="$3"
+CP2t=(cp2 --del)
+CP2in=("${CP2t[@]}" --filter='. filter' --delete-excluded)
+CP2out=("${CP2t[@]}" --filter='. filter' --no-t --checksum) # be nice to mtimes
+export LC_COLLATE="C"
+
+. settings
+
+echo "Copying in, checking for changes..."
+"${CP2in[@]}" --link-dest=../trunk-save -i "$trunk/" trunk/
+diff -r trunk{-save,} >/dev/null || trunkch=ch
+"${CP2in[@]}" --link-dest=../branch-save -i "$branch/" branch/
+diff -r branch{-save,} >/dev/null || branchch=ch
+cp2 --link-dest=../patch-save -i "$patch" patch
+diff -r patch{-save,} >/dev/null || patchch=ch
+echo "Done."
+
+if [ $trunkch ] || [ $branchch ] || [ $patchch ]; then
+       # Something changed.
+       # Update either branch or patch, whichever didn't change.
+       # If trunk changes, update branch, not patch.
+       if [ "$whichtochange" == 'branch' ] || ! [ $branchch ]; then
+               echo "Updating branch..."
+               "${CP2t[@]}" trunk/ branch/
+               do_patch
+               echo "Done."
+               copyout=1
+       elif [ "$whichtochange" == 'patch' ] || ! [ $patchch ]; then
+               echo "Updating patch..."
+               do_diff
+               echo "Done."
+               copyout=1
+       else
+               echo "Conflict: both branch and patch changed!"
+               echo "Run patchsync <staging> <dry-run> [branch | patch] to"
+               echo "update the specified area from the others."
+               exit 1
+       fi
+else
+       # Easy case
+       echo "Nothing changed."
+fi
+
+if [ $copyout ]; then
+if ! [ $dryrun ]; then
+       ! [ -e lock ] || { echo "Locked!  Please fix!"; exit 1; }
+       echo "patchsync lock file pid $$ date $(date)" >lock
+       
+       echo "Copying out..."
+       "${CP2out[@]}" -i branch/ "$branch/"
+       cp2 -i --checksum patch "$patch"
+       echo "Done."
+       echo "Noting..."
+       for i in trunk branch patch; do
+               rm -rf $i-save
+               mv $i{,-save}
+       done
+       echo "Done."
+       
+       rm lock
+else
+       echo "Dry run; no action.  You can inspect the results if you want."
+       echo "Fake copying out..."
+       "${CP2out[@]}" -in branch/ "$branch/"
+       cp2 -in --checksum patch "$patch"
+       echo "Done."
+fi
+fi
+
+exit 0