pkgutils/rejmerge.in
2007-04-18 22:38:09 +02:00

317 lines
6.0 KiB
Bash
Executable File

#!/bin/bash
#
# rejmerge (pkgutils)
#
# Copyright (c) 2000-2005 Per Liden
# Copyright (c) 2006-2007 by CRUX team (http://crux.nu)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
# USA.
#
info_n() {
echo -n "=======> $1"
}
info() {
info_n "$1"
echo
}
interrupted() {
echo ""
info "Aborted."
exit 1
}
atexit() {
if [ -e "$TMPFILE" ]; then
rm -f "$TMPFILE"
fi
}
rejmerge_diff() {
diff -u "$1" "$2" > "$3"
}
rejmerge_merge() {
diff --old-group-format="%<" \
--new-group-format="%>" \
--changed-group-format="<<<<< MERGE CONFLICT $1 >>>>>
%<<<<<< MERGE CONFLICT $2 >>>>>
%><<<<< END MERGE CONFLICT >>>>>
" \
"$1" "$2" > "$3"
REJMERGE_MERGE_INFO="$(grep -c '^<<<<< END MERGE CONFLICT >>>>>$' "$3") merge conflict(s)."
}
permissions_menu() {
while true; do
info "Access permissions $1"
stat -c '%A %U %G %n' "$1"
stat -c '%A %U %G %n' "$2"
while true; do
info_n "[K]eep [U]pgrade [D]iff [S]kip? "
read -n1 CMD
echo
case "$CMD" in
k|K) chown --reference="$1" "$2"
chmod --reference="$1" "$2"
break 2
;;
u|U) chown --reference="$2" "$1"
chmod --reference="$2" "$1"
break 2
;;
d|D) break 1
;;
s|S) break 2
;;
esac
done
done
}
merge_menu() {
rejmerge_merge "$1" "$2" "$TMPFILE"
while true; do
info "Merged $1"
cat "$TMPFILE" | more
if [ "$REJMERGE_MERGE_INFO" ]; then
info "$REJMERGE_MERGE_INFO"
unset REJMERGE_MERGE_INFO
fi
while true; do
info_n "[I]nstall [E]dit [V]iew [S]kip? "
read -n1 CMD
echo
case "$CMD" in
i|I) chmod --reference="$1" "$TMPFILE"
mv -f "$TMPFILE" "$1"
rm -f "$2"
break 2
;;
e|E) $EDITOR "$TMPFILE"
break 1
;;
v|V) break 1
;;
s|S) break 2
;;
esac
done
done
: > "$TMPFILE"
}
diff_menu() {
rejmerge_diff "$1" "$2" "$TMPFILE"
while true; do
info "$1"
cat "$TMPFILE" | more
while true; do
info_n "[K]eep [U]pgrade [M]erge [D]iff [S]kip? "
read -n1 CMD
echo
case "$CMD" in
k|K) rm -f "$2"
break 2
;;
u|U) mv -f "$2" "$1"
break 2
;;
m|M) merge_menu "$1" "$2"
break 2
;;
d|D) break 1
;;
s|S) break 2
;;
esac
done
done
: > "$TMPFILE"
}
file_menu() {
while true; do
info "$1"
file "$1" "$2"
while true; do
info_n "[K]eep [U]pgrade [D]iff [S]kip? "
read -n1 CMD
echo
case "$CMD" in
k|K) rm -f "$2"
break 2
;;
u|U) mv -f "$2" "$1"
break 2
;;
d|D) break 1
;;
s|S) break 2
;;
esac
done
done
}
print_help() {
echo "usage: $REJMERGE_COMMAND [options]"
echo "options:"
echo " -r, --root <path> specify alternative root"
echo " -v, --version print version and exit "
echo " -h, --help print help and exit"
}
parse_options() {
while [ "$1" ]; do
case $1 in
-r|--root)
if [ ! "$2" ]; then
echo "$REJMERGE_COMMAND: option $1 requires an argument"
exit 1
fi
REJMERGE_ROOT="$2"
REJMERGE_CONF="$2$REJMERGE_CONF"
REJECTED_DIR="$2$REJECTED_DIR"
shift ;;
-v|--version)
echo "$REJMERGE_COMMAND (pkgutils) $REJMERGE_VERSION"
exit 0 ;;
-h|--help)
print_help
exit 0 ;;
*)
echo "$REJMERGE_COMMAND: invalid option $1"
exit 1 ;;
esac
shift
done
if [ ! -d "$REJECTED_DIR" ]; then
echo "$REJMERGE_COMMAND: $REJECTED_DIR not found"
exit 1
fi
}
files_regular() {
local STAT_FILE1=$(stat -c '%F' "$1")
local STAT_FILE2=$(stat -c '%F' "$2")
if [ "$STAT_FILE1" != "regular file" ]; then
return 1
fi
if [ "$STAT_FILE2" != "regular file" ]; then
return 1
fi
return 0
}
main() {
parse_options "$@"
if [ "$UID" != "0" ]; then
echo "$REJMERGE_COMMAND: only root can merge rejected files"
exit 1
fi
# Read configuration
if [ -f "$REJMERGE_CONF" ]; then
. "$REJMERGE_CONF"
fi
REJECTED_FILES_FOUND="no"
# Check files
for REJECTED_FILE in $(find $REJECTED_DIR ! -type d); do
INSTALLED_FILE="$REJMERGE_ROOT${REJECTED_FILE##$REJECTED_DIR}"
# Remove rejected file if there is no installed version
if [ ! -e "$INSTALLED_FILE" ]; then
rm -f "$REJECTED_FILE"
continue
fi
# Check permissions
local STAT_FILE1=$(stat -c '%A %U %G' "$INSTALLED_FILE")
local STAT_FILE2=$(stat -c '%A %U %G' "$REJECTED_FILE")
if [ "$STAT_FILE1" != "$STAT_FILE2" ]; then
REJECTED_FILES_FOUND="yes"
permissions_menu "$INSTALLED_FILE" "$REJECTED_FILE"
fi
# Check file types
if files_regular "$INSTALLED_FILE" "$REJECTED_FILE"; then
# Both files are regular
if cmp -s "$INSTALLED_FILE" "$REJECTED_FILE"; then
rm -f "$REJECTED_FILE"
else
REJECTED_FILES_FOUND="yes"
diff_menu "$INSTALLED_FILE" "$REJECTED_FILE"
fi
else
# At least one file is non-regular
REJECTED_FILES_FOUND="yes"
file_menu "$INSTALLED_FILE" "$REJECTED_FILE"
fi
done
# Remove empty directories
for DIR in $(find $REJECTED_DIR -depth -type d); do
if [ "$DIR" != "$REJECTED_DIR" ]; then
rmdir "$DIR" &> /dev/null
fi
done
if [ "$REJECTED_FILES_FOUND" = "no" ]; then
echo "Nothing to merge"
fi
exit 0
}
trap "interrupted" SIGHUP SIGINT SIGQUIT SIGTERM
trap "atexit" EXIT
export LC_ALL=POSIX
readonly REJMERGE_VERSION="#VERSION#"
readonly REJMERGE_COMMAND="${0##*/}"
REJMERGE_ROOT=""
REJMERGE_CONF="/etc/rejmerge.conf"
REJECTED_DIR="/var/lib/pkg/rejected"
EDITOR=${EDITOR:-vi}
TMPFILE=$(mktemp) || exit 1
main "$@"
# End of file