summaryrefslogtreecommitdiff
path: root/rejmerge.in
blob: faa4f98c19c2b21e85ed6c2dd46087c369ff406c (plain)
    1 #!/bin/bash
    2 #
    3 #  rejmerge (pkgutils)
    4 # 
    5 #  Copyright (c) 2000-2005 Per Liden
    6 #  Copyright (c) 2006-2016 by CRUX team (http://crux.nu)
    7 # 
    8 #  This program is free software; you can redistribute it and/or modify
    9 #  it under the terms of the GNU General Public License as published by
   10 #  the Free Software Foundation; either version 2 of the License, or
   11 #  (at your option) any later version.
   12 #
   13 #  This program is distributed in the hope that it will be useful,
   14 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
   15 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16 #  GNU General Public License for more details.
   17 #
   18 #  You should have received a copy of the GNU General Public License
   19 #  along with this program; if not, write to the Free Software
   20 #  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 
   21 #  USA.
   22 #
   23 
   24 info_n() {
   25 	echo -n "=======> $1"
   26 }
   27 
   28 info() {
   29 	info_n "$1"
   30 	echo
   31 }
   32 
   33 interrupted() {
   34 	echo ""
   35 	info "Aborted."
   36 	exit 1
   37 }
   38 
   39 atexit() {
   40 	if [ -e "$TMPFILE" ]; then
   41 		rm -f "$TMPFILE"
   42 	fi
   43 }
   44 
   45 rejmerge_diff() {
   46 	diff -u "$1" "$2" > "$3"
   47 }
   48 
   49 rejmerge_merge() {
   50 	diff --old-group-format="%<" \
   51 	     --new-group-format="%>" \
   52 	     --changed-group-format="<<<<< MERGE CONFLICT $1 >>>>>
   53 %<<<<<< MERGE CONFLICT $2 >>>>>
   54 %><<<<< END MERGE CONFLICT >>>>>
   55 " \
   56 	"$1" "$2" > "$3"
   57 
   58 	REJMERGE_MERGE_INFO="$(grep -c '^<<<<< END MERGE CONFLICT >>>>>$' "$3") merge conflict(s)."
   59 }
   60 
   61 permissions_menu() {
   62 	while true; do
   63 		info "Access permissions $1"
   64 		stat -c '%A  %U %G  %n' "$1"
   65 		stat -c '%A  %U %G  %n' "$2"
   66 		while true; do
   67 			info_n "[K]eep [U]pgrade [D]iff [S]kip? "
   68 			read -n1 CMD
   69 			echo
   70 
   71 			case "$CMD" in
   72 			k|K)	chown --reference="$1" "$2"
   73 				chmod --reference="$1" "$2"
   74 				break 2
   75 				;;
   76 			u|U)	chown --reference="$2" "$1"
   77 				chmod --reference="$2" "$1"
   78 				break 2
   79 				;;
   80 			d|D)	break 1
   81 				;;
   82 			s|S)	break 2
   83 				;;
   84 			esac
   85 		done
   86 	done
   87 }
   88 
   89 merge_menu() {
   90 	rejmerge_merge "$1" "$2" "$TMPFILE"
   91 
   92 	while true; do
   93 		info "Merged $1"
   94 		cat "$TMPFILE" | more
   95 
   96 		if [ "$REJMERGE_MERGE_INFO" ]; then
   97 			info "$REJMERGE_MERGE_INFO"
   98 			unset REJMERGE_MERGE_INFO
   99 		fi
  100 
  101 		while true; do
  102 			info_n "[I]nstall [E]dit [V]iew [S]kip? "
  103 			read -n1 CMD
  104 			echo
  105 
  106 			case "$CMD" in
  107 			i|I)	chmod --reference="$1" "$TMPFILE"
  108 				mv -f "$TMPFILE" "$1"
  109 				rm -f "$2"
  110 				break 2
  111 				;;
  112 			e|E)	$EDITOR "$TMPFILE"
  113 				break 1
  114 				;;
  115 			v|V)	break 1
  116 				;;
  117 			s|S)	break 2
  118 				;;
  119 			esac
  120 		done
  121 	done
  122 
  123 	: > "$TMPFILE"
  124 }
  125 
  126 diff_menu() {
  127 	rejmerge_diff "$1" "$2" "$TMPFILE"
  128 
  129 	while true; do
  130 		info "$1"
  131 		cat "$TMPFILE" | more
  132 		while true; do
  133 			info_n "[K]eep [U]pgrade [M]erge [D]iff [S]kip? "
  134 			read -n1 CMD
  135 			echo
  136 
  137 			case "$CMD" in
  138 			k|K)	rm -f "$2"
  139 				break 2
  140 				;;
  141 			u|U)	mv -f "$2" "$1"
  142 				break 2
  143 				;;
  144 			m|M)	merge_menu "$1" "$2"
  145 				break 2
  146 				;;
  147 			d|D)	break 1
  148 				;;
  149 			s|S)	break 2
  150 				;;
  151 			esac
  152 		done
  153 	done
  154 
  155 	: > "$TMPFILE"
  156 }
  157 
  158 file_menu() {
  159 	while true; do
  160 		info "$1"
  161 		file "$1" "$2"
  162 		while true; do
  163 			info_n "[K]eep [U]pgrade [D]iff [S]kip? "
  164 			read -n1 CMD
  165 			echo
  166 
  167 			case "$CMD" in
  168 			k|K)	rm -f "$2"
  169 				break 2
  170 				;;
  171 			u|U)	mv -f "$2" "$1"
  172 				break 2
  173 				;;
  174 			d|D)	break 1
  175 				;;
  176 			s|S)	break 2
  177 				;;
  178 			esac
  179 		done
  180 	done
  181 }
  182 
  183 print_help() {
  184 	echo "usage: $REJMERGE_COMMAND [options]"
  185 	echo "options:"
  186 	echo "  -r,   --root <path>         specify alternative root"
  187 	echo "  -v,   --version             print version and exit "
  188 	echo "  -h,   --help                print help and exit"
  189 }
  190 
  191 parse_options() {
  192 	while [ "$1" ]; do
  193 		case $1 in
  194 			-r|--root)
  195 				if [ ! "$2" ]; then
  196 					echo "$REJMERGE_COMMAND: option $1 requires an argument"
  197 					exit 1
  198 				fi
  199 				REJMERGE_ROOT="$2"
  200 				REJMERGE_CONF="$2$REJMERGE_CONF"
  201 				REJECTED_DIR="$2$REJECTED_DIR"
  202 				shift ;;
  203 			-v|--version)
  204 				echo "$REJMERGE_COMMAND (pkgutils) $REJMERGE_VERSION"
  205 				exit 0 ;;
  206 			-h|--help)
  207 				print_help
  208 				exit 0 ;;
  209 			*)
  210 				echo "$REJMERGE_COMMAND: invalid option $1"
  211 				exit 1 ;;
  212 		esac
  213 		shift
  214 	done
  215 
  216 	if [ ! -d "$REJECTED_DIR" ]; then
  217 		echo "$REJMERGE_COMMAND: $REJECTED_DIR not found"
  218 		exit 1
  219 	fi
  220 }
  221 
  222 files_regular() {
  223 	local STAT_FILE1=$(stat -c '%F' "$1")
  224 	local STAT_FILE2=$(stat -c '%F' "$2")
  225 
  226 	if [ "$STAT_FILE1" != "regular file" ]; then
  227 		return 1
  228 	fi
  229 
  230 	if [ "$STAT_FILE2" != "regular file" ]; then
  231 		return 1
  232 	fi
  233 
  234 	return 0
  235 }
  236 
  237 main() {
  238 	parse_options "$@"
  239 
  240 	if [ "$UID" != "0" ]; then
  241 		echo "$REJMERGE_COMMAND: only root can merge rejected files"
  242 		exit 1
  243 	fi
  244 
  245 	# Read configuration
  246 	if [ -f "$REJMERGE_CONF" ]; then
  247 		. "$REJMERGE_CONF"
  248 	fi
  249 	
  250 	REJECTED_FILES_FOUND="no"
  251 
  252 	# Check files
  253 	for REJECTED_FILE in $(find $REJECTED_DIR ! -type d); do
  254 		INSTALLED_FILE="$REJMERGE_ROOT${REJECTED_FILE##$REJECTED_DIR}"
  255 
  256 		# Remove rejected file if there is no installed version
  257 		if [ ! -e "$INSTALLED_FILE" ]; then
  258 			rm -f "$REJECTED_FILE"
  259 			continue
  260 		fi
  261 
  262 		# Check permissions
  263 		local STAT_FILE1=$(stat -c '%A %U %G' "$INSTALLED_FILE")
  264 		local STAT_FILE2=$(stat -c '%A %U %G' "$REJECTED_FILE")
  265 
  266 		if [ "$STAT_FILE1" != "$STAT_FILE2" ]; then
  267 			REJECTED_FILES_FOUND="yes"
  268 			permissions_menu "$INSTALLED_FILE" "$REJECTED_FILE"
  269 		fi
  270 
  271 		# Check file types
  272 		if files_regular "$INSTALLED_FILE" "$REJECTED_FILE"; then
  273 			# Both files are regular
  274 			if cmp -s "$INSTALLED_FILE" "$REJECTED_FILE"; then
  275 				rm -f "$REJECTED_FILE"
  276 			else
  277 				REJECTED_FILES_FOUND="yes"
  278 				diff_menu "$INSTALLED_FILE" "$REJECTED_FILE"
  279 			fi
  280 		else
  281 			# At least one file is non-regular
  282 			REJECTED_FILES_FOUND="yes"
  283 			file_menu "$INSTALLED_FILE" "$REJECTED_FILE"
  284 		fi
  285 	done
  286 
  287 	# Remove empty directories
  288 	for DIR in $(find $REJECTED_DIR -depth -type d); do
  289 		if [ "$DIR" != "$REJECTED_DIR" ]; then
  290 			rmdir "$DIR" &> /dev/null
  291 		fi
  292 	done
  293 
  294 	if [ "$REJECTED_FILES_FOUND" = "no" ]; then
  295 		echo "Nothing to merge"
  296 	fi
  297 
  298 	exit 0
  299 }
  300 
  301 trap "interrupted" SIGHUP SIGINT SIGQUIT SIGTERM
  302 trap "atexit" EXIT
  303 
  304 export LC_ALL=POSIX
  305 
  306 readonly REJMERGE_VERSION="#VERSION#"
  307 readonly REJMERGE_COMMAND="${0##*/}"
  308 REJMERGE_ROOT=""
  309 REJMERGE_CONF="/etc/rejmerge.conf"
  310 REJECTED_DIR="/var/lib/pkg/rejected"
  311 EDITOR=${EDITOR:-vi}
  312 TMPFILE=$(mktemp) || exit 1
  313 
  314 main "$@"
  315 
  316 # End of file

Generated by cgit