[PATCH 0/4] pacdiff: learn (M)erge mode
This series teaches pacdiff to perform 3-way merges on config files. The first commit is a cleanup that should be done regardless of whether the rest of this series is merged. The next two commits are small refactors to make final change more readable. The last patch implements the bulk of the logic. It also includes some comment requests. Denton Liu (4): pacdiff: Reindent awk script pacdiff: Implement die() pacdiff: Reduce repetition in input loop pacdiff: Learn the (M)erge mode doc/pacdiff.8.txt | 9 +++- src/pacdiff.sh.in | 102 ++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 97 insertions(+), 14 deletions(-) -- 2.29.2.889.g5298b911bd
The way that the awk script used for fetching files from the pacdb is indented is very misleading. It appears as if the `print $1` is part of the if. Unindent the `print $1` and the following closing brace so that it's obvious that they are part of the while. Signed-off-by: Denton Liu <liu.denton@gmail.com> --- src/pacdiff.sh.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pacdiff.sh.in b/src/pacdiff.sh.in index af85abb..c4dbd89 100644 --- a/src/pacdiff.sh.in +++ b/src/pacdiff.sh.in @@ -87,8 +87,8 @@ cmd() { awk '/^%BACKUP%$/ { while (getline) { if (/^$/) { nextfile } - print $1 - } + print $1 + } }' "${pac_db}"/*/files | while read -r bkup; do print_existing "/$bkup.pacnew" print_existing "/$bkup.pacorig" -- 2.29.2.889.g5298b911bd
In a future commit, we will be making more use of this function. For now, implement it and use it in the one place where it's applicable. Signed-off-by: Denton Liu <liu.denton@gmail.com> --- src/pacdiff.sh.in | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/pacdiff.sh.in b/src/pacdiff.sh.in index c4dbd89..46a5adf 100644 --- a/src/pacdiff.sh.in +++ b/src/pacdiff.sh.in @@ -34,6 +34,11 @@ declare -i USE_FIND=0 USE_LOCATE=0 USE_PACDB=0 OUTPUTONLY=0 # Import libmakepkg source "$LIBRARY"/util/message.sh +die() { + error "$@" + exit 1 +} + usage() { cat <<EOF ${myname} v${myver} @@ -127,8 +132,7 @@ else fi if ! type -p ${diffprog%% *} >/dev/null && (( ! OUTPUTONLY )); then - error "Cannot find the $diffprog binary required for viewing differences." - exit 1 + die "Cannot find the $diffprog binary required for viewing differences." fi case $(( USE_FIND + USE_LOCATE + USE_PACDB )) in -- 2.29.2.889.g5298b911bd
The input loop repeats the `ask` code twice. In a future commit, we will be introducing another instance of the `ask` code. This makes it possible to mistakenly make the code to get out of sync. Refactor the loop so that the `ask` code happens once at the top of the loop. This introduces one functional change in the "Invalid answer" case but it also makes it more consistent with the remaining cases. Signed-off-by: Denton Liu <liu.denton@gmail.com> --- src/pacdiff.sh.in | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/pacdiff.sh.in b/src/pacdiff.sh.in index 46a5adf..a50cb93 100644 --- a/src/pacdiff.sh.in +++ b/src/pacdiff.sh.in @@ -180,8 +180,9 @@ while IFS= read -u 3 -r -d '' pacfile; do msg2 "Files are identical, removing..." rm -v "$pacfile" else - ask "(V)iew, (S)kip, (R)emove %s, (O)verwrite with %s, (Q)uit: [v/s/r/o/q] " "$file_type" "$file_type" - while read c; do + 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" + read c || break case $c in q|Q) exit 0;; r|R) rm -v "$pacfile"; break ;; @@ -192,11 +193,9 @@ while IFS= read -u 3 -r -d '' pacfile; do msg2 "Files are identical, removing..." rm -v "$pacfile" break - fi - ask "(V)iew, (S)kip, (R)emove %s, (O)verwrite with %s, (Q)uit: [v/s/r/o/q] " "$file_type" "$file_type"; - continue ;; + fi ;; s|S) break ;; - *) ask "Invalid answer. Try again: [v/s/r/o/q] "; continue ;; + *) msg2 "Invalid answer." ;; esac done fi -- 2.29.2.889.g5298b911bd
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@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
This series teaches pacdiff to perform 3-way merges on config files. The first two commits are small refactors to make final change more readable. The final commit is what actually implements the meat of the change. Changes since v1: * Add an example of $MERGEPROG usage * Always ask user if they'd like to use merge results (I've been bitten by the lack of this feature!) * Drop refactoring patch (it's been merged) Denton Liu (3): pacdiff: Implement die() pacdiff: Reduce repetition in input loop pacdiff: Learn the (M)erge mode doc/pacdiff.8.txt | 9 ++++- src/pacdiff.sh.in | 100 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 96 insertions(+), 13 deletions(-) Range-diff against v1: 1: 7c6223d < -: ------- pacdiff: Reindent awk script 2: e377ae2 = 1: 4ddc2db pacdiff: Implement die() 3: bdbe0b2 = 2: 0a53816 pacdiff: Reduce repetition in input loop 4: cb73198 ! 3: ae12e25 pacdiff: Learn the (M)erge mode @@ Commit message given $MERGEPROG (`diff3 -m` by default). The base file is taken from from the second-newest package in the cache. - - ## 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 ## @@ doc/pacdiff.8.txt: Description ----------- @@ src/pacdiff.sh.in: Search Options: select one (default: --pacmandb) (default: /etc) + MERGEPROG override the 3-way merge program: (default: 'diff3 -m') - Example: DIFFPROG=meld DIFFSEARCHPATH="/boot /etc /usr" $myname +-Example: DIFFPROG=meld DIFFSEARCHPATH="/boot /etc /usr" $myname ++Example: DIFFPROG=meld DIFFSEARCHPATH="/boot /etc /usr" MERGEPROG="git merge-file -p" $myname Example: $myname --output --locate + + EOF @@ src/pacdiff.sh.in: print_existing_pacsave(){ done } @@ src/pacdiff.sh.in: print_existing_pacsave(){ + 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 + ++ $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 ++ + if ! cp -v "$merged" "$file"; then + warning "Unable to write merged file to %s. Merged file is preserved at %s" "$file" "$merged" + return 1 -- 2.31.0.rc1.228.gb75b4e4ce2
In a future commit, we will be making more use of this function. For now, implement it and use it in the one place where it's applicable. Signed-off-by: Denton Liu <liu.denton@gmail.com> --- src/pacdiff.sh.in | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/pacdiff.sh.in b/src/pacdiff.sh.in index c4dbd89..46a5adf 100644 --- a/src/pacdiff.sh.in +++ b/src/pacdiff.sh.in @@ -34,6 +34,11 @@ declare -i USE_FIND=0 USE_LOCATE=0 USE_PACDB=0 OUTPUTONLY=0 # Import libmakepkg source "$LIBRARY"/util/message.sh +die() { + error "$@" + exit 1 +} + usage() { cat <<EOF ${myname} v${myver} @@ -127,8 +132,7 @@ else fi if ! type -p ${diffprog%% *} >/dev/null && (( ! OUTPUTONLY )); then - error "Cannot find the $diffprog binary required for viewing differences." - exit 1 + die "Cannot find the $diffprog binary required for viewing differences." fi case $(( USE_FIND + USE_LOCATE + USE_PACDB )) in -- 2.31.0.rc1.228.gb75b4e4ce2
The input loop repeats the `ask` code twice. In a future commit, we will be introducing another instance of the `ask` code. This makes it possible to mistakenly make the code to get out of sync. Refactor the loop so that the `ask` code happens once at the top of the loop. This introduces one functional change in the "Invalid answer" case but it also makes it more consistent with the remaining cases. Signed-off-by: Denton Liu <liu.denton@gmail.com> --- src/pacdiff.sh.in | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/pacdiff.sh.in b/src/pacdiff.sh.in index 46a5adf..a50cb93 100644 --- a/src/pacdiff.sh.in +++ b/src/pacdiff.sh.in @@ -180,8 +180,9 @@ while IFS= read -u 3 -r -d '' pacfile; do msg2 "Files are identical, removing..." rm -v "$pacfile" else - ask "(V)iew, (S)kip, (R)emove %s, (O)verwrite with %s, (Q)uit: [v/s/r/o/q] " "$file_type" "$file_type" - while read c; do + 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" + read c || break case $c in q|Q) exit 0;; r|R) rm -v "$pacfile"; break ;; @@ -192,11 +193,9 @@ while IFS= read -u 3 -r -d '' pacfile; do msg2 "Files are identical, removing..." rm -v "$pacfile" break - fi - ask "(V)iew, (S)kip, (R)emove %s, (O)verwrite with %s, (Q)uit: [v/s/r/o/q] " "$file_type" "$file_type"; - continue ;; + fi ;; s|S) break ;; - *) ask "Invalid answer. Try again: [v/s/r/o/q] "; continue ;; + *) msg2 "Invalid answer." ;; esac done fi -- 2.31.0.rc1.228.gb75b4e4ce2
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@gmail.com> --- doc/pacdiff.8.txt | 9 +++-- src/pacdiff.sh.in | 83 ++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 86 insertions(+), 6 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..fc18023 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,15 +55,18 @@ 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: DIFFPROG=meld DIFFSEARCHPATH="/boot /etc /usr" MERGEPROG="git merge-file -p" $myname Example: $myname --output --locate EOF @@ -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." + fi + + $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 + + 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.31.0.rc1.228.gb75b4e4ce2
On March 4, 2021 6:55:44 AM EST, Denton Liu via pacman-contrib <pacman-contrib@lists.archlinux.org> wrote:
This series teaches pacdiff to perform 3-way merges on config files. The first two commits are small refactors to make final change more readable. The final commit is what actually implements the meat of the change.
Changes since v1:
* Add an example of $MERGEPROG usage
* Always ask user if they'd like to use merge results (I've been bitten by the lack of this feature!)
* Drop refactoring patch (it's been merged)
Denton Liu (3): pacdiff: Implement die() pacdiff: Reduce repetition in input loop pacdiff: Learn the (M)erge mode
doc/pacdiff.8.txt | 9 ++++- src/pacdiff.sh.in | 100 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 96 insertions(+), 13 deletions(-)
Range-diff against v1: 1: 7c6223d < -: ------- pacdiff: Reindent awk script 2: e377ae2 = 1: 4ddc2db pacdiff: Implement die() 3: bdbe0b2 = 2: 0a53816 pacdiff: Reduce repetition in input loop 4: cb73198 ! 3: ae12e25 pacdiff: Learn the (M)erge mode @@ Commit message given $MERGEPROG (`diff3 -m` by default). The base file is taken from from the second-newest package in the cache.
- - ## 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 ## @@ doc/pacdiff.8.txt: Description ----------- @@ src/pacdiff.sh.in: Search Options: select one (default: --pacmandb) (default: /etc) + MERGEPROG override the 3-way merge program: (default: 'diff3 -m')
- Example: DIFFPROG=meld DIFFSEARCHPATH="/boot /etc /usr" $myname +-Example: DIFFPROG=meld DIFFSEARCHPATH="/boot /etc /usr" $myname ++Example: DIFFPROG=meld DIFFSEARCHPATH="/boot /etc /usr" MERGEPROG="git merge-file -p" $myname Example: $myname --output --locate + + EOF @@ src/pacdiff.sh.in: print_existing_pacsave(){ done } @@ src/pacdiff.sh.in: print_existing_pacsave(){ + 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 + ++ $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 ++ + if ! cp -v "$merged" "$file"; then + warning "Unable to write merged file to %s. Merged file is preserved at %s" "$file" "$merged" + return 1
Works great, thank you, pushed. -- Best, Daniel <https://danielcapella.com>
participants (2)
-
Daniel M. Capella
-
Denton Liu