X-Git-Url: https://mattmccutchen.net/utils/utils.git/blobdiff_plain/2a4c04302618a3888c0af087daa78d70adeeab33..40ea9b7868f2b7746e7cbabfba6aba982096392a:/patchsync diff --git a/patchsync b/patchsync index 31a4001..ccd3390 100755 --- a/patchsync +++ b/patchsync @@ -1,9 +1,11 @@ #!/bin/bash # patchsync: Synchronizes a trunk, a branch, and a patch containing the # differences between them. -# Version 2 # -- Matt McCutchen -# + +# If I had to update the version in the --version message separately, I would forget. +PATCHSYNC_VERSION=2.4 + # usage: patchsync [--dry-run] [branch | patch] # # Patchsync is invoked on a "staging directory", which holds some configuration @@ -52,10 +54,10 @@ # - do_patch : apply the patch to the # specified trunk; define it to understand your favorite diff format # - example: patch --no-backup-if-mismatch -d $2/ -p1 <$1 -# - Note: patchsync runs these functions under "pipefail", but the -# "set -e" it uses does not propagate into the functions. Patchsync -# provides an "exitoneok" function you can use to treat an exit code of -# 1 as 0. You might want to && successive commands together. +# - Note: Patchsync runs these functions under "pipefail" and "set -e". +# Caution: "set -e" is idiosyncratic; you may wish to && together +# successive commands anyway. Patchsync provides an "exitoneok" +# function you can use to treat an exit code of 1 as 0. # - There are several possible ways to handle failed hunks. The simplest # and safest is to make do_patch fail, but that's inconvenient for the # user, who must investigate the *.rej files in the staging directory @@ -81,8 +83,14 @@ # Disable branch/.patchsync support because it's a bad idea in general, and the # cyclic symlink confuses Eclipse in particular. -- Matt 2006.11.30 -set -e -trap "echo 'Patchsync encountered an unexpected error! ABORTING!' 1>&2; exit 2;" ERR +# Error handling +function handle_error { + exec >&2 + echo "Patchsync encountered an unexpected error! Aborting!" + echo "The failed command was: $1" + exit 2 +} +trap 'handle_error "$BASH_COMMAND"' ERR set -o errtrace set -o pipefail @@ -90,7 +98,7 @@ set -o pipefail type rsync >/dev/null 2>&1 || \ { echo "Patchsync requires rsync, but there's no rsync on your path!" 1>&2; exit 1; } # If a cp2 is available, use it; otherwise define our own. -type cp2 >/dev/null 2>&1 || function cp2 { rsync -rltE --chmod=ugo=rwx "$@"; } +type cp2 >/dev/null 2>&1 || function cp2 { exec rsync -rltE --chmod=ugo=rwx "$@"; } function exitoneok { "$@" || [ $? == 1 ] @@ -106,7 +114,7 @@ function wdpp_from { # NOT bash builtin pwd; it tells us how we got here, not where we are pA="$(/bin/pwd)/" pA="${pA#/}" - pB="$( (cd "$AtoB" && /bin/pwd) )/" + pB="$(cd "$AtoB" && /bin/pwd)/" pB="${pB#/}" # Lop off the longest common prefix of components that we can. # While first components are equal... @@ -119,11 +127,12 @@ function wdpp_from { ans="$pA" # Translate remaining components of $pB to ../s while [ -n "$pB" ]; do - ans="$ans../" + ans="../$ans" pB="${pB#*/}" done # Double check; add dot to the end to enforce ending in a slash and handle empty ans (cd "$AtoB" && [ "$ans." -ef /proc/self/fd/3 ]) 3<. + [ $? == 0 ] # Yay echo "$ans" } @@ -151,17 +160,11 @@ fi cd "$staging" || { echo "Failed to enter staging dir!" 1>&2; exit 1; } shift -. settings +. ./settings type do_diff >/dev/null 2>&1 || { echo "do_diff is not defined!" 1>&2; exit 1; } type do_patch >/dev/null 2>&1 || { echo "do_patch is not defined!" 1>&2; exit 1; } whichtoupdate="$1" -# patchsync --new doesn't need this any more except for identical-branch -#if [ -z "$whichtoupdate" ] && [ -s whichtoupdate ]; then -# # Hook for patchsync --new -# whichtoupdate="$(< whichtoupdate)" -# echo "Updating $whichtoupdate according to staging dir." -#el if [ -n "$whichtoupdate" ]; then echo "Updating $whichtoupdate according to command line argument." else @@ -227,8 +230,8 @@ function prepare_branch { echo "Preparing updated branch..." # No link-dest because we will modify and then link-dest when copying out "${COPYIN[@]}" trunk/ branch-new/ - do_patch patch branch-new || \ - { error=1; echo "Failed to prepare updated branch!" 1>&2; rm -rf branch-new; } + (do_patch patch branch-new) + [ $? == 0 ] || { error=1; echo "Failed to prepare updated branch!" 1>&2; rm -rf branch-new; } } function prepare_patch { @@ -236,8 +239,8 @@ function prepare_patch { # Link-dest is fine because these are temporary read-only copies "${COPYIN[@]}" --link-dest=../trunk/ trunk/ trunk-tmp/ "${COPYIN[@]}" --link-dest=../branch/ branch/ branch-tmp/ - do_diff trunk-tmp branch-tmp patch-new || \ - { error=1; echo "Failed to prepare updated patch!" 1>&2; rm -rf patch-new; } + (do_diff trunk-tmp branch-tmp patch-new) + [ $? == 0 ] || { error=1; echo "Failed to prepare updated patch!" 1>&2; rm -rf patch-new; } rm -rf trunk-tmp branch-tmp } @@ -247,8 +250,8 @@ case $whichtoupdate in # No link-dest because we will link-dest when copying out "${COPYIN[@]}" trunk/ branch-new/ echo "Creating empty patch..." - do_diff branch-new branch-new patch-new || \ - { error=1; echo "Failed to create empty patch!" 1>&2; rm -rf patch-new; } + (do_diff branch-new branch-new patch-new) + [ $? == 0 ] || { error=1; echo "Failed to create empty patch!" 1>&2; rm -rf patch-new; } ;; (branch) prepare_branch @@ -276,17 +279,14 @@ EOF esac if ! [ $error ] && ! [ $dryrun ]; then - # Disable locking for now... - # ! [ -e lock ] || { echo "Staging dir is locked! Delete the file \`lock' if the other instance of patchsync is gone." 1>&2; exit 1; } - # echo "patchsync lock file pid $$ date $(date)" >lock - echo "Copying out..." ! [ -e branch-new ] || { hash_dir branch-new/ >branch-new-hash - "${COPYOUT[@]}" -i --link-dest="$(wdpp_from branch/)branch-new/" branch-new/ branch/ + linkdest="$(wdpp_from branch/)branch-new/" # Do separately so a failure in wdpp_from is noticed. + "${COPYOUT[@]}" -i --link-dest="$linkdest" branch-new/ branch/ rm -rf branch-new } - ! [ -e patch-new ] || cmp -s patch-work patch || { + ! [ -e patch-new ] || cmp -s patch patch-new || { hash_file patch-new >patch-new-hash # Don't use rsync because we might have to write through a symlink. echo "> patch" @@ -298,16 +298,15 @@ if ! [ $error ] && ! [ $dryrun ]; then for i in trunk patch branch; do mv $i-new-hash $i-save-hash done - - # rm lock else echo "Would copy out as follows:" ! [ -e branch-new ] || { hash_dir branch-new/ >branch-new-hash - "${COPYOUT[@]}" -n -i --link-dest="$(wdpp_from branch/)branch-new/" branch-new/ branch/ + linkdest="$(wdpp_from branch/)branch-new/" # Do separately so a failure in wdpp_from is noticed. + "${COPYOUT[@]}" -n -i --link-dest="$linkdest" branch-new/ branch/ #rm -rf branch-new } - ! [ -e patch-new ] || cmp -s patch-work patch || { + ! [ -e patch-new ] || cmp -s patch patch-new || { hash_file patch-new >patch-new-hash # Don't use rsync because we might have to write through a symlink. echo "> patch" @@ -348,13 +347,13 @@ function patchsync_new { exit 1 fi - # Set up arguments. Open templates because we will change directories. + # Set up arguments. trunk="$1" patch="$2" branch="$3" staging="$4" - # What exists? Whichtochange first? + # What exists? ! [ -e "$staging" ] || { echo "Staging dir already exists!" 1>&2; exit 1; } [ -d "$trunk" ] || { echo "Trunk does not exist!" 1>&2; exit 1; } @@ -365,9 +364,9 @@ function patchsync_new { echo "Created staging dir at $staging." # Adjust paths appropriately. - trunk="$wdpp$trunk" - patch="$wdpp$patch" - branch="$wdpp$branch" + [[ "$trunk" == /* ]] || trunk="$wdpp$trunk" + [[ "$patch" == /* ]] || patch="$wdpp$patch" + [[ "$branch" == /* ]] || branch="$wdpp$branch" # Create links to areas ln -s "$trunk" trunk @@ -423,7 +422,7 @@ END function patchsync_help { cat < [branch | patch] patchsync --new Please read the top of the script for complete documentation.