From patchwork Sat Dec 26 07:27:20 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Denton Liu X-Patchwork-Id: 1844 Return-Path: Delivered-To: patchwork@archlinux.org Received: from mail.archlinux.org [2a01:4f9:c010:3052::1] by patchwork.archlinux.org with IMAP (fetchmail-6.4.14) for (single-drop); Sat, 26 Dec 2020 07:30:43 +0000 (UTC) Received: from mail.archlinux.org by mail.archlinux.org with LMTP id OIHmKKLm5l/oFgMAK+/4rw (envelope-from ) for ; Sat, 26 Dec 2020 07:30:42 +0000 Received: from luna.archlinux.org (luna.archlinux.org [5.9.250.164]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits)) (No client certificate requested) by mail.archlinux.org (Postfix) with ESMTPS id 58770322990; Sat, 26 Dec 2020 07:30:42 +0000 (UTC) Received: from luna.archlinux.org (luna.archlinux.org [127.0.0.1]) by luna.archlinux.org (Postfix) with ESMTP id CCBBD2C52B; Sat, 26 Dec 2020 07:30:34 +0000 (UTC) Received: from luna.archlinux.org (luna.archlinux.org [127.0.0.1]) by luna.archlinux.org (Postfix) with ESMTP id 8D61B2111B for ; Sat, 26 Dec 2020 07:27:43 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on luna.archlinux.org X-Spam-Level: X-Spam-Status: No, score=0.4 required=5.0 tests=DKIM_SIGNED=0.1, DKIM_VALID=-0.1,DKIM_VALID_AU=-0.1,FREEMAIL_FROM=0.5, RCVD_IN_DNSWL_NONE=-0.0001,SPF_HELO_NONE=0.001, T_DMARC_POLICY_NONE=0.01,T_DMARC_SIMPLE_DKIM=0.01 autolearn=no autolearn_force=no version=3.4.4 X-Spam-BL-Results: [127.0.5.0] [127.0.0.10] [127.0.0.10] Received: from mail-pf1-x42a.google.com (mail-pf1-x42a.google.com [IPv6:2607:f8b0:4864:20::42a]) by luna.archlinux.org (Postfix) with ESMTPS for ; Sat, 26 Dec 2020 07:27:43 +0000 (UTC) Received: by mail-pf1-x42a.google.com with SMTP id s21so3500842pfu.13 for ; Fri, 25 Dec 2020 23:27:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=H2MohNUPs9ATnBju4J/NH12dSqLoF8BU//F9NMan6xw=; b=kUPhFWQGE9ZxazHG1yYEi2r0SMPsaciUB6b8dBVt/4B7cf8Xs5cE06qGq2dtsqCdqF PR/2ThF1H6i4eqFwL+SK5/NdB/LoSuXd7djhuID2OHFseWnTE+XwDTgAM+d/noMxXakY 3um55Uz6L7ruUAlVN9GYV+u/leJFE4W5CcxVTX2rlxrK5qbQb0m6WWzExrj1zhvVBzYp dDqUDmnOCo1WFh1O+elRzE/TK4MUTh+PLkuBt7Q4c7wjYSqqkMHuL80g9uUO4eGhTelC Bx0+itPfRhi7AvETPfNJwt8PtKXWbk1eVBLJ6GQYxr0TNLeXyOYig/ucqFBNY+pPI2qj ZgJg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=H2MohNUPs9ATnBju4J/NH12dSqLoF8BU//F9NMan6xw=; b=jsZ5GxN/ZFXgwrun7J4x/s4+4cqgThKPlltL32s6wPHVO+HX8LlumTJkVxzsKWd8KX Lx5AUM3al+GMAxhlBlkc3nRyKla/zaLq9XMGt5ztutK9aCa3ZI2iwVX5NNm3gW+GL4kh 1/UdEkg67Ty3oubhqCXrM2puK/GN30PDwnkhmA/+Li+P0sh/Br8M+k8DjbPrMI8yBKaL /r6qHDnkeQVFXS0YtjijSiPJ0ahn3XY/z130GjMXNuvYd7xw2HIgGteBWQkd+v9kIY1C ZE3b71vXqnEWbB8B3JwROtOYoaImEtLpSH1BU7fECHxmQXsFeGr17ylmqngqVITNjcf2 nM7A== X-Gm-Message-State: AOAM530ScW+yoeoI8EYVdZH4cSpPDqp4EB7QI19ko0HLr4ncBtm47xqe wuJTkvzfoM/hju53OroWf6l1VUpo8PA= X-Google-Smtp-Source: ABdhPJyMdS9yMtph4KZuCoKSdroQc2LUYksyDV36qKQ4CjPwQoku/fVUoVjgPaiRvxTpUk5F/Ea0Ug== X-Received: by 2002:a62:2cc3:0:b029:197:dda8:476a with SMTP id s186-20020a622cc30000b0290197dda8476amr12023992pfs.37.1608967661537; Fri, 25 Dec 2020 23:27:41 -0800 (PST) Received: from archbookpro.hsd1.ca.comcast.net (c-67-188-114-10.hsd1.ca.comcast.net. [67.188.114.10]) by smtp.gmail.com with ESMTPSA id q35sm7234652pjh.38.2020.12.25.23.27.40 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Dec 2020 23:27:41 -0800 (PST) From: Denton Liu To: pacman-contrib@lists.archlinux.org Subject: [PATCH 4/4] pacdiff: Learn the (M)erge mode Date: Fri, 25 Dec 2020 23:27:20 -0800 Message-Id: X-Mailer: git-send-email 2.29.2.889.g5298b911bd In-Reply-To: References: MIME-Version: 1.0 X-BeenThere: pacman-contrib@lists.archlinux.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Discussion list for pacman-contrib development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: pacman-contrib-bounces@lists.archlinux.org Sender: "pacman-contrib" Authentication-Results: mail.archlinux.org; dkim=pass header.d=gmail.com header.s=20161025 header.b=kUPhFWQG; dmarc=pass (policy=none) header.from=gmail.com; spf=none (mail.archlinux.org: domain of pacman-contrib-bounces@lists.archlinux.org has no SPF policy when checking 5.9.250.164) smtp.mailfrom=pacman-contrib-bounces@lists.archlinux.org X-Rspamd-Queue-Id: 58770322990 X-Spamd-Result: default: False [2.99 / 15.00]; RCVD_VIA_SMTP_AUTH(0.00)[]; FREEMAIL_FROM(0.00)[gmail.com]; R_MISSING_CHARSET(2.50)[]; TO_DN_NONE(0.00)[]; BROKEN_CONTENT_TYPE(1.50)[]; DKIM_TRACE(0.00)[gmail.com:+]; DMARC_POLICY_ALLOW(-0.50)[gmail.com,none]; MAILLIST(-0.20)[mailman]; FORGED_RECIPIENTS_MAILLIST(0.00)[]; RECEIVED_SPAMHAUS_PBL(0.00)[67.188.114.10:received]; MIME_TRACE(0.00)[0:+]; RCVD_TLS_LAST(0.00)[]; ASN(0.00)[asn:24940, ipnet:5.9.0.0/16, country:DE]; MID_RHS_MATCH_FROM(0.00)[]; TAGGED_FROM(0.00)[]; ARC_NA(0.00)[]; R_DKIM_ALLOW(-0.20)[gmail.com:s=20161025]; RCVD_COUNT_FIVE(0.00)[6]; FROM_HAS_DN(0.00)[]; FROM_NEQ_ENVFROM(0.00)[liudenton@gmail.com,pacman-contrib-bounces@lists.archlinux.org]; MIME_GOOD(-0.10)[text/plain]; PREVIOUSLY_DELIVERED(0.00)[pacman-contrib@lists.archlinux.org]; HAS_LIST_UNSUB(-0.01)[]; RCPT_COUNT_ONE(0.00)[1]; NEURAL_HAM(-0.00)[-1.000]; R_SPF_NA(0.00)[no SPF record]; FORGED_SENDER_MAILLIST(0.00)[] X-Rspamd-Server: mail.archlinux.org 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 --- 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 *:: + 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 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