[PATCH 4/4] pacdiff: Learn the (M)erge mode
Denton Liu
liu.denton at gmail.com
Sat Dec 26 07:27:20 UTC 2020
Currently, pacdiff only allows users to diff between the current file
and the new file. However, the merging of files could be automated by
the use of some 3-way merge utility.
Teach pacdiff the (M)erge mode which performs a 3-way merge using a
given $MERGEPROG (`diff3 -m` by default). The base file is taken from
from the second-newest package in the cache.
Signed-off-by: Denton Liu <liu.denton at gmail.com>
---
Notes:
There are a few things I'd like some comments on:
* Is there a better way of getting the base file? I assume that
most people will run pacdiff right after an update but what if
they run pacdiff after two or more updates?
* How is the UI flow for the merge command? Do we want to let
automerges write out without warning or do we want to do
something else?
* When displaying conflicts, I currently display a diff against
the base and the merged version. Do we want to display a diff
against the merged and the current version?
doc/pacdiff.8.txt | 9 ++++--
src/pacdiff.sh.in | 81 +++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 85 insertions(+), 5 deletions(-)
diff --git a/doc/pacdiff.8.txt b/doc/pacdiff.8.txt
index a89c0e7..592da72 100644
--- a/doc/pacdiff.8.txt
+++ b/doc/pacdiff.8.txt
@@ -18,8 +18,8 @@ Description
-----------
pacdiff is a script which looks for pacorig, pacnew and pacsave files from the
backup entries found in the local Pacman db. For every found file the option is
-given to view, skip, diff, remove or overwrite the found pacorig, pacnew or
-pacsave file.
+given to view, merge, skip, diff, remove or overwrite the found pacorig, pacnew
+or pacsave file.
Environment
-----------
@@ -29,6 +29,9 @@ Environment
*DIFFSEARCHPATH*::
Override the default search path '/etc', only when using find.
+*MERGEPROG*::
+ Override the default 'diff3 -m' 3-way merge program. One possible
+ alternative is 'git merge-file -p'.
Options
-------
@@ -47,6 +50,8 @@ Options
*\--nocolor*::
Remove colors from output.
+*-c, \--cachedir <dir>*::
+ Scan 'dir' instead as the pacman cache for 3-way merge base candidates.
See Also
--------
diff --git a/src/pacdiff.sh.in b/src/pacdiff.sh.in
index a50cb93..cdecdb4 100644
--- a/src/pacdiff.sh.in
+++ b/src/pacdiff.sh.in
@@ -27,6 +27,8 @@ LIBRARY=${LIBRARY:-'@libmakepkgdir@'}
diffprog=${DIFFPROG:-'vim -d'}
diffsearchpath=${DIFFSEARCHPATH:-/etc}
+mergeprog=${MERGEPROG:-'diff3 -m'}
+cachedir=
USE_COLOR='y'
declare -a oldsaves
declare -i USE_FIND=0 USE_LOCATE=0 USE_PACDB=0 OUTPUTONLY=0
@@ -53,13 +55,16 @@ Search Options: select one (default: --pacmandb)
-p/--pacmandb scan active config files from pacman database
General Options:
- -o/--output print files instead of merging them
- --nocolor remove colors from output
+ -o/--output print files instead of merging them
+ --nocolor remove colors from output
+ -c/--cachedir <dir> scan "dir" for 3-way merge base candidates.
+ (default: read from @sysconfdir@/pacman.conf)
Environment Variables:
DIFFPROG override the merge program: (default: 'vim -d')
DIFFSEARCHPATH override the search path. (only when using find)
(default: /etc)
+ MERGEPROG override the 3-way merge program: (default: 'diff3 -m')
Example: DIFFPROG=meld DIFFSEARCHPATH="/boot /etc /usr" $myname
Example: $myname --output --locate
@@ -83,6 +88,62 @@ print_existing_pacsave(){
done
}
+base_cache_tar() {
+ package="$1"
+
+ [[ -d $cachedir ]] ||
+ die "cachedir '%s' does not exist or is not a directory" "$cachedir"
+
+ # unlikely that this will fail, but better make sure
+ pushd "$cachedir" &>/dev/null || die "failed to chdir to '%s'" "$cachedir"
+
+ find "$PWD" -name "$package-[0-9]*.pkg.tar*" | pacsort --files | sed -ne '2p'
+
+ popd &>/dev/null
+}
+
+merge_file() {
+ pacfile="$1"
+ file="$2"
+
+ package="$(pacman -Qoq "$file")" || return 1
+ base_tar="$(base_cache_tar "$package")"
+
+ if [[ -z $base_tar ]]; then
+ msg2 "Unable to find a base package."
+ return 1
+ fi
+
+ basename="$(basename "$file")"
+ base="$(mktemp --tmpdir "$basename.base.XXX")"
+ merged="$(mktemp --tmpdir "$basename.merged.XXX")"
+
+ tar -xOf "$base_tar" "${file#/}" >"$base"
+ if $mergeprog "$file" "$base" "$pacfile" >"$merged"; then
+ msg2 "Merged without conflicts."
+ else
+ $diffprog "$file" "$merged"
+
+ while :; do
+ ask "Would you like to use the results of the merge? [y/n] "
+
+ read c || return 1
+ case $c in
+ y|Y) break ;;
+ n|N) return 1 ;;
+ *) msg2 "Invalid answer." ;;
+ esac
+ done
+ fi
+
+ if ! cp -v "$merged" "$file"; then
+ warning "Unable to write merged file to %s. Merged file is preserved at %s" "$file" "$merged"
+ return 1
+ fi
+ rm -v "$pacfile" "$base" "$merged"
+ return 0
+}
+
cmd() {
if (( USE_LOCATE )); then
locate -0 -e -b \*.pacnew \*.pacorig \*.pacsave '*.pacsave.[0-9]*'
@@ -114,6 +175,8 @@ while [[ -n "$1" ]]; do
OUTPUTONLY=1;;
--nocolor)
USE_COLOR='n';;
+ -c|--cachedir)
+ cachedir="$2"; shift;;
-V|--version)
version; exit 0;;
-h|--help)
@@ -135,6 +198,10 @@ if ! type -p ${diffprog%% *} >/dev/null && (( ! OUTPUTONLY )); then
die "Cannot find the $diffprog binary required for viewing differences."
fi
+if ! type -p ${mergeprog%% *} >/dev/null && (( ! OUTPUTONLY )); then
+ die "Cannot find the $mergeprog binary required for merging differences."
+fi
+
case $(( USE_FIND + USE_LOCATE + USE_PACDB )) in
0) USE_PACDB=1;; # set the default search option
[^1]) error "Only one search option may be used at a time"
@@ -153,6 +220,10 @@ if (( USE_PACDB )); then
fi
fi
+if [[ -z $cachedir ]]; then
+ cachedir="$(pacman-conf CacheDir)"
+fi
+
# see http://mywiki.wooledge.org/BashFAQ/020
while IFS= read -u 3 -r -d '' pacfile; do
file="${pacfile%.pac*}"
@@ -181,7 +252,7 @@ while IFS= read -u 3 -r -d '' pacfile; do
rm -v "$pacfile"
else
while :; do
- ask "(V)iew, (S)kip, (R)emove %s, (O)verwrite with %s, (Q)uit: [v/s/r/o/q] " "$file_type" "$file_type"
+ ask "(V)iew, (M)erge, (S)kip, (R)emove %s, (O)verwrite with %s, (Q)uit: [v/m/s/r/o/q] " "$file_type" "$file_type"
read c || break
case $c in
q|Q) exit 0;;
@@ -194,6 +265,10 @@ while IFS= read -u 3 -r -d '' pacfile; do
rm -v "$pacfile"
break
fi ;;
+ m|M)
+ if merge_file "$pacfile" "$file"; then
+ break
+ fi ;;
s|S) break ;;
*) msg2 "Invalid answer." ;;
esac
--
2.29.2.889.g5298b911bd
More information about the pacman-contrib
mailing list