(DONTCOMPILE): Fix typo in file name.
[bpt/emacs.git] / lisp / vc.el
CommitLineData
594722a8
ER
1;;; vc.el --- drive a version-control system from within Emacs
2
3d30b8bc 3;; Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
594722a8 4
28a25aa5
AS
5;; Author: Eric S. Raymond <esr@snark.thyrsus.com>
6;; Maintainer: Andre Spiegel <spiegel@inf.fu-berlin.de>
594722a8 7
a2272f32 8;; $Id: vc.el,v 1.259 2000/01/26 10:31:13 gerd Exp $
0d53f466 9
594722a8
ER
10;; This file is part of GNU Emacs.
11
12;; GNU Emacs is free software; you can redistribute it and/or modify
13;; it under the terms of the GNU General Public License as published by
14;; the Free Software Foundation; either version 2, or (at your option)
15;; any later version.
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
b578f267
EN
23;; along with GNU Emacs; see the file COPYING. If not, write to the
24;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25;; Boston, MA 02111-1307, USA.
594722a8
ER
26
27;;; Commentary:
28
1a2f456b
ER
29;; This mode is fully documented in the Emacs user's manual.
30;;
594722a8
ER
31;; This was designed and implemented by Eric Raymond <esr@snark.thyrsus.com>.
32;; Paul Eggert <eggert@twinsun.com>, Sebastian Kremer <sk@thp.uni-koeln.de>,
33;; and Richard Stallman contributed valuable criticism, support, and testing.
632e9525 34;; CVS support was added by Per Cederqvist <ceder@lysator.liu.se>
3d30b8bc 35;; in Jan-Feb 1994. Further enhancements came from ttn@netcom.com and
28a25aa5 36;; Andre Spiegel <spiegel@inf.fu-berlin.de>.
594722a8 37;;
632e9525 38;; Supported version-control systems presently include SCCS, RCS, and CVS.
b0c9bc8c
AS
39;;
40;; Some features will not work with old RCS versions. Where
41;; appropriate, VC finds out which version you have, and allows or
42;; disallows those features (stealing locks, for example, works only
43;; from 5.6.2 onwards).
632e9525
RS
44;; Even initial checkins will fail if your RCS version is so old that ci
45;; doesn't understand -t-; this has been known to happen to people running
46;; NExTSTEP 3.0.
594722a8 47;;
6b9d0764
AS
48;; You can support the RCS -x option by adding pairs to the
49;; vc-master-templates list.
594722a8
ER
50;;
51;; Proper function of the SCCS diff commands requires the shellscript vcdiff
52;; to be installed somewhere on Emacs's path for executables.
53;;
1a2f456b 54;; If your site uses the ChangeLog convention supported by Emacs, the
594be62e 55;; function vc-comment-to-change-log should prove a useful checkin hook.
1a2f456b 56;;
594722a8 57;; This code depends on call-process passing back the subprocess exit
e1f297e6 58;; status. Thus, you need Emacs 18.58 or later to run it. For the
6ed5075c 59;; vc-directory command to work properly as documented, you need 19.
7ef84cf9 60;; You also need Emacs 19's ring.el.
594722a8
ER
61;;
62;; The vc code maintains some internal state in order to reduce expensive
63;; version-control operations to a minimum. Some names are only computed
34291cd2 64;; once. If you perform version control operations with RCS/SCCS/CVS while
594722a8
ER
65;; vc's back is turned, or move/rename master files while vc is running,
66;; vc may get seriously confused. Don't do these things!
67;;
68;; Developer's notes on some concurrency issues are included at the end of
69;; the file.
70
71;;; Code:
72
73(require 'vc-hooks)
8c0aaf40 74(require 'ring)
5c6f8be0 75(eval-when-compile (require 'dired)) ; for dired-map-over-marks macro
8c0aaf40
ER
76
77(if (not (assoc 'vc-parent-buffer minor-mode-alist))
78 (setq minor-mode-alist
79 (cons '(vc-parent-buffer vc-parent-buffer-name)
80 minor-mode-alist)))
594722a8 81
d7eff0e0
RS
82;; To implement support for a new version-control system, add another
83;; branch to the vc-backend-dispatch macro and fill it in in each
84;; call. The variable vc-master-templates in vc-hooks.el will also
85;; have to change.
86
87(defmacro vc-backend-dispatch (f s r c)
88 "Execute FORM1, FORM2 or FORM3 for SCCS, RCS or CVS respectively.
89If FORM3 is `RCS', use FORM2 for CVS as well as RCS.
90\(CVS shares some code with RCS)."
91 (list 'let (list (list 'type (list 'vc-backend f)))
92 (list 'cond
93 (list (list 'eq 'type (quote 'SCCS)) s) ;; SCCS
94 (list (list 'eq 'type (quote 'RCS)) r) ;; RCS
95 (list (list 'eq 'type (quote 'CVS)) ;; CVS
96 (if (eq c 'RCS) r c))
97 )))
98
594722a8
ER
99;; General customization
100
0101cc40
RS
101(defgroup vc nil
102 "Version-control system in Emacs."
103 :group 'tools)
104
105(defcustom vc-suppress-confirm nil
106 "*If non-nil, treat user as expert; suppress yes-no prompts on some things."
107 :type 'boolean
108 :group 'vc)
109
2c4eea90
KH
110(defcustom vc-delete-logbuf-window t
111 "*If non-nil, delete the *VC-log* buffer and window after each logical action.
112If nil, bury that buffer instead.
113This is most useful if you have multiple windows on a frame and would like to
114preserve the setting."
115 :type 'boolean
116 :group 'vc)
117
0101cc40
RS
118(defcustom vc-initial-comment nil
119 "*If non-nil, prompt for initial comment when a file is registered."
120 :type 'boolean
121 :group 'vc)
122
0d53f466
AS
123(defcustom vc-default-init-version "1.1"
124 "*A string used as the default version number when a new file is registered.
125This can be overriden by giving a prefix argument to \\[vc-register]."
126 :type 'string
cd32a7ba
DN
127 :group 'vc
128 :version "20.3")
0d53f466 129
0101cc40
RS
130(defcustom vc-command-messages nil
131 "*If non-nil, display run messages from back-end commands."
132 :type 'boolean
133 :group 'vc)
134
135(defcustom vc-checkin-switches nil
136 "*A string or list of strings specifying extra switches for checkin.
137These are passed to the checkin program by \\[vc-checkin]."
138 :type '(choice (const :tag "None" nil)
139 (string :tag "Argument String")
140 (repeat :tag "Argument List"
141 :value ("")
142 string))
143 :group 'vc)
144
145(defcustom vc-checkout-switches nil
146 "*A string or list of strings specifying extra switches for checkout.
147These are passed to the checkout program by \\[vc-checkout]."
148 :type '(choice (const :tag "None" nil)
149 (string :tag "Argument String")
150 (repeat :tag "Argument List"
151 :value ("")
152 string))
153 :group 'vc)
154
155(defcustom vc-register-switches nil
156 "*A string or list of strings; extra switches for registering a file.
157These are passed to the checkin program by \\[vc-register]."
158 :type '(choice (const :tag "None" nil)
159 (string :tag "Argument String")
160 (repeat :tag "Argument List"
161 :value ("")
162 string))
163 :group 'vc)
164
3b574573
AS
165(defcustom vc-dired-recurse t
166 "*If non-nil, show directory trees recursively in VC Dired."
167 :type 'boolean
168 :group 'vc
169 :version "20.3")
170
171(defcustom vc-dired-terse-display t
172 "*If non-nil, show only locked files in VC Dired."
173 :type 'boolean
174 :group 'vc
175 :version "20.3")
176
0101cc40
RS
177(defcustom vc-directory-exclusion-list '("SCCS" "RCS" "CVS")
178 "*List of directory names to be ignored while recursively walking file trees."
179 :type '(repeat string)
180 :group 'vc)
666a0ebb 181
8c0aaf40
ER
182(defconst vc-maximum-comment-ring-size 32
183 "Maximum number of saved comments in the comment ring.")
184
2e810285
RS
185;;; This is duplicated in diff.el.
186(defvar diff-switches "-c"
187 "*A string or list of strings specifying switches to be be passed to diff.")
188
7d2d9482
RS
189(defcustom vc-annotate-color-map
190 '(( 26.3672 . "#FF0000")
191 ( 52.7344 . "#FF3800")
192 ( 79.1016 . "#FF7000")
193 (105.4688 . "#FFA800")
194 (131.8359 . "#FFE000")
195 (158.2031 . "#E7FF00")
196 (184.5703 . "#AFFF00")
197 (210.9375 . "#77FF00")
198 (237.3047 . "#3FFF00")
199 (263.6719 . "#07FF00")
200 (290.0391 . "#00FF31")
201 (316.4063 . "#00FF69")
202 (342.7734 . "#00FFA1")
203 (369.1406 . "#00FFD9")
204 (395.5078 . "#00EEFF")
205 (421.8750 . "#00B6FF")
206 (448.2422 . "#007EFF"))
207 "*Association list of age versus color, for \\[vc-annotate].
208Ages are given in units of 2**-16 seconds.
209Default is eighteen steps using a twenty day increment."
210 :type 'sexp
211 :group 'vc)
212
213(defcustom vc-annotate-very-old-color "#0046FF"
214 "*Color for lines older than CAR of last cons in `vc-annotate-color-map'."
215 :type 'string
216 :group 'vc)
217
218(defcustom vc-annotate-background "black"
219 "*Background color for \\[vc-annotate].
220Default color is used if nil."
221 :type 'string
222 :group 'vc)
223
224(defcustom vc-annotate-menu-elements '(2 0.5 0.1 0.01)
225 "*Menu elements for the mode-specific menu of VC-Annotate mode.
226List of factors, used to expand/compress the time scale. See `vc-annotate'."
227 :type 'sexp
228 :group 'vc)
229
f0b188ed 230;;;###autoload
0101cc40 231(defcustom vc-checkin-hook nil
861f3c29 232 "*Normal hook (list of functions) run after a checkin is done.
0101cc40
RS
233See `run-hooks'."
234 :type 'hook
861f3c29 235 :options '(vc-comment-to-change-log)
0101cc40 236 :group 'vc)
f0b188ed 237
67242a23 238;;;###autoload
0101cc40
RS
239(defcustom vc-before-checkin-hook nil
240 "*Normal hook (list of functions) run before a file gets checked in.
241See `run-hooks'."
242 :type 'hook
243 :group 'vc)
67242a23 244
7d2d9482
RS
245;;;###autoload
246(defcustom vc-annotate-mode-hook nil
247 "*Hooks to run when VC-Annotate mode is turned on."
248 :type 'hook
249 :group 'vc)
250
594722a8
ER
251;; Header-insertion hair
252
0101cc40 253(defcustom vc-header-alist
80688f5c 254 '((SCCS "\%W\%") (RCS "\$Id\$") (CVS "\$Id\$"))
7e48e092
AS
255 "*Header keywords to be inserted by `vc-insert-headers'.
256Must be a list of two-element lists, the first element of each must
257be `RCS', `CVS', or `SCCS'. The second element is the string to
0101cc40
RS
258be inserted for this particular backend."
259 :type '(repeat (list :format "%v"
260 (choice :tag "System"
261 (const SCCS)
262 (const RCS)
263 (const CVS))
264 (string :tag "Header")))
265 :group 'vc)
266
267(defcustom vc-static-header-alist
594722a8
ER
268 '(("\\.c$" .
269 "\n#ifndef lint\nstatic char vcid[] = \"\%s\";\n#endif /* lint */\n"))
270 "*Associate static header string templates with file types. A \%s in the
271template is replaced with the first string associated with the file's
0101cc40
RS
272version-control type in `vc-header-alist'."
273 :type '(repeat (cons :format "%v"
274 (regexp :tag "File Type")
275 (string :tag "Header String")))
276 :group 'vc)
7b4f934d 277
0101cc40 278(defcustom vc-comment-alist
594722a8
ER
279 '((nroff-mode ".\\\"" ""))
280 "*Special comment delimiters to be used in generating vc headers only.
281Add an entry in this list if you need to override the normal comment-start
282and comment-end variables. This will only be necessary if the mode language
0101cc40
RS
283is sensitive to blank lines."
284 :type '(repeat (list :format "%v"
285 (symbol :tag "Mode")
286 (string :tag "Comment Start")
287 (string :tag "Comment End")))
288 :group 'vc)
594722a8 289
bbf97570 290;; Default is to be extra careful for super-user.
0101cc40 291(defcustom vc-checkout-carefully (= (user-uid) 0)
bbf97570
RS
292 "*Non-nil means be extra-careful in checkout.
293Verify that the file really is not locked
0101cc40
RS
294and that its contents match what the master file says."
295 :type 'boolean
296 :group 'vc)
bbf97570 297
0101cc40 298(defcustom vc-rcs-release nil
b0c9bc8c 299 "*The release number of your RCS installation, as a string.
0101cc40
RS
300If nil, VC itself computes this value when it is first needed."
301 :type '(choice (const :tag "Auto" nil)
8816386c
MR
302 string
303 (const :tag "Unknown" unknown))
0101cc40 304 :group 'vc)
b0c9bc8c 305
0101cc40 306(defcustom vc-sccs-release nil
b0c9bc8c 307 "*The release number of your SCCS installation, as a string.
0101cc40
RS
308If nil, VC itself computes this value when it is first needed."
309 :type '(choice (const :tag "Auto" nil)
8816386c
MR
310 string
311 (const :tag "Unknown" unknown))
0101cc40 312 :group 'vc)
b0c9bc8c 313
0101cc40 314(defcustom vc-cvs-release nil
7e48e092 315 "*The release number of your CVS installation, as a string.
0101cc40
RS
316If nil, VC itself computes this value when it is first needed."
317 :type '(choice (const :tag "Auto" nil)
8816386c
MR
318 string
319 (const :tag "Unknown" unknown))
0101cc40 320 :group 'vc)
b0c9bc8c 321
594722a8
ER
322;; Variables the user doesn't need to know about.
323(defvar vc-log-entry-mode nil)
324(defvar vc-log-operation nil)
67242a23 325(defvar vc-log-after-operation-hook nil)
34291cd2 326(defvar vc-checkout-writable-buffer-hook 'vc-checkout-writable-buffer)
dbf87856
RS
327;; In a log entry buffer, this is a local variable
328;; that points to the buffer for which it was made
329;; (either a file, or a VC dired buffer).
1a2f456b 330(defvar vc-parent-buffer nil)
8c0aaf40 331(defvar vc-parent-buffer-name nil)
594722a8 332
db59472c
RS
333(defvar vc-log-file)
334(defvar vc-log-version)
335
594722a8
ER
336(defconst vc-name-assoc-file "VC-names")
337
8c0aaf40 338(defvar vc-dired-mode nil)
e1f297e6
ER
339(make-variable-buffer-local 'vc-dired-mode)
340
c9b35ece 341(defvar vc-comment-ring (make-ring vc-maximum-comment-ring-size))
8c0aaf40
ER
342(defvar vc-comment-ring-index nil)
343(defvar vc-last-comment-match nil)
344
b0c9bc8c
AS
345;;; Find and compare backend releases
346
347(defun vc-backend-release (backend)
348 ;; Returns which backend release is installed on this system.
349 (cond
350 ((eq backend 'RCS)
351 (or vc-rcs-release
2bb00bdd 352 (and (zerop (vc-do-command nil nil "rcs" nil nil "-V"))
b0c9bc8c
AS
353 (save-excursion
354 (set-buffer (get-buffer "*vc*"))
355 (setq vc-rcs-release
356 (car (vc-parse-buffer
357 '(("^RCS version \\([0-9.]+ *.*\\)" 1)))))))
358 (setq vc-rcs-release 'unknown)))
359 ((eq backend 'CVS)
360 (or vc-cvs-release
361 (and (zerop (vc-do-command nil 1 "cvs" nil nil "-v"))
362 (save-excursion
363 (set-buffer (get-buffer "*vc*"))
364 (setq vc-cvs-release
365 (car (vc-parse-buffer
366 '(("^Concurrent Versions System (CVS) \\([0-9.]+\\)"
367 1)))))))
368 (setq vc-cvs-release 'unknown)))
369 ((eq backend 'SCCS)
370 vc-sccs-release)))
371
372(defun vc-release-greater-or-equal (r1 r2)
373 ;; Compare release numbers, represented as strings.
374 ;; Release components are assumed cardinal numbers, not decimal
375 ;; fractions (5.10 is a higher release than 5.9). Omitted fields
376 ;; are considered lower (5.6.7 is earlier than 5.6.7.1).
377 ;; Comparison runs till the end of the string is found, or a
378 ;; non-numeric component shows up (5.6.7 is earlier than "5.6.7 beta",
379 ;; which is probably not what you want in some cases).
380 ;; This code is suitable for existing RCS release numbers.
381 ;; CVS releases are handled reasonably, too (1.3 < 1.4* < 1.5).
382 (let (v1 v2 i1 i2)
383 (catch 'done
384 (or (and (string-match "^\\.?\\([0-9]+\\)" r1)
385 (setq i1 (match-end 0))
386 (setq v1 (string-to-number (match-string 1 r1)))
387 (or (and (string-match "^\\.?\\([0-9]+\\)" r2)
388 (setq i2 (match-end 0))
389 (setq v2 (string-to-number (match-string 1 r2)))
390 (if (> v1 v2) (throw 'done t)
391 (if (< v1 v2) (throw 'done nil)
392 (throw 'done
393 (vc-release-greater-or-equal
394 (substring r1 i1)
395 (substring r2 i2)))))))
396 (throw 'done t)))
397 (or (and (string-match "^\\.?\\([0-9]+\\)" r2)
398 (throw 'done nil))
399 (throw 'done t)))))
400
401(defun vc-backend-release-p (backend release)
402 ;; Return t if we have RELEASE of BACKEND or better
403 (let (i r (ri 0) (ii 0) is rs (installation (vc-backend-release backend)))
404 (if (not (eq installation 'unknown))
405 (cond
406 ((or (eq backend 'RCS) (eq backend 'CVS))
407 (vc-release-greater-or-equal installation release))))))
408
c8de1d91
AS
409;;; functions that operate on RCS revision numbers
410
411(defun vc-trunk-p (rev)
412 ;; return t if REV is a revision on the trunk
413 (not (eq nil (string-match "\\`[0-9]+\\.[0-9]+\\'" rev))))
414
ccb141e8
AS
415(defun vc-branch-p (rev)
416 ;; return t if REV is a branch revision
417 (not (eq nil (string-match "\\`[0-9]+\\(\\.[0-9]+\\.[0-9]+\\)*\\'" rev))))
418
c8de1d91
AS
419(defun vc-branch-part (rev)
420 ;; return the branch part of a revision number REV
421 (substring rev 0 (string-match "\\.[0-9]+\\'" rev)))
422
c0d66cb2
RS
423(defun vc-minor-part (rev)
424 ;; return the minor version number of a revision number REV
425 (string-match "[0-9]+\\'" rev)
426 (substring rev (match-beginning 0) (match-end 0)))
427
428(defun vc-previous-version (rev)
429 ;; guess the previous version number
430 (let ((branch (vc-branch-part rev))
431 (minor-num (string-to-number (vc-minor-part rev))))
432 (if (> minor-num 1)
433 ;; version does probably not start a branch or release
434 (concat branch "." (number-to-string (1- minor-num)))
435 (if (vc-trunk-p rev)
436 ;; we are at the beginning of the trunk --
437 ;; don't know anything to return here
438 ""
439 ;; we are at the beginning of a branch --
440 ;; return version of starting point
441 (vc-branch-part branch)))))
442
594722a8
ER
443;; File property caching
444
8c0aaf40
ER
445(defun vc-clear-context ()
446 "Clear all cached file properties and the comment ring."
447 (interactive)
448 (fillarray vc-file-prop-obarray nil)
449 ;; Note: there is potential for minor lossage here if there is an open
450 ;; log buffer with a nonzero local value of vc-comment-ring-index.
c9b35ece 451 (setq vc-comment-ring (make-ring vc-maximum-comment-ring-size)))
8c0aaf40 452
88a2ffaf
RS
453(defun vc-file-clear-masterprops (file)
454 ;; clear all properties of FILE that were retrieved
455 ;; from the master file
456 (vc-file-setprop file 'vc-latest-version nil)
457 (vc-file-setprop file 'vc-your-latest-version nil)
458 (vc-backend-dispatch file
459 (progn ;; SCCS
460 (vc-file-setprop file 'vc-master-locks nil))
461 (progn ;; RCS
462 (vc-file-setprop file 'vc-default-branch nil)
463 (vc-file-setprop file 'vc-head-version nil)
8dd71345 464 (vc-file-setprop file 'vc-master-workfile-version nil)
88a2ffaf
RS
465 (vc-file-setprop file 'vc-master-locks nil))
466 (progn
467 (vc-file-setprop file 'vc-cvs-status nil))))
f3c61d82 468
c8de1d91
AS
469(defun vc-head-version (file)
470 ;; Return the RCS head version of FILE
471 (cond ((vc-file-getprop file 'vc-head-version))
472 (t (vc-fetch-master-properties file)
473 (vc-file-getprop file 'vc-head-version))))
f3c61d82 474
594722a8
ER
475;; Random helper functions
476
c8de1d91
AS
477(defun vc-latest-on-branch-p (file)
478 ;; return t iff the current workfile version of FILE is
479 ;; the latest on its branch.
480 (vc-backend-dispatch file
481 ;; SCCS
482 (string= (vc-workfile-version file) (vc-latest-version file))
483 ;; RCS
484 (let ((workfile-version (vc-workfile-version file)) tip-version)
485 (if (vc-trunk-p workfile-version)
486 (progn
487 ;; Re-fetch the head version number. This is to make
488 ;; sure that no-one has checked in a new version behind
489 ;; our back.
490 (vc-fetch-master-properties file)
491 (string= (vc-file-getprop file 'vc-head-version)
492 workfile-version))
493 ;; If we are not on the trunk, we need to examine the
7d88be52
AS
494 ;; whole current branch. (vc-master-workfile-version
495 ;; is not what we need.)
c8de1d91
AS
496 (save-excursion
497 (set-buffer (get-buffer-create "*vc-info*"))
498 (vc-insert-file (vc-name file) "^desc")
499 (setq tip-version (car (vc-parse-buffer (list (list
500 (concat "^\\(" (regexp-quote (vc-branch-part workfile-version))
501 "\\.[0-9]+\\)\ndate[ \t]+\\([0-9.]+\\);") 1 2)))))
502 (if (get-buffer "*vc-info*")
503 (kill-buffer (get-buffer "*vc-info*")))
504 (string= tip-version workfile-version))))
505 ;; CVS
8dd71345 506 t))
c8de1d91 507
709822e8
AS
508;;; Two macros for elisp programming
509;;;###autoload
510(defmacro with-vc-file (file comment &rest body)
511 "Execute BODY, checking out a writable copy of FILE first if necessary.
512After BODY has been executed, check-in FILE with COMMENT (a string).
513FILE is passed through `expand-file-name'; BODY executed within
514`save-excursion'. If FILE is not under version control, or locked by
515somebody else, signal error."
516 `(let ((file (expand-file-name ,file)))
517 (or (vc-registered file)
518 (error (format "File not under version control: `%s'" file)))
519 (let ((locking-user (vc-locking-user file)))
520 (cond ((and (not locking-user)
521 (eq (vc-checkout-model file) 'manual))
522 (vc-checkout file t))
523 ((and (stringp locking-user)
524 (not (string= locking-user (vc-user-login-name))))
525 (error (format "`%s' is locking `%s'" locking-user file)))))
526 (save-excursion
527 ,@body)
528 (vc-checkin file nil ,comment)))
529
530;;;###autoload
531(defmacro edit-vc-file (file comment &rest body)
532 "Edit FILE under version control, executing BODY. Checkin with COMMENT.
533This macro uses `with-vc-file', passing args to it.
534However, before executing BODY, find FILE, and after BODY, save buffer."
535 `(with-vc-file
536 ,file ,comment
537 (find-file ,file)
538 ,@body
539 (save-buffer)))
540
b6909007
AS
541(defun vc-ensure-vc-buffer ()
542 ;; Make sure that the current buffer visits a version-controlled file.
543 (if vc-dired-mode
544 (set-buffer (find-file-noselect (dired-get-filename)))
545 (while vc-parent-buffer
546 (pop-to-buffer vc-parent-buffer))
547 (if (not (buffer-file-name))
548 (error "Buffer %s is not associated with a file" (buffer-name))
549 (if (not (vc-backend (buffer-file-name)))
550 (error "File %s is not under version control" (buffer-file-name))))))
7ef84cf9 551
594722a8 552(defvar vc-binary-assoc nil)
87a00c4f
EZ
553(defvar vc-binary-suffixes
554 (if (memq system-type '(ms-dos windows-nt))
555 '(".exe" ".com" ".bat" ".cmd" ".btm" "")
556 '("")))
594722a8
ER
557(defun vc-find-binary (name)
558 "Look for a command anywhere on the subprocess-command search path."
559 (or (cdr (assoc name vc-binary-assoc))
deb9ebc6
PE
560 (catch 'found
561 (mapcar
562 (function
563 (lambda (s)
564 (if s
87a00c4f
EZ
565 (let ((full (concat s "/" name))
566 (suffixes vc-binary-suffixes)
567 candidate)
568 (while suffixes
569 (setq candidate (concat full (car suffixes)))
570 (if (and (file-executable-p candidate)
571 (not (file-directory-p candidate)))
572 (progn
573 (setq vc-binary-assoc
574 (cons (cons name candidate) vc-binary-assoc))
575 (throw 'found candidate))
576 (setq suffixes (cdr suffixes))))))))
deb9ebc6
PE
577 exec-path)
578 nil)))
594722a8 579
6aa13729 580(defun vc-do-command (buffer okstatus command file last &rest flags)
594722a8 581 "Execute a version-control command, notifying user and checking for errors.
a0b87bc1
AS
582Output from COMMAND goes to BUFFER, or *vc* if BUFFER is nil. The
583command is considered successful if its exit status does not exceed
584OKSTATUS (if OKSTATUS is nil, that means to ignore errors). FILE is
585the name of the working file (may also be nil, to execute commands
586that don't expect a file name). If FILE is non-nil, the argument LAST
587indicates what filename should actually be passed to the command: if
588it is `MASTER', the name of FILE's master file is used, if it is
589`WORKFILE', then FILE is passed through unchanged. If an optional
590list of FLAGS is present, that is inserted into the command line
591before the filename."
b0c9bc8c 592 (and file (setq file (expand-file-name file)))
6aa13729 593 (if (not buffer) (setq buffer "*vc*"))
594722a8 594 (if vc-command-messages
02da6253 595 (message "Running %s on %s..." command file))
1a2f456b 596 (let ((obuf (current-buffer)) (camefrom (current-buffer))
594722a8 597 (squeezed nil)
632e9525 598 (olddir default-directory)
3d30b8bc 599 vc-file status)
6aa13729 600 (set-buffer (get-buffer-create buffer))
8c0aaf40
ER
601 (set (make-local-variable 'vc-parent-buffer) camefrom)
602 (set (make-local-variable 'vc-parent-buffer-name)
603 (concat " from " (buffer-name camefrom)))
632e9525 604 (setq default-directory olddir)
8c0aaf40 605
594722a8 606 (erase-buffer)
315e49ed 607
594722a8
ER
608 (mapcar
609 (function (lambda (s) (and s (setq squeezed (append squeezed (list s))))))
610 flags)
3d30b8bc 611 (if (and (eq last 'MASTER) file (setq vc-file (vc-name file)))
594722a8 612 (setq squeezed (append squeezed (list vc-file))))
a0b87bc1 613 (if (and file (eq last 'WORKFILE))
632e9525
RS
614 (progn
615 (let* ((pwd (expand-file-name default-directory))
616 (preflen (length pwd)))
617 (if (string= (substring file 0 preflen) pwd)
618 (setq file (substring file preflen))))
619 (setq squeezed (append squeezed (list file)))))
46cd263f 620 (let ((exec-path (append vc-path exec-path))
eadcb02c
RS
621 ;; Add vc-path to PATH for the execution of this command.
622 (process-environment
623 (cons (concat "PATH=" (getenv "PATH")
993a1a44
RS
624 path-separator
625 (mapconcat 'identity vc-path path-separator))
bcbe4d57 626 process-environment))
b86b9918 627 (w32-quote-process-args t))
1a2f456b 628 (setq status (apply 'call-process command nil t nil squeezed)))
594722a8 629 (goto-char (point-max))
632e9525 630 (set-buffer-modified-p nil)
4805f679 631 (forward-line -1)
2bb00bdd 632 (if (or (not (integerp status)) (and okstatus (< okstatus status)))
594722a8 633 (progn
6aa13729 634 (pop-to-buffer buffer)
594722a8 635 (goto-char (point-min))
4c2d8cf9 636 (shrink-window-if-larger-than-buffer)
02da6253
PE
637 (error "Running %s...FAILED (%s)" command
638 (if (integerp status)
639 (format "status %d" status)
640 status))
594722a8
ER
641 )
642 (if vc-command-messages
02da6253 643 (message "Running %s...OK" command))
594722a8
ER
644 )
645 (set-buffer obuf)
646 status)
647 )
648
c4ae7096
JB
649;;; Save a bit of the text around POSN in the current buffer, to help
650;;; us find the corresponding position again later. This works even
651;;; if all markers are destroyed or corrupted.
c8de1d91 652;;; A lot of this was shamelessly lifted from Sebastian Kremer's rcs.el mode.
c4ae7096
JB
653(defun vc-position-context (posn)
654 (list posn
655 (buffer-size)
656 (buffer-substring posn
657 (min (point-max) (+ posn 100)))))
658
659;;; Return the position of CONTEXT in the current buffer, or nil if we
660;;; couldn't find it.
661(defun vc-find-position-by-context (context)
662 (let ((context-string (nth 2 context)))
663 (if (equal "" context-string)
664 (point-max)
665 (save-excursion
666 (let ((diff (- (nth 1 context) (buffer-size))))
667 (if (< diff 0) (setq diff (- diff)))
668 (goto-char (nth 0 context))
669 (if (or (search-forward context-string nil t)
670 ;; Can't use search-backward since the match may continue
671 ;; after point.
672 (progn (goto-char (- (point) diff (length context-string)))
673 ;; goto-char doesn't signal an error at
674 ;; beginning of buffer like backward-char would
675 (search-forward context-string nil t)))
676 ;; to beginning of OSTRING
677 (- (point) (length context-string))))))))
678
4b398f5d
AS
679(defun vc-context-matches-p (posn context)
680 ;; Returns t if POSN matches CONTEXT, nil otherwise.
681 (let* ((context-string (nth 2 context))
682 (len (length context-string))
683 (end (+ posn len)))
684 (if (> end (1+ (buffer-size)))
685 nil
686 (string= context-string (buffer-substring posn end)))))
687
c8de1d91
AS
688(defun vc-buffer-context ()
689 ;; Return a list '(point-context mark-context reparse); from which
690 ;; vc-restore-buffer-context can later restore the context.
c4ae7096 691 (let ((point-context (vc-position-context (point)))
cfadef63
RS
692 ;; Use mark-marker to avoid confusion in transient-mark-mode.
693 (mark-context (if (eq (marker-buffer (mark-marker)) (current-buffer))
694 (vc-position-context (mark-marker))))
695 ;; Make the right thing happen in transient-mark-mode.
ab877583
RM
696 (mark-active nil)
697 ;; We may want to reparse the compilation buffer after revert
698 (reparse (and (boundp 'compilation-error-list) ;compile loaded
699 (let ((curbuf (current-buffer)))
700 ;; Construct a list; each elt is nil or a buffer
701 ;; iff that buffer is a compilation output buffer
702 ;; that contains markers into the current buffer.
703 (save-excursion
7ef84cf9
RS
704 (mapcar (function
705 (lambda (buffer)
ab877583
RM
706 (set-buffer buffer)
707 (let ((errors (or
708 compilation-old-error-list
709 compilation-error-list))
710 (buffer-error-marked-p nil))
6fb6ab11 711 (while (and (consp errors)
ab877583 712 (not buffer-error-marked-p))
a1bda481 713 (and (markerp (cdr (car errors)))
e9c8e248
RM
714 (eq buffer
715 (marker-buffer
a1bda481 716 (cdr (car errors))))
e9c8e248 717 (setq buffer-error-marked-p t))
ab877583 718 (setq errors (cdr errors)))
7ef84cf9 719 (if buffer-error-marked-p buffer))))
ab877583 720 (buffer-list)))))))
c8de1d91
AS
721 (list point-context mark-context reparse)))
722
723(defun vc-restore-buffer-context (context)
724 ;; Restore point/mark, and reparse any affected compilation buffers.
725 ;; CONTEXT is that which vc-buffer-context returns.
726 (let ((point-context (nth 0 context))
727 (mark-context (nth 1 context))
728 (reparse (nth 2 context)))
ab877583
RM
729 ;; Reparse affected compilation buffers.
730 (while reparse
731 (if (car reparse)
732 (save-excursion
733 (set-buffer (car reparse))
734 (let ((compilation-last-buffer (current-buffer)) ;select buffer
735 ;; Record the position in the compilation buffer of
736 ;; the last error next-error went to.
737 (error-pos (marker-position
738 (car (car-safe compilation-error-list)))))
739 ;; Reparse the error messages as far as they were parsed before.
740 (compile-reinitialize-errors '(4) compilation-parsing-end)
741 ;; Move the pointer up to find the error we were at before
742 ;; reparsing. Now next-error should properly go to the next one.
743 (while (and compilation-error-list
27f2f10b 744 (/= error-pos (car (car compilation-error-list))))
ab877583
RM
745 (setq compilation-error-list (cdr compilation-error-list))))))
746 (setq reparse (cdr reparse)))
e1f297e6 747
4b398f5d
AS
748 ;; if necessary, restore point and mark
749 (if (not (vc-context-matches-p (point) point-context))
750 (let ((new-point (vc-find-position-by-context point-context)))
751 (if new-point (goto-char new-point))))
01e02ab3
AS
752 (and mark-active
753 mark-context
754 (not (vc-context-matches-p (mark) mark-context))
755 (let ((new-mark (vc-find-position-by-context mark-context)))
756 (if new-mark (set-mark new-mark))))))
c4ae7096 757
767d12f2
SM
758;; Maybe this "smart mark preservation" could be added directly
759;; to revert-buffer since it can be generally useful. -sm
c8de1d91
AS
760(defun vc-revert-buffer1 (&optional arg no-confirm)
761 ;; Revert buffer, try to keep point and mark where user expects them in spite
762 ;; of changes because of expanded version-control key words.
763 ;; This is quite important since otherwise typeahead won't work as expected.
764 (interactive "P")
765 (widen)
766 (let ((context (vc-buffer-context)))
4b398f5d
AS
767 ;; Use save-excursion here, because it may be able to restore point
768 ;; and mark properly even in cases where vc-restore-buffer-context
769 ;; would fail. However, save-excursion might also get it wrong --
770 ;; in this case, vc-restore-buffer-context gives it a second try.
771 (save-excursion
772 ;; t means don't call normal-mode;
773 ;; that's to preserve various minor modes.
774 (revert-buffer arg no-confirm t))
c8de1d91
AS
775 (vc-restore-buffer-context context)))
776
594722a8 777
97d3f950 778(defun vc-buffer-sync (&optional not-urgent)
594722a8 779 ;; Make sure the current buffer and its working file are in sync
97d3f950 780 ;; NOT-URGENT means it is ok to continue if the user says not to save.
bbf97570 781 (if (buffer-modified-p)
97d3f950
RS
782 (if (or vc-suppress-confirm
783 (y-or-n-p (format "Buffer %s modified; save it? " (buffer-name))))
784 (save-buffer)
785 (if not-urgent
786 nil
787 (error "Aborted")))))
788
594722a8 789
9a51ed3a 790(defun vc-workfile-unchanged-p (file &optional want-differences-if-changed)
594722a8
ER
791 ;; Has the given workfile changed since last checkout?
792 (let ((checkout-time (vc-file-getprop file 'vc-checkout-time))
793 (lastmod (nth 5 (file-attributes file))))
9a51ed3a
PE
794 (or (equal checkout-time lastmod)
795 (and (or (not checkout-time) want-differences-if-changed)
796 (let ((unchanged (zerop (vc-backend-diff file nil nil
c6d4f628 797 (not want-differences-if-changed)))))
9a51ed3a
PE
798 ;; 0 stands for an unknown time; it can't match any mod time.
799 (vc-file-setprop file 'vc-checkout-time (if unchanged lastmod 0))
800 unchanged)))))
594722a8 801
e1f297e6
ER
802(defun vc-next-action-on-file (file verbose &optional comment)
803 ;;; If comment is specified, it will be used as an admin or checkin comment.
4b81132c 804 (let ((vc-type (vc-backend file))
8dd71345 805 owner version buffer)
e1f297e6
ER
806 (cond
807
4b81132c
AS
808 ;; If the file is not under version control, register it
809 ((not vc-type)
810 (vc-register verbose comment))
e1f297e6 811
61dee1e7
AS
812 ;; CVS: changes to the master file need to be
813 ;; merged back into the working file
814 ((and (eq vc-type 'CVS)
815 (or (eq (vc-cvs-status file) 'needs-checkout)
816 (eq (vc-cvs-status file) 'needs-merge)))
8dd71345
AS
817 (if (or vc-dired-mode
818 (yes-or-no-p
819 (format "%s is not up-to-date. Merge in changes now? "
820 (buffer-name))))
61dee1e7 821 (progn
8dd71345
AS
822 (if vc-dired-mode
823 (and (setq buffer (get-file-buffer file))
824 (buffer-modified-p buffer)
825 (switch-to-buffer-other-window buffer)
826 (vc-buffer-sync t))
827 (setq buffer (current-buffer))
828 (vc-buffer-sync t))
829 (if (and buffer (buffer-modified-p buffer)
61dee1e7 830 (not (yes-or-no-p
8dd71345
AS
831 (format
832 "Buffer %s modified; merge file on disc anyhow? "
833 (buffer-name buffer)))))
61dee1e7 834 (error "Merge aborted"))
18483cf0
AS
835 (let ((status (vc-backend-merge-news file)))
836 (and buffer
837 (vc-resynch-buffer file t
838 (not (buffer-modified-p buffer))))
839 (if (not (zerop status))
840 (if (y-or-n-p "Conflicts detected. Resolve them now? ")
841 (vc-resolve-conflicts)))))
61dee1e7
AS
842 (error "%s needs update" (buffer-name))))
843
d5859f32
AS
844 ;; For CVS files with implicit checkout: if unmodified, don't do anything
845 ((and (eq vc-type 'CVS)
846 (eq (vc-checkout-model file) 'implicit)
847 (not (vc-locking-user file))
848 (not verbose))
849 (message "%s is up to date" (buffer-name)))
850
4cbeb71c 851 ;; If there is no lock on the file, assert one and get it.
d5859f32
AS
852 ((not (setq owner (vc-locking-user file)))
853 ;; With implicit checkout, make sure not to lose unsaved changes.
854 (and (eq (vc-checkout-model file) 'implicit)
855 (buffer-modified-p buffer)
856 (vc-buffer-sync))
bbf97570 857 (if (and vc-checkout-carefully
9a51ed3a 858 (not (vc-workfile-unchanged-p file t)))
bbf97570 859 (if (save-window-excursion
6aa13729 860 (pop-to-buffer "*vc-diff*")
bbf97570
RS
861 (goto-char (point-min))
862 (insert-string (format "Changes to %s since last lock:\n\n"
863 file))
864 (not (beep))
865 (yes-or-no-p
866 (concat "File has unlocked changes, "
867 "claim lock retaining changes? ")))
868 (progn (vc-backend-steal file)
869 (vc-mode-line file))
870 (if (not (yes-or-no-p "Revert to checked-in version, instead? "))
2c28ac43 871 (error "Checkout aborted")
bbf97570
RS
872 (vc-revert-buffer1 t t)
873 (vc-checkout-writable-buffer file))
874 )
c6d4f628
RS
875 (if verbose
876 (if (not (eq vc-type 'SCCS))
e163b283
AS
877 (vc-checkout file nil
878 (read-string "Branch or version to move to: "))
2c28ac43 879 (error "Sorry, this is not implemented for SCCS"))
9341ff29
AS
880 (if (vc-latest-on-branch-p file)
881 (vc-checkout-writable-buffer file)
882 (if (yes-or-no-p
883 "This is not the latest version. Really lock it? ")
884 (vc-checkout-writable-buffer file)
885 (if (yes-or-no-p "Lock the latest version instead? ")
886 (vc-checkout-writable-buffer file
1ba1cade
AS
887 (if (vc-trunk-p (vc-workfile-version file))
888 "" ;; this means check out latest on trunk
889 (vc-branch-part (vc-workfile-version file)))))))
9341ff29 890 )))
e1f297e6
ER
891
892 ;; a checked-out version exists, but the user may not own the lock
61dee1e7 893 ((and (not (eq vc-type 'CVS))
8172cd86 894 (not (string-equal owner (vc-user-login-name))))
e1f297e6 895 (if comment
590cc449 896 (error "Sorry, you can't steal the lock on %s this way" file))
b0c9bc8c
AS
897 (and (eq vc-type 'RCS)
898 (not (vc-backend-release-p 'RCS "5.6.2"))
2c28ac43 899 (error "File is locked by %s" owner))
e1f297e6
ER
900 (vc-steal-lock
901 file
c6d4f628
RS
902 (if verbose (read-string "Version to steal: ")
903 (vc-workfile-version file))
e1f297e6 904 owner))
80688f5c 905
c6d4f628 906 ;; OK, user owns the lock on the file
8c0aaf40 907 (t
b0c9bc8c
AS
908 (if vc-dired-mode
909 (find-file-other-window file)
910 (find-file file))
e1f297e6 911
a0b87bc1
AS
912 ;; If the file on disk is newer, then the user just
913 ;; said no to rereading it. So the user probably wishes to
914 ;; overwrite the file with the buffer's contents, and check
915 ;; that in.
916 (if (not (verify-visited-file-modtime (current-buffer)))
917 (if (yes-or-no-p "Replace file on disk with buffer contents? ")
918 (write-file (buffer-file-name))
919 (error "Aborted"))
18483cf0 920 ;; if buffer is not saved, give user a chance to do it
a0b87bc1 921 (vc-buffer-sync))
e1f297e6
ER
922
923 ;; Revert if file is unchanged and buffer is too.
924 ;; If buffer is modified, that means the user just said no
925 ;; to saving it; in that case, don't revert,
926 ;; because the user might intend to save
927 ;; after finishing the log entry.
80688f5c 928 (if (and (vc-workfile-unchanged-p file)
e1f297e6 929 (not (buffer-modified-p)))
c6d4f628
RS
930 ;; DO NOT revert the file without asking the user!
931 (cond
932 ((yes-or-no-p "Revert to master version? ")
933 (vc-backend-revert file)
934 (vc-resynch-window file t t)))
e1f297e6
ER
935
936 ;; user may want to set nonstandard parameters
937 (if verbose
938 (setq version (read-string "New version level: ")))
939
940 ;; OK, let's do the checkin
941 (vc-checkin file version comment)
8c0aaf40 942 )))))
e1f297e6 943
beba4bd9
AS
944(defvar vc-dired-window-configuration)
945
e1f297e6 946(defun vc-next-action-dired (file rev comment)
b0c9bc8c
AS
947 ;; Do a vc-next-action-on-file on all the marked files, possibly
948 ;; passing on the log comment we've just entered.
3d30b8bc 949 (let ((dired-buffer (current-buffer))
8dd71345 950 (dired-dir default-directory))
632e9525 951 (dired-map-over-marks
3b574573 952 (let ((file (dired-get-filename)))
b0c9bc8c 953 (message "Processing %s..." file)
8dd71345
AS
954 ;; Adjust the default directory so that checkouts
955 ;; go to the right place.
3b574573
AS
956 (let ((default-directory (file-name-directory file)))
957 (vc-next-action-on-file file nil comment)
958 (set-buffer dired-buffer))
959 ;; Make sure that files don't vanish
960 ;; after they are checked in.
961 (let ((vc-dired-terse-mode nil))
962 (dired-do-redisplay file))
3d30b8bc 963 (set-window-configuration vc-dired-window-configuration)
b0c9bc8c 964 (message "Processing %s...done" file))
3d30b8bc
RS
965 nil t))
966 (dired-move-to-filename))
e1f297e6 967
637a8ae9 968;; Here's the major entry point.
594722a8 969
637a8ae9 970;;;###autoload
594722a8
ER
971(defun vc-next-action (verbose)
972 "Do the next logical checkin or checkout operation on the current file.
c6d4f628
RS
973 If you call this from within a VC dired buffer with no files marked,
974it will operate on the file in the current line.
975 If you call this from within a VC dired buffer, and one or more
976files are marked, it will accept a log message and then operate on
977each one. The log message will be used as a comment for any register
978or checkin operations, but ignored when doing checkouts. Attempted
979lock steals will raise an error.
980 A prefix argument lets you specify the version number to use.
80688f5c
RS
981
982For RCS and SCCS files:
594722a8 983 If the file is not already registered, this registers it for version
4b81132c 984control.
594722a8 985 If the file is registered and not locked by anyone, this checks out
34291cd2 986a writable and locked file ready for editing.
594722a8
ER
987 If the file is checked out and locked by the calling user, this
988first checks to see if the file has changed since checkout. If not,
989it performs a revert.
e1f297e6
ER
990 If the file has been changed, this pops up a buffer for entry
991of a log message; when the message has been entered, it checks in the
594722a8 992resulting changes along with the log message as change commentary. If
34291cd2 993the variable `vc-keep-workfiles' is non-nil (which is its default), a
594722a8
ER
994read-only copy of the changed file is left in place afterwards.
995 If the file is registered and locked by someone else, you are given
e1f297e6 996the option to steal the lock.
80688f5c
RS
997
998For CVS files:
999 If the file is not already registered, this registers it for version
1000control. This does a \"cvs add\", but no \"cvs commit\".
1001 If the file is added but not committed, it is committed.
80688f5c
RS
1002 If your working file is changed, but the repository file is
1003unchanged, this pops up a buffer for entry of a log message; when the
1004message has been entered, it checks in the resulting changes along
1005with the logmessage as change commentary. A writable file is retained.
1006 If the repository file is changed, you are asked if you want to
c6d4f628 1007merge in the changes into your working copy."
bbf97570 1008
594722a8 1009 (interactive "P")
8c0aaf40
ER
1010 (catch 'nogo
1011 (if vc-dired-mode
1012 (let ((files (dired-get-marked-files)))
3d30b8bc
RS
1013 (set (make-local-variable 'vc-dired-window-configuration)
1014 (current-window-configuration))
8dd71345
AS
1015 (if (string= ""
1016 (mapconcat
b0c9bc8c
AS
1017 (function (lambda (f)
1018 (if (eq (vc-backend f) 'CVS)
8dd71345
AS
1019 (if (or (eq (vc-cvs-status f) 'locally-modified)
1020 (eq (vc-cvs-status f) 'locally-added))
b0c9bc8c
AS
1021 "@" "")
1022 (if (vc-locking-user f) "@" ""))))
1023 files ""))
1024 (vc-next-action-dired nil nil "dummy")
1025 (vc-start-entry nil nil nil
1026 "Enter a change comment for the marked files."
1027 'vc-next-action-dired))
8dd71345 1028 (throw 'nogo nil)))
dc08a6b5
AS
1029 (while vc-parent-buffer
1030 (pop-to-buffer vc-parent-buffer))
1031 (if buffer-file-name
1032 (vc-next-action-on-file buffer-file-name verbose)
1033 (error "Buffer %s is not associated with a file" (buffer-name)))))
594722a8
ER
1034
1035;;; These functions help the vc-next-action entry point
1036
c6d4f628 1037(defun vc-checkout-writable-buffer (&optional file rev)
34291cd2 1038 "Retrieve a writable copy of the latest version of the current buffer's file."
c6d4f628 1039 (vc-checkout (or file (buffer-file-name)) t rev)
02da6253
PE
1040 )
1041
637a8ae9 1042;;;###autoload
e1f297e6 1043(defun vc-register (&optional override comment)
594722a8
ER
1044 "Register the current file into your version-control system."
1045 (interactive "P")
f1b82fc8
KH
1046 (or buffer-file-name
1047 (error "No visited file"))
e837a82f
RS
1048 (let ((master (vc-name buffer-file-name)))
1049 (and master (file-exists-p master)
1050 (error "This file is already registered"))
1051 (and master
1052 (not (y-or-n-p "Previous master file has vanished. Make a new one? "))
1053 (error "This file is already registered")))
02da6253
PE
1054 ;; Watch out for new buffers of size 0: the corresponding file
1055 ;; does not exist yet, even though buffer-modified-p is nil.
1056 (if (and (not (buffer-modified-p))
1057 (zerop (buffer-size))
1058 (not (file-exists-p buffer-file-name)))
1059 (set-buffer-modified-p t))
594722a8 1060 (vc-buffer-sync)
993a1a44
RS
1061 (cond ((not vc-make-backup-files)
1062 ;; inhibit backup for this buffer
1063 (make-local-variable 'backup-inhibited)
1064 (setq backup-inhibited t)))
594722a8
ER
1065 (vc-admin
1066 buffer-file-name
0d53f466
AS
1067 (or (and override
1068 (read-string
1069 (format "Initial version level for %s: " buffer-file-name)))
1070 vc-default-init-version)
1071 comment)
4b398f5d 1072 ;; Recompute backend property (it may have been set to nil before).
c863c92d 1073 (setq vc-buffer-backend (vc-backend (buffer-file-name)))
594722a8
ER
1074 )
1075
624b4662 1076(defun vc-resynch-window (file &optional keep noquery)
594722a8 1077 ;; If the given file is in the current buffer,
a7acbbe4 1078 ;; either revert on it so we see expanded keywords,
594722a8 1079 ;; or unvisit it (depending on vc-keep-workfiles)
624b4662
RS
1080 ;; NOQUERY if non-nil inhibits confirmation for reverting.
1081 ;; NOQUERY should be t *only* if it is known the only difference
1082 ;; between the buffer and the file is due to RCS rather than user editing!
594722a8
ER
1083 (and (string= buffer-file-name file)
1084 (if keep
1085 (progn
1ab31687 1086 (vc-revert-buffer1 t noquery)
f8791ebe
AS
1087 (and view-read-only
1088 (if (file-writable-p file)
1089 (and view-mode
1090 (let ((view-old-buffer-read-only nil))
1091 (view-mode-exit)))
1092 (and (not view-mode)
1093 (not (eq (get major-mode 'mode-class) 'special))
1094 (view-mode-enter))))
594722a8 1095 (vc-mode-line buffer-file-name))
88a2ffaf 1096 (kill-buffer (current-buffer)))))
594722a8 1097
503b5c85 1098(defun vc-resynch-buffer (file &optional keep noquery)
b0c9bc8c 1099 ;; if FILE is currently visited, resynch its buffer
4b398f5d
AS
1100 (if (string= buffer-file-name file)
1101 (vc-resynch-window file keep noquery)
1102 (let ((buffer (get-file-buffer file)))
1103 (if buffer
1104 (save-excursion
1105 (set-buffer buffer)
1106 (vc-resynch-window file keep noquery))))))
503b5c85 1107
b965445f 1108(defun vc-start-entry (file rev comment msg action &optional after-hook)
e1f297e6
ER
1109 ;; Accept a comment for an operation on FILE revision REV. If COMMENT
1110 ;; is nil, pop up a VC-log buffer, emit MSG, and set the
1111 ;; action on close to ACTION; otherwise, do action immediately.
cdaf7a1a 1112 ;; Remember the file's buffer in vc-parent-buffer (current one if no file).
b965445f 1113 ;; AFTER-HOOK specifies the local value for vc-log-operation-hook.
e1f297e6 1114 (let ((parent (if file (find-file-noselect file) (current-buffer))))
f0b188ed
RS
1115 (if vc-before-checkin-hook
1116 (if file
1117 (save-excursion
1118 (set-buffer parent)
1119 (run-hooks 'vc-before-checkin-hook))
1120 (run-hooks 'vc-before-checkin-hook)))
e1f297e6
ER
1121 (if comment
1122 (set-buffer (get-buffer-create "*VC-log*"))
1123 (pop-to-buffer (get-buffer-create "*VC-log*")))
8c0aaf40
ER
1124 (set (make-local-variable 'vc-parent-buffer) parent)
1125 (set (make-local-variable 'vc-parent-buffer-name)
1126 (concat " from " (buffer-name vc-parent-buffer)))
7e869659 1127 (if file (vc-mode-line file))
37667a5c 1128 (vc-log-mode file)
b965445f
RS
1129 (make-local-variable 'vc-log-after-operation-hook)
1130 (if after-hook
1131 (setq vc-log-after-operation-hook after-hook))
e1f297e6 1132 (setq vc-log-operation action)
e1f297e6
ER
1133 (setq vc-log-version rev)
1134 (if comment
1135 (progn
1136 (erase-buffer)
8c0aaf40
ER
1137 (if (eq comment t)
1138 (vc-finish-logentry t)
1139 (insert comment)
1140 (vc-finish-logentry nil)))
e1f297e6 1141 (message "%s Type C-c C-c when done." msg))))
594722a8 1142
e1f297e6 1143(defun vc-admin (file rev &optional comment)
624b4662 1144 "Check a file into your version-control system.
594722a8 1145FILE is the unmodified name of the file. REV should be the base version
e1f297e6 1146level to check it in under. COMMENT, if specified, is the checkin comment."
b965445f
RS
1147 (vc-start-entry file rev
1148 (or comment (not vc-initial-comment))
1149 "Enter initial comment." 'vc-backend-admin
6bcb1d4e 1150 nil))
e1f297e6 1151
c6d4f628 1152(defun vc-checkout (file &optional writable rev)
e1f297e6
ER
1153 "Retrieve a copy of the latest version of the given file."
1154 ;; If ftp is on this system and the name matches the ange-ftp format
1155 ;; for a remote file, the user is trying something that won't work.
1156 (if (and (string-match "^/[^/:]+:" file) (vc-find-binary "ftp"))
1157 (error "Sorry, you can't check out files over FTP"))
c6d4f628 1158 (vc-backend-checkout file writable rev)
b0c9bc8c 1159 (vc-resynch-buffer file t t))
594722a8
ER
1160
1161(defun vc-steal-lock (file rev &optional owner)
1162 "Steal the lock on the current workfile."
29fc1ce9
RS
1163 (let (file-description)
1164 (if (not owner)
1165 (setq owner (vc-locking-user file)))
1166 (if rev
1167 (setq file-description (format "%s:%s" file rev))
1168 (setq file-description file))
4bc504c8
RS
1169 (if (not (yes-or-no-p (format "Steal the lock on %s from %s? "
1170 file-description owner)))
29fc1ce9
RS
1171 (error "Steal cancelled"))
1172 (pop-to-buffer (get-buffer-create "*VC-mail*"))
1173 (setq default-directory (expand-file-name "~/"))
1174 (auto-save-mode auto-save-default)
1175 (mail-mode)
1176 (erase-buffer)
1177 (mail-setup owner (format "Stolen lock on %s" file-description) nil nil nil
3e3da61f 1178 (list (list 'vc-finish-steal file rev)))
29fc1ce9
RS
1179 (goto-char (point-max))
1180 (insert
1181 (format "I stole the lock on %s, " file-description)
1182 (current-time-string)
1183 ".\n")
1184 (message "Please explain why you stole the lock. Type C-c C-c when done.")))
594722a8 1185
ad014629 1186;; This is called when the notification has been sent.
594722a8 1187(defun vc-finish-steal (file version)
594722a8 1188 (vc-backend-steal file version)
3e3da61f
RS
1189 (if (get-file-buffer file)
1190 (save-excursion
6242bee4 1191 (set-buffer (get-file-buffer file))
3e3da61f 1192 (vc-resynch-window file t t))))
594722a8 1193
594722a8
ER
1194(defun vc-checkin (file &optional rev comment)
1195 "Check in the file specified by FILE.
1196The optional argument REV may be a string specifying the new version level
67242a23 1197\(if nil increment the current level). The file is either retained with write
34291cd2 1198permissions zeroed, or deleted (according to the value of `vc-keep-workfiles').
80688f5c 1199If the back-end is CVS, a writable workfile is always kept.
861f3c29
DL
1200COMMENT is a comment string; if omitted, a buffer is popped up to accept a
1201comment.
1202
1203Runs the normal hook `vc-checkin-hook'."
61446fe7 1204 (vc-start-entry file rev comment
b965445f
RS
1205 "Enter a change comment." 'vc-backend-checkin
1206 'vc-checkin-hook))
594722a8 1207
3b4dd9a9
RM
1208(defun vc-comment-to-change-log (&optional whoami file-name)
1209 "Enter last VC comment into change log file for current buffer's file.
1210Optional arg (interactive prefix) non-nil means prompt for user name and site.
1211Second arg is file name of change log. \
861f3c29
DL
1212If nil, uses `change-log-default-name'.
1213
1214May be useful as a `vc-checkin-hook' to update change logs automatically."
43cea1ab
RM
1215 (interactive (if current-prefix-arg
1216 (list current-prefix-arg
1217 (prompt-for-change-log-name))))
41208291
KH
1218 ;; Make sure the defvar for add-log-current-defun-function has been executed
1219 ;; before binding it.
1220 (require 'add-log)
3b4dd9a9
RM
1221 (let (;; Extract the comment first so we get any error before doing anything.
1222 (comment (ring-ref vc-comment-ring 0))
43cea1ab 1223 ;; Don't let add-change-log-entry insert a defun name.
3b4dd9a9
RM
1224 (add-log-current-defun-function 'ignore)
1225 end)
1226 ;; Call add-log to do half the work.
43cea1ab 1227 (add-change-log-entry whoami file-name t t)
3b4dd9a9
RM
1228 ;; Insert the VC comment, leaving point before it.
1229 (setq end (save-excursion (insert comment) (point-marker)))
1230 (if (looking-at "\\s *\\s(")
1231 ;; It starts with an open-paren, as in "(foo): Frobbed."
43cea1ab 1232 ;; So remove the ": " add-log inserted.
3b4dd9a9
RM
1233 (delete-char -2))
1234 ;; Canonicalize the white space between the file name and comment.
1235 (just-one-space)
1236 ;; Indent rest of the text the same way add-log indented the first line.
1237 (let ((indentation (current-indentation)))
1238 (save-excursion
1239 (while (< (point) end)
1240 (forward-line 1)
1241 (indent-to indentation))
c124b1b4 1242 (setq end (point))))
3b4dd9a9 1243 ;; Fill the inserted text, preserving open-parens at bol.
6b60c5d1
BG
1244 (let ((paragraph-separate (concat paragraph-separate "\\|\\s *\\s("))
1245 (paragraph-start (concat paragraph-start "\\|\\s *\\s(")))
43cea1ab 1246 (beginning-of-line)
c124b1b4
RM
1247 (fill-region (point) end))
1248 ;; Canonicalize the white space at the end of the entry so it is
1249 ;; separated from the next entry by a single blank line.
1250 (skip-syntax-forward " " end)
1251 (delete-char (- (skip-syntax-backward " ")))
1252 (or (eobp) (looking-at "\n\n")
1253 (insert "\n"))))
3b4dd9a9 1254
8c0aaf40 1255(defun vc-finish-logentry (&optional nocomment)
594722a8
ER
1256 "Complete the operation implied by the current log entry."
1257 (interactive)
8c0aaf40
ER
1258 ;; Check and record the comment, if any.
1259 (if (not nocomment)
1260 (progn
8c0aaf40
ER
1261 ;; Comment too long?
1262 (vc-backend-logentry-check vc-log-file)
1263 ;; Record the comment in the comment ring
8c0aaf40
ER
1264 (ring-insert vc-comment-ring (buffer-string))
1265 ))
b2396d1f 1266 ;; Sync parent buffer in case the user modified it while editing the comment.
cdaf7a1a 1267 ;; But not if it is a vc-dired buffer.
b2396d1f 1268 (save-excursion
cdaf7a1a
RS
1269 (set-buffer vc-parent-buffer)
1270 (or vc-dired-mode
1271 (vc-buffer-sync)))
61dee1e7
AS
1272 (if (not vc-log-operation) (error "No log operation is pending"))
1273 ;; save the parameters held in buffer-local variables
1274 (let ((log-operation vc-log-operation)
1275 (log-file vc-log-file)
1276 (log-version vc-log-version)
1277 (log-entry (buffer-string))
2c4eea90
KH
1278 (after-hook vc-log-after-operation-hook)
1279 (tmp-vc-parent-buffer vc-parent-buffer))
e2bef5c3 1280 (pop-to-buffer vc-parent-buffer)
61dee1e7
AS
1281 ;; OK, do it to it
1282 (save-excursion
1283 (funcall log-operation
1284 log-file
1285 log-version
1286 log-entry))
df1e7b91
KH
1287 ;; Remove checkin window (after the checkin so that if that fails
1288 ;; we don't zap the *VC-log* buffer and the typing therein).
1289 (let ((logbuf (get-buffer "*VC-log*")))
2c4eea90
KH
1290 (cond ((and logbuf vc-delete-logbuf-window)
1291 (delete-windows-on logbuf (selected-frame))
262c8cea 1292 ;; Kill buffer and delete any other dedicated windows/frames.
2c4eea90
KH
1293 (kill-buffer logbuf))
1294 (t (pop-to-buffer "*VC-log*")
1295 (bury-buffer)
1296 (pop-to-buffer tmp-vc-parent-buffer))))
e2bef5c3
RS
1297 ;; Now make sure we see the expanded headers
1298 (if buffer-file-name
e1f297e6 1299 (vc-resynch-window buffer-file-name vc-keep-workfiles t))
3d30b8bc
RS
1300 (if vc-dired-mode
1301 (dired-move-to-filename))
37667a5c 1302 (run-hooks after-hook 'vc-finish-logentry-hook)))
594722a8
ER
1303
1304;; Code for access to the comment ring
1305
8c0aaf40
ER
1306(defun vc-previous-comment (arg)
1307 "Cycle backwards through comment history."
1308 (interactive "*p")
1309 (let ((len (ring-length vc-comment-ring)))
1310 (cond ((<= len 0)
1311 (message "Empty comment ring")
1312 (ding))
1313 (t
1314 (erase-buffer)
1315 ;; Initialize the index on the first use of this command
1316 ;; so that the first M-p gets index 0, and the first M-n gets
1317 ;; index -1.
1318 (if (null vc-comment-ring-index)
1319 (setq vc-comment-ring-index
1320 (if (> arg 0) -1
1321 (if (< arg 0) 1 0))))
1322 (setq vc-comment-ring-index
c6bfcd12 1323 (mod (+ vc-comment-ring-index arg) len))
8c0aaf40
ER
1324 (message "%d" (1+ vc-comment-ring-index))
1325 (insert (ring-ref vc-comment-ring vc-comment-ring-index))))))
1326
1327(defun vc-next-comment (arg)
1328 "Cycle forwards through comment history."
1329 (interactive "*p")
1330 (vc-previous-comment (- arg)))
1331
1332(defun vc-comment-search-reverse (str)
1333 "Searches backwards through comment history for substring match."
1334 (interactive "sComment substring: ")
1335 (if (string= str "")
1336 (setq str vc-last-comment-match)
1337 (setq vc-last-comment-match str))
1338 (if (null vc-comment-ring-index)
1339 (setq vc-comment-ring-index -1))
1340 (let ((str (regexp-quote str))
1341 (len (ring-length vc-comment-ring))
1342 (n (1+ vc-comment-ring-index)))
1343 (while (and (< n len) (not (string-match str (ring-ref vc-comment-ring n))))
1344 (setq n (+ n 1)))
1345 (cond ((< n len)
1346 (vc-previous-comment (- n vc-comment-ring-index)))
1347 (t (error "Not found")))))
1348
1349(defun vc-comment-search-forward (str)
1350 "Searches forwards through comment history for substring match."
1351 (interactive "sComment substring: ")
1352 (if (string= str "")
1353 (setq str vc-last-comment-match)
1354 (setq vc-last-comment-match str))
1355 (if (null vc-comment-ring-index)
1356 (setq vc-comment-ring-index 0))
1357 (let ((str (regexp-quote str))
1358 (len (ring-length vc-comment-ring))
1359 (n vc-comment-ring-index))
1360 (while (and (>= n 0) (not (string-match str (ring-ref vc-comment-ring n))))
1361 (setq n (- n 1)))
1362 (cond ((>= n 0)
1363 (vc-next-comment (- n vc-comment-ring-index)))
1364 (t (error "Not found")))))
594722a8
ER
1365
1366;; Additional entry points for examining version histories
1367
637a8ae9 1368;;;###autoload
97d3f950 1369(defun vc-diff (historic &optional not-urgent)
e8ee1ccf
RS
1370 "Display diffs between file versions.
1371Normally this compares the current file and buffer with the most recent
1372checked in version of that file. This uses no arguments.
1373With a prefix argument, it reads the file name to use
1374and two version designators specifying which versions to compare."
48078f8f 1375 (interactive (list current-prefix-arg t))
b6909007 1376 (vc-ensure-vc-buffer)
594722a8
ER
1377 (if historic
1378 (call-interactively 'vc-version-diff)
02da6253 1379 (let ((file buffer-file-name)
594722a8 1380 unchanged)
c0d66cb2
RS
1381 (vc-buffer-sync not-urgent)
1382 (setq unchanged (vc-workfile-unchanged-p buffer-file-name))
1383 (if unchanged
1384 (message "No changes to %s since latest version" file)
1385 (vc-backend-diff file)
1386 ;; Ideally, we'd like at this point to parse the diff so that
1387 ;; the buffer effectively goes into compilation mode and we
1388 ;; can visit the old and new change locations via next-error.
1389 ;; Unfortunately, this is just too painful to do. The basic
1390 ;; problem is that the `old' file doesn't exist to be
1391 ;; visited. This plays hell with numerous assumptions in
1392 ;; the diff.el and compile.el machinery.
1393 (set-buffer "*vc-diff*")
1394 (setq default-directory (file-name-directory file))
1395 (if (= 0 (buffer-size))
1396 (progn
1397 (setq unchanged t)
1398 (message "No changes to %s since latest version" file))
1399 (pop-to-buffer "*vc-diff*")
1400 (goto-char (point-min))
1401 (shrink-window-if-larger-than-buffer)))
1402 (not unchanged))))
594722a8
ER
1403
1404(defun vc-version-diff (file rel1 rel2)
1405 "For FILE, report diffs between two stored versions REL1 and REL2 of it.
1406If FILE is a directory, generate diffs between versions for all registered
1407files in or below it."
c0d66cb2 1408 (interactive
4e6473c8
GM
1409 (let ((file (expand-file-name
1410 (read-file-name (if buffer-file-name
1411 "File or dir to diff: (default visited file) "
1412 "File or dir to diff: ")
1413 default-directory buffer-file-name t)))
c0d66cb2
RS
1414 (rel1-default nil) (rel2-default nil))
1415 ;; compute default versions based on the file state
1416 (cond
1417 ;; if it's a directory, don't supply any version defauolt
1418 ((file-directory-p file)
1419 nil)
1420 ;; if the file is locked, use current version as older version
1421 ((vc-locking-user file)
1422 (setq rel1-default (vc-workfile-version file)))
1423 ;; if the file is not locked, use last and previous version as default
1424 (t
1425 (setq rel1-default (vc-previous-version (vc-workfile-version file)))
1426 (setq rel2-default (vc-workfile-version file))))
1427 ;; construct argument list
1428 (list file
8e710301
RS
1429 (read-string (if rel1-default
1430 (concat "Older version: (default "
1431 rel1-default ") ")
1432 "Older version: ")
1433 nil nil rel1-default)
1434 (read-string (if rel2-default
1435 (concat "Newer version: (default "
1436 rel2-default ") ")
ba27415c 1437 "Newer version (default: current source): ")
8e710301 1438 nil nil rel2-default))))
594722a8
ER
1439 (if (string-equal rel1 "") (setq rel1 nil))
1440 (if (string-equal rel2 "") (setq rel2 nil))
1441 (if (file-directory-p file)
1a2f456b 1442 (let ((camefrom (current-buffer)))
594722a8 1443 (set-buffer (get-buffer-create "*vc-status*"))
8c0aaf40
ER
1444 (set (make-local-variable 'vc-parent-buffer) camefrom)
1445 (set (make-local-variable 'vc-parent-buffer-name)
1446 (concat " from " (buffer-name camefrom)))
594722a8 1447 (erase-buffer)
3234e2a3
ER
1448 (insert "Diffs between "
1449 (or rel1 "last version checked in")
1450 " and "
1451 (or rel2 "current workfile(s)")
1452 ":\n\n")
6aa13729 1453 (set-buffer (get-buffer-create "*vc-diff*"))
e1f297e6 1454 (cd file)
594722a8 1455 (vc-file-tree-walk
2f119435 1456 default-directory
594722a8 1457 (function (lambda (f)
a9a59766 1458 (message "Looking at %s" f)
594722a8 1459 (and
3234e2a3
ER
1460 (not (file-directory-p f))
1461 (vc-registered f)
02da6253
PE
1462 (vc-backend-diff f rel1 rel2)
1463 (append-to-buffer "*vc-status*" (point-min) (point-max)))
1464 )))
594722a8
ER
1465 (pop-to-buffer "*vc-status*")
1466 (insert "\nEnd of diffs.\n")
1467 (goto-char (point-min))
1468 (set-buffer-modified-p nil)
1469 )
36bed8bc
RS
1470 (if (zerop (vc-backend-diff file rel1 rel2))
1471 (message "No changes to %s between %s and %s." file rel1 rel2)
6aa13729 1472 (pop-to-buffer "*vc-diff*"))))
594722a8 1473
f1818994
PE
1474;;;###autoload
1475(defun vc-version-other-window (rev)
1476 "Visit version REV of the current buffer in another window.
1477If the current buffer is named `F', the version is named `F.~REV~'.
1478If `F.~REV~' already exists, it is used instead of being re-created."
1479 (interactive "sVersion to visit (default is latest version): ")
b6909007
AS
1480 (vc-ensure-vc-buffer)
1481 (let* ((version (if (string-equal rev "")
1482 (vc-latest-version buffer-file-name)
1483 rev))
1484 (filename (concat buffer-file-name ".~" version "~")))
1485 (or (file-exists-p filename)
1486 (vc-backend-checkout buffer-file-name nil version filename))
1487 (find-file-other-window filename)))
f1818994 1488
594722a8
ER
1489;; Header-insertion code
1490
637a8ae9 1491;;;###autoload
594722a8
ER
1492(defun vc-insert-headers ()
1493 "Insert headers in a file for use with your version-control system.
b524ce9f 1494Headers desired are inserted at point, and are pulled from
34291cd2 1495the variable `vc-header-alist'."
594722a8 1496 (interactive)
b6909007 1497 (vc-ensure-vc-buffer)
594722a8
ER
1498 (save-excursion
1499 (save-restriction
1500 (widen)
1501 (if (or (not (vc-check-headers))
820bde8d 1502 (y-or-n-p "Version headers already exist. Insert another set? "))
594722a8
ER
1503 (progn
1504 (let* ((delims (cdr (assq major-mode vc-comment-alist)))
1505 (comment-start-vc (or (car delims) comment-start "#"))
1506 (comment-end-vc (or (car (cdr delims)) comment-end ""))
f3c61d82 1507 (hdstrings (cdr (assoc (vc-backend (buffer-file-name)) vc-header-alist))))
594722a8
ER
1508 (mapcar (function (lambda (s)
1509 (insert comment-start-vc "\t" s "\t"
1510 comment-end-vc "\n")))
1511 hdstrings)
1512 (if vc-static-header-alist
1513 (mapcar (function (lambda (f)
1514 (if (string-match (car f) buffer-file-name)
1515 (insert (format (cdr f) (car hdstrings))))))
1516 vc-static-header-alist))
1517 )
1518 )))))
1519
c8de1d91
AS
1520(defun vc-clear-headers ()
1521 ;; Clear all version headers in the current buffer, i.e. reset them
1522 ;; to the nonexpanded form. Only implemented for RCS, yet.
1523 ;; Don't lose point and mark during this.
d5859f32
AS
1524 (let ((context (vc-buffer-context))
1525 (case-fold-search nil))
4b398f5d
AS
1526 ;; save-excursion may be able to relocate point and mark properly.
1527 ;; If it fails, vc-restore-buffer-context will give it a second try.
1528 (save-excursion
1529 (goto-char (point-min))
1530 (while (re-search-forward
1531 (concat "\\$\\(Author\\|Date\\|Header\\|Id\\|Locker\\|Name\\|"
1532 "RCSfile\\|Revision\\|Source\\|State\\): [^$\n]+\\$")
1533 nil t)
1534 (replace-match "$\\1$")))
c8de1d91
AS
1535 (vc-restore-buffer-context context)))
1536
b6909007 1537;;;###autoload
ccb141e8
AS
1538(defun vc-merge ()
1539 (interactive)
1540 (vc-ensure-vc-buffer)
1541 (vc-buffer-sync)
1542 (let* ((file buffer-file-name)
1543 (backend (vc-backend file))
1544 first-version second-version locking-user)
1545 (if (eq backend 'SCCS)
1546 (error "Sorry, merging is not implemented for SCCS")
1547 (setq locking-user (vc-locking-user file))
1548 (if (eq (vc-checkout-model file) 'manual)
1549 (if (not locking-user)
1550 (if (not (y-or-n-p
1551 (format "File must be %s for merging. %s now? "
1552 (if (eq backend 'RCS) "locked" "writable")
1553 (if (eq backend 'RCS) "Lock" "Check out"))))
1554 (error "Merge aborted")
1555 (vc-checkout file t))
1556 (if (not (string= locking-user (vc-user-login-name)))
1557 (error "File is locked by %s" locking-user))))
1558 (setq first-version (read-string "Branch or version to merge from: "))
1559 (if (and (>= (elt first-version 0) ?0)
1560 (<= (elt first-version 0) ?9))
1561 (if (not (vc-branch-p first-version))
1562 (setq second-version
1563 (read-string "Second version: "
1564 (concat (vc-branch-part first-version) ".")))
1565 ;; We want to merge an entire branch. Set versions
1566 ;; accordingly, so that vc-backend-merge understands us.
1567 (setq second-version first-version)
1568 ;; first-version must be the starting point of the branch
1569 (setq first-version (vc-branch-part first-version))))
1570 (let ((status (vc-backend-merge file first-version second-version)))
1571 (if (and (eq (vc-checkout-model file) 'implicit)
1572 (not (vc-locking-user file)))
1573 (vc-file-setprop file 'vc-locking-user nil))
1574 (vc-resynch-buffer file t t)
1575 (if (not (zerop status))
1576 (if (y-or-n-p "Conflicts detected. Resolve them now? ")
1577 (vc-resolve-conflicts "WORKFILE" "MERGE SOURCE")
1578 (message "File contains conflict markers"))
1579 (message "Merge successful"))))))
1580
beba4bd9
AS
1581(defvar vc-ediff-windows)
1582(defvar vc-ediff-result)
1583
ccb141e8
AS
1584;;;###autoload
1585(defun vc-resolve-conflicts (&optional name-A name-B)
18483cf0
AS
1586 "Invoke ediff to resolve conflicts in the current buffer.
1587The conflicts must be marked with rcsmerge conflict markers."
1588 (interactive)
b6909007 1589 (vc-ensure-vc-buffer)
18483cf0
AS
1590 (let* ((found nil)
1591 (file-name (file-name-nondirectory buffer-file-name))
1592 (your-buffer (generate-new-buffer
ccb141e8
AS
1593 (concat "*" file-name
1594 " " (or name-A "WORKFILE") "*")))
18483cf0 1595 (other-buffer (generate-new-buffer
ccb141e8
AS
1596 (concat "*" file-name
1597 " " (or name-B "CHECKED-IN") "*")))
18483cf0
AS
1598 (result-buffer (current-buffer)))
1599 (save-excursion
1600 (set-buffer your-buffer)
1601 (erase-buffer)
1602 (insert-buffer result-buffer)
1603 (goto-char (point-min))
1604 (while (re-search-forward (concat "^<<<<<<< "
1605 (regexp-quote file-name) "\n") nil t)
1606 (setq found t)
1607 (replace-match "")
1608 (if (not (re-search-forward "^=======\n" nil t))
1609 (error "Malformed conflict marker"))
1610 (replace-match "")
1611 (let ((start (point)))
1612 (if (not (re-search-forward "^>>>>>>> [0-9.]+\n" nil t))
1613 (error "Malformed conflict marker"))
1614 (delete-region start (point))))
1615 (if (not found)
1616 (progn
1617 (kill-buffer your-buffer)
1618 (kill-buffer other-buffer)
1619 (error "No conflict markers found")))
1620 (set-buffer other-buffer)
1621 (erase-buffer)
1622 (insert-buffer result-buffer)
1623 (goto-char (point-min))
1624 (while (re-search-forward (concat "^<<<<<<< "
1625 (regexp-quote file-name) "\n") nil t)
1626 (let ((start (match-beginning 0)))
1627 (if (not (re-search-forward "^=======\n" nil t))
1628 (error "Malformed conflict marker"))
1629 (delete-region start (point))
1630 (if (not (re-search-forward "^>>>>>>> [0-9.]+\n" nil t))
1631 (error "Malformed conflict marker"))
1632 (replace-match "")))
1633 (let ((config (current-window-configuration))
1634 (ediff-default-variant 'default-B))
1635
1636 ;; Fire up ediff.
1637
1638 (set-buffer (ediff-merge-buffers your-buffer other-buffer))
1639
1640 ;; Ediff is now set up, and we are in the control buffer.
1641 ;; Do a few further adjustments and take precautions for exit.
1642
1643 (make-local-variable 'vc-ediff-windows)
1644 (setq vc-ediff-windows config)
1645 (make-local-variable 'vc-ediff-result)
1646 (setq vc-ediff-result result-buffer)
1647 (make-local-variable 'ediff-quit-hook)
1648 (setq ediff-quit-hook
1649 (function
1650 (lambda ()
1651 (let ((buffer-A ediff-buffer-A)
1652 (buffer-B ediff-buffer-B)
1653 (buffer-C ediff-buffer-C)
1654 (result vc-ediff-result)
1655 (windows vc-ediff-windows))
1656 (ediff-cleanup-mess)
1657 (set-buffer result)
1658 (erase-buffer)
1659 (insert-buffer buffer-C)
1660 (kill-buffer buffer-A)
1661 (kill-buffer buffer-B)
1662 (kill-buffer buffer-C)
1663 (set-window-configuration windows)
1664 (message "Conflict resolution finished; you may save the buffer")))))
1665 (message "Please resolve conflicts now; exit ediff when done")
1666 nil))))
1667
2f119435 1668;; The VC directory major mode. Coopt Dired for this.
e1f297e6
ER
1669;; All VC commands get mapped into logical equivalents.
1670
beba4bd9
AS
1671(defvar vc-dired-switches)
1672(defvar vc-dired-terse-mode)
1673
2f119435 1674(define-derived-mode vc-dired-mode dired-mode "Dired under VC"
3d30b8bc
RS
1675 "The major mode used in VC directory buffers. It works like Dired,
1676but lists only files under version control, with the current VC state of
1677each file being indicated in the place of the file's link count, owner,
1678group and size. Subdirectories are also listed, and you may insert them
1679into the buffer as desired, like in Dired.
1680 All Dired commands operate normally, with the exception of `v', which
1681is redefined as the version control prefix, so that you can type
1682`vl', `v=' etc. to invoke `vc-print-log', `vc-diff', and the like on
1683the file named in the current Dired buffer line. `vv' invokes
1684`vc-next-action' on this file, or on all files currently marked.
1685There is a special command, `*l', to mark all files currently locked."
421f0bfe
AS
1686 (make-local-hook 'dired-after-readin-hook)
1687 (add-hook 'dired-after-readin-hook 'vc-dired-hook nil t)
edcb979f
AS
1688 ;; The following is slightly modified from dired.el,
1689 ;; because file lines look a bit different in vc-dired-mode.
1690 (set (make-local-variable 'dired-move-to-filename-regexp)
1691 (let*
1692 ((l "\\([A-Za-z]\\|[^\0-\177]\\)")
1693 ;; In some locales, month abbreviations are as short as 2 letters,
1694 ;; and they can be padded on the right with spaces.
1695 (month (concat l l "+ *"))
1696 ;; Recognize any non-ASCII character.
1697 ;; The purpose is to match a Kanji character.
1698 (k "[^\0-\177]")
1699 ;; (k "[^\x00-\x7f\x80-\xff]")
1700 (s " ")
1701 (yyyy "[0-9][0-9][0-9][0-9]")
1702 (mm "[ 0-1][0-9]")
1703 (dd "[ 0-3][0-9]")
1704 (HH:MM "[ 0-2][0-9]:[0-5][0-9]")
1705 (western (concat "\\(" month s dd "\\|" dd s month "\\)"
61d6c25d 1706 s "\\(" HH:MM "\\|" s yyyy"\\|" yyyy s "\\)"))
edcb979f 1707 (japanese (concat mm k s dd k s "\\(" s HH:MM "\\|" yyyy k "\\)")))
fdc3f606 1708 (concat s "\\(" western "\\|" japanese "\\)" s)))
a0019b45
AS
1709 (and (boundp 'vc-dired-switches)
1710 vc-dired-switches
1711 (set (make-local-variable 'dired-actual-switches)
1712 vc-dired-switches))
3b574573 1713 (set (make-local-variable 'vc-dired-terse-mode) vc-dired-terse-display)
2f119435
AS
1714 (setq vc-dired-mode t))
1715
1716(define-key vc-dired-mode-map "\C-xv" vc-prefix-map)
3d30b8bc 1717(define-key vc-dired-mode-map "v" vc-prefix-map)
3b574573
AS
1718
1719(defun vc-dired-toggle-terse-mode ()
1720 "Toggle terse display in VC Dired."
1721 (interactive)
1722 (if (not vc-dired-mode)
1723 nil
1724 (setq vc-dired-terse-mode (not vc-dired-terse-mode))
1725 (if vc-dired-terse-mode
1726 (vc-dired-hook)
1727 (revert-buffer))))
1728
1729(define-key vc-dired-mode-map "vt" 'vc-dired-toggle-terse-mode)
594722a8 1730
3d30b8bc
RS
1731(defun vc-dired-mark-locked ()
1732 "Mark all files currently locked."
1733 (interactive)
1734 (dired-mark-if (let ((f (dired-get-filename nil t)))
1735 (and f
1736 (not (file-directory-p f))
1737 (vc-locking-user f)))
1738 "locked file"))
1739
1740(define-key vc-dired-mode-map "*l" 'vc-dired-mark-locked)
1741
1742(defun vc-fetch-cvs-status (dir)
1743 (let ((default-directory dir))
eccceb78
AS
1744 ;; Don't specify DIR in this command, the default-directory is
1745 ;; enough. Otherwise it might fail with remote repositories.
2b4603f4 1746 (vc-do-command "*vc-info*" 0 "cvs" nil nil "status" "-l")
3d30b8bc
RS
1747 (save-excursion
1748 (set-buffer (get-buffer "*vc-info*"))
1749 (goto-char (point-min))
1750 (while (re-search-forward "^=+\n\\([^=\n].*\n\\|\n\\)+" nil t)
1751 (narrow-to-region (match-beginning 0) (match-end 0))
1752 (vc-parse-cvs-status)
1753 (goto-char (point-max))
1754 (widen)))))
1755
b0c9bc8c
AS
1756(defun vc-dired-state-info (file)
1757 ;; Return the string that indicates the version control status
1758 ;; on a VC dired line.
3d30b8bc
RS
1759 (let* ((cvs-state (and (eq (vc-backend file) 'CVS)
1760 (vc-cvs-status file)))
1761 (state
1762 (if cvs-state
1763 (cond ((eq cvs-state 'up-to-date) nil)
1764 ((eq cvs-state 'needs-checkout) "patch")
1765 ((eq cvs-state 'locally-modified) "modified")
1766 ((eq cvs-state 'needs-merge) "merge")
1767 ((eq cvs-state 'unresolved-conflict) "conflict")
1768 ((eq cvs-state 'locally-added) "added"))
1769 (vc-locking-user file))))
1770 (if state (concat "(" state ")"))))
b0c9bc8c 1771
8c0aaf40 1772(defun vc-dired-reformat-line (x)
edcb979f
AS
1773 ;; Reformat a directory-listing line, replacing various columns with
1774 ;; version control information.
8c0aaf40 1775 ;; This code, like dired, assumes UNIX -l format.
3d30b8bc 1776 (beginning-of-line)
edcb979f 1777 (let ((pos (point)) limit perm date-and-file)
2f119435
AS
1778 (end-of-line)
1779 (setq limit (point))
1780 (goto-char pos)
edcb979f
AS
1781 (when
1782 (or
1783 (re-search-forward ;; owner and group
1784 "^\\(..[drwxlts-]+ \\) *[0-9]+ [^ ]+ +[^ ]+ +[0-9]+\\( .*\\)"
1785 limit t)
1786 (re-search-forward ;; only owner displayed
1787 "^\\(..[drwxlts-]+ \\) *[0-9]+ [^ ]+ +[0-9]+\\( .*\\)"
1788 limit t)
1789 (re-search-forward ;; OS/2 -l format, no links, owner, group
1790 "^\\(..[drwxlts-]+ \\) *[0-9]+\\( .*\\)"
1791 limit t))
2f119435 1792 (setq perm (match-string 1)
edcb979f
AS
1793 date-and-file (match-string 2))
1794 (setq x (substring (concat x " ") 0 10))
1795 (replace-match (concat perm x date-and-file)))))
3d30b8bc
RS
1796
1797(defun vc-dired-hook ()
1798 ;; Called by dired after any portion of a vc-dired buffer has been read in.
1799 ;; Reformat the listing according to version control.
1800 (message "Getting version information... ")
eccceb78 1801 (let (subdir filename (buffer-read-only nil) cvs-dir)
3d30b8bc
RS
1802 (goto-char (point-min))
1803 (while (not (eq (point) (point-max)))
1804 (cond
1805 ;; subdir header line
1806 ((setq subdir (dired-get-subdir))
1807 (if (file-directory-p (concat subdir "/CVS"))
eccceb78
AS
1808 (progn
1809 (vc-fetch-cvs-status (file-name-as-directory subdir))
1810 (setq cvs-dir t))
1811 (setq cvs-dir nil))
3d30b8bc
RS
1812 (forward-line 1)
1813 ;; erase (but don't remove) the "total" line
1814 (let ((start (point)))
1815 (end-of-line)
1816 (delete-region start (point))
1817 (beginning-of-line)
1818 (forward-line 1)))
3b574573 1819 ;; directory entry
3d30b8bc
RS
1820 ((setq filename (dired-get-filename nil t))
1821 (cond
3b574573 1822 ;; subdir
3d30b8bc 1823 ((file-directory-p filename)
3b574573
AS
1824 (cond
1825 ((member (file-name-nondirectory filename)
1826 vc-directory-exclusion-list)
1827 (let ((pos (point)))
1828 (dired-kill-tree filename)
1829 (goto-char pos)
1830 (dired-kill-line)))
1831 (vc-dired-terse-mode
633cee46
AS
1832 ;; Don't show directories in terse mode. Don't use
1833 ;; dired-kill-line to remove it, because in recursive listings,
1834 ;; that would remove the directory contents as well.
1835 (delete-region (progn (beginning-of-line) (point))
1836 (progn (forward-line 1) (point))))
3b574573
AS
1837 ((string-match "\\`\\.\\.?\\'" (file-name-nondirectory filename))
1838 (dired-kill-line))
1839 (t
3d30b8bc 1840 (vc-dired-reformat-line nil)
3b574573
AS
1841 (forward-line 1))))
1842 ;; ordinary file
1843 ((if cvs-dir
1844 (and (eq (vc-file-getprop filename 'vc-backend) 'CVS)
1845 (or (not vc-dired-terse-mode)
1846 (not (eq (vc-cvs-status filename) 'up-to-date))))
1847 (and (vc-backend filename)
1848 (or (not vc-dired-terse-mode)
1849 (vc-locking-user filename))))
3d30b8bc
RS
1850 (vc-dired-reformat-line (vc-dired-state-info filename))
1851 (forward-line 1))
1852 (t
1853 (dired-kill-line))))
1854 ;; any other line
3b574573
AS
1855 (t (forward-line 1))))
1856 (vc-dired-purge))
1857 (message "Getting version information... done")
1858 (save-restriction
1859 (widen)
633cee46
AS
1860 (cond ((eq (count-lines (point-min) (point-max)) 1)
1861 (goto-char (point-min))
1862 (message "No files locked under %s" default-directory)))))
3b574573
AS
1863
1864(defun vc-dired-purge ()
1865 ;; Remove empty subdirs
1866 (let (subdir)
1867 (goto-char (point-min))
1868 (while (setq subdir (dired-get-subdir))
1869 (forward-line 2)
1870 (if (dired-get-filename nil t)
1871 (if (not (dired-next-subdir 1 t))
1872 (goto-char (point-max)))
1873 (forward-line -2)
1874 (if (not (string= (dired-current-directory) default-directory))
1875 (dired-do-kill-lines t "")
633cee46
AS
1876 ;; We cannot remove the top level directory.
1877 ;; Just make it look a little nicer.
1878 (forward-line 1)
1879 (kill-line)
3b574573
AS
1880 (if (not (dired-next-subdir 1 t))
1881 (goto-char (point-max))))))
1882 (goto-char (point-min))))
2f119435 1883
637a8ae9 1884;;;###autoload
3d30b8bc 1885(defun vc-directory (dirname read-switches)
2f119435 1886 (interactive "DDired under VC (directory): \nP")
3b574573
AS
1887 (let ((vc-dired-switches (concat dired-listing-switches
1888 (if vc-dired-recurse "R" ""))))
1889 (if read-switches
1890 (setq vc-dired-switches
1891 (read-string "Dired listing switches: "
1892 vc-dired-switches)))
3d30b8bc
RS
1893 (require 'dired)
1894 (require 'dired-aux)
1895 ;; force a trailing slash
1896 (if (not (eq (elt dirname (1- (length dirname))) ?/))
1897 (setq dirname (concat dirname "/")))
1898 (switch-to-buffer
1899 (dired-internal-noselect (expand-file-name dirname)
a0019b45 1900 (or vc-dired-switches dired-listing-switches)
3d30b8bc 1901 'vc-dired-mode))))
e70bdc98 1902
594722a8
ER
1903;; Named-configuration support for SCCS
1904
1905(defun vc-add-triple (name file rev)
1906 (save-excursion
993a1a44
RS
1907 (find-file (expand-file-name
1908 vc-name-assoc-file
a0b87bc1 1909 (file-name-directory (vc-name file))))
594722a8
ER
1910 (goto-char (point-max))
1911 (insert name "\t:\t" file "\t" rev "\n")
1912 (basic-save-buffer)
1913 (kill-buffer (current-buffer))
1914 ))
1915
1916(defun vc-record-rename (file newname)
1917 (save-excursion
993a1a44
RS
1918 (find-file
1919 (expand-file-name
1920 vc-name-assoc-file
a0b87bc1 1921 (file-name-directory (vc-name file))))
594722a8 1922 (goto-char (point-min))
7d847440
RS
1923 ;; (replace-regexp (concat ":" (regexp-quote file) "$") (concat ":" newname))
1924 (while (re-search-forward (concat ":" (regexp-quote file) "$") nil t)
1925 (replace-match (concat ":" newname) nil nil))
594722a8
ER
1926 (basic-save-buffer)
1927 (kill-buffer (current-buffer))
1928 ))
1929
1930(defun vc-lookup-triple (file name)
7b4f934d
ER
1931 ;; Return the numeric version corresponding to a named snapshot of file
1932 ;; If name is nil or a version number string it's just passed through
47ca02a6 1933 (cond ((null name) name)
7b4f934d
ER
1934 ((let ((firstchar (aref name 0)))
1935 (and (>= firstchar ?0) (<= firstchar ?9)))
1936 name)
1937 (t
b7011339
RS
1938 (save-excursion
1939 (set-buffer (get-buffer-create "*vc-info*"))
993a1a44
RS
1940 (vc-insert-file
1941 (expand-file-name
1942 vc-name-assoc-file
a0b87bc1 1943 (file-name-directory (vc-name file))))
b7011339
RS
1944 (prog1
1945 (car (vc-parse-buffer
1946 (list (list (concat name "\t:\t" file "\t\\(.+\\)") 1))))
1947 (kill-buffer "*vc-info*"))))
1948 ))
594722a8
ER
1949
1950;; Named-configuration entry points
1951
503b5c85
RS
1952(defun vc-snapshot-precondition ()
1953 ;; Scan the tree below the current directory.
1954 ;; If any files are locked, return the name of the first such file.
1955 ;; (This means, neither snapshot creation nor retrieval is allowed.)
1956 ;; If one or more of the files are currently visited, return `visited'.
1957 ;; Otherwise, return nil.
1958 (let ((status nil))
1959 (catch 'vc-locked-example
1960 (vc-file-tree-walk
2f119435 1961 default-directory
503b5c85
RS
1962 (function (lambda (f)
1963 (and (vc-registered f)
1964 (if (vc-locking-user f) (throw 'vc-locked-example f)
1965 (if (get-file-buffer f) (setq status 'visited)))))))
1966 status)))
594722a8 1967
637a8ae9 1968;;;###autoload
594722a8
ER
1969(defun vc-create-snapshot (name)
1970 "Make a snapshot called NAME.
1971The snapshot is made from all registered files at or below the current
1972directory. For each file, the version level of its latest
1973version becomes part of the named configuration."
1974 (interactive "sNew snapshot name: ")
503b5c85
RS
1975 (let ((result (vc-snapshot-precondition)))
1976 (if (stringp result)
1977 (error "File %s is locked" result)
1dabb4e6 1978 (vc-file-tree-walk
2f119435 1979 default-directory
1dabb4e6
PE
1980 (function (lambda (f) (and
1981 (vc-name f)
1982 (vc-backend-assign-name f name)))))
1983 )))
594722a8 1984
637a8ae9 1985;;;###autoload
594722a8 1986(defun vc-retrieve-snapshot (name)
d5859f32
AS
1987 "Retrieve the snapshot called NAME, or latest versions if NAME is empty.
1988When retrieving a snapshot, there must not be any locked files at or below
1989the current directory. If none are locked, all registered files are
1990checked out (unlocked) at their version levels in the snapshot NAME.
1991If NAME is the empty string, all registered files that are not currently
1992locked are updated to the latest versions."
1993 (interactive "sSnapshot name to retrieve (default latest versions): ")
1994 (let ((update (yes-or-no-p "Update any affected buffers? ")))
1995 (if (string= name "")
1996 (progn
1997 (vc-file-tree-walk
1998 default-directory
1999 (function (lambda (f) (and
2000 (vc-registered f)
2001 (not (vc-locking-user f))
2002 (vc-error-occurred
2003 (vc-backend-checkout f nil "")
2004 (if update (vc-resynch-buffer f t t))))))))
2005 (let ((result (vc-snapshot-precondition)))
2006 (if (stringp result)
2007 (error "File %s is locked" result)
2008 (setq update (and (eq result 'visited) update))
2009 (vc-file-tree-walk
2010 default-directory
2011 (function (lambda (f) (and
2012 (vc-name f)
2013 (vc-error-occurred
2014 (vc-backend-checkout f nil name)
2015 (if update (vc-resynch-buffer f t t)))))))
2016 )))))
594722a8
ER
2017
2018;; Miscellaneous other entry points
2019
637a8ae9 2020;;;###autoload
594722a8
ER
2021(defun vc-print-log ()
2022 "List the change log of the current buffer in a window."
2023 (interactive)
b6909007
AS
2024 (vc-ensure-vc-buffer)
2025 (let ((file buffer-file-name))
2026 (vc-backend-print-log file)
2027 (pop-to-buffer (get-buffer-create "*vc*"))
2028 (setq default-directory (file-name-directory file))
2029 (goto-char (point-max)) (forward-line -1)
2030 (while (looking-at "=*\n")
2031 (delete-char (- (match-end 0) (match-beginning 0)))
2032 (forward-line -1))
2033 (goto-char (point-min))
2034 (if (looking-at "[\b\t\n\v\f\r ]+")
2035 (delete-char (- (match-end 0) (match-beginning 0))))
2036 (shrink-window-if-larger-than-buffer)
2037 ;; move point to the log entry for the current version
2038 (and (not (eq (vc-backend file) 'SCCS))
2039 (re-search-forward
2040 ;; also match some context, for safety
2041 (concat "----\nrevision " (vc-workfile-version file)
2042 "\\(\tlocked by:.*\n\\|\n\\)date: ") nil t)
2043 ;; set the display window so that
2044 ;; the whole log entry is displayed
2045 (let (start end lines)
2046 (beginning-of-line) (forward-line -1) (setq start (point))
2047 (if (not (re-search-forward "^----*\nrevision" nil t))
2048 (setq end (point-max))
2049 (beginning-of-line) (forward-line -1) (setq end (point)))
2050 (setq lines (count-lines start end))
2051 (cond
2052 ;; if the global information and this log entry fit
2053 ;; into the window, display from the beginning
2054 ((< (count-lines (point-min) end) (window-height))
2055 (goto-char (point-min))
2056 (recenter 0)
2057 (goto-char start))
2058 ;; if the whole entry fits into the window,
2059 ;; display it centered
2060 ((< (1+ lines) (window-height))
2061 (goto-char start)
2062 (recenter (1- (- (/ (window-height) 2) (/ lines 2)))))
2063 ;; otherwise (the entry is too large for the window),
2064 ;; display from the start
2065 (t
2066 (goto-char start)
2067 (recenter 0)))))))
594722a8 2068
637a8ae9 2069;;;###autoload
594722a8 2070(defun vc-revert-buffer ()
18483cf0 2071 "Revert the current buffer's file back to the version it was based on.
9c95ac44 2072This asks for confirmation if the buffer contents are not identical
18483cf0
AS
2073to that version. Note that for RCS and CVS, this function does not
2074automatically pick up newer changes found in the master file;
2075use C-u \\[vc-next-action] RET to do so."
594722a8 2076 (interactive)
b6909007 2077 (vc-ensure-vc-buffer)
594722a8 2078 (let ((file buffer-file-name)
221cc4f4
RS
2079 ;; This operation should always ask for confirmation.
2080 (vc-suppress-confirm nil)
97d3f950 2081 (obuf (current-buffer)) (changed (vc-diff nil t)))
751fa747
AS
2082 (if changed
2083 (unwind-protect
2084 (if (not (yes-or-no-p "Discard changes? "))
2085 (error "Revert cancelled"))
fab2e906
RS
2086 (if (and (window-dedicated-p (selected-window))
2087 (one-window-p t 'selected-frame))
2088 (make-frame-invisible (selected-frame))
751fa747
AS
2089 (delete-window))))
2090 (set-buffer obuf)
594722a8 2091 (vc-backend-revert file)
751fa747 2092 (vc-resynch-window file t t)))
594722a8 2093
637a8ae9 2094;;;###autoload
594722a8 2095(defun vc-cancel-version (norevert)
34291cd2
RS
2096 "Get rid of most recently checked in version of this file.
2097A prefix argument means do not revert the buffer afterwards."
594722a8 2098 (interactive "P")
b6909007 2099 (vc-ensure-vc-buffer)
c8de1d91 2100 (cond
1694bd16 2101 ((eq (vc-backend (buffer-file-name)) 'CVS)
c8de1d91
AS
2102 (error "Unchecking files under CVS is dangerous and not supported in VC"))
2103 ((vc-locking-user (buffer-file-name))
2c28ac43 2104 (error "This version is locked; use vc-revert-buffer to discard changes"))
c8de1d91 2105 ((not (vc-latest-on-branch-p (buffer-file-name)))
2c28ac43 2106 (error "This is not the latest version--VC cannot cancel it")))
7e48e092
AS
2107 (let* ((target (vc-workfile-version (buffer-file-name)))
2108 (recent (if (vc-trunk-p target) "" (vc-branch-part target)))
2109 (config (current-window-configuration)) done)
2110 (if (null (yes-or-no-p (format "Remove version %s from master? " target)))
7b4f934d 2111 nil
c8de1d91
AS
2112 (setq norevert (or norevert (not
2113 (yes-or-no-p "Revert buffer to most recent remaining version? "))))
7b4f934d 2114 (vc-backend-uncheck (buffer-file-name) target)
7e48e092
AS
2115 ;; Check out the most recent remaining version. If it fails, because
2116 ;; the whole branch got deleted, do a double-take and check out the
2117 ;; version where the branch started.
2118 (while (not done)
2119 (condition-case err
2120 (progn
2121 (if norevert
2122 ;; Check out locked, but only to disc, and keep
2123 ;; modifications in the buffer.
2124 (vc-backend-checkout (buffer-file-name) t recent)
2125 ;; Check out unlocked, and revert buffer.
2126 (vc-checkout (buffer-file-name) nil recent))
2127 (setq done t))
ae2506d0
AS
2128 ;; If the checkout fails, vc-do-command signals an error.
2129 ;; We catch this error, check the reason, correct the
2130 ;; version number, and try a second time.
7e48e092
AS
2131 (error (set-buffer "*vc*")
2132 (goto-char (point-min))
ae2506d0 2133 (if (search-forward "no side branches present for" nil t)
7e48e092 2134 (progn (setq recent (vc-branch-part recent))
ae2506d0
AS
2135 ;; vc-do-command popped up a window with
2136 ;; the error message. Get rid of it, by
2137 ;; restoring the old window configuration.
7e48e092
AS
2138 (set-window-configuration config))
2139 ;; No, it was some other error: re-signal it.
2140 (signal (car err) (cdr err))))))
2141 ;; If norevert, clear version headers and mark the buffer modified.
2142 (if norevert
2143 (progn
2144 (set-visited-file-name (buffer-file-name))
2145 (if (not vc-make-backup-files)
2146 ;; inhibit backup for this buffer
2147 (progn (make-local-variable 'backup-inhibited)
2148 (setq backup-inhibited t)))
2149 (if (eq (vc-backend (buffer-file-name)) 'RCS)
2150 (progn (setq buffer-read-only nil)
2151 (vc-clear-headers)))
2152 (vc-mode-line (buffer-file-name))))
2153 (message "Version %s has been removed from the master" target)
c8de1d91 2154 )))
594722a8 2155
29fc1ce9 2156;;;###autoload
594722a8 2157(defun vc-rename-file (old new)
34291cd2
RS
2158 "Rename file OLD to NEW, and rename its master file likewise."
2159 (interactive "fVC rename file: \nFRename to: ")
80688f5c
RS
2160 ;; There are several ways of renaming files under CVS 1.3, but they all
2161 ;; have serious disadvantages. See the FAQ (available from think.com in
2162 ;; pub/cvs/). I'd rather send the user an error, than do something he might
2163 ;; consider to be wrong. When the famous, long-awaited rename database is
2164 ;; implemented things might change for the better. This is unlikely to occur
2165 ;; until CVS 2.0 is released. --ceder 1994-01-23 21:27:51
f3c61d82 2166 (if (eq (vc-backend old) 'CVS)
2c28ac43 2167 (error "Renaming files under CVS is dangerous and not supported in VC"))
594722a8 2168 (let ((oldbuf (get-file-buffer old)))
d52f0de9 2169 (if (and oldbuf (buffer-modified-p oldbuf))
590cc449 2170 (error "Please save files before moving them"))
594722a8 2171 (if (get-file-buffer new)
590cc449 2172 (error "Already editing new file name"))
d52f0de9
RS
2173 (if (file-exists-p new)
2174 (error "New file already exists"))
a0b87bc1 2175 (let ((oldmaster (vc-name old)) newmaster)
594722a8 2176 (if oldmaster
d52f0de9
RS
2177 (progn
2178 (if (vc-locking-user old)
2179 (error "Please check in files before moving them"))
2180 (if (or (file-symlink-p oldmaster)
2181 ;; This had FILE, I changed it to OLD. -- rms.
2182 (file-symlink-p (vc-backend-subdirectory-name old)))
2183 (error "This is not a safe thing to do in the presence of symbolic links"))
a0b87bc1
AS
2184 (setq newmaster
2185 (let ((backend (vc-backend old))
2186 (newdir (or (file-name-directory new) ""))
2187 (newbase (file-name-nondirectory new)))
2188 (catch 'found
2189 (mapcar
2190 (function
2191 (lambda (s)
2192 (if (eq backend (cdr s))
2193 (let* ((newmaster (format (car s) newdir newbase))
2194 (newmasterdir (file-name-directory newmaster)))
2195 (if (or (not newmasterdir)
2196 (file-directory-p newmasterdir))
2197 (throw 'found newmaster))))))
2198 vc-master-templates)
2199 (error "New file lacks a version control directory"))))
2200 ;; Handle the SCCS PROJECTDIR feature. It is odd that this
2201 ;; is a special case, but a more elegant solution would require
2202 ;; significant changes in other parts of VC.
2203 (if (eq (vc-backend old) 'SCCS)
2204 (let ((project-dir (vc-sccs-project-dir)))
2205 (if project-dir
2206 (setq newmaster
2207 (concat project-dir
2208 (file-name-nondirectory newmaster))))))
2209 (rename-file oldmaster newmaster)))
594722a8
ER
2210 (if (or (not oldmaster) (file-exists-p old))
2211 (rename-file old new)))
2212; ?? Renaming a file might change its contents due to keyword expansion.
2213; We should really check out a new copy if the old copy was precisely equal
2214; to some checked in version. However, testing for this is tricky....
2215 (if oldbuf
2216 (save-excursion
2217 (set-buffer oldbuf)
4c145b9e
RS
2218 (let ((buffer-read-only buffer-read-only))
2219 (set-visited-file-name new))
2220 (vc-backend new)
2221 (vc-mode-line new)
594722a8 2222 (set-buffer-modified-p nil))))
60213ed0
RS
2223 ;; This had FILE, I changed it to OLD. -- rms.
2224 (vc-backend-dispatch old
80688f5c
RS
2225 (vc-record-rename old new) ;SCCS
2226 nil ;RCS
2227 nil ;CVS
2228 )
594722a8
ER
2229 )
2230
637a8ae9 2231;;;###autoload
f35ecf88 2232(defun vc-update-change-log (&rest args)
73a9679c 2233 "Find change log file and add entries from recent RCS/CVS logs.
d68e6990
RS
2234Normally, find log entries for all registered files in the default
2235directory using `rcs2log', which finds CVS logs preferentially.
f35ecf88 2236The mark is left at the end of the text prepended to the change log.
d68e6990 2237
f35ecf88 2238With prefix arg of C-u, only find log entries for the current buffer's file.
d68e6990
RS
2239
2240With any numeric prefix arg, find log entries for all currently visited
2241files that are under version control. This puts all the entries in the
2242log for the default directory, which may not be appropriate.
2243
73a9679c
RS
2244From a program, any arguments are assumed to be filenames and are
2245passed to the `rcs2log' script after massaging to be relative to the
2246default directory."
67242a23
RM
2247 (interactive
2248 (cond ((consp current-prefix-arg) ;C-u
2249 (list buffer-file-name))
2250 (current-prefix-arg ;Numeric argument.
2251 (let ((files nil)
2252 (buffers (buffer-list))
2253 file)
2254 (while buffers
2255 (setq file (buffer-file-name (car buffers)))
f3c61d82 2256 (and file (vc-backend file)
4b40fdea 2257 (setq files (cons file files)))
67242a23 2258 (setq buffers (cdr buffers)))
4b40fdea
PE
2259 files))
2260 (t
73a9679c
RS
2261 ;; `rcs2log' will find the relevant RCS or CVS files
2262 ;; relative to the curent directory if none supplied.
2263 nil)))
449decf5 2264 (let ((odefault default-directory)
124c852b
RS
2265 (changelog (find-change-log))
2266 ;; Presumably not portable to non-Unixy systems, along with rcs2log:
767d12f2 2267 (tempfile (make-temp-file
57c298c4
EZ
2268 (expand-file-name "vc"
2269 (or small-temporary-file-directory
2270 temporary-file-directory))))
b91916f3 2271 (full-name (or add-log-full-name
8172cd86
AS
2272 (user-full-name)
2273 (user-login-name)
2274 (format "uid%d" (number-to-string (user-uid)))))
b91916f3
RS
2275 (mailing-address (or add-log-mailing-address
2276 user-mail-address)))
124c852b 2277 (find-file-other-window changelog)
41dfb835
RS
2278 (barf-if-buffer-read-only)
2279 (vc-buffer-sync)
2280 (undo-boundary)
2281 (goto-char (point-min))
2282 (push-mark)
2283 (message "Computing change log entries...")
4b40fdea 2284 (message "Computing change log entries... %s"
124c852b
RS
2285 (unwind-protect
2286 (progn
2287 (cd odefault)
fb29efe9
GM
2288 (if (eq 0 (apply 'call-process
2289 (expand-file-name "rcs2log" exec-directory)
2290 nil
2291 (list t tempfile) nil
2292 "-c" changelog
2293 "-u" (concat (vc-user-login-name)
2294 "\t" full-name
2295 "\t" mailing-address)
2296 (mapcar
2297 (function
2298 (lambda (f)
2299 (file-relative-name
2300 (if (file-name-absolute-p f)
2301 f
2302 (concat odefault f)))))
2303 args)))
2304 "done"
124c852b
RS
2305 (pop-to-buffer
2306 (set-buffer (get-buffer-create "*vc*")))
2307 (erase-buffer)
2308 (insert-file tempfile)
2309 "failed"))
2310 (cd (file-name-directory changelog))
2311 (delete-file tempfile)))))
7d2d9482
RS
2312\f
2313;; vc-annotate functionality (CVS only).
f80f7bc2 2314(defvar vc-annotate-mode-map nil
7d2d9482
RS
2315 "Local keymap used for VC-Annotate mode.")
2316
f80f7bc2
RS
2317(defvar vc-annotate-mode-menu nil
2318 "Local keymap used for VC-Annotate mode's menu bar menu.")
2319
7d2d9482
RS
2320;; Syntax Table
2321(defvar vc-annotate-mode-syntax-table nil
2322 "Syntax table used in VC-Annotate mode buffers.")
2323
f80f7bc2
RS
2324;; Declare globally instead of additional parameter to
2325;; temp-buffer-show-function (not possible to pass more than one
2326;; parameter).
2327(defvar vc-annotate-ratio nil)
2328
7d2d9482
RS
2329(defun vc-annotate-mode-variables ()
2330 (if (not vc-annotate-mode-syntax-table)
2331 (progn (setq vc-annotate-mode-syntax-table (make-syntax-table))
2332 (set-syntax-table vc-annotate-mode-syntax-table)))
2333 (if (not vc-annotate-mode-map)
f80f7bc2
RS
2334 (setq vc-annotate-mode-map (make-sparse-keymap)))
2335 (setq vc-annotate-mode-menu (make-sparse-keymap "Annotate"))
2336 (define-key vc-annotate-mode-map [menu-bar]
2337 (make-sparse-keymap "VC-Annotate"))
2338 (define-key vc-annotate-mode-map [menu-bar vc-annotate-mode]
2339 (cons "VC-Annotate" vc-annotate-mode-menu)))
7d2d9482
RS
2340
2341(defun vc-annotate-mode ()
2342 "Major mode for buffers displaying output from the CVS `annotate' command.
2343
2344You can use the mode-specific menu to alter the time-span of the used
2345colors. See variable `vc-annotate-menu-elements' for customizing the
2346menu items."
2347 (interactive)
2348 (kill-all-local-variables) ; Recommended by RMS.
2349 (vc-annotate-mode-variables) ; This defines various variables.
2350 (use-local-map vc-annotate-mode-map) ; This provides the local keymap.
2351 (set-syntax-table vc-annotate-mode-syntax-table)
2352 (setq major-mode 'vc-annotate-mode) ; This is how `describe-mode'
2353 ; finds out what to describe.
2354 (setq mode-name "Annotate") ; This goes into the mode line.
2355 (run-hooks 'vc-annotate-mode-hook)
2356 (vc-annotate-add-menu))
2357
2358(defun vc-annotate-display-default (&optional event)
2359 "Use the default color spectrum for VC Annotate mode."
2360 (interactive)
f80f7bc2
RS
2361 (message "Redisplaying annotation...")
2362 (vc-annotate-display (get-buffer (buffer-name)))
2363 (message "Redisplaying annotation...done"))
7d2d9482
RS
2364
2365(defun vc-annotate-add-menu ()
2366 "Adds the menu 'Annotate' to the menu bar in VC-Annotate mode."
7d2d9482
RS
2367 (define-key vc-annotate-mode-menu [default]
2368 '("Default" . vc-annotate-display-default))
2369 (let ((menu-elements vc-annotate-menu-elements))
2370 (while menu-elements
2371 (let* ((element (car menu-elements))
2372 (days (round (* element
2373 (vc-annotate-car-last-cons vc-annotate-color-map)
2374 0.7585))))
2375 (setq menu-elements (cdr menu-elements))
2376 (define-key vc-annotate-mode-menu
2377 (vector days)
2378 (cons (format "Span %d days"
2379 days)
2380 `(lambda ()
2381 ,(format "Use colors spanning %d days" days)
f80f7bc2
RS
2382 (interactive)
2383 (message "Redisplaying annotation...")
2384 (vc-annotate-display
2385 (get-buffer (buffer-name))
2386 (vc-annotate-time-span vc-annotate-color-map ,element))
2387 (message "Redisplaying annotation...done"))))))))
594722a8 2388
7d2d9482
RS
2389;;;###autoload
2390(defun vc-annotate (ratio)
2391 "Display the result of the CVS `annotate' command using colors.
2392New lines are displayed in red, old in blue.
2393A prefix argument specifies a factor for stretching the time scale.
2394
2395`vc-annotate-menu-elements' customizes the menu elements of the
2396mode-specific menu. `vc-annotate-color-map' and
2397`vc-annotate-very-old-color' defines the mapping of time to
2398colors. `vc-annotate-background' specifies the background color."
2399 (interactive "p")
b6909007
AS
2400 (vc-ensure-vc-buffer)
2401 (if (not (eq (vc-backend (buffer-file-name)) 'CVS))
2402 (error "Sorry, vc-annotate is only implemented for CVS"))
7d2d9482
RS
2403 (message "Annotating...")
2404 (let ((temp-buffer-name (concat "*cvs annotate " (buffer-name) "*"))
2405 (temp-buffer-show-function 'vc-annotate-display)
2406 (vc-annotate-ratio ratio))
2407 (with-output-to-temp-buffer temp-buffer-name
2408 (call-process "cvs" nil (get-buffer temp-buffer-name) nil
2409 "annotate" (file-name-nondirectory (buffer-file-name)))))
2410 (message "Annotating... done"))
2411
f70419a8
RS
2412(defun vc-annotate-car-last-cons (a-list)
2413 "Return car of last cons in association list A-LIST."
2414 (if (not (eq nil (cdr a-list)))
2415 (vc-annotate-car-last-cons (cdr a-list))
2416 (car (car a-list))))
2417
2418(defun vc-annotate-time-span (a-list span &optional quantize)
2419"Return an association list with factor SPAN applied to the time-span
2420of association list A-LIST. Optionaly quantize to the factor of
2421QUANTIZE."
7d2d9482 2422 ;; Apply span to each car of every cons
f70419a8
RS
2423 (if (not (eq nil a-list))
2424 (append (list (cons (* (car (car a-list)) span)
2425 (cdr (car a-list))))
7d2d9482
RS
2426 (vc-annotate-time-span (nthcdr (cond (quantize) ; optional
2427 (1)) ; Default to cdr
f70419a8
RS
2428 a-list) span quantize))))
2429
2430(defun vc-annotate-compcar (threshold a-list)
2431 "Test successive cons cells of association list A-LIST against
2432THRESHOLD. Return the first cons cell which car is not less than
2433THRESHOLD, nil otherwise"
2434 (let ((i 1)
2435 (tmp-cons (car a-list)))
2436 (while (and tmp-cons (< (car tmp-cons) threshold))
2437 (setq tmp-cons (car (nthcdr i a-list)))
2438 (setq i (+ i 1)))
2439 tmp-cons)) ; Return the appropriate value
2440
7d2d9482
RS
2441
2442(defun vc-annotate-display (buffer &optional color-map)
2443 "Do the VC-Annotate display in BUFFER using COLOR-MAP."
2444
f80f7bc2
RS
2445 ;; Handle the case of the global variable vc-annotate-ratio being
2446 ;; set. This variable is used to pass information from function
2447 ;; vc-annotate since it is not possible to use another parameter
2448 ;; (see temp-buffer-show-function).
7d2d9482 2449 (if (and (not color-map) vc-annotate-ratio)
f80f7bc2
RS
2450 ;; This will only be true if called from vc-annotate with ratio
2451 ;; being non-nil.
2452 (setq color-map (vc-annotate-time-span vc-annotate-color-map
2453 vc-annotate-ratio)))
7d2d9482
RS
2454
2455 ;; We need a list of months and their corresponding numbers.
2456 (let* ((local-month-numbers
2457 '(("Jan" . 1) ("Feb" . 2) ("Mar" . 3) ("Apr" . 4)
2458 ("May" . 5) ("Jun" . 6) ("Jul" . 7) ("Aug" . 8)
f70419a8 2459 ("Sep" . 9) ("Oct" . 10) ("Nov" . 11) ("Dec" . 12))))
7d2d9482
RS
2460 (set-buffer buffer)
2461 (display-buffer buffer)
05dad1e6 2462 (or (eq major-mode 'vc-annotate-mode) ; Turn on vc-annotate-mode if not done
7d2d9482 2463 (vc-annotate-mode))
05dad1e6
AS
2464 ;; Delete old overlays
2465 (mapcar
2466 (lambda (overlay)
2467 (if (overlay-get overlay 'vc-annotation)
2468 (delete-overlay overlay)))
2469 (overlays-in (point-min) (point-max)))
7d2d9482 2470 (goto-char (point-min)) ; Position at the top of the buffer.
f70419a8
RS
2471 (while (re-search-forward
2472 "^\\S-+\\s-+\\S-+\\s-+\\([0-9]+\\)-\\(\\sw+\\)-\\([0-9]+\\)): "
2473;; "^[0-9]+\\(\.[0-9]+\\)*\\s-+(\\sw+\\s-+\\([0-9]+\\)-\\(\\sw+\\)-\\([0-9]+\\)): "
7d2d9482
RS
2474 nil t)
2475
2476 (let* (;; Unfortunately, order is important. match-string will
2477 ;; be corrupted by extent functions in XEmacs. Access
2478 ;; string-matches first.
f70419a8
RS
2479 (day (string-to-number (match-string 1)))
2480 (month (cdr (assoc (match-string 2) local-month-numbers)))
2481 (year-tmp (string-to-number (match-string 3)))
8f0ab358
RS
2482 ;; Years 0..68 are 2000..2068.
2483 ;; Years 69..99 are 1969..1999.
2484 (year (+ (cond ((> 69 year-tmp) 2000)
fc1d66a4
RS
2485 ((> 100 year-tmp) 1900)
2486 (t 0))
2487 year-tmp))
7d2d9482
RS
2488 (high (- (car (current-time))
2489 (car (encode-time 0 0 0 day month year))))
2490 (color (cond ((vc-annotate-compcar high (cond (color-map)
2491 (vc-annotate-color-map))))
2492 ((cons nil vc-annotate-very-old-color))))
2493 ;; substring from index 1 to remove any leading `#' in the name
2494 (face-name (concat "vc-annotate-face-" (substring (cdr color) 1)))
2495 ;; Make the face if not done.
2496 (face (cond ((intern-soft face-name))
f70419a8
RS
2497 ((let ((tmp-face (make-face (intern face-name))))
2498 (set-face-foreground tmp-face (cdr color))
2499 (if vc-annotate-background
2500 (set-face-background tmp-face vc-annotate-background))
2501 tmp-face)))) ; Return the face
05dad1e6
AS
2502 (point (point))
2503 overlay)
f70419a8
RS
2504
2505 (forward-line 1)
05dad1e6
AS
2506 (setq overlay (make-overlay point (point)))
2507 (overlay-put overlay 'face face)
2508 (overlay-put overlay 'vc-annotation t)))))
f70419a8 2509
7d2d9482 2510\f
c6d4f628 2511;; Collect back-end-dependent stuff here
594722a8 2512
594722a8
ER
2513(defun vc-backend-admin (file &optional rev comment)
2514 ;; Register a file into the version-control system
2515 ;; Automatically retrieves a read-only version of the file with
2516 ;; keywords expanded if vc-keep-workfiles is non-nil, otherwise
2517 ;; it deletes the workfile.
2518 (vc-file-clearprops file)
2519 (or vc-default-back-end
2520 (setq vc-default-back-end (if (vc-find-binary "rcs") 'RCS 'SCCS)))
2521 (message "Registering %s..." file)
a0b87bc1
AS
2522 (let* ((switches
2523 (if (stringp vc-register-switches)
2524 (list vc-register-switches)
2525 vc-register-switches))
2526 (project-dir)
2527 (backend
2528 (cond
2529 ((file-exists-p (vc-backend-subdirectory-name)) vc-default-back-end)
2530 ((file-exists-p "RCS") 'RCS)
2531 ((file-exists-p "CVS") 'CVS)
2532 ((file-exists-p "SCCS") 'SCCS)
2533 ((setq project-dir (vc-sccs-project-dir)) 'SCCS)
2534 (t vc-default-back-end))))
594722a8 2535 (cond ((eq backend 'SCCS)
a0b87bc1
AS
2536 (let ((vc-name
2537 (if project-dir (concat project-dir
2538 "s." (file-name-nondirectory file))
2539 (format
2540 (car (rassq 'SCCS vc-master-templates))
2541 (or (file-name-directory file) "")
2542 (file-name-nondirectory file)))))
2543 (apply 'vc-do-command nil 0 "admin" nil nil ;; SCCS
2544 (and rev (concat "-r" rev))
2545 "-fb"
2546 (concat "-i" file)
2547 (and comment (concat "-y" comment))
2548 vc-name
2549 switches))
594722a8
ER
2550 (delete-file file)
2551 (if vc-keep-workfiles
6aa13729 2552 (vc-do-command nil 0 "get" file 'MASTER)))
594722a8 2553 ((eq backend 'RCS)
a633d9af
RS
2554 (apply 'vc-do-command nil 0 "ci" file 'WORKFILE ;; RCS
2555 ;; if available, use the secure registering option
2556 (and (vc-backend-release-p 'RCS "5.6.4") "-i")
2557 (concat (if vc-keep-workfiles "-u" "-r") rev)
2558 (and comment (concat "-t-" comment))
2559 switches))
80688f5c 2560 ((eq backend 'CVS)
a633d9af
RS
2561 (apply 'vc-do-command nil 0 "cvs" file 'WORKFILE ;; CVS
2562 "add"
2563 (and comment (string-match "[^\t\n ]" comment)
2564 (concat "-m" comment))
2565 switches)
594722a8
ER
2566 )))
2567 (message "Registering %s...done" file)
2568 )
2569
f1818994 2570(defun vc-backend-checkout (file &optional writable rev workfile)
594722a8 2571 ;; Retrieve a copy of a saved version into a workfile
503b5c85
RS
2572 (let ((filename (or workfile file))
2573 (file-buffer (get-file-buffer file))
2c28ac43 2574 switches)
f1818994 2575 (message "Checking out %s..." filename)
f797cb30 2576 (save-excursion
2c28ac43 2577 ;; Change buffers to get local value of vc-checkout-switches.
503b5c85 2578 (if file-buffer (set-buffer file-buffer))
2c28ac43
RS
2579 (setq switches (if (stringp vc-checkout-switches)
2580 (list vc-checkout-switches)
2581 vc-checkout-switches))
f008ca58
KH
2582 ;; Save this buffer's default-directory
2583 ;; and use save-excursion to make sure it is restored
2584 ;; in the same buffer it was saved in.
2585 (let ((default-directory default-directory))
2586 (save-excursion
2587 ;; Adjust the default-directory so that the check-out creates
2588 ;; the file in the right place.
2589 (setq default-directory (file-name-directory filename))
2590 (vc-backend-dispatch file
2591 (progn ;; SCCS
2592 (and rev (string= rev "") (setq rev nil))
2593 (if workfile
2594 ;; Some SCCS implementations allow checking out directly to a
2595 ;; file using the -G option, but then some don't so use the
2596 ;; least common denominator approach and use the -p option
2597 ;; ala RCS.
2598 (let ((vc-modes (logior (file-modes (vc-name file))
2599 (if writable 128 0)))
2600 (failed t))
2601 (unwind-protect
2602 (progn
3b9dc2bc
AS
2603 (let ((coding-system-for-read 'no-conversion)
2604 (coding-system-for-write 'no-conversion))
2605 (with-temp-file filename
2606 (apply 'vc-do-command
2607 (current-buffer) 0 "get" file 'MASTER
2608 "-s" ;; suppress diagnostic output
2609 (if writable "-e")
2610 "-p"
2611 (and rev
2612 (concat "-r"
2613 (vc-lookup-triple file rev)))
2614 switches)))
d76a596e
AS
2615 (set-file-modes filename
2616 (logior (file-modes (vc-name file))
2617 (if writable 128 0)))
2618 (setq failed nil))
f008ca58
KH
2619 (and failed (file-exists-p filename)
2620 (delete-file filename))))
2621 (apply 'vc-do-command nil 0 "get" file 'MASTER ;; SCCS
2622 (if writable "-e")
2623 (and rev (concat "-r" (vc-lookup-triple file rev)))
2624 switches)
2625 (vc-file-setprop file 'vc-workfile-version nil)))
2626 (if workfile ;; RCS
2627 ;; RCS doesn't let us check out into arbitrary file names directly.
2628 ;; Use `co -p' and make stdout point to the correct file.
2629 (let ((vc-modes (logior (file-modes (vc-name file))
2630 (if writable 128 0)))
2631 (failed t))
2632 (unwind-protect
2633 (progn
3b9dc2bc
AS
2634 (let ((coding-system-for-read 'no-conversion)
2635 (coding-system-for-write 'no-conversion))
2636 (with-temp-file filename
2637 (apply 'vc-do-command
2638 (current-buffer) 0 "co" file 'MASTER
2639 "-q" ;; suppress diagnostic output
2640 (if writable "-l")
2641 (concat "-p" rev)
2642 switches)))
d76a596e
AS
2643 (set-file-modes filename
2644 (logior (file-modes (vc-name file))
2645 (if writable 128 0)))
2646 (setq failed nil))
f008ca58
KH
2647 (and failed (file-exists-p filename) (delete-file filename))))
2648 (let (new-version)
2649 ;; if we should go to the head of the trunk,
2650 ;; clear the default branch first
2651 (and rev (string= rev "")
2652 (vc-do-command nil 0 "rcs" file 'MASTER "-b"))
2653 ;; now do the checkout
2654 (apply 'vc-do-command
2655 nil 0 "co" file 'MASTER
2656 ;; If locking is not strict, force to overwrite
2657 ;; the writable workfile.
2658 (if (eq (vc-checkout-model file) 'implicit) "-f")
2659 (if writable "-l")
2660 (if rev (concat "-r" rev)
2661 ;; if no explicit revision was specified,
2662 ;; check out that of the working file
2663 (let ((workrev (vc-workfile-version file)))
2664 (if workrev (concat "-r" workrev)
2665 nil)))
2666 switches)
2667 ;; determine the new workfile version
2668 (save-excursion
2669 (set-buffer "*vc*")
2670 (goto-char (point-min))
2671 (setq new-version
2672 (if (re-search-forward "^revision \\([0-9.]+\\).*\n" nil t)
2673 (buffer-substring (match-beginning 1) (match-end 1)))))
2674 (vc-file-setprop file 'vc-workfile-version new-version)
2675 ;; if necessary, adjust the default branch
2676 (and rev (not (string= rev ""))
2677 (vc-do-command nil 0 "rcs" file 'MASTER
2678 (concat "-b" (if (vc-latest-on-branch-p file)
2679 (if (vc-trunk-p new-version) nil
2680 (vc-branch-part new-version))
2681 new-version))))))
2682 (if workfile ;; CVS
2683 ;; CVS is much like RCS
2684 (let ((failed t))
2685 (unwind-protect
2686 (progn
3b9dc2bc
AS
2687 (let ((coding-system-for-read 'no-conversion)
2688 (coding-system-for-write 'no-conversion))
2689 (with-temp-file filename
2690 (apply 'vc-do-command
2691 (current-buffer) 0 "cvs" file 'WORKFILE
2692 "-Q" ;; suppress diagnostic output
2693 "update"
2694 (concat "-r" rev)
2695 "-p"
2696 switches)))
f008ca58
KH
2697 (setq failed nil))
2698 (and failed (file-exists-p filename) (delete-file filename))))
2699 ;; default for verbose checkout: clear the sticky tag
2700 ;; so that the actual update will get the head of the trunk
2701 (and rev (string= rev "")
2702 (vc-do-command nil 0 "cvs" file 'WORKFILE "update" "-A"))
2703 ;; If a revision was specified, check that out.
2704 (if rev
2705 (apply 'vc-do-command nil 0 "cvs" file 'WORKFILE
2706 (and writable (eq (vc-checkout-model file) 'manual) "-w")
2707 "update"
2708 (and rev (not (string= rev ""))
2709 (concat "-r" rev))
2710 switches)
c0d66cb2
RS
2711 ;; If no revision was specified, call "cvs edit" to make
2712 ;; the file writeable.
2713 (and writable (eq (vc-checkout-model file) 'manual)
2714 (vc-do-command nil 0 "cvs" file 'WORKFILE "edit")))
2715 (if rev (vc-file-setprop file 'vc-workfile-version nil))))
f008ca58
KH
2716 (cond
2717 ((not workfile)
2718 (vc-file-clear-masterprops file)
2719 (if writable
8172cd86 2720 (vc-file-setprop file 'vc-locking-user (vc-user-login-name)))
f008ca58
KH
2721 (vc-file-setprop file
2722 'vc-checkout-time (nth 5 (file-attributes file)))))
2723 (message "Checking out %s...done" filename))))))
594722a8
ER
2724
2725(defun vc-backend-logentry-check (file)
2726 (vc-backend-dispatch file
8c0aaf40 2727 (if (>= (buffer-size) 512) ;; SCCS
594722a8
ER
2728 (progn
2729 (goto-char 512)
2730 (error
590cc449 2731 "Log must be less than 512 characters; point is now at pos 512")))
80688f5c
RS
2732 nil ;; RCS
2733 nil) ;; CVS
594722a8
ER
2734 )
2735
80688f5c 2736(defun vc-backend-checkin (file rev comment)
594722a8
ER
2737 ;; Register changes to FILE as level REV with explanatory COMMENT.
2738 ;; Automatically retrieves a read-only version of the file with
2739 ;; keywords expanded if vc-keep-workfiles is non-nil, otherwise
2740 ;; it deletes the workfile.
a7acbbe4 2741 ;; Adaptation for RCS branch support: if this is an explicit checkin,
c6d4f628
RS
2742 ;; or if the checkin creates a new branch, set the master file branch
2743 ;; accordingly.
594722a8 2744 (message "Checking in %s..." file)
7d665008 2745 ;; "This log message intentionally left almost blank".
9e0cc6e6
RS
2746 ;; RCS 5.7 gripes about white-space-only comments too.
2747 (or (and comment (string-match "[^\t\n ]" comment))
2748 (setq comment "*** empty log message ***"))
2ea8ce47
RM
2749 (save-excursion
2750 ;; Change buffers to get local value of vc-checkin-switches.
2751 (set-buffer (or (get-file-buffer file) (current-buffer)))
2c28ac43 2752 (let ((switches
90681ae2
EN
2753 (if (stringp vc-checkin-switches)
2754 (list vc-checkin-switches)
2755 vc-checkin-switches)))
2c28ac43
RS
2756 ;; Clear the master-properties. Do that here, not at the
2757 ;; end, because if the check-in fails we want them to get
2758 ;; re-computed before the next try.
2759 (vc-file-clear-masterprops file)
2760 (vc-backend-dispatch file
2761 ;; SCCS
2762 (progn
2763 (apply 'vc-do-command nil 0 "delta" file 'MASTER
2764 (if rev (concat "-r" rev))
2765 (concat "-y" comment)
2766 switches)
2767 (vc-file-setprop file 'vc-locking-user 'none)
2768 (vc-file-setprop file 'vc-workfile-version nil)
2769 (if vc-keep-workfiles
2770 (vc-do-command nil 0 "get" file 'MASTER))
2771 )
2772 ;; RCS
2773 (let ((old-version (vc-workfile-version file)) new-version)
2774 (apply 'vc-do-command nil 0 "ci" file 'MASTER
2775 ;; if available, use the secure check-in option
2776 (and (vc-backend-release-p 'RCS "5.6.4") "-j")
2777 (concat (if vc-keep-workfiles "-u" "-r") rev)
2778 (concat "-m" comment)
2779 switches)
2780 (vc-file-setprop file 'vc-locking-user 'none)
2781 (vc-file-setprop file 'vc-workfile-version nil)
2782
2783 ;; determine the new workfile version
2784 (set-buffer "*vc*")
2785 (goto-char (point-min))
2786 (if (or (re-search-forward
2787 "new revision: \\([0-9.]+\\);" nil t)
2788 (re-search-forward
2789 "reverting to previous revision \\([0-9.]+\\)" nil t))
2790 (progn (setq new-version (buffer-substring (match-beginning 1)
2791 (match-end 1)))
2792 (vc-file-setprop file 'vc-workfile-version new-version)))
2793
2794 ;; if we got to a different branch, adjust the default
2795 ;; branch accordingly
2796 (cond
2797 ((and old-version new-version
2798 (not (string= (vc-branch-part old-version)
2799 (vc-branch-part new-version))))
2800 (vc-do-command nil 0 "rcs" file 'MASTER
2801 (if (vc-trunk-p new-version) "-b"
2802 (concat "-b" (vc-branch-part new-version))))
2803 ;; If this is an old RCS release, we might have
2804 ;; to remove a remaining lock.
2805 (if (not (vc-backend-release-p 'RCS "5.6.2"))
2806 ;; exit status of 1 is also accepted.
2807 ;; It means that the lock was removed before.
2808 (vc-do-command nil 1 "rcs" file 'MASTER
2809 (concat "-u" old-version))))))
2810 ;; CVS
2811 (progn
2812 ;; explicit check-in to the trunk requires a
2813 ;; double check-in (first unexplicit) (CVS-1.3)
2814 (condition-case nil
2815 (progn
2816 (if (and rev (vc-trunk-p rev))
2817 (apply 'vc-do-command nil 0 "cvs" file 'WORKFILE
2818 "ci" "-m" "intermediate"
2819 switches))
2820 (apply 'vc-do-command nil 0 "cvs" file 'WORKFILE
2821 "ci" (if rev (concat "-r" rev))
2822 (concat "-m" comment)
2823 switches))
2824 (error (if (eq (vc-cvs-status file) 'needs-merge)
2825 ;; The CVS output will be on top of this message.
2826 (error "Type C-x 0 C-x C-q to merge in changes")
2827 (error "Check-in failed"))))
2828 ;; determine and store the new workfile version
2829 (set-buffer "*vc*")
2830 (goto-char (point-min))
2831 (if (re-search-forward
2832 "^\\(new\\|initial\\) revision: \\([0-9.]+\\)" nil t)
2833 (vc-file-setprop file 'vc-workfile-version
2834 (buffer-substring (match-beginning 2)
2835 (match-end 2)))
2836 (vc-file-setprop file 'vc-workfile-version nil))
2837 ;; if this was an explicit check-in, remove the sticky tag
2838 (if rev
2839 (vc-do-command nil 0 "cvs" file 'WORKFILE "update" "-A"))
c0d66cb2
RS
2840 ;; Forget the checkout model, because we might have assumed
2841 ;; a wrong one when we found the file. After commit, we can
2842 ;; tell it from the permissions of the file
2843 ;; (see vc-checkout-model).
2844 (vc-file-setprop file 'vc-checkout-model nil)
2c28ac43
RS
2845 (vc-file-setprop file 'vc-locking-user 'none)
2846 (vc-file-setprop file 'vc-checkout-time
2847 (nth 5 (file-attributes file)))))))
88a2ffaf 2848 (message "Checking in %s...done" file))
594722a8
ER
2849
2850(defun vc-backend-revert (file)
18483cf0 2851 ;; Revert file to the version it was based on.
594722a8 2852 (message "Reverting %s..." file)
61dee1e7 2853 (vc-file-clear-masterprops file)
594722a8
ER
2854 (vc-backend-dispatch
2855 file
c6d4f628
RS
2856 ;; SCCS
2857 (progn
6aa13729 2858 (vc-do-command nil 0 "unget" file 'MASTER nil)
18483cf0
AS
2859 (vc-do-command nil 0 "get" file 'MASTER nil)
2860 ;; Checking out explicit versions is not supported under SCCS, yet.
2861 ;; We always "revert" to the latest version; therefore
2862 ;; vc-workfile-version is cleared here so that it gets recomputed.
ae4c7029 2863 (vc-file-setprop file 'vc-workfile-version nil))
c6d4f628 2864 ;; RCS
6aa13729 2865 (vc-do-command nil 0 "co" file 'MASTER
c6d4f628
RS
2866 "-f" (concat "-u" (vc-workfile-version file)))
2867 ;; CVS
b9482d15
AS
2868 (progn
2869 ;; Check out via standard output (caused by the final argument
2870 ;; FILE below), so that no sticky tag is set.
2871 (vc-backend-checkout file nil (vc-workfile-version file) file)
2872 ;; If "cvs edit" was used to make the file writeable,
2873 ;; call "cvs unedit" now to undo that.
2874 (if (eq (vc-checkout-model file) 'manual)
2875 (vc-do-command nil 0 "cvs" file 'WORKFILE "unedit"))))
88a2ffaf 2876 (vc-file-setprop file 'vc-locking-user 'none)
c6d4f628 2877 (vc-file-setprop file 'vc-checkout-time (nth 5 (file-attributes file)))
594722a8
ER
2878 (message "Reverting %s...done" file)
2879 )
2880
2881(defun vc-backend-steal (file &optional rev)
2882 ;; Steal the lock on the current workfile. Needs RCS 5.6.2 or later for -M.
2883 (message "Stealing lock on %s..." file)
af1b8606 2884 (vc-backend-dispatch file
80688f5c 2885 (progn ;SCCS
6aa13729
RS
2886 (vc-do-command nil 0 "unget" file 'MASTER "-n" (if rev (concat "-r" rev)))
2887 (vc-do-command nil 0 "get" file 'MASTER "-g" (if rev (concat "-r" rev)))
d76b8d38 2888 )
6aa13729 2889 (vc-do-command nil 0 "rcs" file 'MASTER ;RCS
80688f5c 2890 "-M" (concat "-u" rev) (concat "-l" rev))
2c28ac43 2891 (error "You cannot steal a CVS lock; there are no CVS locks to steal") ;CVS
80688f5c 2892 )
8172cd86 2893 (vc-file-setprop file 'vc-locking-user (vc-user-login-name))
594722a8
ER
2894 (message "Stealing lock on %s...done" file)
2895 )
2896
2897(defun vc-backend-uncheck (file target)
c8de1d91 2898 ;; Undo the latest checkin.
594722a8
ER
2899 (message "Removing last change from %s..." file)
2900 (vc-backend-dispatch file
6aa13729
RS
2901 (vc-do-command nil 0 "rmdel" file 'MASTER (concat "-r" target))
2902 (vc-do-command nil 0 "rcs" file 'MASTER (concat "-o" target))
88a2ffaf 2903 nil ;; this is never reached under CVS
594722a8
ER
2904 )
2905 (message "Removing last change from %s...done" file)
2906 )
2907
2908(defun vc-backend-print-log (file)
6aa13729 2909 ;; Get change log associated with FILE.
80688f5c
RS
2910 (vc-backend-dispatch
2911 file
6aa13729
RS
2912 (vc-do-command nil 0 "prs" file 'MASTER)
2913 (vc-do-command nil 0 "rlog" file 'MASTER)
81b8f0e6 2914 (vc-do-command nil 0 "cvs" file 'WORKFILE "log")))
594722a8
ER
2915
2916(defun vc-backend-assign-name (file name)
2917 ;; Assign to a FILE's latest version a given NAME.
2918 (vc-backend-dispatch file
6aa13729
RS
2919 (vc-add-triple name file (vc-latest-version file)) ;; SCCS
2920 (vc-do-command nil 0 "rcs" file 'MASTER (concat "-n" name ":")) ;; RCS
2921 (vc-do-command nil 0 "cvs" file 'WORKFILE "tag" name) ;; CVS
3234e2a3 2922 )
3234e2a3 2923 )
594722a8 2924
9a51ed3a
PE
2925(defun vc-backend-diff (file &optional oldvers newvers cmp)
2926 ;; Get a difference report between two versions of FILE.
2927 ;; Get only a brief comparison report if CMP, a difference report otherwise.
eb302e54
AS
2928 (let ((backend (vc-backend file)) options status
2929 (diff-switches-list (if (listp diff-switches)
2930 diff-switches
2931 (list diff-switches))))
80688f5c
RS
2932 (cond
2933 ((eq backend 'SCCS)
7b4f934d 2934 (setq oldvers (vc-lookup-triple file oldvers))
eb302e54
AS
2935 (setq newvers (vc-lookup-triple file newvers))
2936 (setq options (append (list (and cmp "--brief") "-q"
2937 (and oldvers (concat "-r" oldvers))
2938 (and newvers (concat "-r" newvers)))
2939 (and (not cmp) diff-switches-list)))
2940 (apply 'vc-do-command "*vc-diff*" 1 "vcdiff" file 'MASTER options))
c6d4f628 2941 ((eq backend 'RCS)
99e76dda
AS
2942 (if (not oldvers) (setq oldvers (vc-workfile-version file)))
2943 ;; If we know that --brief is not supported, don't try it.
eb302e54
AS
2944 (setq cmp (and cmp (not (eq vc-rcsdiff-knows-brief 'no))))
2945 (setq options (append (list (and cmp "--brief") "-q"
2946 (concat "-r" oldvers)
2947 (and newvers (concat "-r" newvers)))
2948 (and (not cmp) diff-switches-list)))
2949 (setq status (apply 'vc-do-command "*vc-diff*" 2
2950 "rcsdiff" file 'WORKFILE options))
2951 ;; If --brief didn't work, do a double-take and remember it
2952 ;; for the future.
2953 (if (eq status 2)
a2272f32
GM
2954 (setq status
2955 (prog1
2956 (apply 'vc-do-command "*vc-diff*" 1 "rcsdiff" file 'WORKFILE
2957 (if cmp (cdr options) options))
2958 (if cmp (setq vc-rcsdiff-knows-brief 'no))))
eb302e54
AS
2959 ;; If --brief DID work, remember that, too.
2960 (and cmp (not vc-rcsdiff-knows-brief)
2961 (setq vc-rcsdiff-knows-brief 'yes))
2962 status))
80688f5c 2963 ;; CVS is different.
80688f5c 2964 ((eq backend 'CVS)
eb302e54 2965 (if (string= (vc-workfile-version file) "0")
80688f5c 2966 ;; This file is added but not yet committed; there is no master file.
80688f5c 2967 (if (or oldvers newvers)
b0c9bc8c
AS
2968 (error "No revisions of %s exist" file)
2969 (if cmp 1 ;; file is added but not committed,
2970 ;; we regard this as "changed".
2971 ;; diff it against /dev/null.
2972 (apply 'vc-do-command
2973 "*vc-diff*" 1 "diff" file 'WORKFILE
ac3db2e4 2974 (append diff-switches-list '("/dev/null")))))
b0c9bc8c 2975 ;; cmp is not yet implemented -- we always do a full diff.
80688f5c 2976 (apply 'vc-do-command
6aa13729 2977 "*vc-diff*" 1 "cvs" file 'WORKFILE "diff"
80688f5c
RS
2978 (and oldvers (concat "-r" oldvers))
2979 (and newvers (concat "-r" newvers))
ac3db2e4 2980 diff-switches-list))))))
80688f5c
RS
2981
2982(defun vc-backend-merge-news (file)
2983 ;; Merge in any new changes made to FILE.
61dee1e7
AS
2984 (message "Merging changes into %s..." file)
2985 (prog1
2986 (vc-backend-dispatch
2987 file
2988 (error "vc-backend-merge-news not meaningful for SCCS files") ;SCCS
2989 (error "vc-backend-merge-news not meaningful for RCS files") ;RCS
2990 (save-excursion ; CVS
2991 (vc-file-clear-masterprops file)
2992 (vc-file-setprop file 'vc-workfile-version nil)
2993 (vc-file-setprop file 'vc-locking-user nil)
d5859f32 2994 (vc-file-setprop file 'vc-checkout-time nil)
61dee1e7 2995 (vc-do-command nil 0 "cvs" file 'WORKFILE "update")
d5859f32
AS
2996 ;; Analyze the merge result reported by CVS, and set
2997 ;; file properties accordingly.
61dee1e7
AS
2998 (set-buffer (get-buffer "*vc*"))
2999 (goto-char (point-min))
d5859f32
AS
3000 ;; get new workfile version
3001 (if (re-search-forward (concat "^Merging differences between "
3002 "[01234567890.]* and "
3003 "\\([01234567890.]*\\) into")
3004 nil t)
3005 (vc-file-setprop file 'vc-workfile-version (match-string 1)))
3006 ;; get file status
3007 (if (re-search-forward
051848e4 3008 (concat "^\\(\\([CMUP]\\) \\)?"
b73820b0
AS
3009 (regexp-quote (file-name-nondirectory file))
3010 "\\( already contains the differences between \\)?")
d5859f32
AS
3011 nil t)
3012 (cond
3013 ;; Merge successful, we are in sync with repository now
b73820b0 3014 ((or (string= (match-string 2) "U")
927d7566 3015 (string= (match-string 2) "P")
b73820b0
AS
3016 ;; Special case: file contents in sync with
3017 ;; repository anyhow:
3018 (match-string 3))
3019 (vc-file-setprop file 'vc-locking-user 'none)
d5859f32
AS
3020 (vc-file-setprop file 'vc-checkout-time
3021 (nth 5 (file-attributes file)))
3022 0) ;; indicate success to the caller
3023 ;; Merge successful, but our own changes are still in the file
b73820b0 3024 ((string= (match-string 2) "M")
d5859f32
AS
3025 (vc-file-setprop file 'vc-locking-user (vc-file-owner file))
3026 (vc-file-setprop file 'vc-checkout-time 0)
3027 0) ;; indicate success to the caller
3028 ;; Conflicts detected!
b73820b0 3029 ((string= (match-string 2) "C")
d5859f32
AS
3030 (vc-file-setprop file 'vc-locking-user (vc-file-owner file))
3031 (vc-file-setprop file 'vc-checkout-time 0)
3032 1) ;; signal the error to the caller
3033 )
3034 (pop-to-buffer "*vc*")
3035 (error "Couldn't analyze cvs update result"))))
61dee1e7 3036 (message "Merging changes into %s...done" file)))
594722a8 3037
ccb141e8
AS
3038(defun vc-backend-merge (file first-version &optional second-version)
3039 ;; Merge the changes between FIRST-VERSION and SECOND-VERSION into
3040 ;; the current working copy of FILE. It is assumed that FILE is
3041 ;; locked and writable (vc-merge ensures this).
3042 (vc-backend-dispatch file
3043 ;; SCCS
3044 (error "Sorry, merging is not implemented for SCCS")
3045 ;; RCS
3046 (vc-do-command nil 1 "rcsmerge" file 'MASTER
3047 "-kk" ;; ignore keyword conflicts
3048 (concat "-r" first-version)
3049 (if second-version (concat "-r" second-version)))
3050 ;; CVS
3051 (progn
3052 (vc-do-command nil 0 "cvs" file 'WORKFILE
3053 "update" "-kk"
3054 (concat "-j" first-version)
3055 (concat "-j" second-version))
3056 (save-excursion
3057 (set-buffer (get-buffer "*vc*"))
3058 (goto-char (point-min))
3059 (if (re-search-forward "conflicts during merge" nil t)
3060 1 ;; signal error
3061 0 ;; signal success
3062 )))))
3063
594722a8
ER
3064(defun vc-check-headers ()
3065 "Check if the current file has any headers in it."
3066 (interactive)
3067 (save-excursion
3068 (goto-char (point-min))
3069 (vc-backend-dispatch buffer-file-name
3070 (re-search-forward "%[MIRLBSDHTEGUYFPQCZWA]%" nil t) ;; SCCS
3071 (re-search-forward "\\$[A-Za-z\300-\326\330-\366\370-\377]+\\(: [\t -#%-\176\240-\377]*\\)?\\$" nil t) ;; RCS
80688f5c 3072 'RCS ;; CVS works like RCS in this regard.
594722a8
ER
3073 )
3074 ))
3075
3076;; Back-end-dependent stuff ends here.
3077
3078;; Set up key bindings for use while editing log messages
3079
37667a5c 3080(defun vc-log-mode (&optional file)
594722a8
ER
3081 "Minor mode for driving version-control tools.
3082These bindings are added to the global keymap when you enter this mode:
3083\\[vc-next-action] perform next logical version-control operation on current file
3084\\[vc-register] register current file
3085\\[vc-toggle-read-only] like next-action, but won't register files
3086\\[vc-insert-headers] insert version-control headers in current file
3087\\[vc-print-log] display change history of current file
3088\\[vc-revert-buffer] revert buffer to latest version
3089\\[vc-cancel-version] undo latest checkin
3090\\[vc-diff] show diffs between file versions
f1818994 3091\\[vc-version-other-window] visit old version in another window
594722a8 3092\\[vc-directory] show all files locked by any user in or below .
7d2d9482 3093\\[vc-annotate] colorful display of the cvs annotate command
594722a8
ER
3094\\[vc-update-change-log] add change log entry from recent checkins
3095
3096While you are entering a change log message for a version, the following
3097additional bindings will be in effect.
3098
3099\\[vc-finish-logentry] proceed with check in, ending log message entry
3100
3101Whenever you do a checkin, your log comment is added to a ring of
3102saved comments. These can be recalled as follows:
3103
3104\\[vc-next-comment] replace region with next message in comment ring
3105\\[vc-previous-comment] replace region with previous message in comment ring
8c0aaf40
ER
3106\\[vc-comment-search-reverse] search backward for regexp in the comment ring
3107\\[vc-comment-search-forward] search backward for regexp in the comment ring
594722a8
ER
3108
3109Entry to the change-log submode calls the value of text-mode-hook, then
3110the value of vc-log-mode-hook.
3111
3112Global user options:
3113 vc-initial-comment If non-nil, require user to enter a change
3114 comment upon first checkin of the file.
3115
3116 vc-keep-workfiles Non-nil value prevents workfiles from being
3117 deleted when changes are checked in
3118
3119 vc-suppress-confirm Suppresses some confirmation prompts,
3120 notably for reversions.
3121
7b4f934d 3122 vc-header-alist Which keywords to insert when adding headers
594722a8 3123 with \\[vc-insert-headers]. Defaults to
80688f5c
RS
3124 '(\"\%\W\%\") under SCCS, '(\"\$Id\$\") under
3125 RCS and CVS.
594722a8
ER
3126
3127 vc-static-header-alist By default, version headers inserted in C files
3128 get stuffed in a static string area so that
80688f5c
RS
3129 ident(RCS/CVS) or what(SCCS) can see them in
3130 the compiled object code. You can override
3131 this by setting this variable to nil, or change
594722a8
ER
3132 the header template by changing it.
3133
3134 vc-command-messages if non-nil, display run messages from the
3135 actual version-control utilities (this is
3136 intended primarily for people hacking vc
3137 itself).
3138"
3139 (interactive)
3140 (set-syntax-table text-mode-syntax-table)
3141 (use-local-map vc-log-entry-mode)
3142 (setq local-abbrev-table text-mode-abbrev-table)
3143 (setq major-mode 'vc-log-mode)
3144 (setq mode-name "VC-Log")
3145 (make-local-variable 'vc-log-file)
37667a5c 3146 (setq vc-log-file file)
594722a8 3147 (make-local-variable 'vc-log-version)
8c0aaf40 3148 (make-local-variable 'vc-comment-ring-index)
594722a8
ER
3149 (set-buffer-modified-p nil)
3150 (setq buffer-file-name nil)
3151 (run-hooks 'text-mode-hook 'vc-log-mode-hook)
3152)
3153
3154;; Initialization code, to be done just once at load-time
3155(if vc-log-entry-mode
3156 nil
3157 (setq vc-log-entry-mode (make-sparse-keymap))
3158 (define-key vc-log-entry-mode "\M-n" 'vc-next-comment)
3159 (define-key vc-log-entry-mode "\M-p" 'vc-previous-comment)
8c0aaf40 3160 (define-key vc-log-entry-mode "\M-r" 'vc-comment-search-reverse)
594722a8
ER
3161 (define-key vc-log-entry-mode "\M-s" 'vc-comment-search-forward)
3162 (define-key vc-log-entry-mode "\C-c\C-c" 'vc-finish-logentry)
3163 )
3164
3165;;; These things should probably be generally available
3166
2f119435
AS
3167(defun vc-file-tree-walk (dirname func &rest args)
3168 "Walk recursively through DIRNAME.
34291cd2 3169Invoke FUNC f ARGS on each non-directory file f underneath it."
2f119435
AS
3170 (vc-file-tree-walk-internal (expand-file-name dirname) func args)
3171 (message "Traversing directory %s...done" dirname))
02da6253
PE
3172
3173(defun vc-file-tree-walk-internal (file func args)
3174 (if (not (file-directory-p file))
3175 (apply func file args)
993a1a44 3176 (message "Traversing directory %s..." (abbreviate-file-name file))
02da6253
PE
3177 (let ((dir (file-name-as-directory file)))
3178 (mapcar
3179 (function
3180 (lambda (f) (or
3181 (string-equal f ".")
3182 (string-equal f "..")
632e9525 3183 (member f vc-directory-exclusion-list)
02da6253
PE
3184 (let ((dirf (concat dir f)))
3185 (or
3186 (file-symlink-p dirf) ;; Avoid possible loops
3187 (vc-file-tree-walk-internal dirf func args))))))
3188 (directory-files dir)))))
594722a8
ER
3189
3190(provide 'vc)
3191
3192;;; DEVELOPER'S NOTES ON CONCURRENCY PROBLEMS IN THIS CODE
3193;;;
3194;;; These may be useful to anyone who has to debug or extend the package.
c6d4f628
RS
3195;;; (Note that this information corresponds to versions 5.x. Some of it
3196;;; might have been invalidated by the additions to support branching
3197;;; and RCS keyword lookup. AS, 1995/03/24)
594722a8
ER
3198;;;
3199;;; A fundamental problem in VC is that there are time windows between
3200;;; vc-next-action's computations of the file's version-control state and
3201;;; the actions that change it. This is a window open to lossage in a
3202;;; multi-user environment; someone else could nip in and change the state
3203;;; of the master during it.
3204;;;
3205;;; The performance problem is that rlog/prs calls are very expensive; we want
3206;;; to avoid them as much as possible.
3207;;;
3208;;; ANALYSIS:
3209;;;
3210;;; The performance problem, it turns out, simplifies in practice to the
3211;;; problem of making vc-locking-user fast. The two other functions that call
3212;;; prs/rlog will not be so commonly used that the slowdown is a problem; one
3213;;; makes snapshots, the other deletes the calling user's last change in the
3214;;; master.
3215;;;
3216;;; The race condition implies that we have to either (a) lock the master
3217;;; during the entire execution of vc-next-action, or (b) detect and
3218;;; recover from errors resulting from dispatch on an out-of-date state.
3219;;;
a7acbbe4 3220;;; Alternative (a) appears to be infeasible. The problem is that we can't
594722a8
ER
3221;;; guarantee that the lock will ever be removed. Suppose a user starts a
3222;;; checkin, the change message buffer pops up, and the user, having wandered
3223;;; off to do something else, simply forgets about it?
3224;;;
3225;;; Alternative (b), on the other hand, works well with a cheap way to speed up
3226;;; vc-locking-user. Usually, if a file is registered, we can read its locked/
3227;;; unlocked state and its current owner from its permissions.
3228;;;
3229;;; This shortcut will fail if someone has manually changed the workfile's
3230;;; permissions; also if developers are munging the workfile in several
3231;;; directories, with symlinks to a master (in this latter case, the
3232;;; permissions shortcut will fail to detect a lock asserted from another
3233;;; directory).
3234;;;
3235;;; Note that these cases correspond exactly to the errors which could happen
3236;;; because of a competing checkin/checkout race in between two instances of
3237;;; vc-next-action.
3238;;;
3239;;; For VC's purposes, a workfile/master pair may have the following states:
3240;;;
3241;;; A. Unregistered. There is a workfile, there is no master.
3242;;;
3243;;; B. Registered and not locked by anyone.
3244;;;
3245;;; C. Locked by calling user and unchanged.
3246;;;
3247;;; D. Locked by the calling user and changed.
3248;;;
3249;;; E. Locked by someone other than the calling user.
3250;;;
3251;;; This makes for 25 states and 20 error conditions. Here's the matrix:
3252;;;
3253;;; VC's idea of state
3254;;; |
3255;;; V Actual state RCS action SCCS action Effect
3256;;; A B C D E
3257;;; A . 1 2 3 4 ci -u -t- admin -fb -i<file> initial admin
3258;;; B 5 . 6 7 8 co -l get -e checkout
3259;;; C 9 10 . 11 12 co -u unget; get revert
3260;;; D 13 14 15 . 16 ci -u -m<comment> delta -y<comment>; get checkin
b0c9bc8c 3261;;; E 17 18 19 20 . rcs -u -M -l unget -n ; get -g steal lock
594722a8
ER
3262;;;
3263;;; All commands take the master file name as a last argument (not shown).
3264;;;
3265;;; In the discussion below, a "self-race" is a pathological situation in
3266;;; which VC operations are being attempted simultaneously by two or more
3267;;; Emacsen running under the same username.
3268;;;
3269;;; The vc-next-action code has the following windows:
3270;;;
3271;;; Window P:
3272;;; Between the check for existence of a master file and the call to
3273;;; admin/checkin in vc-buffer-admin (apparent state A). This window may
3274;;; never close if the initial-comment feature is on.
3275;;;
3276;;; Window Q:
3277;;; Between the call to vc-workfile-unchanged-p in and the immediately
3278;;; following revert (apparent state C).
3279;;;
3280;;; Window R:
3281;;; Between the call to vc-workfile-unchanged-p in and the following
3282;;; checkin (apparent state D). This window may never close.
3283;;;
3284;;; Window S:
3285;;; Between the unlock and the immediately following checkout during a
3286;;; revert operation (apparent state C). Included in window Q.
3287;;;
3288;;; Window T:
3289;;; Between vc-locking-user and the following checkout (apparent state B).
3290;;;
3291;;; Window U:
3292;;; Between vc-locking-user and the following revert (apparent state C).
3293;;; Includes windows Q and S.
3294;;;
3295;;; Window V:
3296;;; Between vc-locking-user and the following checkin (apparent state
3297;;; D). This window may never be closed if the user fails to complete the
3298;;; checkin message. Includes window R.
3299;;;
3300;;; Window W:
3301;;; Between vc-locking-user and the following steal-lock (apparent
34291cd2 3302;;; state E). This window may never close if the user fails to complete
594722a8
ER
3303;;; the steal-lock message. Includes window X.
3304;;;
3305;;; Window X:
3306;;; Between the unlock and the immediately following re-lock during a
3307;;; steal-lock operation (apparent state E). This window may never cloce
3308;;; if the user fails to complete the steal-lock message.
3309;;;
3310;;; Errors:
3311;;;
3312;;; Apparent state A ---
3313;;;
3314;;; 1. File looked unregistered but is actually registered and not locked.
3315;;;
3316;;; Potential cause: someone else's admin during window P, with
3317;;; caller's admin happening before their checkout.
3318;;;
b0c9bc8c
AS
3319;;; RCS: Prior to version 5.6.4, ci fails with message
3320;;; "no lock set by <user>". From 5.6.4 onwards, VC uses the new
3321;;; ci -i option and the message is "<file>,v: already exists".
594722a8
ER
3322;;; SCCS: admin will fail with error (ad19).
3323;;;
3324;;; We can let these errors be passed up to the user.
3325;;;
3326;;; 2. File looked unregistered but is actually locked by caller, unchanged.
3327;;;
3328;;; Potential cause: self-race during window P.
3329;;;
b0c9bc8c
AS
3330;;; RCS: Prior to version 5.6.4, reverts the file to the last saved
3331;;; version and unlocks it. From 5.6.4 onwards, VC uses the new
3332;;; ci -i option, failing with message "<file>,v: already exists".
594722a8
ER
3333;;; SCCS: will fail with error (ad19).
3334;;;
3335;;; Either of these consequences is acceptable.
3336;;;
3337;;; 3. File looked unregistered but is actually locked by caller, changed.
3338;;;
3339;;; Potential cause: self-race during window P.
3340;;;
b0c9bc8c
AS
3341;;; RCS: Prior to version 5.6.4, VC registers the caller's workfile as
3342;;; a delta with a null change comment (the -t- switch will be
3343;;; ignored). From 5.6.4 onwards, VC uses the new ci -i option,
3344;;; failing with message "<file>,v: already exists".
594722a8
ER
3345;;; SCCS: will fail with error (ad19).
3346;;;
3347;;; 4. File looked unregistered but is locked by someone else.
3348;;;
3349;;; Potential cause: someone else's admin during window P, with
3350;;; caller's admin happening *after* their checkout.
3351;;;
b0c9bc8c
AS
3352;;; RCS: Prior to version 5.6.4, ci fails with a
3353;;; "no lock set by <user>" message. From 5.6.4 onwards,
3354;;; VC uses the new ci -i option, failing with message
3355;;; "<file>,v: already exists".
594722a8
ER
3356;;; SCCS: will fail with error (ad19).
3357;;;
3358;;; We can let these errors be passed up to the user.
3359;;;
3360;;; Apparent state B ---
3361;;;
3362;;; 5. File looked registered and not locked, but is actually unregistered.
3363;;;
3364;;; Potential cause: master file got nuked during window P.
3365;;;
3366;;; RCS: will fail with "RCS/<file>: No such file or directory"
3367;;; SCCS: will fail with error ut4.
3368;;;
3369;;; We can let these errors be passed up to the user.
3370;;;
3371;;; 6. File looked registered and not locked, but is actually locked by the
3372;;; calling user and unchanged.
3373;;;
3374;;; Potential cause: self-race during window T.
3375;;;
3376;;; RCS: in the same directory as the previous workfile, co -l will fail
3377;;; with "co error: writable foo exists; checkout aborted". In any other
3378;;; directory, checkout will succeed.
3379;;; SCCS: will fail with ge17.
3380;;;
3381;;; Either of these consequences is acceptable.
3382;;;
3383;;; 7. File looked registered and not locked, but is actually locked by the
3384;;; calling user and changed.
3385;;;
3386;;; As case 6.
3387;;;
3388;;; 8. File looked registered and not locked, but is actually locked by another
3389;;; user.
3390;;;
3391;;; Potential cause: someone else checks it out during window T.
3392;;;
3393;;; RCS: co error: revision 1.3 already locked by <user>
3394;;; SCCS: fails with ge4 (in directory) or ut7 (outside it).
3395;;;
3396;;; We can let these errors be passed up to the user.
3397;;;
3398;;; Apparent state C ---
3399;;;
3400;;; 9. File looks locked by calling user and unchanged, but is unregistered.
3401;;;
3402;;; As case 5.
3403;;;
3404;;; 10. File looks locked by calling user and unchanged, but is actually not
3405;;; locked.
3406;;;
3407;;; Potential cause: a self-race in window U, or by the revert's
3408;;; landing during window X of some other user's steal-lock or window S
3409;;; of another user's revert.
3410;;;
3411;;; RCS: succeeds, refreshing the file from the identical version in
3412;;; the master.
3413;;; SCCS: fails with error ut4 (p file nonexistent).
3414;;;
3415;;; Either of these consequences is acceptable.
3416;;;
3417;;; 11. File is locked by calling user. It looks unchanged, but is actually
3418;;; changed.
3419;;;
3420;;; Potential cause: the file would have to be touched by a self-race
3421;;; during window Q.
3422;;;
3423;;; The revert will succeed, removing whatever changes came with
3424;;; the touch. It is theoretically possible that work could be lost.
3425;;;
3426;;; 12. File looks like it's locked by the calling user and unchanged, but
3427;;; it's actually locked by someone else.
3428;;;
3429;;; Potential cause: a steal-lock in window V.
3430;;;
3431;;; RCS: co error: revision <rev> locked by <user>; use co -r or rcs -u
3432;;; SCCS: fails with error un2
3433;;;
3434;;; We can pass these errors up to the user.
3435;;;
3436;;; Apparent state D ---
3437;;;
3438;;; 13. File looks like it's locked by the calling user and changed, but it's
3439;;; actually unregistered.
3440;;;
3441;;; Potential cause: master file got nuked during window P.
3442;;;
b0c9bc8c
AS
3443;;; RCS: Prior to version 5.6.4, checks in the user's version as an
3444;;; initial delta. From 5.6.4 onwards, VC uses the new ci -j
3445;;; option, failing with message "no such file or directory".
594722a8
ER
3446;;; SCCS: will fail with error ut4.
3447;;;
b0c9bc8c
AS
3448;;; This case is kind of nasty. Under RCS prior to version 5.6.4,
3449;;; VC may fail to detect the loss of previous version information.
594722a8
ER
3450;;;
3451;;; 14. File looks like it's locked by the calling user and changed, but it's
3452;;; actually unlocked.
3453;;;
3454;;; Potential cause: self-race in window V, or the checkin happening
3455;;; during the window X of someone else's steal-lock or window S of
3456;;; someone else's revert.
3457;;;
3458;;; RCS: ci will fail with "no lock set by <user>".
3459;;; SCCS: delta will fail with error ut4.
3460;;;
3461;;; 15. File looks like it's locked by the calling user and changed, but it's
3462;;; actually locked by the calling user and unchanged.
3463;;;
3464;;; Potential cause: another self-race --- a whole checkin/checkout
3465;;; sequence by the calling user would have to land in window R.
3466;;;
3467;;; SCCS: checks in a redundant delta and leaves the file unlocked as usual.
3468;;; RCS: reverts to the file state as of the second user's checkin, leaving
3469;;; the file unlocked.
3470;;;
3471;;; It is theoretically possible that work could be lost under RCS.
3472;;;
3473;;; 16. File looks like it's locked by the calling user and changed, but it's
3474;;; actually locked by a different user.
3475;;;
3476;;; RCS: ci error: no lock set by <user>
3477;;; SCCS: unget will fail with error un2
3478;;;
3479;;; We can pass these errors up to the user.
3480;;;
3481;;; Apparent state E ---
3482;;;
3483;;; 17. File looks like it's locked by some other user, but it's actually
3484;;; unregistered.
3485;;;
3486;;; As case 13.
3487;;;
3488;;; 18. File looks like it's locked by some other user, but it's actually
3489;;; unlocked.
3490;;;
3491;;; Potential cause: someone released a lock during window W.
3492;;;
3493;;; RCS: The calling user will get the lock on the file.
3494;;; SCCS: unget -n will fail with cm4.
3495;;;
3496;;; Either of these consequences will be OK.
3497;;;
3498;;; 19. File looks like it's locked by some other user, but it's actually
3499;;; locked by the calling user and unchanged.
3500;;;
3501;;; Potential cause: the other user relinquishing a lock followed by
3502;;; a self-race, both in window W.
3503;;;
3504;;; Under both RCS and SCCS, both unlock and lock will succeed, making
3505;;; the sequence a no-op.
3506;;;
3507;;; 20. File looks like it's locked by some other user, but it's actually
3508;;; locked by the calling user and changed.
3509;;;
3510;;; As case 19.
3511;;;
3512;;; PROBLEM CASES:
3513;;;
3514;;; In order of decreasing severity:
3515;;;
b0c9bc8c 3516;;; Cases 11 and 15 are the only ones that potentially lose work.
594722a8
ER
3517;;; They would require a self-race for this to happen.
3518;;;
3519;;; Case 13 in RCS loses information about previous deltas, retaining
3520;;; only the information in the current workfile. This can only happen
3521;;; if the master file gets nuked in window P.
3522;;;
3523;;; Case 3 in RCS and case 15 under SCCS insert a redundant delta with
3524;;; no change comment in the master. This would require a self-race in
3525;;; window P or R respectively.
3526;;;
3527;;; Cases 2, 10, 19 and 20 do extra work, but make no changes.
3528;;;
3529;;; Unfortunately, it appears to me that no recovery is possible in these
3530;;; cases. They don't yield error messages, so there's no way to tell that
3531;;; a race condition has occurred.
3532;;;
3533;;; All other cases don't change either the workfile or the master, and
3534;;; trigger command errors which the user will see.
3535;;;
3536;;; Thus, there is no explicit recovery code.
3537
3538;;; vc.el ends here