;;; vc-svn.el --- non-resident support for Subversion version-control
-;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
+;; Free Software Foundation, Inc.
;; Author: FSF (see vc.el for full credits)
;; Maintainer: Stefan Monnier <monnier@gnu.org>
;;; Customization options
;;;
+;; FIXME there is also svnadmin.
+(defcustom vc-svn-program "svn"
+ "Name of the SVN executable."
+ :type 'string
+ :group 'vc)
+
(defcustom vc-svn-global-switches nil
- "*Global switches to pass to any SVN command."
+ "Global switches to pass to any SVN command."
:type '(choice (const :tag "None" nil)
(string :tag "Argument String")
(repeat :tag "Argument List"
:group 'vc)
(defcustom vc-svn-register-switches nil
- "*Extra switches for registering a file into SVN.
+ "Switches for registering a file into SVN.
A string or list of strings passed to the checkin program by
-\\[vc-register]."
- :type '(choice (const :tag "None" nil)
+\\[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 "22.1"
:group 'vc)
(defcustom vc-svn-diff-switches
t ;`svn' doesn't support common args like -c or -b.
"String or list of strings specifying extra switches for svn diff under VC.
-If nil, use the value of `vc-diff-switches'.
-If you want to force an empty list of arguments, use t."
+If nil, use the value of `vc-diff-switches' (or `diff-switches'),
+together with \"-x --diff-cmd=diff\" (since svn diff does not
+support the default \"-c\" value of `diff-switches'). If you
+want to force an empty list of arguments, use t."
:type '(choice (const :tag "Unspecified" nil)
(const :tag "None" t)
(string :tag "Argument String")
:group 'vc)
(defcustom vc-svn-header (or (cdr (assoc 'SVN vc-header-alist)) '("\$Id\$"))
- "*Header keywords to be inserted by `vc-insert-headers'."
+ "Header keywords to be inserted by `vc-insert-headers'."
:version "22.1"
:type '(repeat string)
:group 'vc)
;;;###autoload (load "vc-svn")
;;;###autoload (vc-svn-registered f))))
-;;;###autoload
-(add-to-list 'completion-ignored-extensions ".svn/")
-
(defun vc-svn-registered (file)
"Check if FILE is SVN registered."
(when (file-readable-p (expand-file-name (concat vc-svn-admin-directory
"SVN-specific state heuristic."
(vc-svn-state file 'local))
-(defun vc-svn-after-dir-status (callback)
+;; FIXME it would be better not to have the "remote" argument,
+;; but to distinguish the two output formats based on content.
+(defun vc-svn-after-dir-status (callback &optional remote)
(let ((state-map '((?A . added)
(?C . conflict)
(?D . removed)
(?? . unregistered)
;; This is what vc-svn-parse-status does.
(?~ . edited)))
+ (re (if remote "^\\(.\\)..... \\([ *]\\) +\\(?:[-0-9]+\\)? \\(.*\\)$"
+ ;; Subexp 2 is a dummy in this case, so the numbers match.
+ "^\\(.\\)....\\(.\\) \\(.*\\)$"))
result)
(goto-char (point-min))
- (while (re-search-forward "^\\(.\\)..... \\(.*\\)$" nil t)
+ (while (re-search-forward re nil t)
(let ((state (cdr (assq (aref (match-string 1) 0) state-map)))
- (filename (match-string 2)))
- (when state
+ (filename (match-string 3)))
+ (and remote (string-equal (match-string 2) "*")
+ ;; FIXME are there other possible combinations?
+ (cond ((eq state 'edited) (setq state 'needs-merge))
+ ((not state) (setq state 'needs-update))))
+ (when (and state (not (string= "." filename)))
(setq result (cons (list filename state) result)))))
(funcall callback result)))
"Run 'svn status' for DIR and update BUFFER via CALLBACK.
CALLBACK is called as (CALLBACK RESULT BUFFER), where
RESULT is a list of conses (FILE . STATE) for directory DIR."
- (vc-svn-command (current-buffer) 'async nil "status")
+ ;; FIXME should this rather be all the files in dir?
+ ;; FIXME: the vc-stay-local-p logic below is disabled, it ends up
+ ;; calling synchronously (vc-svn-registered DIR) => calling svn status -v DIR
+ ;; which is VERY SLOW for big trees and it makes emacs
+ ;; completely unresponsive during that time.
+ (let* ((local (and nil (vc-stay-local-p dir)))
+ (remote (or t (not local) (eq local 'only-file))))
+ (vc-svn-command (current-buffer) 'async nil "status"
+ (if remote "-u"))
+ (vc-exec-after
+ `(vc-svn-after-dir-status (quote ,callback) ,remote))))
+
+(defun vc-svn-dir-status-files (dir files default-state callback)
+ (apply 'vc-svn-command (current-buffer) 'async nil "status" files)
(vc-exec-after
`(vc-svn-after-dir-status (quote ,callback))))
-(defun vc-svn-status-extra-headers (dir)
+(defun vc-svn-dir-extra-headers (dir)
"Generate extra status headers for a Subversion working copy."
(vc-svn-command "*vc*" 0 nil "info")
(let ((repo
(defun vc-svn-create-repo ()
"Create a new SVN repository."
(vc-do-command "*vc*" 0 "svnadmin" '("create" "SVN"))
- (vc-do-command "*vc*" 0 "svn" '(".")
+ (vc-do-command "*vc*" 0 vc-svn-program '(".")
"checkout" (concat "file://" default-directory "SVN")))
(defun vc-svn-register (files &optional rev comment)
"Register FILES into the SVN version-control system.
The COMMENT argument is ignored This does an add but not a commit.
-
-`vc-register-switches' and `vc-svn-register-switches' are passed to
-the SVN command (in that order)."
+Passes either `vc-svn-register-switches' or `vc-register-switches'
+to the SVN command."
(apply 'vc-svn-command nil 0 files "add" (vc-switches 'SVN 'register)))
(defun vc-svn-responsible-p (file)
(defun vc-svn-modify-change-comment (files rev comment)
"Modify the change comments for a specified REV.
You must have ssh access to the repository host, and the directory Emacs
-uses locally for temp files must also be writeable by you on that host.
+uses locally for temp files must also be writable by you on that host.
This is only supported if the repository access method is either file://
or svn+ssh://."
(let (tempfile host remotefile directory fileurl-p)
(with-temp-buffer
- (vc-do-command (current-buffer) 0 "svn" nil "info")
+ (vc-do-command (current-buffer) 0 vc-svn-program nil "info")
(goto-char (point-min))
(unless (re-search-forward "Repository Root: \\(file://\\(/.*\\)\\)\\|\\(svn\\+ssh://\\([^/]+\\)\\(/.*\\)\\)" nil t)
(error "Repository information is unavailable"))
(defun vc-svn-diff (files &optional oldvers newvers buffer)
"Get a difference report using SVN between two revisions of fileset FILES."
(and oldvers
+ (not newvers)
+ files
(catch 'no
(dolist (f files)
(or (equal oldvers (vc-working-revision f))
(let* ((switches
(if vc-svn-diff-switches
(vc-switches 'SVN 'diff)
- (list "-x" (mapconcat 'identity (vc-switches nil 'diff) " "))))
+ (list "--diff-cmd=diff" "-x"
+ (mapconcat 'identity (vc-switches nil 'diff) " "))))
(async (and (not vc-disable-async-diff)
(vc-stay-local-p files)
(or oldvers newvers)))) ; Svn diffs those locally.
;;; Internal functions
;;;
-(defcustom vc-svn-program "svn"
- "Name of the SVN executable."
- :type 'string
- :group 'vc)
-
-(defun vc-svn-root (dir)
- (vc-find-root dir vc-svn-admin-directory t))
-
(defun vc-svn-command (buffer okstatus file-or-list &rest flags)
"A wrapper around `vc-do-command' for use in vc-svn.el.
The difference to vc-do-command is that this function always invokes `svn',