;;; vc-rcs.el --- support for RCS version-control
;; Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-;; 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+;; 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+;; Free Software Foundation, Inc.
;; Author: FSF (see vc.el for full credits)
;; Maintainer: Andre Spiegel <spiegel@gnu.org>
-;; $Id$
-
;; This file is part of GNU Emacs.
;; GNU Emacs is free software: you can redistribute it and/or modify
(require 'vc))
(defcustom vc-rcs-release nil
- "*The release number of your RCS installation, as a string.
+ "The release number of your RCS installation, as a string.
If nil, VC itself computes this value when it is first needed."
:type '(choice (const :tag "Auto" nil)
(string :tag "Specified")
:group 'vc)
(defcustom vc-rcs-register-switches nil
- "*Extra switches for registering a file in RCS.
-A string or list of strings. These are passed to the checkin program
-by \\[vc-rcs-register]."
- :type '(choice (const :tag "None" nil)
+ "Switches for registering a file in RCS.
+A string or list of strings passed to the checkin program by
+\\[vc-register]. If nil, use the value of `vc-register-switches'.
+If t, use no switches."
+ :type '(choice (const :tag "Unspecified" nil)
+ (const :tag "None" t)
(string :tag "Argument String")
- (repeat :tag "Argument List"
- :value ("")
- string))
+ (repeat :tag "Argument List" :value ("") string))
:version "21.1"
:group 'vc)
(defcustom vc-rcs-diff-switches nil
- "*A string or list of strings specifying extra switches for rcsdiff under VC."
- :type '(choice (const :tag "None" nil)
+ "String or list of strings specifying switches for RCS diff under VC.
+If nil, use the value of `vc-diff-switches'. If t, use no switches."
+ :type '(choice (const :tag "Unspecified" nil)
+ (const :tag "None" t)
(string :tag "Argument String")
- (repeat :tag "Argument List"
- :value ("")
- string))
+ (repeat :tag "Argument List" :value ("") string))
:version "21.1"
:group 'vc)
(defcustom vc-rcs-header (or (cdr (assoc 'RCS vc-header-alist)) '("\$Id\$"))
- "*Header keywords to be inserted by `vc-insert-headers'."
+ "Header keywords to be inserted by `vc-insert-headers'."
:type '(repeat string)
:version "21.1"
:group 'vc)
(defcustom vc-rcsdiff-knows-brief nil
- "*Indicates whether rcsdiff understands the --brief option.
+ "Indicates whether rcsdiff understands the --brief option.
The value is either `yes', `no', or nil. If it is nil, VC tries
to use --brief and sets this variable to remember whether it worked."
:type '(choice (const :tag "Work out" nil) (const yes) (const no))
;;;###autoload
(defcustom vc-rcs-master-templates
'("%sRCS/%s,v" "%s%s,v" "%sRCS/%s")
- "*Where to look for RCS master files.
+ "Where to look for RCS master files.
For a description of possible values, see `vc-check-master-templates'."
:type '(choice (const :tag "Use standard RCS file names"
'("%sRCS/%s,v" "%s%s,v" "%sRCS/%s"))
;; permissions can tell us whether locking is used for
;; the file or not.
(if (and (eq state 'up-to-date)
- (not (vc-mistrust-permissions file)))
+ (not (vc-mistrust-permissions file))
+ (file-exists-p file))
(cond
((string-match ".rw..-..-." (nth 8 (file-attributes file)))
(vc-file-setprop file 'vc-checkout-model 'implicit)
(let* ((attributes (file-attributes file 'string))
(owner-name (nth 2 attributes))
(permissions (nth 8 attributes)))
- (cond ((string-match ".r-..-..-." permissions)
+ (cond ((and permissions (string-match ".r-..-..-." permissions))
(vc-file-setprop file 'vc-checkout-model 'locking)
'up-to-date)
- ((string-match ".rw..-..-." permissions)
+ ((and permissions (string-match ".rw..-..-." permissions))
(if (eq (vc-rcs-checkout-model file) 'locking)
(if (file-ownership-preserved-p file)
'edited
(vc-rcs-state file)))))
(defun vc-rcs-dir-status (dir update-function)
- ;; Doing individual vc-state calls is painful but tgere
- ;; is no better way in RCS-land.
+ ;; FIXME: this function should be rewritten or `vc-expand-dirs'
+ ;; should be changed to take a backend parameter. Using
+ ;; `vc-expand-dirs' is not TRTD because it returns files from
+ ;; multiple backends. It should also return 'unregistered files.
+
+ ;; Doing individual vc-state calls is painful but there
+ ;; is no better way in RCS-land.
(let ((flist (vc-expand-dirs (list dir)))
(result nil))
(dolist (file flist)
(let ((state (vc-state file))
(frel (file-relative-name file)))
- (push (list frel state) result)))
+ (when (and (eq (vc-backend file) 'RCS)
+ (not (eq state 'up-to-date)))
+ (push (list frel state) result))))
(funcall update-function result)))
(defun vc-rcs-working-revision (file)
;; do a double take and remember the fact for the future
(let* ((version (concat "-r" (vc-working-revision file)))
(status (if (eq vc-rcsdiff-knows-brief 'no)
- (vc-do-command nil 1 "rcsdiff" file version)
- (vc-do-command nil 2 "rcsdiff" file "--brief" version))))
+ (vc-do-command "*vc*" 1 "rcsdiff" file version)
+ (vc-do-command "*vc*" 2 "rcsdiff" file "--brief" version))))
(if (eq status 2)
(if (not vc-rcsdiff-knows-brief)
(setq vc-rcsdiff-knows-brief 'no
- status (vc-do-command nil 1 "rcsdiff" file version))
+ status (vc-do-command "*vc*" 1 "rcsdiff" file version))
(error "rcsdiff failed"))
(if (not vc-rcsdiff-knows-brief) (setq vc-rcsdiff-knows-brief 'yes)))
;; The workfile is unchanged if rcsdiff found no differences.
(defun vc-rcs-create-repo ()
"Create a new RCS repository."
- ;; RCS is totally file-oriented, so all we have to do is make the directory
+ ;; RCS is totally file-oriented, so all we have to do is make the directory.
(make-directory "RCS"))
(defun vc-rcs-register (files &optional rev comment)
"Register FILES into the RCS version-control system.
REV is the optional revision number for the files. COMMENT can be used
to provide an initial description for each FILES.
-
-`vc-register-switches' and `vc-rcs-register-switches' are passed to
-the RCS command (in that order).
+Passes either `vc-rcs-register-switches' or `vc-register-switches'
+to the RCS command.
Automatically retrieve a read-only version of the file with keywords
expanded if `vc-keep-workfiles' is non-nil, otherwise, delete the workfile."
nil ".*,v$" t))
(yes-or-no-p "Create RCS subdirectory? ")
(make-directory subdir))
- (apply 'vc-do-command nil 0 "ci" file
+ (apply 'vc-do-command "*vc*" 0 "ci" file
;; if available, use the secure registering option
(and (vc-rcs-release-p "5.6.4") "-i")
(concat (if vc-keep-workfiles "-u" "-r") rev)
(setq switches (cons "-f" switches)))
(if (and (not rev) old-version)
(setq rev (vc-branch-part old-version)))
- (apply 'vc-do-command nil 0 "ci" (vc-name file)
+ (apply 'vc-do-command "*vc*" 0 "ci" (vc-name file)
;; if available, use the secure check-in option
(and (vc-rcs-release-p "5.6.4") "-j")
(concat (if vc-keep-workfiles "-u" "-r") rev)
(if (not (vc-rcs-release-p "5.6.2"))
;; exit status of 1 is also accepted.
;; It means that the lock was removed before.
- (vc-do-command nil 1 "rcs" (vc-name file)
+ (vc-do-command "*vc*" 1 "rcs" (vc-name file)
(concat "-u" old-version)))))))))
(defun vc-rcs-find-revision (file rev buffer)
(apply 'vc-do-command
- buffer 0 "co" (vc-name file)
+ (or buffer "*vc*") 0 "co" (vc-name file)
"-q" ;; suppress diagnostic output
(concat "-p" rev)
(vc-switches 'RCS 'checkout)))
(defun vc-rcs-checkout (file &optional editable rev)
- "Retrieve a copy of a saved version of FILE. If FILE is a directory,
+ "Retrieve a copy of a saved version of FILE. If FILE is a directory,
attempt the checkout for all registered files beneath it."
(if (file-directory-p file)
(mapc 'vc-rcs-checkout (vc-expand-dirs (list file)))
(vc-rcs-set-default-branch file nil))
;; now do the checkout
(apply 'vc-do-command
- nil 0 "co" (vc-name file)
+ "*vc*" 0 "co" (vc-name file)
;; If locking is not strict, force to overwrite
;; the writable workfile.
(if (eq (vc-rcs-checkout-model (list file)) 'implicit) "-f")
(message "Checking out %s...done" file))))))
(defun vc-rcs-rollback (files)
- "Roll back, undoing the most recent checkins of FILES. Directories are
-expanded to all regidtered subfuiles in them."
+ "Roll back, undoing the most recent checkins of FILES. Directories are
+expanded to all registered subfiles in them."
(if (not files)
(error "RCS backend doesn't support directory-level rollback."))
(dolist (file (vc-expand-dirs files))
discard file)))
(error "Aborted"))
(message "Removing revision %s from %s." discard file)
- (vc-do-command nil 0 "rcs" (vc-name file) (concat "-o" discard))
+ (vc-do-command "*vc*" 0 "rcs" (vc-name file) (concat "-o" discard))
;; Check out the most recent remaining version. If it
;; fails, because the whole branch got deleted, do a
;; double-take and check out the version where the branch
(while (not done)
(condition-case err
(progn
- (vc-do-command nil 0 "co" (vc-name file) "-f"
+ (vc-do-command "*vc*" 0 "co" (vc-name file) "-f"
(concat "-u" previous))
(setq done t))
(error (set-buffer "*vc*")
(signal (car err) (cdr err)))))))))
(defun vc-rcs-revert (file &optional contents-done)
- "Revert FILE to the version it was based on. If FILE is a directory,
+ "Revert FILE to the version it was based on. If FILE is a directory,
revert all registered files beneath it."
(if (file-directory-p file)
(mapc 'vc-rcs-revert (vc-expand-dirs (list file)))
- (vc-do-command nil 0 "co" (vc-name file) "-f"
+ (vc-do-command "*vc*" 0 "co" (vc-name file) "-f"
(concat (if (eq (vc-state file) 'edited) "-u" "-r")
(vc-working-revision file)))))
(defun vc-rcs-merge (file first-version &optional second-version)
"Merge changes into current working copy of FILE.
The changes are between FIRST-VERSION and SECOND-VERSION."
- (vc-do-command nil 1 "rcsmerge" (vc-name file)
+ (vc-do-command "*vc*" 1 "rcsmerge" (vc-name file)
"-kk" ; ignore keyword conflicts
(concat "-r" first-version)
(if second-version (concat "-r" second-version))))
(defun vc-rcs-steal-lock (file &optional rev)
"Steal the lock on the current workfile for FILE and revision REV.
-If FUILEis a directory, steal the lock on all registered files beneath it.
+If FILE is a directory, steal the lock on all registered files beneath it.
Needs RCS 5.6.2 or later for -M."
(if (file-directory-p file)
(mapc 'vc-rcs-steal-lock (vc-expand-dirs (list file)))
- (vc-do-command nil 0 "rcs" (vc-name file) "-M" (concat "-u" rev))
+ (vc-do-command "*vc*" 0 "rcs" (vc-name file) "-M" (concat "-u" rev))
;; Do a real checkout after stealing the lock, so that we see
;; expanded headers.
- (vc-do-command nil 0 "co" (vc-name file) "-f" (concat "-l" rev))))
+ (vc-do-command "*vc*" 0 "co" (vc-name file) "-f" (concat "-l" rev))))
(defun vc-rcs-modify-change-comment (files rev comment)
"Modify the change comments change on FILES on a specified REV. If FILE is a
directory the operation is applied to all registered files beneath it."
(dolist (file (vc-expand-dirs files))
- (vc-do-command nil 0 "rcs" (vc-name file)
+ (vc-do-command "*vc*" 0 "rcs" (vc-name file)
(concat "-m" rev ":" comment))))
\f
(defun vc-rcs-print-log (files &optional buffer)
"Get change log associated with FILE. If FILE is a
directory the operation is applied to all registered files beneath it."
- (vc-do-command buffer 0 "rlog" (mapcar 'vc-name (vc-expand-dirs files))))
+ (vc-do-command (or buffer "*vc*") 0 "rlog" (mapcar 'vc-name (vc-expand-dirs files))))
(defun vc-rcs-diff (files &optional oldvers newvers buffer)
"Get a difference report using RCS between two sets of files."
(insert (gethash (get-text-property (point) :vc-rcs-r/d/a) ht))
(forward-line 1))))
+(declare-function vc-annotate-convert-time "vc-annotate" (time))
+
(defun vc-rcs-annotate-current-time ()
"Return the current time, based at midnight of the current day, and
encoded as fractional days."
\f
;;;
-;;; Snapshot system
+;;; Tag system
;;;
-(defun vc-rcs-assign-name (file name)
- "Assign to FILE's latest version a given NAME."
- (vc-do-command nil 0 "rcs" (vc-name file) (concat "-n" name ":")))
+(defun vc-rcs-create-tag (backend dir name branchp)
+ (when branchp
+ (error "RCS backend %s does not support module branches" backend))
+ (let ((result (vc-tag-precondition dir)))
+ (if (stringp result)
+ (error "File %s is not up-to-date" result)
+ (vc-file-tree-walk
+ dir
+ (lambda (f)
+ (vc-do-command "*vc*" 0 "rcs" (vc-name f) (concat "-n" name ":")))))))
\f
;;;
;;; Internal functions
;;;
-(defun vc-rcs-root (dir)
- (vc-find-root dir "RCS" t))
-
(defun vc-rcs-workfile-is-newer (file)
"Return non-nil if FILE is newer than its RCS master.
This likely means that FILE has been changed with respect
(defun vc-rcs-fetch-master-state (file &optional working-revision)
"Compute the master file's idea of the state of FILE.
-If a WORKFILE-VERSION is given, compute the state of that version,
+If a WORKING-REVISION is given, compute the state of that version,
otherwise determine the workfile version based on the master file.
This function sets the properties `vc-working-revision' and
`vc-checkout-model' to their correct values, based on the master
(defun vc-rcs-system-release ()
"Return the RCS release installed on this system, as a string.
-Return symbol UNKNOWN if the release cannot be deducted. The user can
+Return symbol `unknown' if the release cannot be deducted. The user can
override this using variable `vc-rcs-release'.
If the user has not set variable `vc-rcs-release' and it is nil,
variable `vc-rcs-release' is set to the returned value."
(or vc-rcs-release
(setq vc-rcs-release
- (or (and (zerop (vc-do-command nil nil "rcs" nil "-V"))
+ (or (and (zerop (vc-do-command "*vc*" nil "rcs" nil "-V"))
(with-current-buffer (get-buffer "*vc*")
(vc-parse-buffer "^RCS version \\([0-9.]+ *.*\\)" 1)))
'unknown))))
(defun vc-rcs-set-non-strict-locking (file)
- (vc-do-command nil 0 "rcs" file "-U")
+ (vc-do-command "*vc*" 0 "rcs" file "-U")
(vc-file-setprop file 'vc-checkout-model 'implicit)
(set-file-modes file (logior (file-modes file) 128)))
(defun vc-rcs-set-default-branch (file branch)
- (vc-do-command nil 0 "rcs" (vc-name file) (concat "-b" branch))
+ (vc-do-command "*vc*" 0 "rcs" (vc-name file) (concat "-b" branch))
(vc-file-setprop file 'vc-rcs-default-branch branch))
(defun vc-rcs-parse (&optional buffer)