X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/7ffc77d367eff5e8bc16a36a7cfaacf67ddde6e1..1b74c4346e92c9ac1ae0575c2ad69f8d81126d7e:/lisp/vc-svn.el diff --git a/lisp/vc-svn.el b/lisp/vc-svn.el index aeea2ff5b2..de34fa847e 100644 --- a/lisp/vc-svn.el +++ b/lisp/vc-svn.el @@ -1,6 +1,6 @@ ;;; vc-svn.el --- non-resident support for Subversion version-control -;; Copyright (C) 1995,98,99,2000,2001,2002 Free Software Foundation, Inc. +;; Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. ;; Author: FSF (see vc.el for full credits) ;; Maintainer: Stefan Monnier @@ -19,8 +19,8 @@ ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. ;;; Commentary: @@ -50,7 +50,7 @@ (repeat :tag "Argument List" :value ("") string)) - :version "21.4" + :version "22.1" :group 'vc) (defcustom vc-svn-register-switches nil @@ -62,32 +62,38 @@ A string or list of strings passed to the checkin program by (repeat :tag "Argument List" :value ("") string)) - :version "21.4" + :version "22.1" :group 'vc) -(defcustom vc-svn-diff-switches nil - "*A string or list of strings specifying extra switches for svn diff under VC." - :type '(choice (const :tag "None" nil) +(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." + :type '(choice (const :tag "Unspecified" nil) + (const :tag "None" t) (string :tag "Argument String") (repeat :tag "Argument List" :value ("") string)) - :version "21.4" + :version "22.1" :group 'vc) (defcustom vc-svn-header (or (cdr (assoc 'SVN vc-header-alist)) '("\$Id\$")) "*Header keywords to be inserted by `vc-insert-headers'." - :version "21.4" + :version "22.1" :type '(repeat string) :group 'vc) -(defcustom vc-svn-use-edit nil +(defconst vc-svn-use-edit nil + ;; Subversion does not provide this feature (yet). "*Non-nil means to use `svn edit' to \"check out\" a file. This is only meaningful if you don't use the implicit checkout model \(i.e. if you have $SVNREAD set)." - :type 'boolean - :version "21.4" - :group 'vc) + ;; :type 'boolean + ;; :version "22.1" + ;; :group 'vc + ) ;;; ;;; State-querying functions @@ -99,6 +105,9 @@ This is only meaningful if you don't use the implicit checkout model ;;;###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 ".svn/entries" @@ -148,6 +157,9 @@ This is only meaningful if you don't use the implicit checkout model ;; It looks like Subversion has no equivalent of CVSREAD. 'implicit) +;; vc-svn-mode-line-string doesn't exist because the default implementation +;; works just fine. + (defun vc-svn-dired-state-info (file) "SVN-specific version of `vc-dired-state-info'." (let ((svn-state (vc-state file))) @@ -168,11 +180,7 @@ COMMENT can be used to provide an initial description of FILE. `vc-register-switches' and `vc-svn-register-switches' are passed to the SVN command (in that order)." - (apply 'vc-svn-command nil 0 file - "add" - ;; (and comment (string-match "[^\t\n ]" comment) - ;; (concat "-m" comment)) - (vc-switches 'SVN 'register))) + (apply 'vc-svn-command nil 0 file "add" (vc-switches 'SVN 'register))) (defun vc-svn-responsible-p (file) "Return non-nil if SVN thinks it is responsible for FILE." @@ -187,8 +195,9 @@ This is only possible if SVN is responsible for FILE's directory.") (defun vc-svn-checkin (file rev comment) "SVN-specific version of `vc-backend-checkin'." - (let ((status (apply 'vc-svn-command nil 1 file - "ci" (list* "-m" comment (vc-switches 'SVN 'checkin))))) + (let ((status (apply + 'vc-svn-command nil 1 file "ci" + (nconc (list "-m" comment) (vc-switches 'SVN 'checkin))))) (set-buffer "*vc*") (goto-char (point-min)) (unless (equal status 0) @@ -237,15 +246,18 @@ This is only possible if SVN is responsible for FILE's directory.") ;; Check out a particular version (or recreate the file). (vc-file-setprop file 'vc-workfile-version nil) (apply 'vc-svn-command nil 0 file - "-w" "update" ;; default for verbose checkout: clear the sticky tag so ;; that the actual update will get the head of the trunk - (if (or (not rev) (string= rev "")) - "-A" - (concat "-r" rev)) + (cond + ((null rev) "-rBASE") + ((or (eq rev t) (equal rev "")) nil) + (t (concat "-r" rev))) switches))) +(defun vc-svn-delete-file (file) + (vc-svn-command nil 0 file "remove")) + (defun vc-svn-rename-file (old new) (vc-svn-command nil 0 new "move" (file-relative-name old))) @@ -323,21 +335,26 @@ The changes are between FIRST-VERSION and SECOND-VERSION." ;;; History functions ;;; -(defun vc-svn-print-log (file) +(defun vc-svn-print-log (file &optional buffer) "Get change log associated with FILE." (save-current-buffer - (vc-setup-buffer nil) + (vc-setup-buffer buffer) (let ((inhibit-read-only t)) (goto-char (point-min)) ;; Add a line to tell log-view-mode what file this is. (insert "Working file: " (file-relative-name file) "\n")) (vc-svn-command - t + buffer (if (and (vc-stay-local-p file) (fboundp 'start-process)) 'async 0) file "log"))) -(defun vc-svn-diff (file &optional oldvers newvers) +(defun vc-svn-diff (file &optional oldvers newvers buffer) "Get a difference report using SVN between two versions of FILE." + (unless buffer (setq buffer "*vc-diff*")) + (if (and oldvers (equal oldvers (vc-workfile-version file))) + ;; Use nil rather than the current revision because svn handles it + ;; better (i.e. locally). + (setq oldvers nil)) (if (string= (vc-workfile-version file) "0") ;; This file is added but not yet committed; there is no master file. (if (or oldvers newvers) @@ -345,54 +362,35 @@ The changes are between FIRST-VERSION and SECOND-VERSION." ;; We regard this as "changed". ;; Diff it against /dev/null. ;; Note: this is NOT a "svn diff". - (apply 'vc-do-command "*vc-diff*" + (apply 'vc-do-command buffer 1 "diff" file (append (vc-switches nil 'diff) '("/dev/null"))) ;; Even if it's empty, it's locally modified. 1) - (let* ((switches (vc-switches 'SVN 'diff)) - (async (and (vc-stay-local-p file) + (let* ((switches + (if vc-svn-diff-switches + (vc-switches 'SVN 'diff) + (list "-x" (mapconcat 'identity (vc-switches nil 'diff) " ")))) + (async (and (not vc-disable-async-diff) + (vc-stay-local-p file) (or oldvers newvers) ; Svn diffs those locally. (fboundp 'start-process)))) - (apply 'vc-svn-command "*vc-diff*" + (apply 'vc-svn-command buffer (if async 'async 0) file "diff" (append - (when switches - (list "-x" (mapconcat 'identity switches " "))) + switches (when oldvers (list "-r" (if newvers (concat oldvers ":" newvers) oldvers))))) (if async 1 ; async diff => pessimistic assumption ;; For some reason `svn diff' does not return a useful ;; status w.r.t whether the diff was empty or not. - (buffer-size (get-buffer "*vc-diff*")))))) + (buffer-size (get-buffer buffer)))))) (defun vc-svn-diff-tree (dir &optional rev1 rev2) "Diff all files at and below DIR." - (with-current-buffer "*vc-diff*" - (setq default-directory dir) - (if (vc-stay-local-p dir) - ;; local diff: do it filewise, and only for files that are modified - (vc-file-tree-walk - dir - (lambda (f) - (vc-exec-after - `(let ((coding-system-for-read (vc-coding-system-for-diff ',f))) - ;; possible optimization: fetch the state of all files - ;; in the tree via vc-svn-dir-state-heuristic - (unless (vc-up-to-date-p ',f) - (message "Looking at %s" ',f) - (vc-diff-internal ',f ',rev1 ',rev2)))))) - ;; svn diff: use a single call for the entire tree - (let ((coding-system-for-read (or coding-system-for-read 'undecided)) - (switches (vc-switches 'SVN 'diff))) - (apply 'vc-svn-command "*vc-diff*" 1 nil "diff" - (append - (when rev1 - (list "-r" (if rev2 (concat rev1 ":" rev2) rev1))) - (when switches - (list "-x" (mapconcat 'identity switches " "))))))))) + (vc-svn-diff (file-name-as-directory dir) rev1 rev2)) ;;; ;;; Snapshot system @@ -401,46 +399,19 @@ The changes are between FIRST-VERSION and SECOND-VERSION." (defun vc-svn-create-snapshot (dir name branchp) "Assign to DIR's current version a given NAME. If BRANCHP is non-nil, the name is created as a branch (and the current -workspace is immediately moved to that new branch)." - (vc-svn-command nil 0 dir "tag" "-c" (if branchp "-b") name) - (when branchp (vc-svn-command nil 0 dir "update" "-r" name))) +workspace is immediately moved to that new branch). +NAME is assumed to be a URL." + (vc-svn-command nil 0 dir "copy" name) + (when branchp (vc-svn-retrieve-snapshot dir name nil))) (defun vc-svn-retrieve-snapshot (dir name update) "Retrieve a snapshot at and below DIR. NAME is the name of the snapshot; if it is empty, do a `svn update'. -If UPDATE is non-nil, then update (resynch) any affected buffers." - (with-current-buffer (get-buffer-create "*vc*") - (let ((default-directory dir) - (sticky-tag)) - (erase-buffer) - (if (or (not name) (string= name "")) - (vc-svn-command t 0 nil "update") - (vc-svn-command t 0 nil "update" "-r" name) - (setq sticky-tag name)) - (when update - (goto-char (point-min)) - (while (not (eobp)) - (if (looking-at "\\([CMUP]\\) \\(.*\\)") - (let* ((file (expand-file-name (match-string 2) dir)) - (state (match-string 1)) - (buffer (find-buffer-visiting file))) - (when buffer - (cond - ((or (string= state "U") - (string= state "P")) - (vc-file-setprop file 'vc-state 'up-to-date) - (vc-file-setprop file 'vc-workfile-version nil) - (vc-file-setprop file 'vc-checkout-time - (nth 5 (file-attributes file)))) - ((or (string= state "M") - (string= state "C")) - (vc-file-setprop file 'vc-state 'edited) - (vc-file-setprop file 'vc-workfile-version nil) - (vc-file-setprop file 'vc-checkout-time 0))) - (vc-file-setprop file 'vc-svn-sticky-tag sticky-tag) - (vc-resynch-buffer file t t)))) - (forward-line 1)))))) - +If UPDATE is non-nil, then update (resynch) any affected buffers. +NAME is assumed to be a URL." + (vc-svn-command nil 0 dir "switch" name) + ;; FIXME: parse the output and obey `update'. + ) ;;; ;;; Miscellaneous @@ -480,10 +451,14 @@ and that it passes `vc-svn-global-switches' to it before FLAGS." (vc-insert-file (expand-file-name ".svn/entries" dirname))) (goto-char (point-min)) (when (re-search-forward - (concat "name=\"svn:this_dir\"[\n\t ]*" - "\\([-a-z]+=\"[^\"]*\"[\n\t ]*\\)*?" + ;; Old `svn' used name="svn:dir", newer use just name="". + (concat "name=\"\\(?:svn:this_dir\\)?\"[\n\t ]*" + "\\(?:[-a-z]+=\"[^\"]*\"[\n\t ]*\\)*?" "url=\"\\([^\"]+\\)\"") nil t) - (match-string 2)))) + ;; This is not a hostname but a URL. This may actually be considered + ;; as a feature since it allows vc-svn-stay-local to specify different + ;; behavior for different modules on the same server. + (match-string 1)))) (defun vc-svn-parse-status (localp) "Parse output of \"svn status\" command in the current buffer. @@ -538,6 +513,31 @@ essential information." (and (string-match "^[0-9]" tag) (not (string-match "[^0-9]" tag)))) +;; Support for `svn annotate' + +(defun vc-svn-annotate-command (file buf &optional rev) + (vc-svn-command buf 0 file "annotate" (if rev (concat "-r" rev)))) + +(defun vc-svn-annotate-time-of-rev (rev) + ;; Arbitrarily assume 10 commmits per day. + (/ (string-to-number rev) 10.0)) + +(defun vc-svn-annotate-current-time () + (vc-svn-annotate-time-of-rev vc-annotate-parent-rev)) + +(defconst vc-svn-annotate-re "[ \t]*\\([0-9]+\\)[ \t]+[^\t ]+ ") + +(defun vc-svn-annotate-time () + (when (looking-at vc-svn-annotate-re) + (goto-char (match-end 0)) + (vc-svn-annotate-time-of-rev (match-string 1)))) + +(defun vc-svn-annotate-extract-revision-at-line () + (save-excursion + (beginning-of-line) + (if (looking-at vc-svn-annotate-re) (match-string 1)))) + (provide 'vc-svn) +;; arch-tag: 02f10c68-2b4d-453a-90fc-1eee6cfb268d ;;; vc-svn.el ends here