* bug#26028: 26.0.50; epatch for multifile patches @ 2017-03-08 17:29 Arseny Sher 2017-03-08 19:17 ` Eli Zaretskii 0 siblings, 1 reply; 16+ messages in thread From: Arseny Sher @ 2017-03-08 17:29 UTC (permalink / raw) To: 26028 Hello, I am having trouble using epatch while applying multifile patches. Consider the following simple example: ars@ars-thinkpad ~/tmp $ mkdir -p old/src ars@ars-thinkpad ~/tmp $ echo "void main() { }" > old/src/hello.c ars@ars-thinkpad ~/tmp $ mkdir -p new/src ars@ars-thinkpad ~/tmp $ echo "int main() { return 0; }" > new/src/hello.c ars@ars-thinkpad ~/tmp $ diff -cr old/ new/ > tmp.patch ars@ars-thinkpad ~/tmp $ cat tmp.patch diff -cr old/src/hello.c new/src/hello.c *** old/src/hello.c 2017-03-08 14:29:24.743846995 +0300 --- new/src/hello.c 2017-03-08 14:29:32.399846824 +0300 *************** *** 1 **** ! void main() { } --- 1 ---- ! int main() { return 0; } Now I start emacs and do M-x epatch. First of all, it asks me for patch buffer or file, I point to '~/tmp/tmp.patch'. Then it asks for directory to patch, I say '~/tmp/old' and ediff complains Ediff has inferred that /home/ars/tmp/old/hello.c is assumed to be the target for this patch. However, this file does not exist. Please enter an alternative patch target ... because it ignores the path ('src' directory in this case) to the file. Ediff manual says: "Ediff can recognize multi-file patches only if they are in the context format or GNU unified format. All other patches are treated as 1-file patches. Ediff is [hopefully] using the same algorithm as patch to determine which files need to be patched." If I understand this correctly, my scenario should work, so it seems like a bug. I tried it on GNU Emacs versions 25.1, 25.2 RC2 and daily build 26.0.50.2, sometimes on clean Emacs (emacs -q), and sometimes with unified diff format (diff -u), the result is the same. I use GNU/Linux, Linux Mint 17 (based on Ubuntu 14.04). Below goes autogenerated info from report-emacs-bug. In GNU Emacs 26.0.50.2 (x86_64-pc-linux-gnu, GTK+ Version 3.10.8) of 2016-10-26 built on lgw01-50 Windowing system distributor 'The X.Org Foundation', version 11.0.11501000 System Description: Linux Mint 17 Qiana Recent messages: my-misc loaded Loading /home/ars/.emacs.d/recentf...done Cleaning up the recentf list...done (0 removed) my-text-processing loaded Loading font-lock...done my-windows-frames-funcs loaded coding styles loaded my-gdb-stuff loaded Loading quail/cyrillic...done For information about GNU Emacs and the GNU system, type C-h C-a. Configured using: 'configure --build=x86_64-linux-gnu --prefix=/usr '--includedir=${prefix}/include' '--mandir=${prefix}/share/man' '--infodir=${prefix}/share/info' --sysconfdir=/etc --localstatedir=/var '--libdir=${prefix}/lib/x86_64-linux-gnu' '--libexecdir=${prefix}/lib/x86_64-linux-gnu' --disable-maintainer-mode --disable-dependency-tracking --prefix=/usr --sharedstatedir=/var/lib --program-suffix=-snapshot --with-modules=yes --with-x=yes --with-x-toolkit=gtk3 --with-xwidgets=yes 'CFLAGS=-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security' CPPFLAGS=-D_FORTIFY_SOURCE=2 'LDFLAGS=-Wl,-Bsymbolic-functions -Wl,-z,relro'' Configured features: XPM JPEG TIFF GIF PNG RSVG IMAGEMAGICK SOUND GPM DBUS GCONF GSETTINGS NOTIFY LIBSELINUX GNUTLS LIBXML2 FREETYPE M17N_FLT LIBOTF XFT ZLIB TOOLKIT_SCROLL_BARS GTK3 X11 MODULES XWIDGETS Important settings: value of $LC_ALL: en_US.UTF-8 value of $LC_MONETARY: ru_RU.UTF-8 value of $LC_NUMERIC: ru_RU.UTF-8 value of $LC_TIME: ru_RU.UTF-8 value of $LANG: en_US.UTF-8 locale-coding-system: utf-8-unix Major mode: Fundamental Minor modes in effect: gud-tooltip-mode: t diff-hl-flydiff-mode: t global-diff-hl-mode: t diff-auto-refine-mode: t global-flycheck-mode: t projectile-mode: t ivy-mode: t show-paren-mode: t my-global-fci-mode: t global-linum-mode: t dired-omit-mode: t delete-selection-mode: t cua-mode: t recentf-mode: t savehist-mode: t global-undo-tree-mode: t global-auto-revert-mode: t tooltip-mode: t global-eldoc-mode: t electric-indent-mode: t mouse-wheel-mode: t file-name-shadow-mode: t global-font-lock-mode: t blink-cursor-mode: t auto-composition-mode: t auto-encryption-mode: t auto-compression-mode: t buffer-read-only: t column-number-mode: t line-number-mode: t transient-mark-mode: t Load-path shadows: ~/.emacs.d/static_packages/all-the-icons.el/all-the-icons hides ~/.emacs.d/static_packages/all-the-icons /usr/share/emacs/site-lisp/dictionaries-common/ispell hides /usr/share/emacs/26.0.50/lisp/textmodes/ispell /usr/share/emacs/site-lisp/dictionaries-common/flyspell hides /usr/share/emacs/26.0.50/lisp/textmodes/flyspell /usr/share/emacs/site-lisp/latex-cjk-thai/thai-word hides /usr/share/emacs/26.0.50/lisp/language/thai-word Features: (shadow sort mail-extr emacsbug message puny format-spec rfc822 mml mml-sec epa derived epg gnus-util rmail rmail-loaddefs mm-decode mm-bodies mm-encode mail-parse rfc2231 mailabbrev gmm-utils mailheader sendmail rfc2047 rfc2045 ietf-drums mm-util mail-prsvr mail-utils colir color ggtags etags xref project windmove quail gud my-gdb-stuff diff-hl-flydiff diff-hl edmacro kmacro face-remap vc-hg vc-git vc-dir ewoc vc vc-dispatcher diff-mode flycheck json map find-func rx subr-x coding-styles cc-styles cc-align cc-engine cc-vars cc-defs projectile advice grep compile comint ansi-color ibuf-ext ibuffer ibuffer-loaddefs ivy ivy-overlay ffap thingatpt xcscope ring paren disp-table fill-column-indicator easy-mmode linum dired-x dired dired-loaddefs my-windows-frames-funcs all-the-icons all-the-icons-faces data-weathericons data-octicons data-fileicons data-faicons data-alltheicons font-lock+ cl dash my-text-processing drag-stuff delsel cua-base recentf tree-widget wid-edit savehist undo-tree diff autorevert filenotify wombat-theme my-misc finder-inf tex-site info package epg-config url-handlers url-parse auth-source cl-seq eieio eieio-core cl-macs eieio-loaddefs password-cache url-vars seq byte-opt gv bytecomp byte-compile cl-extra help-mode easymenu cconv cl-loaddefs pcase cl-lib time-date mule-util tooltip eldoc electric uniquify ediff-hook vc-hooks lisp-float-type mwheel term/x-win x-win term/common-win x-dnd tool-bar dnd fontset image regexp-opt fringe tabulated-list newcomment elisp-mode lisp-mode prog-mode register page menu-bar rfn-eshadow timer select scroll-bar mouse jit-lock font-lock syntax facemenu font-core term/tty-colors frame cl-generic cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms cp51932 hebrew greek romanian slovak czech european ethiopic indian cyrillic chinese charscript case-table epa-hook jka-cmpr-hook help simple abbrev obarray minibuffer cl-preloaded nadvice loaddefs button faces cus-face macroexp files text-properties overlay sha1 md5 base64 format env code-pages mule custom widget hashtable-print-readable backquote dbusbind inotify dynamic-setting system-font-setting font-render-setting xwidget-internal move-toolbar gtk x-toolkit x multi-tty make-network-process emacs) Memory information: ((conses 16 288745 21478) (symbols 48 35267 1) (miscs 40 517 1228) (strings 32 74748 9913) (string-bytes 1 2122820) (vectors 16 35442) (vector-slots 8 683178 9673) (floats 8 665 276) (intervals 56 444 300) (buffers 976 13) (heap 1024 41802 1607)) ^ permalink raw reply [flat|nested] 16+ messages in thread
* bug#26028: 26.0.50; epatch for multifile patches 2017-03-08 17:29 bug#26028: 26.0.50; epatch for multifile patches Arseny Sher @ 2017-03-08 19:17 ` Eli Zaretskii 2017-03-08 21:53 ` Arseny Sher 0 siblings, 1 reply; 16+ messages in thread From: Eli Zaretskii @ 2017-03-08 19:17 UTC (permalink / raw) To: Arseny Sher; +Cc: 26028 > From: Arseny Sher <sher-ars@yandex.ru> > Date: Wed, 08 Mar 2017 20:29:52 +0300 > > ars@ars-thinkpad ~/tmp $ mkdir -p old/src > ars@ars-thinkpad ~/tmp $ echo "void main() { }" > old/src/hello.c > ars@ars-thinkpad ~/tmp $ mkdir -p new/src > ars@ars-thinkpad ~/tmp $ echo "int main() { return 0; }" > new/src/hello.c > ars@ars-thinkpad ~/tmp $ diff -cr old/ new/ > tmp.patch > ars@ars-thinkpad ~/tmp $ cat tmp.patch > diff -cr old/src/hello.c new/src/hello.c > *** old/src/hello.c 2017-03-08 14:29:24.743846995 +0300 > --- new/src/hello.c 2017-03-08 14:29:32.399846824 +0300 > *************** > *** 1 **** > ! void main() { } > --- 1 ---- > ! int main() { return 0; } > > > Now I start emacs and do M-x epatch. First of all, it asks me for > patch buffer or file, I point to '~/tmp/tmp.patch'. Then it asks for > directory to patch, I say '~/tmp/old' and ediff complains > > Ediff has inferred that > /home/ars/tmp/old/hello.c > is assumed to be the target for this patch. However, this file does not exist. 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. ^ permalink raw reply [flat|nested] 16+ messages in thread
* bug#26028: 26.0.50; epatch for multifile patches 2017-03-08 19:17 ` Eli Zaretskii @ 2017-03-08 21:53 ` Arseny Sher 2017-03-09 1:41 ` Tino Calancha 2017-05-23 11:26 ` Tino Calancha 0 siblings, 2 replies; 16+ messages in thread From: Arseny Sher @ 2017-03-08 21:53 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 26028 Eli Zaretskii <eliz@gnu.org> 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? Yet am not still sure that this is not a bug; some other guy said that this behaviour doesn't make sense, and similar bug was fixed recently: http://lists.gnu.org/archive/html/help-gnu-emacs/2017-03/msg00064.html http://emacs.1067599.n8.nabble.com/bug-25010-26-0-50-epatch-might-parse-wrongly-a-file-name-td413747.html And while I am here, I would like to express my gratitude to ediff developers; it is in overall a great tool, and it is a pleasure to read its manual. Thank you guys! ^ permalink raw reply related [flat|nested] 16+ messages in thread
* bug#26028: 26.0.50; epatch for multifile patches 2017-03-08 21:53 ` Arseny Sher @ 2017-03-09 1:41 ` Tino Calancha 2017-03-09 11:44 ` Arseny Sher 2017-05-23 11:26 ` Tino Calancha 1 sibling, 1 reply; 16+ messages in thread From: Tino Calancha @ 2017-03-09 1:41 UTC (permalink / raw) To: Arseny Sher; +Cc: Michael Heerdegen, 26028, tino.calancha Arseny Sher <sher-ars@yandex.ru> writes: > How then I am expected to apply > patches generated by VCS, where paths are prefixed with a/ and b/? Ediff will skip those 'a/', 'b/' automatically. > 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? Ediff uses the `default-directory' for the patch buffer as a hint. When i apply patches generated with VCS i _always_ set the `default-directory' of the patch buffer equal as the root directory of the project. That makes multi patches work OK. This is how i would do in your exmple: M-: (dired "/tmp/proj") RET C-x b *p* RET ; Now copy the patch here in your favourite way. C-x 4 r /tmp/tmp.patch RET C-x h M-w C-x o C-y M-x epatch RET y *p* RET /tmp/proj/src RET > Yet am not still sure that this is not a bug; some other guy said that > this behaviour doesn't make sense, and similar bug was fixed recently: > http://lists.gnu.org/archive/html/help-gnu-emacs/2017-03/msg00064.html > http://emacs.1067599.n8.nabble.com/bug-25010-26-0-50-epatch-might-parse-wrongly-a-file-name-td413747.html I tend to agree that it might be possible to improve how Ediff handle these things. That said, as a user i haven't being disturbed so much by this inconvenience. I am also worry if i could break other important feature while trying to improve this; that's essentially why i didn't try hard to work in this issue. If you have some an idea about how to prepare a patch improving Ediff on this area i am welcome to support you in that task. Regards, Tino ^ permalink raw reply [flat|nested] 16+ messages in thread
* bug#26028: 26.0.50; epatch for multifile patches 2017-03-09 1:41 ` Tino Calancha @ 2017-03-09 11:44 ` Arseny Sher 0 siblings, 0 replies; 16+ messages in thread From: Arseny Sher @ 2017-03-09 11:44 UTC (permalink / raw) To: Tino Calancha; +Cc: Michael Heerdegen, 26028 Tino Calancha <tino.calancha@gmail.com> writes: >> How should I apply tmp.patch to proj? > Ediff uses the `default-directory' for the patch buffer as a hint. > When i apply patches generated with VCS i _always_ set the > `default-directory' of the patch buffer equal as the root directory of > the project. That makes multi patches work OK. > This is how i would do in your exmple: > M-: (dired "/tmp/proj") RET > C-x b *p* RET ; Now copy the patch here in your favourite way. > C-x 4 r /tmp/tmp.patch RET > C-x h M-w C-x o C-y > M-x epatch RET y *p* RET /tmp/proj/src RET Honestly, I didn't understand your answer. 1) I don't see any effects of changing the default directory. I set default directory of buffer with patch to ~/tmp/proj as you say, then run epatch, firstly point it to this buffer, then specify ~/tmp/proj (because this is project root, and I want to patch the whole project!) as target directory and it fails again, exactly as before. 2) Interpreting your instructions literally, I should specify ~/tmp/proj/src as target directory to ediff (answer to its last question). Well, then it works, but this is precisely the behaviour which doesn't make any sense to me: ediff just ignores the path to file ('src' directory here). And it happens totally independent of default directory value, I tried with different ones. I suppose that the whole point of applying multifile patch is to allow ediff deduce which files (with full paths) it needs to patch automatically, without manually specifying dirs like 'src'. Imagine we have also hello.h file under proj/include; then, if I tell ediff to use ~/tmp/proj/src dir as target directory as you say, it will successfully patch hello.c, but it will fail again attempting to patch hello.h, because there is no such file proj/src/hello.h. So, it is hard for me to suggest better epatch behaviour because I actually don't comprehend its current one. I don't know why other people don't encounter these problems. Probably they just apply patches via git and only then look at the diff via ediff, and I should go the same way... ^ permalink raw reply [flat|nested] 16+ messages in thread
* bug#26028: 26.0.50; epatch for multifile patches 2017-03-08 21:53 ` Arseny Sher 2017-03-09 1:41 ` Tino Calancha @ 2017-05-23 11:26 ` Tino Calancha 2017-05-23 22:45 ` Michael Heerdegen 1 sibling, 1 reply; 16+ messages in thread From: Tino Calancha @ 2017-05-23 11:26 UTC (permalink / raw) To: Arseny Sher; +Cc: Michael Heerdegen, 26028, Kaushal Modi, tino.calancha Arseny Sher <sher-ars@yandex.ru> writes: > Eli Zaretskii <eliz@gnu.org> 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 <tino.calancha@gmail.com> 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 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* bug#26028: 26.0.50; epatch for multifile patches 2017-05-23 11:26 ` Tino Calancha @ 2017-05-23 22:45 ` Michael Heerdegen 2017-05-24 0:46 ` Tino Calancha 0 siblings, 1 reply; 16+ messages in thread From: Michael Heerdegen @ 2017-05-23 22:45 UTC (permalink / raw) To: Tino Calancha; +Cc: 26028, Arseny Sher, Kaushal Modi Tino Calancha <tino.calancha@gmail.com> writes: > Recently i am not using `epatch', but maybe following patch > is of interest for someone: FWIW, do you think you understood all of the code you changed (I ask because I gave up after a while)? If you did, do you think we should install your fix, or are there open questions? Thanks, Michael. ^ permalink raw reply [flat|nested] 16+ messages in thread
* bug#26028: 26.0.50; epatch for multifile patches 2017-05-23 22:45 ` Michael Heerdegen @ 2017-05-24 0:46 ` Tino Calancha 2020-08-11 7:34 ` Stefan Kangas 0 siblings, 1 reply; 16+ messages in thread From: Tino Calancha @ 2017-05-24 0:46 UTC (permalink / raw) To: Michael Heerdegen; +Cc: 26028, Tino Calancha, Arseny Sher, Kaushal Modi On Wed, 24 May 2017, Michael Heerdegen wrote: > Tino Calancha <tino.calancha@gmail.com> writes: > >> Recently i am not using `epatch', but maybe following patch >> is of interest for someone: > > FWIW, do you think you understood all of the code you changed (I ask > because I gave up after a while)? I think so. I you exclude from the patch the added tests in test/lisp/vc/ediff-ptch-tests.el then this patch just touch: 2 files changed, 42 insertions(+), 18 deletions(-) The only it does: * tweak the original heuristic part for guessing the file names * change the suggested defaults in the prompts asking for the patch and dirs to patch. > If you did, do you think we should > install your fix, or are there open questions? I have tested with plain diffs and with Git diffs. I didn't test it with other VC than Git. I don't think solves all the problems, but at least it makes `epatch' usable for the most common multipatch situations. I) You know, `epatch' has never parsed multipatches with files in different dirs, as: foo/file1 bar/file2 II) The only multipatches `epatch' worked before is when all the files belong to the same dir, as: foo/file1 foo/file2 This patch makes possible to handle I) as well. ^ permalink raw reply [flat|nested] 16+ messages in thread
* bug#26028: 26.0.50; epatch for multifile patches 2017-05-24 0:46 ` Tino Calancha @ 2020-08-11 7:34 ` Stefan Kangas 2020-10-03 22:25 ` Michael Heerdegen 0 siblings, 1 reply; 16+ messages in thread From: Stefan Kangas @ 2020-08-11 7:34 UTC (permalink / raw) To: Tino Calancha; +Cc: Michael Heerdegen, 26028, Arseny Sher, Kaushal Modi Tino Calancha <tino.calancha@gmail.com> writes: > On Wed, 24 May 2017, Michael Heerdegen wrote: > >> Tino Calancha <tino.calancha@gmail.com> writes: >> >>> Recently i am not using `epatch', but maybe following patch >>> is of interest for someone: >> >> FWIW, do you think you understood all of the code you changed (I ask >> because I gave up after a while)? > I think so. I you exclude from the patch the added tests in > test/lisp/vc/ediff-ptch-tests.el > then this patch just touch: > 2 files changed, 42 insertions(+), 18 deletions(-) > The only it does: > * tweak the original heuristic part for guessing the file names > * change the suggested defaults in the prompts asking for the patch and > dirs to patch. > >> If you did, do you think we should >> install your fix, or are there open questions? > I have tested with plain diffs and with Git diffs. I didn't test it > with other VC than Git. > I don't think solves all the problems, but at least it makes `epatch' usable for > the most common multipatch situations. That was 3 years ago. It looks like this patch was never installed. Should it be? Best regards, Stefan Kangas ^ permalink raw reply [flat|nested] 16+ messages in thread
* bug#26028: 26.0.50; epatch for multifile patches 2020-08-11 7:34 ` Stefan Kangas @ 2020-10-03 22:25 ` Michael Heerdegen 2021-05-10 12:02 ` Lars Ingebrigtsen 0 siblings, 1 reply; 16+ messages in thread From: Michael Heerdegen @ 2020-10-03 22:25 UTC (permalink / raw) To: Stefan Kangas; +Cc: 26028, Tino Calancha, Arseny Sher, Kaushal Modi Stefan Kangas <stefan@marxist.se> writes: > It looks like this patch was never installed. Should it be? AFAIR it solved my problem, but I can't judge whether it's ok to install since I don't know the code. Michael. ^ permalink raw reply [flat|nested] 16+ messages in thread
* bug#26028: 26.0.50; epatch for multifile patches 2020-10-03 22:25 ` Michael Heerdegen @ 2021-05-10 12:02 ` Lars Ingebrigtsen 2021-05-12 9:27 ` Michael Heerdegen 2021-05-13 16:29 ` Filipp Gunbin 0 siblings, 2 replies; 16+ messages in thread From: Lars Ingebrigtsen @ 2021-05-10 12:02 UTC (permalink / raw) To: Michael Heerdegen Cc: 26028, Kaushal Modi, Stefan Kangas, Arseny Sher, Tino Calancha Michael Heerdegen <michael_heerdegen@web.de> writes: > AFAIR it solved my problem, but I can't judge whether it's ok to > install since I don't know the code. The patch no longer applies cleanly -- do you have an up-to-date version of Tino's patch in your tree, by any chance? Or did you just try it then, and then back it out again? Looking at the commit history for ediff, it doesn't really look like we have any ediff domain experts to evaluate the patch, which makes it hard to decide whether to try to apply the patch or not. -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no ^ permalink raw reply [flat|nested] 16+ messages in thread
* bug#26028: 26.0.50; epatch for multifile patches 2021-05-10 12:02 ` Lars Ingebrigtsen @ 2021-05-12 9:27 ` Michael Heerdegen 2021-05-13 16:29 ` Filipp Gunbin 1 sibling, 0 replies; 16+ messages in thread From: Michael Heerdegen @ 2021-05-12 9:27 UTC (permalink / raw) To: Lars Ingebrigtsen Cc: 26028, Tino Calancha, Stefan Kangas, Arseny Sher, Kaushal Modi Lars Ingebrigtsen <larsi@gnus.org> writes: > > AFAIR it solved my problem, but I can't judge whether it's ok to > > install since I don't know the code. > > The patch no longer applies cleanly -- do you have an up-to-date version > of Tino's patch in your tree, by any chance? Or did you just try it > then, and then back it out again? I'm very sorry Lars, but I don't have anything better than Tino's original patch. I removed the patch from my tree when the collisions started to occur. Regards, Michael. ^ permalink raw reply [flat|nested] 16+ messages in thread
* bug#26028: 26.0.50; epatch for multifile patches 2021-05-10 12:02 ` Lars Ingebrigtsen 2021-05-12 9:27 ` Michael Heerdegen @ 2021-05-13 16:29 ` Filipp Gunbin 2021-05-16 13:57 ` Lars Ingebrigtsen 1 sibling, 1 reply; 16+ messages in thread From: Filipp Gunbin @ 2021-05-13 16:29 UTC (permalink / raw) To: Lars Ingebrigtsen Cc: 26028, Arseny Sher, Tino Calancha, Michael Heerdegen, Stefan Kangas, Kaushal Modi On 10/05/2021 14:02 +0200, Lars Ingebrigtsen wrote: > Michael Heerdegen <michael_heerdegen@web.de> writes: > >> AFAIR it solved my problem, but I can't judge whether it's ok to >> install since I don't know the code. > > The patch no longer applies cleanly -- do you have an up-to-date version > of Tino's patch in your tree, by any chance? Or did you just try it > then, and then back it out again? > > Looking at the commit history for ediff, it doesn't really look like we > have any ediff domain experts to evaluate the patch, which makes it hard > to decide whether to try to apply the patch or not. I've looked into ediff some months ago (when writing a function which opens new multifile ediff session for comparing vc commits; it's unfinished yet). So I could look at the patch if needed. Filipp ^ permalink raw reply [flat|nested] 16+ messages in thread
* bug#26028: 26.0.50; epatch for multifile patches 2021-05-13 16:29 ` Filipp Gunbin @ 2021-05-16 13:57 ` Lars Ingebrigtsen 2021-07-23 12:54 ` Lars Ingebrigtsen 0 siblings, 1 reply; 16+ messages in thread From: Lars Ingebrigtsen @ 2021-05-16 13:57 UTC (permalink / raw) To: Filipp Gunbin Cc: 26028, Arseny Sher, Tino Calancha, Michael Heerdegen, Stefan Kangas, Kaushal Modi Filipp Gunbin <fgunbin@fastmail.fm> writes: > I've looked into ediff some months ago (when writing a function which > opens new multifile ediff session for comparing vc commits; it's > unfinished yet). So I could look at the patch if needed. Yes, that would be very helpful. -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no ^ permalink raw reply [flat|nested] 16+ messages in thread
* bug#26028: 26.0.50; epatch for multifile patches 2021-05-16 13:57 ` Lars Ingebrigtsen @ 2021-07-23 12:54 ` Lars Ingebrigtsen 2022-03-24 8:34 ` Lars Ingebrigtsen 0 siblings, 1 reply; 16+ messages in thread From: Lars Ingebrigtsen @ 2021-07-23 12:54 UTC (permalink / raw) To: Filipp Gunbin Cc: 26028, Arseny Sher, Tino Calancha, Michael Heerdegen, Stefan Kangas, Kaushal Modi Lars Ingebrigtsen <larsi@gnus.org> writes: > Filipp Gunbin <fgunbin@fastmail.fm> writes: > >> I've looked into ediff some months ago (when writing a function which >> opens new multifile ediff session for comparing vc commits; it's >> unfinished yet). So I could look at the patch if needed. > > Yes, that would be very helpful. Did you get any further here? ^ permalink raw reply [flat|nested] 16+ messages in thread
* bug#26028: 26.0.50; epatch for multifile patches 2021-07-23 12:54 ` Lars Ingebrigtsen @ 2022-03-24 8:34 ` Lars Ingebrigtsen 0 siblings, 0 replies; 16+ messages in thread From: Lars Ingebrigtsen @ 2022-03-24 8:34 UTC (permalink / raw) To: Filipp Gunbin Cc: 26028, Arseny Sher, Tino Calancha, Michael Heerdegen, Stefan Kangas, Kaushal Modi [-- Attachment #1: Type: text/plain, Size: 342 bytes --] Lars Ingebrigtsen <larsi@gnus.org> 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 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: ediff.patch --] [-- Type: text/x-diff, Size: 14112 bytes --] 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 ^ permalink raw reply related [flat|nested] 16+ messages in thread
end of thread, other threads:[~2022-03-24 8:34 UTC | newest] Thread overview: 16+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2017-03-08 17:29 bug#26028: 26.0.50; epatch for multifile patches Arseny Sher 2017-03-08 19:17 ` Eli Zaretskii 2017-03-08 21:53 ` Arseny Sher 2017-03-09 1:41 ` Tino Calancha 2017-03-09 11:44 ` Arseny Sher 2017-05-23 11:26 ` Tino Calancha 2017-05-23 22:45 ` Michael Heerdegen 2017-05-24 0:46 ` Tino Calancha 2020-08-11 7:34 ` Stefan Kangas 2020-10-03 22:25 ` Michael Heerdegen 2021-05-10 12:02 ` Lars Ingebrigtsen 2021-05-12 9:27 ` Michael Heerdegen 2021-05-13 16:29 ` Filipp Gunbin 2021-05-16 13:57 ` Lars Ingebrigtsen 2021-07-23 12:54 ` Lars Ingebrigtsen 2022-03-24 8:34 ` Lars Ingebrigtsen
Code repositories for project(s) associated with this external index https://git.savannah.gnu.org/cgit/emacs.git https://git.savannah.gnu.org/cgit/emacs/org-mode.git This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.