From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Lars Ingebrigtsen Newsgroups: gmane.emacs.bugs Subject: bug#26028: 26.0.50; epatch for multifile patches Date: Thu, 24 Mar 2022 09:34:01 +0100 Message-ID: <87ils3696u.fsf@gnus.org> References: <87varjfzhr.fsf@yandex.ru> <838tofh93b.fsf@gnu.org> <87y3wfv3iy.fsf@yandex.ru> <871srfbyps.fsf@calancha-pc> <87efvfkx9l.fsf@drachen> <87wo07c5gb.fsf@web.de> <87v97qre46.fsf@gnus.org> <87k0nyok79.fsf@gnus.org> <8735s5dwcm.fsf@gnus.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="37754"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux) Cc: 26028@debbugs.gnu.org, Arseny Sher , Tino Calancha , Michael Heerdegen , Stefan Kangas , Kaushal Modi To: Filipp Gunbin Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Thu Mar 24 09:59:02 2022 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1nXJJ6-0009aV-OS for geb-bug-gnu-emacs@m.gmane-mx.org; Thu, 24 Mar 2022 09:59:01 +0100 Original-Received: from localhost ([::1]:60490 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nXJJ5-0005gG-LB for geb-bug-gnu-emacs@m.gmane-mx.org; Thu, 24 Mar 2022 04:58:59 -0400 Original-Received: from eggs.gnu.org ([209.51.188.92]:55012) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nXIw3-0007gB-Vz for bug-gnu-emacs@gnu.org; Thu, 24 Mar 2022 04:35:17 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:52849) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1nXIvu-000744-7W for bug-gnu-emacs@gnu.org; Thu, 24 Mar 2022 04:35:11 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1nXIvu-0008Ql-4k for bug-gnu-emacs@gnu.org; Thu, 24 Mar 2022 04:35:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Lars Ingebrigtsen Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Thu, 24 Mar 2022 08:35:02 +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: patch Original-Received: via spool by 26028-submit@debbugs.gnu.org id=B26028.164811085932352 (code B ref 26028); Thu, 24 Mar 2022 08:35:02 +0000 Original-Received: (at 26028) by debbugs.gnu.org; 24 Mar 2022 08:34:19 +0000 Original-Received: from localhost ([127.0.0.1]:46746 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nXIvC-0008Pj-Lj for submit@debbugs.gnu.org; Thu, 24 Mar 2022 04:34:19 -0400 Original-Received: from quimby.gnus.org ([95.216.78.240]:55912) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nXIv9-0008PT-WE for 26028@debbugs.gnu.org; Thu, 24 Mar 2022 04:34:16 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnus.org; s=20200322; h=Content-Type:MIME-Version:Message-ID:In-Reply-To:Date: References:Subject:Cc:To:From:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=IyO1FsOXB4D/mHApQzEwHKLvJc1VPkYwhDhPSSje7Sg=; b=g8xNgE7O7Kr81aARk85k1vJF2x 6BEedAVCZgoK5Xqp9cGvBA/z2f2itZq36GKyIKQljcTj2KvCMN53u4cNEqOh2I0FGmSaAGk7coUiE qswsWTeQWhoUkIHQ6U28OGlKX/QqBHfgMZZsMiIpk1FfFGUOASVbg+eC3phvqQFXCc78=; Original-Received: from 109.179.236.69.tmi.telenormobil.no ([109.179.236.69] helo=xo) by quimby.gnus.org with esmtpsa (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1nXIux-0001Kr-7W; Thu, 24 Mar 2022 09:34:05 +0100 In-Reply-To: <8735s5dwcm.fsf@gnus.org> (Lars Ingebrigtsen's message of "Fri, 23 Jul 2021 14:54:17 +0200") X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list 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-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:228864 Archived-At: --=-=-= Content-Type: text/plain Lars Ingebrigtsen writes: > Did you get any further here? I forgot that the patch no longer applied. I've respun it now, but somewhat unsure of how the changes to ediff-fixup-patch-map should be adjusted to the patch. -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no --=-=-= Content-Type: text/x-diff Content-Disposition: inline; filename=ediff.patch diff --git a/lisp/vc/ediff-ptch.el b/lisp/vc/ediff-ptch.el index 17654f80ec..db39368397 100644 --- a/lisp/vc/ediff-ptch.el +++ b/lisp/vc/ediff-ptch.el @@ -217,10 +217,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) null-device) (if (and beg2 end2) - (buffer-substring beg2 end2) + (buffer-substring-no-properties beg2 end2) null-device))) ;; Remove file junk (Bug#26084). (while (re-search-backward @@ -285,31 +285,42 @@ 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)) - (if (and (file-exists-p base-dir1) - (file-exists-p base-dir2)) - (setq base-dir1 "" - base-dir2 "") - ;; Strip possible source/destination prefixes - ;; such as a/ and b/ from dir names. - (save-match-data - (let ((m1 (when (string-match "^[^/]+/" base-dir1) - (cons (substring base-dir1 0 (match-end 0)) - (substring base-dir1 (match-end 0))))) - (m2 (when (string-match "^[^/]+/" base-dir2) - (cons (substring base-dir2 0 (match-end 0)) - (substring base-dir2 (match-end 0)))))) - (when (and (file-exists-p (cdr m1)) - (file-exists-p (cdr m2))) - (setq base-dir1 (car m1) - base-dir2 (car m2)))))))) + (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)) + (if (and (file-exists-p base-dir1) + (file-exists-p base-dir2)) + (setq base-dir1 "" + base-dir2 "") + ;; Strip possible source/destination prefixes + ;; such as a/ and b/ from dir names. + (save-match-data + (let ((m1 + (when (string-match "^[^/]+/" base-dir1) + (cons (substring base-dir1 0 (match-end 0)) + (substring base-dir1 (match-end 0))))) + (m2 + (when (string-match "^[^/]+/" base-dir2) + (cons (substring base-dir2 0 (match-end 0)) + (substring base-dir2 (match-end 0)))))) + (when (and (file-exists-p (cdr m1)) + (file-exists-p (cdr m2))) + (setq base-dir1 (car m1) + base-dir2 (car m2)))))))))) (or (string= (car proposed-file-names) null-device) (setcar proposed-file-names (ediff-file-name-sans-prefix diff --git a/lisp/vc/ediff.el b/lisp/vc/ediff.el index 840ab8cf51..e7ee36eb10 100644 --- a/lisp/vc/ediff.el +++ b/lisp/vc/ediff.el @@ -111,6 +111,7 @@ ediff-version (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'." @@ -1412,6 +1413,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. @@ -1433,11 +1435,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 935046198f..7f143fe139 100644 --- a/test/lisp/vc/ediff-ptch-tests.el +++ b/test/lisp/vc/ediff-ptch-tests.el @@ -24,6 +24,8 @@ (require 'ert) (require 'ert-x) (require 'ediff-ptch) +(require 'ediff-diff) ; For `ediff-diff-program'. +(eval-when-compile (require 'cl-lib)) (ert-deftest ediff-ptch-test-bug25010 () "Test for https://debbugs.gnu.org/25010 ." @@ -118,6 +120,151 @@ ediff-ptch-test-bug26084 (insert-file-contents backup) (buffer-string)))))))))))) +(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 --=-=-=--