Refill some copyright headers.
[bpt/emacs.git] / lisp / vc / ediff-ptch.el
CommitLineData
fce30d79
MK
1;;; ediff-ptch.el --- Ediff's patch support
2
e9bffc61
GM
3;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
4;; 2005, 2006, 2007, 2008, 2009, 2010, 2011
5;; Free Software Foundation, Inc.
fce30d79 6
50a07e18 7;; Author: Michael Kifer <kifer@cs.stonybrook.edu>
bd78fa1d 8;; Package: ediff
fce30d79
MK
9
10;; This file is part of GNU Emacs.
11
eb3fa2cf 12;; GNU Emacs is free software: you can redistribute it and/or modify
fce30d79 13;; it under the terms of the GNU General Public License as published by
eb3fa2cf
GM
14;; the Free Software Foundation, either version 3 of the License, or
15;; (at your option) any later version.
fce30d79
MK
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
eb3fa2cf 23;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
fce30d79 24
3afbc435 25;;; Commentary:
fce30d79
MK
26
27;;; Code:
71296446 28
ddc90f39 29
2d84cc27
MK
30(provide 'ediff-ptch)
31
ddc90f39 32(defgroup ediff-ptch nil
143b42a6 33 "Ediff patch support."
ddc90f39
MK
34 :tag "Patch"
35 :prefix "ediff-"
36 :group 'ediff)
37
38;; compiler pacifier
ddc90f39 39(eval-when-compile
8480ec72 40 (require 'ediff))
ddc90f39 41;; end pacifier
fce30d79 42
4b45b44f
RS
43(require 'ediff-init)
44
1e70790f 45(defcustom ediff-patch-program "patch"
9201cc28 46 "Name of the program that applies patches.
1e70790f
MK
47It is recommended to use GNU-compatible versions."
48 :type 'string
49 :group 'ediff-ptch)
50(defcustom ediff-patch-options "-f"
9201cc28 51 "Options to pass to ediff-patch-program.
1e70790f
MK
52
53Note: the `-b' option should be specified in `ediff-backup-specs'.
54
55It is recommended to pass the `-f' option to the patch program, so it won't ask
3af0304a 56questions. However, some implementations don't accept this option, in which
1e70790f
MK
57case the default value for this variable should be changed."
58 :type 'string
59 :group 'ediff-ptch)
60
fce30d79
MK
61(defvar ediff-last-dir-patch nil
62 "Last directory used by an Ediff command for file to patch.")
63
1e70790f
MK
64;; the default backup extension
65(defconst ediff-default-backup-extension
24ac444f 66 (if (eq system-type 'ms-dos)
1e70790f 67 "_orig" ".orig"))
71296446 68
1e70790f
MK
69
70(defcustom ediff-backup-extension ediff-default-backup-extension
92c51e07 71 "Backup extension used by the patch program.
1e70790f
MK
72See also `ediff-backup-specs'."
73 :type 'string
74 :group 'ediff-ptch)
92c51e07 75
bd698e98 76(defun ediff-test-patch-utility ()
d29a70fe 77 (condition-case nil
15502042 78 (cond ((eq 0 (call-process ediff-patch-program nil nil nil "-z." "-b"))
d29a70fe
RS
79 ;; GNU `patch' v. >= 2.2
80 'gnu)
15502042 81 ((eq 0 (call-process ediff-patch-program nil nil nil "-b"))
d29a70fe
RS
82 'posix)
83 (t 'traditional))
84 (file-error nil)))
bd698e98 85
71296446 86(defcustom ediff-backup-specs
bd698e98
MK
87 (let ((type (ediff-test-patch-utility)))
88 (cond ((eq type 'gnu)
89 ;; GNU `patch' v. >= 2.2
90 (format "-z%s -b" ediff-backup-extension))
91 ((eq type 'posix)
92 ;; POSIX `patch' -- ediff-backup-extension must be ".orig"
93 (setq ediff-backup-extension ediff-default-backup-extension)
94 "-b")
95 (t
96 ;; traditional `patch'
97 (format "-b %s" ediff-backup-extension))))
9201cc28 98 "Backup directives to pass to the patch program.
92c51e07 99Ediff requires that the old version of the file \(before applying the patch\)
3af0304a 100be saved in a file named `the-patch-file.extension'. Usually `extension' is
92c51e07
MK
101`.orig', but this can be changed by the user and may depend on the system.
102Therefore, Ediff needs to know the backup extension used by the patch program.
103
104Some versions of the patch program let you specify `-b backup-extension'.
1e70790f 105Other versions only permit `-b', which assumes the extension `.orig'
3af0304a 106\(in which case ediff-backup-extension MUST be also `.orig'\). The latest
1e70790f 107versions of GNU patch require `-b -z backup-extension'.
92c51e07
MK
108
109Note that both `ediff-backup-extension' and `ediff-backup-specs'
3af0304a 110must be set properly. If your patch program takes the option `-b',
92c51e07 111but not `-b extension', the variable `ediff-backup-extension' must
bd698e98
MK
112still be set so Ediff will know which extension to use.
113
3af0304a 114Ediff tries to guess the appropriate value for this variables. It is believed
bd698e98 115to be working for `traditional' patch, all versions of GNU patch, and for POSIX
3af0304a 116patch. So, don't change these variables, unless the default doesn't work."
ddc90f39
MK
117 :type 'string
118 :group 'ediff-ptch)
92c51e07 119
fce30d79 120
ddc90f39 121(defcustom ediff-patch-default-directory nil
9201cc28 122 "Default directory to look for patches."
ddc90f39
MK
123 :type '(choice (const nil) string)
124 :group 'ediff-ptch)
fce30d79 125
141f0c03
MK
126;; This context diff does not recognize spaces inside files, but removing ' '
127;; from [^ \t] breaks normal patches for some reason
ddc90f39 128(defcustom ediff-context-diff-label-regexp
fce30d79 129 (concat "\\(" ; context diff 2-liner
141f0c03 130 "^\\*\\*\\* +\\([^ \t]+\\)[^*]+[\t ]*\n--- +\\([^ \t]+\\)"
ff6f4585
JL
131 "\\|" ; unified format diff 2-liner
132 "^--- +\\([^ \t]+\\).*\n\\+\\+\\+ +\\([^ \t]+\\)"
77c57270 133 "\\)")
9201cc28 134 "Regexp matching filename 2-liners at the start of each context diff.
1e70790f
MK
135You probably don't want to change that, unless you are using an obscure patch
136program."
ddc90f39
MK
137 :type 'regexp
138 :group 'ediff-ptch)
fce30d79 139
3af0304a 140;; The buffer of the patch file. Local to control buffer.
fce30d79
MK
141(ediff-defvar-local ediff-patchbufer nil "")
142
143;; The buffer where patch displays its diagnostics.
144(ediff-defvar-local ediff-patch-diagnostics nil "")
145
3af0304a 146;; Map of patch buffer. Has the form:
fce30d79
MK
147;; ((filename1 marker1 marker2) (filename2 marker1 marker2) ...)
148;; where filenames are files to which patch would have applied the patch;
149;; marker1 delimits the beginning of the corresponding patch and marker2 does
150;; it for the end.
151(ediff-defvar-local ediff-patch-map nil "")
152
153;; strip prefix from filename
154;; returns /dev/null, if can't strip prefix
155(defsubst ediff-file-name-sans-prefix (filename prefix)
15c77b9e
MK
156 (if prefix
157 (save-match-data
158 (if (string-match (concat "^" (if (stringp prefix)
159 (regexp-quote prefix)
160 ""))
161 filename)
162 (substring filename (match-end 0))
163 (concat "/null/" filename)))
164 filename)
165 )
fce30d79
MK
166
167
168
169;; no longer used
170;; return the number of matches of regexp in buf starting from the beginning
171(defun ediff-count-matches (regexp buf)
e756eb9f 172 (ediff-with-current-buffer buf
fce30d79
MK
173 (let ((count 0) opoint)
174 (save-excursion
175 (goto-char (point-min))
176 (while (and (not (eobp))
177 (progn (setq opoint (point))
178 (re-search-forward regexp nil t)))
179 (if (= opoint (point))
180 (forward-char 1)
181 (setq count (1+ count)))))
182 count)))
183
71296446 184;; Scan BUF (which is supposed to contain a patch) and make a list of the form
743a79af
MK
185;; ((nil nil filename-spec1 marker1 marker2)
186;; (nil nil filename-spec2 marker1 marker2) ...)
71296446 187;; where filename-spec[12] are files to which the `patch' program would
743a79af
MK
188;; have applied the patch.
189;; nin, nil are placeholders. See ediff-make-new-meta-list-element in
190;; ediff-meta.el for the explanations.
191;; In the beginning we don't know exactly which files need to be patched.
192;; We usually come up with two candidates and ediff-file-name-sans-prefix
193;; resolves this later.
194;;
195;; The marker `marker1' delimits the beginning of the corresponding patch and
196;; `marker2' does it for the end.
197;; The result of ediff-map-patch-buffer is a list, which is then assigned
198;; to ediff-patch-map.
199;; The function returns the number of elements in the list ediff-patch-map
fce30d79 200(defun ediff-map-patch-buffer (buf)
e756eb9f 201 (ediff-with-current-buffer buf
fce30d79
MK
202 (let ((count 0)
203 (mark1 (move-marker (make-marker) (point-min)))
204 (mark1-end (point-min))
205 (possible-file-names '("/dev/null" . "/dev/null"))
206 mark2-end mark2 filenames
207 beg1 beg2 end1 end2
208 patch-map opoint)
209 (save-excursion
210 (goto-char (point-min))
211 (setq opoint (point))
212 (while (and (not (eobp))
213 (re-search-forward ediff-context-diff-label-regexp nil t))
214 (if (= opoint (point))
215 (forward-char 1) ; ensure progress towards the end
216 (setq mark2 (move-marker (make-marker) (match-beginning 0))
217 mark2-end (match-end 0)
a8b7f4b9 218 beg1 (or (match-beginning 2) (match-beginning 4))
92c51e07
MK
219 end1 (or (match-end 2) (match-end 4))
220 beg2 (or (match-beginning 3) (match-beginning 5))
221 end2 (or (match-end 3) (match-end 5)))
fce30d79
MK
222 ;; possible-file-names is holding the new file names until we
223 ;; insert the old file name in the patch map
743a79af 224 ;; It is a pair
ac64a728 225 ;; (filename-from-1st-header-line . filename-from-2nd-line)
fce30d79
MK
226 (setq possible-file-names
227 (cons (if (and beg1 end1)
228 (buffer-substring beg1 end1)
229 "/dev/null")
230 (if (and beg2 end2)
231 (buffer-substring beg2 end2)
232 "/dev/null")))
233 ;; check for any `Index:' or `Prereq:' lines, but don't use them
234 (if (re-search-backward "^Index:" mark1-end 'noerror)
235 (move-marker mark2 (match-beginning 0)))
236 (if (re-search-backward "^Prereq:" mark1-end 'noerror)
237 (move-marker mark2 (match-beginning 0)))
238
239 (goto-char mark2-end)
71296446 240
fce30d79 241 (if filenames
743a79af
MK
242 (setq patch-map
243 (cons (ediff-make-new-meta-list-element
244 filenames mark1 mark2)
245 patch-map)))
fce30d79
MK
246 (setq mark1 mark2
247 mark1-end mark2-end
248 filenames possible-file-names))
249 (setq opoint (point)
250 count (1+ count))))
251 (setq mark2 (point-max-marker)
743a79af
MK
252 patch-map (cons (ediff-make-new-meta-list-element
253 possible-file-names mark1 mark2)
254 patch-map))
fce30d79
MK
255 (setq ediff-patch-map (nreverse patch-map))
256 count)))
257
258;; Fix up the file names in the list using the argument FILENAME
15c77b9e
MK
259;; Algorithm: find the files' directories in the patch and, if a directory is
260;; absolute, cut it out from the corresponding file name in the patch.
261;; Relative directories are not cut out.
262;; Prepend the directory of FILENAME to each resulting file (which came
263;; originally from the patch).
264;; In addition, the first file in the patch document is replaced by FILENAME.
265;; Each file is actually a pair of files found in the context diff header
266;; In the end, for each pair, we ask the user which file to patch.
fce30d79 267;; Note: Ediff doesn't recognize multi-file patches that are separated
3af0304a 268;; with the `Index:' line. It treats them as a single-file patch.
fce30d79
MK
269;;
270;; Executes inside the patch buffer
271(defun ediff-fixup-patch-map (filename)
272 (setq filename (expand-file-name filename))
273 (let ((actual-dir (if (file-directory-p filename)
274 ;; directory part of filename
275 (file-name-as-directory filename)
276 (file-name-directory filename)))
15c77b9e
MK
277 ;; In case 2 files are possible patch targets, the user will be offered
278 ;; to choose file1 or file2. In a multifile patch, if the user chooses
279 ;; 1 or 2, this choice is preserved to decide future alternatives.
280 chosen-alternative
fce30d79
MK
281 )
282
283 ;; chop off base-dirs
3f0f4f6f
JB
284 (mapc (lambda (session-info)
285 (let* ((proposed-file-names
286 ;; Filename-spec is objA; it is represented as
287 ;; (file1 . file2). Get it using ediff-get-session-objA.
288 (ediff-get-session-objA-name session-info))
289 ;; base-dir1 is the dir part of the 1st file in the patch
290 (base-dir1
291 (or (file-name-directory (car proposed-file-names))
292 ""))
293 ;; directory part of the 2nd file in the patch
294 (base-dir2
295 (or (file-name-directory (cdr proposed-file-names))
296 ""))
297 )
298 ;; If both base-dir1 and base-dir2 are relative and exist,
299 ;; assume that
300 ;; these dirs lead to the actual files starting at the present
301 ;; directory. So, we don't strip these relative dirs from the
302 ;; file names. This is a heuristic intended to improve guessing
303 (let ((default-directory (file-name-directory filename)))
304 (unless (or (file-name-absolute-p base-dir1)
305 (file-name-absolute-p base-dir2)
306 (not (file-exists-p base-dir1))
307 (not (file-exists-p base-dir2)))
308 (setq base-dir1 ""
309 base-dir2 "")))
310 (or (string= (car proposed-file-names) "/dev/null")
311 (setcar proposed-file-names
312 (ediff-file-name-sans-prefix
313 (car proposed-file-names) base-dir1)))
314 (or (string=
315 (cdr proposed-file-names) "/dev/null")
316 (setcdr proposed-file-names
317 (ediff-file-name-sans-prefix
318 (cdr proposed-file-names) base-dir2)))
319 ))
320 ediff-patch-map)
fce30d79
MK
321
322 ;; take the given file name into account
323 (or (file-directory-p filename)
324 (string= "/dev/null" filename)
743a79af
MK
325 (setcar (ediff-get-session-objA (car ediff-patch-map))
326 (cons (file-name-nondirectory filename)
327 (file-name-nondirectory filename))))
fce30d79
MK
328
329 ;; prepend actual-dir
3f0f4f6f
JB
330 (mapc (lambda (session-info)
331 (let ((proposed-file-names
332 (ediff-get-session-objA-name session-info)))
333 (if (and (string-match "^/null/" (car proposed-file-names))
334 (string-match "^/null/" (cdr proposed-file-names)))
335 ;; couldn't intuit the file name to patch, so
336 ;; something is amiss
337 (progn
338 (with-output-to-temp-buffer ediff-msg-buffer
339 (ediff-with-current-buffer standard-output
340 (fundamental-mode))
341 (princ
342 (format "
fce30d79
MK
343The patch file contains a context diff for
344 %s
345 %s
fce30d79 346However, Ediff cannot infer the name of the actual file
3af0304a 347to be patched on your system. If you know the correct file name,
fce30d79
MK
348please enter it now.
349
350If you don't know and still would like to apply patches to
351other files, enter /dev/null
352"
3f0f4f6f
JB
353 (substring (car proposed-file-names) 6)
354 (substring (cdr proposed-file-names) 6))))
355 (let ((directory t)
356 user-file)
357 (while directory
358 (setq user-file
359 (read-file-name
360 "Please enter file name: "
361 actual-dir actual-dir t))
362 (if (not (file-directory-p user-file))
363 (setq directory nil)
364 (setq directory t)
365 (beep)
366 (message "%s is a directory" user-file)
367 (sit-for 2)))
368 (setcar (ediff-get-session-objA session-info)
369 (cons user-file user-file))))
370 (setcar proposed-file-names
371 (expand-file-name
372 (concat actual-dir (car proposed-file-names))))
373 (setcdr proposed-file-names
374 (expand-file-name
375 (concat actual-dir (cdr proposed-file-names)))))
376 ))
377 ediff-patch-map)
e2de3a29
MK
378 ;; Check for the existing files in each pair and discard the nonexisting
379 ;; ones. If both exist, ask the user.
743a79af
MK
380 (mapcar (lambda (session-info)
381 (let* ((file1 (car (ediff-get-session-objA-name session-info)))
382 (file2 (cdr (ediff-get-session-objA-name session-info)))
383 (session-file-object
384 (ediff-get-session-objA session-info))
3af0304a
MK
385 (f1-exists (file-exists-p file1))
386 (f2-exists (file-exists-p file2)))
387 (cond
15c77b9e
MK
388 ((and
389 ;; The patch program prefers the shortest file as the patch
390 ;; target. However, this is a questionable heuristic. In an
391 ;; interactive program, like ediff, we can offer the user a
392 ;; choice.
393 ;; (< (length file2) (length file1))
394 (not f1-exists)
395 f2-exists)
743a79af
MK
396 ;; replace file-pair with the winning file2
397 (setcar session-file-object file2))
15c77b9e
MK
398 ((and
399 ;; (< (length file1) (length file2))
400 (not f2-exists)
401 f1-exists)
743a79af
MK
402 ;; replace file-pair with the winning file1
403 (setcar session-file-object file1))
3af0304a
MK
404 ((and f1-exists f2-exists
405 (string= file1 file2))
743a79af 406 (setcar session-file-object file1))
15c77b9e
MK
407 ((and f1-exists f2-exists (eq chosen-alternative 1))
408 (setcar session-file-object file1))
409 ((and f1-exists f2-exists (eq chosen-alternative 2))
410 (setcar session-file-object file2))
3af0304a
MK
411 ((and f1-exists f2-exists)
412 (with-output-to-temp-buffer ediff-msg-buffer
2acc9e43
DL
413 (ediff-with-current-buffer standard-output
414 (fundamental-mode))
3af0304a 415 (princ (format "
fce30d79
MK
416Ediff has inferred that
417 %s
418 %s
bd698e98 419are two possible targets for applying the patch.
fce30d79
MK
420Both files seem to be plausible alternatives.
421
422Please advice:
423 Type `y' to use %s as the target;
424 Type `n' to use %s as the target.
425"
15c77b9e 426 file1 file2 file1 file2)))
743a79af 427 (setcar session-file-object
15c77b9e
MK
428 (if (y-or-n-p (format "Use %s ? " file1))
429 (progn
430 (setq chosen-alternative 1)
431 file1)
432 (setq chosen-alternative 2)
433 file2))
434 )
743a79af
MK
435 (f2-exists (setcar session-file-object file2))
436 (f1-exists (setcar session-file-object file1))
3af0304a
MK
437 (t
438 (with-output-to-temp-buffer ediff-msg-buffer
2acc9e43
DL
439 (ediff-with-current-buffer standard-output
440 (fundamental-mode))
3af0304a
MK
441 (princ "\nEdiff has inferred that")
442 (if (string= file1 file2)
443 (princ (format "
fce30d79 444 %s
15c77b9e 445is assumed to be the target for this patch. However, this file does not exist."
3af0304a
MK
446 file1))
447 (princ (format "
fce30d79 448 %s
bd698e98 449 %s
3af0304a
MK
450are two possible targets for this patch. However, these files do not exist."
451 file1 file2)))
452 (princ "
bd698e98 453\nPlease enter an alternative patch target ...\n"))
3af0304a
MK
454 (let ((directory t)
455 target)
456 (while directory
71296446 457 (setq target (read-file-name
3af0304a
MK
458 "Please enter a patch target: "
459 actual-dir actual-dir t))
460 (if (not (file-directory-p target))
461 (setq directory nil)
462 (beep)
463 (message "%s is a directory" target)
464 (sit-for 2)))
743a79af 465 (setcar session-file-object target))))))
fce30d79
MK
466 ediff-patch-map)
467 ))
468
469(defun ediff-show-patch-diagnostics ()
470 (interactive)
471 (cond ((window-live-p ediff-window-A)
472 (set-window-buffer ediff-window-A ediff-patch-diagnostics))
473 ((window-live-p ediff-window-B)
474 (set-window-buffer ediff-window-B ediff-patch-diagnostics))
475 (t (display-buffer ediff-patch-diagnostics 'not-this-window))))
476
3af0304a
MK
477;; prompt for file, get the buffer
478(defun ediff-prompt-for-patch-file ()
15c77b9e
MK
479 (let ((dir (cond (ediff-use-last-dir ediff-last-dir-patch)
480 (ediff-patch-default-directory) ; try patch default dir
4960e757 481 (t default-directory)))
15c77b9e
MK
482 (coding-system-for-read ediff-coding-system-for-read)
483 patch-file-name)
484 (setq patch-file-name
485 (read-file-name
5b76833f 486 (format "Patch is in file%s: "
15c77b9e
MK
487 (cond ((and buffer-file-name
488 (equal (expand-file-name dir)
489 (file-name-directory buffer-file-name)))
490 (concat
491 " (default "
492 (file-name-nondirectory buffer-file-name)
493 ")"))
494 (t "")))
495 dir buffer-file-name 'must-match))
496 (if (file-directory-p patch-file-name)
497 (error "Patch file cannot be a directory: %s" patch-file-name)
498 (find-file-noselect patch-file-name))
3af0304a
MK
499 ))
500
501
502;; Try current buffer, then the other window's buffer. Else, give up.
503(defun ediff-prompt-for-patch-buffer ()
504 (get-buffer
505 (read-buffer
7261ece3 506 "Buffer that holds the patch: "
3af0304a
MK
507 (cond ((save-excursion
508 (goto-char (point-min))
509 (re-search-forward ediff-context-diff-label-regexp nil t))
510 (current-buffer))
511 ((save-window-excursion
512 (other-window 1)
513 (save-excursion
514 (goto-char (point-min))
515 (and (re-search-forward ediff-context-diff-label-regexp nil t)
516 (current-buffer)))))
517 ((save-window-excursion
518 (other-window -1)
519 (save-excursion
520 (goto-char (point-min))
521 (and (re-search-forward ediff-context-diff-label-regexp nil t)
522 (current-buffer)))))
4960e757 523 (t (ediff-other-buffer (current-buffer))))
3af0304a
MK
524 'must-match)))
525
526
527(defun ediff-get-patch-buffer (&optional arg patch-buf)
528 "Obtain patch buffer. If patch is already in a buffer---use it.
529Else, read patch file into a new buffer. If patch buffer is passed as an
530optional argument, then use it."
531 (let ((last-nonmenu-event t) ; Emacs: don't use dialog box
532 last-command-event) ; XEmacs: don't use dialog box
533
534 (cond ((ediff-buffer-live-p patch-buf))
535 ;; even prefix arg: patch in buffer
536 ((and (integerp arg) (eq 0 (mod arg 2)))
537 (setq patch-buf (ediff-prompt-for-patch-buffer)))
538 ;; odd prefix arg: get patch from a file
539 ((and (integerp arg) (eq 1 (mod arg 2)))
540 (setq patch-buf (ediff-prompt-for-patch-file)))
541 (t (setq patch-buf
542 (if (y-or-n-p "Is the patch already in a buffer? ")
543 (ediff-prompt-for-patch-buffer)
544 (ediff-prompt-for-patch-file)))))
71296446 545
e756eb9f 546 (ediff-with-current-buffer patch-buf
fce30d79
MK
547 (goto-char (point-min))
548 (or (ediff-get-visible-buffer-window patch-buf)
549 (progn
550 (pop-to-buffer patch-buf 'other-window)
551 (select-window (previous-window)))))
552 (ediff-map-patch-buffer patch-buf)
553 patch-buf))
554
555;; Dispatch the right patch file function: regular or meta-level,
556;; depending on how many patches are in the patch file.
557;; At present, there is no support for meta-level patches.
558;; Should return either the ctl buffer or the meta-buffer
559(defun ediff-dispatch-file-patching-job (patch-buf filename
560 &optional startup-hooks)
e756eb9f 561 (ediff-with-current-buffer patch-buf
fce30d79
MK
562 ;; relativize names in the patch with respect to source-file
563 (ediff-fixup-patch-map filename)
564 (if (< (length ediff-patch-map) 2)
565 (ediff-patch-file-internal
566 patch-buf
2acc9e43 567 (if (and ediff-patch-map
743a79af
MK
568 (not (string-match
569 "^/dev/null"
570 ;; this is the file to patch
571 (ediff-get-session-objA-name (car ediff-patch-map))))
71296446 572 (> (length
743a79af
MK
573 (ediff-get-session-objA-name (car ediff-patch-map)))
574 1))
575 (ediff-get-session-objA-name (car ediff-patch-map))
fce30d79
MK
576 filename)
577 startup-hooks)
578 (ediff-multi-patch-internal patch-buf startup-hooks))
579 ))
580
581
3af0304a 582;; When patching a buffer, never change the orig file. Instead, create a new
bd698e98
MK
583;; buffer, ***_patched, even if the buff visits a file.
584;; Users who want to actually patch the buffer should use
585;; ediff-patch-file, not ediff-patch-buffer.
586(defun ediff-patch-buffer-internal (patch-buf
587 buf-to-patch-name
588 &optional startup-hooks)
fce30d79 589 (let* ((buf-to-patch (get-buffer buf-to-patch-name))
bd698e98 590 (visited-file (if buf-to-patch (buffer-file-name buf-to-patch)))
fce30d79 591 (buf-mod-status (buffer-modified-p buf-to-patch))
e756eb9f 592 (multifile-patch-p (> (length (ediff-with-current-buffer patch-buf
fce30d79
MK
593 ediff-patch-map)) 1))
594 default-dir file-name ctl-buf)
bd698e98
MK
595 (if multifile-patch-p
596 (error
3af0304a 597 "To apply multi-file patches, please use `ediff-patch-file'"))
bd698e98
MK
598
599 ;; create a temp file to patch
600 (ediff-with-current-buffer buf-to-patch
601 (setq default-dir default-directory)
602 (setq file-name (ediff-make-temp-file buf-to-patch))
603 ;; temporarily switch visited file name, if any
604 (set-visited-file-name file-name)
605 ;; don't create auto-save file, if buff was visiting a file
606 (or visited-file
607 (setq buffer-auto-save-file-name nil))
608 ;; don't confuse the user with a new bufname
609 (rename-buffer buf-to-patch-name)
610 (set-buffer-modified-p nil)
611 (set-visited-file-modtime) ; sync buffer and temp file
612 (setq default-directory default-dir)
613 )
71296446 614
fce30d79
MK
615 ;; dispatch a patch function
616 (setq ctl-buf (ediff-dispatch-file-patching-job
617 patch-buf file-name startup-hooks))
71296446 618
bd698e98
MK
619 (ediff-with-current-buffer ctl-buf
620 (delete-file (buffer-file-name ediff-buffer-A))
621 (delete-file (buffer-file-name ediff-buffer-B))
622 (ediff-with-current-buffer ediff-buffer-A
623 (if default-dir (setq default-directory default-dir))
624 (set-visited-file-name visited-file) ; visited-file might be nil
625 (rename-buffer buf-to-patch-name)
626 (set-buffer-modified-p buf-mod-status))
627 (ediff-with-current-buffer ediff-buffer-B
628 (setq buffer-auto-save-file-name nil) ; don't create auto-save file
629 (if default-dir (setq default-directory default-dir))
630 (set-visited-file-name nil)
71296446 631 (rename-buffer (ediff-unique-buffer-name
bd698e98
MK
632 (concat buf-to-patch-name "_patched") ""))
633 (set-buffer-modified-p t)))
fce30d79
MK
634 ))
635
bd698e98
MK
636
637;; Traditional patch has weird return codes.
638;; GNU and Posix return 1 if some hanks failed and 2 in case of trouble.
639;; 0 is a good code in all cases.
640;; We'll do the concervative thing.
641(defun ediff-patch-return-code-ok (code)
642 (eq code 0))
643;;; (if (eq (ediff-test-patch-utility) 'traditional)
644;;; (eq code 0)
645;;; (not (eq code 2))))
646
fce30d79
MK
647(defun ediff-patch-file-internal (patch-buf source-filename
648 &optional startup-hooks)
649 (setq source-filename (expand-file-name source-filename))
71296446 650
92c51e07 651 (let* ((shell-file-name ediff-shell)
fce30d79
MK
652 (patch-diagnostics (get-buffer-create "*ediff patch diagnostics*"))
653 ;; ediff-find-file may use a temp file to do the patch
654 ;; so, we save source-filename and true-source-filename as a var
655 ;; that initially is source-filename but may be changed to a temp
656 ;; file for the purpose of patching.
657 (true-source-filename source-filename)
658 (target-filename source-filename)
4960e757
MK
659 ;; this ensures that the patch process gets patch buffer in the
660 ;; encoding that Emacs thinks is right for that type of text
71296446 661 (coding-system-for-write
4960e757 662 (if (boundp 'buffer-file-coding-system) buffer-file-coding-system))
71296446 663 target-buf buf-to-patch file-name-magic-p
e756eb9f 664 patch-return-code ctl-buf backup-style aux-wind)
71296446 665
bd698e98 666 (if (string-match "V" ediff-patch-options)
fce30d79
MK
667 (error
668 "Ediff doesn't take the -V option in `ediff-patch-options'--sorry"))
71296446 669
fce30d79
MK
670 ;; Make a temp file, if source-filename has a magic file handler (or if
671 ;; it is handled via auto-mode-alist and similar magic).
672 ;; Check if there is a buffer visiting source-filename and if they are in
673 ;; sync; arrange for the deletion of temp file.
674 (ediff-find-file 'true-source-filename 'buf-to-patch
675 'ediff-last-dir-patch 'startup-hooks)
676
677 ;; Check if source file name has triggered black magic, such as file name
678 ;; handlers or auto mode alist, and make a note of it.
679 ;; true-source-filename should be either the original name or a
680 ;; temporary file where we put the after-product of the file handler.
681 (setq file-name-magic-p (not (equal (file-truename true-source-filename)
682 (file-truename source-filename))))
71296446
JB
683
684 ;; Checkout orig file, if necessary, so that the patched file
bf5d92c5
MK
685 ;; could be checked back in.
686 (ediff-maybe-checkout buf-to-patch)
fce30d79 687
e756eb9f 688 (ediff-with-current-buffer patch-diagnostics
15c77b9e 689 (insert-buffer-substring patch-buf)
fce30d79
MK
690 (message "Applying patch ... ")
691 ;; fix environment for gnu patch, so it won't make numbered extensions
692 (setq backup-style (getenv "VERSION_CONTROL"))
693 (setenv "VERSION_CONTROL" nil)
92c51e07
MK
694 (setq patch-return-code
695 (call-process-region
696 (point-min) (point-max)
697 shell-file-name
698 t ; delete region (which contains the patch
699 t ; insert output (patch diagnostics) in current buffer
700 nil ; don't redisplay
701 shell-command-switch ; usually -c
702 (format "%s %s %s %s"
703 ediff-patch-program
704 ediff-patch-options
705 ediff-backup-specs
706 (expand-file-name true-source-filename))
707 ))
708
fce30d79
MK
709 ;; restore environment for gnu patch
710 (setenv "VERSION_CONTROL" backup-style))
711
712 (message "Applying patch ... done")
713 (message "")
714
715 (switch-to-buffer patch-diagnostics)
716 (sit-for 0) ; synchronize - let the user see diagnostics
71296446 717
bd698e98 718 (or (and (ediff-patch-return-code-ok patch-return-code)
92c51e07
MK
719 (file-exists-p
720 (concat true-source-filename ediff-backup-extension)))
721 (progn
722 (with-output-to-temp-buffer ediff-msg-buffer
2acc9e43
DL
723 (ediff-with-current-buffer standard-output
724 (fundamental-mode))
71296446 725 (princ (format
bd698e98
MK
726 "Patch program has failed due to a bad patch file,
727it couldn't apply all hunks, OR
728it couldn't create the backup for the file being patched.
92c51e07 729
1e70790f
MK
730The former could be caused by a corrupt patch file or because the %S
731program doesn't understand the format of the patch file in use.
92c51e07 732
1e70790f 733The second problem might be due to an incompatibility among these settings:
bd698e98
MK
734 ediff-patch-program = %S ediff-patch-options = %S
735 ediff-backup-extension = %S ediff-backup-specs = %S
92c51e07 736
92c51e07 737See Ediff on-line manual for more details on these variables.
71296446 738In particular, check the documentation for `ediff-backup-specs'.
bd698e98
MK
739
740In any of the above cases, Ediff doesn't compare files automatically.
741However, if the patch was applied partially and the backup file was created,
742you can still examine the changes via M-x ediff-files"
2acc9e43
DL
743 ediff-patch-program
744 ediff-patch-program
745 ediff-patch-options
746 ediff-backup-extension
747 ediff-backup-specs
748 )))
92c51e07
MK
749 (beep 1)
750 (if (setq aux-wind (get-buffer-window ediff-msg-buffer))
751 (progn
752 (select-window aux-wind)
753 (goto-char (point-max))))
1e70790f 754 (switch-to-buffer-other-window patch-diagnostics)
92c51e07 755 (error "Patch appears to have failed")))
71296446 756
fce30d79 757 ;; If black magic is involved, apply patch to a temp copy of the
3af0304a 758 ;; file. Otherwise, apply patch to the orig copy. If patch is applied
fce30d79 759 ;; to temp copy, we name the result old-name_patched for local files
3af0304a 760 ;; and temp-copy_patched for remote files. The orig file name isn't
fce30d79
MK
761 ;; changed, and the temp copy of the original is later deleted.
762 ;; Without magic, the original file is renamed (usually into
763 ;; old-name_orig) and the result of patching will have the same name as
764 ;; the original.
765 (if (not file-name-magic-p)
e756eb9f 766 (ediff-with-current-buffer buf-to-patch
92c51e07
MK
767 (set-visited-file-name
768 (concat source-filename ediff-backup-extension))
fce30d79 769 (set-buffer-modified-p nil))
71296446 770
fce30d79
MK
771 ;; Black magic in effect.
772 ;; If orig file was remote, put the patched file in the temp directory.
773 ;; If orig file is local, put the patched file in the directory of
774 ;; the orig file.
775 (setq target-filename
776 (concat
777 (if (ediff-file-remote-p (file-truename source-filename))
778 true-source-filename
779 source-filename)
780 "_patched"))
71296446 781
fce30d79 782 (rename-file true-source-filename target-filename t)
71296446 783
fce30d79 784 ;; arrange that the temp copy of orig will be deleted
92c51e07 785 (rename-file (concat true-source-filename ediff-backup-extension)
fce30d79 786 true-source-filename t))
71296446 787
fce30d79
MK
788 ;; make orig buffer read-only
789 (setq startup-hooks
790 (cons 'ediff-set-read-only-in-buf-A startup-hooks))
71296446 791
fce30d79
MK
792 ;; set up a buf for the patched file
793 (setq target-buf (find-file-noselect target-filename))
71296446 794
fce30d79
MK
795 (setq ctl-buf
796 (ediff-buffers-internal
797 buf-to-patch target-buf nil
798 startup-hooks 'epatch))
e756eb9f 799 (ediff-with-current-buffer ctl-buf
fce30d79
MK
800 (setq ediff-patchbufer patch-buf
801 ediff-patch-diagnostics patch-diagnostics))
71296446 802
fce30d79
MK
803 (bury-buffer patch-diagnostics)
804 (message "Type `P', if you need to see patch diagnostics")
805 ctl-buf))
806
807(defun ediff-multi-patch-internal (patch-buf &optional startup-hooks)
808 (let (meta-buf)
809 (setq startup-hooks
810 ;; this sets various vars in the meta buffer inside
811 ;; ediff-prepare-meta-buffer
086171bf
MK
812 (cons `(lambda ()
813 ;; tell what to do if the user clicks on a session record
814 (setq ediff-session-action-function
815 'ediff-patch-file-form-meta
816 ediff-meta-patchbufer patch-buf) )
fce30d79 817 startup-hooks))
71296446 818 (setq meta-buf (ediff-prepare-meta-buffer
fce30d79 819 'ediff-filegroup-action
e756eb9f 820 (ediff-with-current-buffer patch-buf
743a79af
MK
821 (cons (ediff-make-new-meta-list-header
822 nil ; regexp
823 (format "%S" patch-buf) ; obj A
824 nil nil ; objects B,C
825 nil ; merge-auto-store-dir
826 nil ; comparison-func
827 )
fce30d79
MK
828 ediff-patch-map))
829 "*Ediff Session Group Panel"
830 'ediff-redraw-directory-group-buffer
831 'ediff-multifile-patch
832 startup-hooks))
833 (ediff-show-meta-buffer meta-buf)
834 ))
835
71296446
JB
836
837
fce30d79 838
fa043571
SM
839;; Local Variables:
840;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun)
841;; eval: (put 'ediff-with-current-buffer 'lisp-indent-hook 1)
842;; eval: (put 'ediff-with-current-buffer 'edebug-form-spec '(form body))
843;; End:
fce30d79 844
fce30d79 845;;; ediff-ptch.el ends here