hgmerge: add cleanup functions
This patch adds functions cleanup, success and failure.
The last two of these should be used instead of exit.
Current code was changed to use them.
It also moves $HGTMP to the top of the file (it's used in the cleanup
function), changes the comment and removes now unneeded trap
in the diff+patch merge.
#!/bin/sh
#
# hgmerge - default merge helper for Mercurial
#
# This tries to find a way to do three-way merge on the current system.
# The result ought to end up in $1.
set -e # bail out quickly on failure
LOCAL="$1"
BASE="$2"
OTHER="$3"
if [ -z "$EDITOR" ]; then
EDITOR="vi"
fi
# find decent versions of our utilities, insisting on the GNU versions where we
# need to
MERGE=merge
DIFF3=gdiff3
DIFF=gdiff
PATCH=gpatch
type $MERGE >/dev/null 2>&1 || MERGE=
type $DIFF3 >/dev/null 2>&1 || DIFF3=diff3
type $DIFF >/dev/null 2>&1 || DIFF=diff
type $PATCH >/dev/null 2>&1 || PATCH=patch
$DIFF3 --version >/dev/null 2>&1 || DIFF3=
# find optional visual utilities
FILEMERGE='/Developer/Applications/Utilities/FileMerge.app/Contents/MacOS/FileMerge'
KDIFF3=kdiff3
TKDIFF=tkdiff
type $FILEMERGE >/dev/null 2>&1 || FILEMERGE=
type $KDIFF3 >/dev/null 2>&1 || KDIFF3=
type $TKDIFF >/dev/null 2>&1 || TKDIFF=
# temporary directory for diff+patch merge
HGTMP="${TMPDIR-/tmp}/hgmerge.$RANDOM.$RANDOM.$RANDOM.$$"
# put all your required cleanup here
cleanup() {
rm -f "$LOCAL.orig"
rm -rf "$HGTMP"
}
# functions concerning program exit
success() {
cleanup
exit 0
}
failure() {
echo "merge failed" 1>&2
cp "$LOCAL.orig" "$LOCAL"
cleanup
exit 1
}
# Clean up when interrupted
trap "failure" 1 2 3 6 15 # HUP INT QUIT ABRT TERM
# Back up our file
cp "$LOCAL" "$LOCAL.orig"
# Attempt to do a non-interactive merge
if [ -n "$MERGE" ]; then
$MERGE "$LOCAL" "$BASE" "$OTHER" 2> /dev/null && success
cp "$LOCAL.orig" "$LOCAL"
elif [ -n "$DIFF3" ]; then
echo $DIFF3 -m "$LOCAL.orig" "$BASE" "$OTHER"
$DIFF3 -m "$LOCAL.orig" "$BASE" "$OTHER" > "$LOCAL" && success
if [ $? -eq 2 ]; then
echo "$DIFF3 failed! Exiting." 1>&2
cp "$LOCAL.orig" "$LOCAL"
failure
fi
cp "$LOCAL.orig" "$LOCAL"
fi
# on MacOS X try FileMerge.app, shipped with Apple's developer tools
# TODO: make proper temp files. foo.orig and foo.link are dangerous
if [ -n "$FILEMERGE" ]; then
cp "$LOCAL.orig" "$LOCAL"
ln "$LOCAL" "$LOCAL.link"
# filemerge prefers the right by default
if ! "$FILEMERGE" -left "$OTHER" -right "$LOCAL" -ancestor "$BASE" -merge "$LOCAL"
then
echo "FileMerge failed to launch"
failure
fi
if ! test "$LOCAL" -ef "$LOCAL.link"
then
rm "$LOCAL.orig" "$LOCAL.link"
success
else
rm "$LOCAL.link"
echo "$LOCAL is unchanged. Was the merge successful?"
select answer in yes no
do
if test "$answer" == "yes"
then
rm "$LOCAL.orig"
success
else
failure
fi
done
failure
fi
fi
if [ -n "$DISPLAY" ]; then
# try using kdiff3, which is fairly nice
if [ -n "$KDIFF3" ]; then
$KDIFF3 --auto "$BASE" "$LOCAL" "$OTHER" -o "$LOCAL" || failure
success
fi
# try using tkdiff, which is a bit less sophisticated
if [ -n "$TKDIFF" ]; then
$TKDIFF "$LOCAL" "$OTHER" -a "$BASE" -o "$LOCAL" || failure
success
fi
fi
# Attempt to do a merge with $EDITOR
if [ -n "$MERGE" ]; then
echo "conflicts detected in $LOCAL"
$MERGE "$LOCAL" "$BASE" "$OTHER" 2>/dev/null || $EDITOR "$LOCAL"
success
fi
if [ -n "$DIFF3" ]; then
echo "conflicts detected in $LOCAL"
$DIFF3 -m "$LOCAL.orig" "$BASE" "$OTHER" > "$LOCAL" || {
case $? in
1)
$EDITOR "$LOCAL" ;;
2) echo "$DIFF3 failed! Exiting." 1>&2
cp "$LOCAL.orig" "$LOCAL"
failure ;;
esac
success
}
fi
# attempt to manually merge with diff and patch
if [ -n "$DIFF" -a -n "$PATCH" ]; then
(umask 077 && mkdir "$HGTMP") || {
echo "Could not create temporary directory $HGTMP" 1>&2
failure
}
$DIFF -u "$BASE" "$OTHER" > "$HGTMP/diff" || :
if $PATCH "$LOCAL" < "$HGTMP/diff"; then
success
else
# If rejects are empty after using the editor, merge was ok
$EDITOR "$LOCAL" "$LOCAL.rej" && test -s "$LOCAL.rej" || success
fi
failure
fi
echo "hgmerge: unable to find merge, tkdiff, kdiff3, or diff+patch!"
failure