From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Tino Calancha Newsgroups: gmane.emacs.bugs Subject: bug#26028: 26.0.50; epatch for multifile patches Date: Tue, 23 May 2017 20:26:55 +0900 Message-ID: <871srfbyps.fsf@calancha-pc> References: <87varjfzhr.fsf@yandex.ru> <838tofh93b.fsf@gnu.org> <87y3wfv3iy.fsf@yandex.ru> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: blaine.gmane.org 1495540612 22175 195.159.176.226 (23 May 2017 11:56:52 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Tue, 23 May 2017 11:56:52 +0000 (UTC) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.0.50 (gnu/linux) Cc: Michael Heerdegen , 26028@debbugs.gnu.org, Kaushal Modi , tino.calancha@gmail.com To: Arseny Sher Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Tue May 23 13:56:45 2017 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dD8Qe-0005be-UW for geb-bug-gnu-emacs@m.gmane.org; Tue, 23 May 2017 13:56:45 +0200 Original-Received: from localhost ([::1]:48027 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dD8Qk-0002B0-Hm for geb-bug-gnu-emacs@m.gmane.org; Tue, 23 May 2017 07:56:50 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:47948) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dD7yw-0003ll-Bv for bug-gnu-emacs@gnu.org; Tue, 23 May 2017 07:28:08 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dD7ys-0002Bd-C0 for bug-gnu-emacs@gnu.org; Tue, 23 May 2017 07:28:06 -0400 Original-Received: from debbugs.gnu.org ([208.118.235.43]:59643) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1dD7ys-0002BG-7W for bug-gnu-emacs@gnu.org; Tue, 23 May 2017 07:28:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1dD7yr-0005bK-P1 for bug-gnu-emacs@gnu.org; Tue, 23 May 2017 07:28:01 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Tino Calancha Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Tue, 23 May 2017 11:28:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 26028 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: Original-Received: via spool by 26028-submit@debbugs.gnu.org id=B26028.149553883121469 (code B ref 26028); Tue, 23 May 2017 11:28:01 +0000 Original-Received: (at 26028) by debbugs.gnu.org; 23 May 2017 11:27:11 +0000 Original-Received: from localhost ([127.0.0.1]:34087 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dD7y3-0005aC-7U for submit@debbugs.gnu.org; Tue, 23 May 2017 07:27:11 -0400 Original-Received: from mail-pf0-f169.google.com ([209.85.192.169]:36754) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dD7y0-0005Zy-7S for 26028@debbugs.gnu.org; Tue, 23 May 2017 07:27:08 -0400 Original-Received: by mail-pf0-f169.google.com with SMTP id m17so111919498pfg.3 for <26028@debbugs.gnu.org>; Tue, 23 May 2017 04:27:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:references:date:in-reply-to:message-id :user-agent:mime-version; bh=ScNIvGqZAe73x1VDW3/3+DRbAPlWJ/z4vX19PSsApUA=; b=io3RIcrBExi+FFGCwLz4JzWQAykEgJntBDO/g97y3V39NYcEmERCixYsRQig0SYP4c 2jDA8VMkSLWPbXefMO6KLHDnXPzI4iLJEK4P/ky13lfnBkC7CFoce/U2hxcT0fL7f1yD ynJTelkVhql64JszhaVagmTW0xqoYVtV0zo0TqDgRGAD/QabZF8ZSxfDRUeqvBDTk4KW qbPA5c9OzlmemSOnyURRHMFZka8dw936L6V8FWAvbWwKrWCQer9VmWIsFT6wBCzc//u/ kREnBT8Tx5lYJ19wmrp+Jy2+s3BDOR93XablmzNQ9DZsLzSLmzunfdnOLTYVAcl3SeUi fYIQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:references:date:in-reply-to :message-id:user-agent:mime-version; bh=ScNIvGqZAe73x1VDW3/3+DRbAPlWJ/z4vX19PSsApUA=; b=g+bBX9SSpZjxYzeQhKEw70YNn2w57sWPumUxHX6VMSCwByRnBkoQ073gssNtXmJmfn zeutM/0Maa4Lr0fIwJHbjVLVSc0u4L6HQh2ffuuujcRot5w0Lh1AVMgDPfzQ9zYjXZmN PdXO1WUxfz7Pri75evTC0TnXv/wnTW5rf8RWB3cSaV2iDlDRu+LoHzwCH6bTg9t2Ii8Y noSNbaH8SLKMuHUfcpKZxXIfqBvU0nuxdfgAzEWUxwDgEpL/fnamy9PeNeN1vSx7LXIi GkZj3TO/PPgoDGH2yNH2PKQ7f1XGXJ9PInuelKDZkYTkRmMZ4owkS2awIwZd9vkH9/LG 66QA== X-Gm-Message-State: AODbwcAv926jdt+098npviRzq4yFv75w/pSJWEtS7GRcxvt7Kwzcgxam OSOybUZFFaWAdw== X-Received: by 10.99.121.13 with SMTP id u13mr31596397pgc.147.1495538822076; Tue, 23 May 2017 04:27:02 -0700 (PDT) Original-Received: from calancha-pc (222.139.137.133.dy.bbexcite.jp. [133.137.139.222]) by smtp.gmail.com with ESMTPSA id x12sm1286919pgc.47.2017.05.23.04.26.59 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 23 May 2017 04:27:01 -0700 (PDT) In-Reply-To: <87y3wfv3iy.fsf@yandex.ru> (Arseny Sher's message of "Thu, 09 Mar 2017 00:53:41 +0300") X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 208.118.235.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.org gmane.emacs.bugs:132762 Archived-At: Arseny Sher writes: > Eli Zaretskii writes: > >> I think you should point it to ~/tmp, not ~/tmp/old. IOW, the >> directory should be the one relative to which the file names in the >> patch file will correctly point to the files. > > Okay, it might be not very convenient (as you might have several > versions of project inside ~/tmp, and ediff will ask you which one is to > be patched), but it works. However, how then I am expected to apply > patches generated by VCS, where paths are prefixed with a/ and b/? > Again, let's consider some simple example: > > mkdir -p proj/src > cd proj > echo "void main() {}" > src/hello.c > git init > git add src/ && git commit -m "commit" > echo "int main() { return 0; }" > src/hello.c > git diff > ../tmp.patch > git reset --hard HEAD > > cat ../tmp.patch > diff --git a/src/hello.c b/src/hello.c > index ab73b3a..76e8197 100644 > --- a/src/hello.c > +++ b/src/hello.c > @@ -1 +1 @@ > -void main() {} > +int main() { return 0; } > > How should I apply tmp.patch to proj? Recently i am not using `epatch', but maybe following patch is of interest for someone: --8<-----------------------------cut here---------------start------------->8--- commit 3f4561b160f2cc9e2b47d16e7f27fbb9b86c3f40 Author: Tino Calancha Date: Tue May 23 19:21:42 2017 +0900 epatch: multi-patch enhancement Handle multi-patches with files belonging to different subdirectories. (ediff-fixup-patch-map): For a multi-patch, set base-dir1 to a/ and base-dir2 to b/ if it is a Git patch; otherwise, set both to . (ediff-map-patch-buffer): Use buffer-substring-no-properties. * lisp/vc/ediff.el (ediff-patch-file): Show differente prompt for multi-patches. For single patches, use the patch header to guess the file to patch, and ensure the input matches an existing file. * test/lisp/vc/ediff-ptch-tests.el (ediff-ptch-test-bug26028): Add test. diff --git a/lisp/vc/ediff-ptch.el b/lisp/vc/ediff-ptch.el index 0340672da2..0d53b2aff4 100644 --- a/lisp/vc/ediff-ptch.el +++ b/lisp/vc/ediff-ptch.el @@ -222,10 +222,10 @@ ediff-map-patch-buffer ;; (filename-from-1st-header-line . filename-from-2nd-line) (setq possible-file-names (cons (if (and beg1 end1) - (buffer-substring beg1 end1) + (buffer-substring-no-properties beg1 end1) "/dev/null") (if (and beg2 end2) - (buffer-substring beg2 end2) + (buffer-substring-no-properties beg2 end2) "/dev/null"))) ;; Remove file junk (Bug#26084). (while (re-search-backward @@ -290,18 +290,25 @@ ediff-fixup-patch-map (or (file-name-directory (cdr proposed-file-names)) "")) ) - ;; If both base-dir1 and base-dir2 are relative and exist, - ;; assume that - ;; these dirs lead to the actual files starting at the present - ;; directory. So, we don't strip these relative dirs from the - ;; file names. This is a heuristic intended to improve guessing (let ((default-directory (file-name-directory filename))) - (unless (or (file-name-absolute-p base-dir1) - (file-name-absolute-p base-dir2) - (not (file-exists-p base-dir1)) - (not (file-exists-p base-dir2))) - (setq base-dir1 "" - base-dir2 ""))) + (cond (multi-patch-p + ;; Git diffs appends 'a/' '/b' to the files. + (if (and (string-match-p "\\`a/" base-dir1) + (string-match-p "\\`b/" base-dir2)) + (setq base-dir1 "a/" base-dir2 "b/") + (setq base-dir1 "" base-dir2 ""))) + (t + ;; If both base-dir1 and base-dir2 are relative and exist, + ;; assume that + ;; these dirs lead to the actual files starting at the present + ;; directory. So, we don't strip these relative dirs from the + ;; file names. This is a heuristic intended to improve guessing + (unless (or (file-name-absolute-p base-dir1) + (file-name-absolute-p base-dir2) + (not (file-exists-p base-dir1)) + (not (file-exists-p base-dir2))) + (setq base-dir1 "" + base-dir2 ""))))) (or (string= (car proposed-file-names) "/dev/null") (setcar proposed-file-names (ediff-file-name-sans-prefix diff --git a/lisp/vc/ediff.el b/lisp/vc/ediff.el index 4751bb6ddc..e41839e968 100644 --- a/lisp/vc/ediff.el +++ b/lisp/vc/ediff.el @@ -121,6 +121,7 @@ ediff-date (require 'ediff-init) (require 'ediff-mult) ; required because of the registry stuff +(require 'diff-mode) ; diff-hunk-file-names (defgroup ediff nil "Comprehensive visual interface to `diff' and `patch'." @@ -1355,6 +1356,7 @@ ediff-patch-default-directory (declare-function ediff-dispatch-file-patching-job "ediff-ptch" (patch-buf filename &optional startup-hooks)) +(defvar ediff-patch-map) ;;;###autoload (defun ediff-patch-file (&optional arg patch-buf) "Query for a file name, and then run Ediff by patching that file. @@ -1376,11 +1378,26 @@ ediff-patch-file (expand-file-name (buffer-file-name patch-buf)))) (t default-directory))) - (setq source-file - (read-file-name - "File to patch (directory, if multifile patch): " - ;; use an explicit initial file - source-dir nil nil (ediff-get-default-file-name))) + (let ((multi-patch-p (with-current-buffer patch-buf (cdr ediff-patch-map)))) + (cond ((not multi-patch-p) + (let* ((files (with-current-buffer patch-buf + (diff-hunk-file-names 'old-first))) + (def (if (and (string-match "\\`a/" (car files)) + (string-match "\\`b/" (cadr files))) + (expand-file-name + (substring-no-properties (car files) 2) + default-directory) + (car files)))) + (setq source-file + (read-file-name + "Single file to patch: " + ;; use an explicit initial file + source-dir nil 'mustmatch def)))) + (t ; multi-patch + (setq source-file + (read-file-name + "Directory to patch, use root project dir: " + source-dir))))) (ediff-dispatch-file-patching-job patch-buf source-file))) (declare-function ediff-patch-buffer-internal "ediff-ptch" diff --git a/test/lisp/vc/ediff-ptch-tests.el b/test/lisp/vc/ediff-ptch-tests.el index 387786ced0..74db053c97 100644 --- a/test/lisp/vc/ediff-ptch-tests.el +++ b/test/lisp/vc/ediff-ptch-tests.el @@ -21,6 +21,8 @@ (require 'ert) (require 'ediff-ptch) +(require 'ediff-diff) ; For `ediff-diff-program'. +(eval-when-compile (require 'cl-lib)) (ert-deftest ediff-ptch-test-bug25010 () "Test for http://debbugs.gnu.org/25010 ." @@ -104,6 +106,151 @@ (delete-directory tmpdir 'recursive) (delete-file patch))))) +(ert-deftest ediff-ptch-test-bug26028 () + "Test for http://debbugs.gnu.org/26028 ." + (skip-unless (executable-find "git")) + (skip-unless (executable-find ediff-patch-program)) + (skip-unless (executable-find ediff-diff-program)) + (let ((git-program (executable-find "git")) + (default-dir default-directory) + tmpdir buffers) + ;;; Simple patch: old/src/hello.c /new/src/hello.c + (unwind-protect + (let* ((dir (make-temp-file "multipatch-test" t)) + (file1 (expand-file-name "old/src/hello.c" dir)) + (file2 (expand-file-name "new/src/hello.c" dir)) + (patch (expand-file-name "tmp.patch" dir)) + (default-directory (file-name-as-directory dir))) + (setq tmpdir dir) + (make-directory (expand-file-name "old/src/" dir) 'parents) + (make-directory (expand-file-name "new/src/" dir) 'parents) + (with-temp-buffer + (insert "void main() { }\n") + (write-region nil nil file1 nil 'silent) + (erase-buffer) + (insert "int main() { return 0; }\n") + (write-region nil nil file2 nil 'silent) + (erase-buffer) + (call-process ediff-diff-program nil t nil "-cr" "old" "new") + (write-region nil nil patch nil 'silent) + (cl-letf (((symbol-function 'y-or-n-p) (lambda (x) nil)) + ((symbol-function 'ediff-prompt-for-patch-file) + (lambda (&rest x) (find-file-noselect patch))) + ((symbol-function 'read-file-name) (lambda (x1 x2 x3 x4 x5) x5)) + ((symbol-function 'ediff-dispatch-file-patching-job) + (lambda (x y) y))) + (should (equal (file-relative-name file1) (epatch nil patch))) + (push (get-file-buffer patch) buffers)))) + (when (file-exists-p tmpdir) + (setq default-directory default-dir) + (delete-directory tmpdir 'recursive)) + (mapc (lambda (b) + (when (buffer-live-p b) (kill-buffer b))) + buffers) + (setq buffers nil)) + ;;; Simple Git patch: proj/src/hello.c + (unwind-protect + (let* ((dir (make-temp-file "multipatch-test" t)) + (rootdir (expand-file-name "proj/src/" dir)) + (file (expand-file-name "hello.c" rootdir)) + (patch (expand-file-name "tmp.patch" dir)) + (default-directory (file-name-as-directory rootdir))) + (make-directory rootdir 'parents) + (setq tmpdir dir) + (with-temp-buffer + (insert "void main() { }\n") + (write-region nil nil file nil 'silent) + (call-process git-program nil nil nil "init") + (call-process git-program nil nil nil "add" ".") + (call-process git-program nil nil nil "commit" "-m" "test repository.") + (erase-buffer) + (insert "int main() { return 0; }\n") + (write-region nil nil file nil 'silent) + (call-process git-program nil `(:file ,patch) nil "diff") + (call-process git-program nil nil nil "reset" "--hard" "head") + (cl-letf (((symbol-function 'y-or-n-p) (lambda (x) nil)) + ((symbol-function 'ediff-prompt-for-patch-file) + (lambda (&rest x) (find-file-noselect patch))) + ((symbol-function 'read-file-name) (lambda (&rest x) file)) + ((symbol-function 'read-file-name) (lambda (x1 x2 x3 x4 x5) x5)) + ((symbol-function 'ediff-dispatch-file-patching-job) + (lambda (x y) y))) + (should (equal file (epatch nil patch))))) + (push (get-file-buffer patch) buffers)) + ;; clean up + (when (file-exists-p tmpdir) + (setq default-directory default-dir) + (delete-directory tmpdir 'recursive)) + (mapc (lambda (b) + (when (buffer-live-p b) (kill-buffer b))) + buffers) + (setq buffers nil)) + ;;; Git multipatch. + (unwind-protect + (let* ((dir (make-temp-file "multipatch-test" t)) + (file1 (expand-file-name "proj/src/hello.c" dir)) + (file2 (expand-file-name "proj/src/bye.c" dir)) + (file3 (expand-file-name "proj/lisp/foo.el" dir)) + (file4 (expand-file-name "proj/lisp/bar.el" dir)) + (file5 (expand-file-name "proj/etc/news" dir)) + (patch (expand-file-name "tmp.patch" dir)) + (default-directory (expand-file-name "proj" dir))) + (setq tmpdir dir) + (dolist (d '("src" "lisp" "etc")) + (setq rootdir (expand-file-name (concat "proj/" d) dir)) + (make-directory rootdir 'parents)) + (with-temp-buffer + (insert "void main() { }\n") + (write-region nil nil file1 nil 'silent) + (write-region nil nil file2 nil 'silent) + (erase-buffer) + (insert "(defun foo () nil)\n") + (write-region nil nil file3 nil 'silent) + (erase-buffer) + (insert "(defun bar () nil)\n") + (write-region nil nil file4 nil 'silent) + (erase-buffer) + (insert "new functions 'foo' and 'bar'\n") + (write-region nil nil file5 nil 'silent) + (call-process git-program nil nil nil "init") + (call-process git-program nil nil nil "add" "src" "lisp" "etc") + (call-process git-program nil nil nil "commit" "-m" "test repository.");) + (erase-buffer) + (insert "int main() { return 0;}\n") + (write-region nil nil file1 nil 'silent) + (write-region nil nil file2 nil 'silent) + (erase-buffer) + (insert "(defun qux () nil)\n") + (write-region nil nil file3 nil 'silent) + (erase-buffer) + (insert "(defun quux () nil)\n") + (write-region nil nil file4 nil 'silent) + (erase-buffer) + (insert "new functions 'qux' and 'quux'\n") + (write-region nil nil file5 nil 'silent) + (call-process git-program nil `(:file ,patch) nil "diff") + (call-process git-program nil nil nil "reset" "--hard" "head")) + (cl-letf (((symbol-function 'y-or-n-p) (lambda (x) nil)) + ((symbol-function 'ediff-get-patch-file) (lambda (&rest x) patch)) + ((symbol-function 'read-file-name) (lambda (&rest x) patch))) + (epatch nil patch) + (with-current-buffer "*Ediff Session Group Panel*" + (push (get-file-buffer patch) buffers) + (should (= 5 (length (cdr ediff-meta-list)))) + ;; don't ask confirmation to exit. + (cl-letf (((symbol-function 'y-or-n-p) (lambda (x) t))) + (ediff-quit-meta-buffer))))) + ;; clean up + (when (file-exists-p tmpdir) + (setq default-directory default-dir) + (delete-directory tmpdir 'recursive)) + (when ediff-registry-buffer + (push ediff-registry-buffer buffers)) + (mapc (lambda (b) + (when (buffer-live-p b) (kill-buffer b))) + buffers) + (setq buffers nil)))) + (provide 'ediff-ptch-tests) ;;; ediff-ptch-tests.el ends here --8<-----------------------------cut here---------------end--------------->8--- In GNU Emacs 26.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.22.11) of 2017-05-23 Repository revision: 4a485410ce74cafd4e9c344e31f7575464a16113