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