* smerge-mode.el (smerge-start-session): Rename from smerge-auto.
[bpt/emacs.git] / lisp / vc-svn.el
index 76fdbe5..e463e13 100644 (file)
@@ -1,6 +1,6 @@
 ;;; vc-svn.el --- non-resident support for Subversion version-control
 
-;; Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 
 ;; Author:      FSF (see vc.el for full credits)
 ;; Maintainer:  Stefan Monnier <monnier@gnu.org>
 ;; Sync'd with Subversion's vc-svn.el as of revision 5801. but this version
 ;; has been extensively modified since to handle filesets.
 
-;;; Bugs:
-
-;; - VC-dired is (really) slow.
-
 ;;; Code:
 
 (eval-when-compile
@@ -136,7 +132,8 @@ If you want to force an empty list of arguments, use t."
                ;; an `error' by vc-do-command.
                (error nil))))
         (when (eq 0 status)
-          (vc-svn-parse-status file))))))
+         (not (memq (vc-svn-parse-status file) 
+                    '(ignored unregistered))))))))
 
 (defun vc-svn-state (file &optional localp)
   "SVN-specific version of `vc-state'."
@@ -151,12 +148,13 @@ If you want to force an empty list of arguments, use t."
   (vc-svn-state file 'local))
 
 (defun vc-svn-dir-state (dir &optional localp)
-  "Find the SVN state of all files in DIR."
+  "Find the SVN state of all files in DIR and its subdirectories."
   (setq localp (or localp (vc-stay-local-p dir)))
   (let ((default-directory dir))
     ;; Don't specify DIR in this command, the default-directory is
     ;; enough.  Otherwise it might fail with remote repositories.
     (with-temp-buffer
+      (buffer-disable-undo)            ;; Because these buffers can get huge
       (vc-svn-command t 0 nil "status" (if localp "-v" "-u"))
       (vc-svn-parse-status))))
 
@@ -182,8 +180,10 @@ If you want to force an empty list of arguments, use t."
     (cond ((eq svn-state 'edited)
           (if (equal (vc-working-revision file) "0")
               "(added)" "(modified)"))
-         ((eq svn-state 'needs-patch) "(patch)")
-         ((eq svn-state 'needs-merge) "(merge)"))))
+         (t
+          ;; fall back to the default VC representation
+          (vc-default-dired-state-info 'SVN file)))))
+
 
 (defun vc-svn-previous-revision (file rev)
   (let ((newrev (1- (string-to-number rev))))
@@ -367,6 +367,30 @@ The changes are between FIRST-VERSION and SECOND-VERSION."
             (error "Couldn't analyze svn update result")))
       (message "Merging changes into %s...done" 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."
+  (vc-do-command nil 0 "svn" nil "info")
+  (set-buffer "*vc*")
+  (goto-char (point-min))
+  (unless (re-search-forward "Repository Root: svn\\+ssh://\\([^/]+\\)\\(/.*\\)" nil t)
+    (error "Repository information is unavailable."))
+  (let* ((tempfile (make-temp-file user-mail-address)) 
+       (host (match-string 1))
+       (directory (match-string 2))
+       (remotefile (concat host ":" tempfile)))
+    (with-temp-buffer
+      (insert comment)
+      (write-region (point-min) (point-max) tempfile))
+    (unless (vc-do-command nil 0 "scp" nil "-q" tempfile remotefile)
+      (error "Copy of comment to %s failed" remotefile))
+    (unless (vc-do-command nil 0 "ssh" nil 
+                          "-q" host 
+                          (format "svnadmin setlog --bypass-hooks %s -r %s %s; rm %s" 
+                                  directory rev tempfile tempfile))
+      (error "Log edit failed"))
+  ))
 
 ;;;
 ;;; History functions
@@ -378,25 +402,22 @@ The changes are between FIRST-VERSION and SECOND-VERSION."
     (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.
-      ;; FIXME if there are multiple files, log-view-current-file
-      ;; breaks.  It's trivial to adapt log-view-file-re for the
-      ;; changed prefix, but less trivial to make
-      ;; log-view-current-file actually do the right thing in the
-      ;; multiple file case.
-      (insert (format "Working file%s: "
-                     (if (= (length files) 1)
-                         ""
-                       "s"))
-                     (vc-delistify (mapcar 'file-relative-name files)) "\n"))
-    (vc-svn-command
-     buffer
-     (if (and (= (length files) 1) (vc-stay-local-p (car files)) (fboundp 'start-process)) 'async 0)
-     files "log"
-     ;; By default Subversion only shows the log upto the working revision,
-     ;; whereas we also want the log of the subsequent commits.  At least
-     ;; that's what the vc-cvs.el code does.
-     "-rHEAD:0")))
+      (if files
+         (dolist (file files)
+                 (insert "Working file: " file "\n")
+                 (vc-svn-command
+                  buffer
+                  'async
+                  ;; (if (and (= (length files) 1) (vc-stay-local-p file)) 'async 0)
+                  (list file)
+                  "log"
+                  ;; By default Subversion only shows the log up to the
+                  ;; working revision, whereas we also want the log of the
+                  ;; subsequent commits.  At least that's what the
+                  ;; vc-cvs.el code does.
+                  "-rHEAD:0"))
+       ;; Dump log for the entire directory.
+       (vc-svn-command buffer 0 nil "log" "-rHEAD:0")))))
 
 (defun vc-svn-wash-log ()
   "Remove all non-comment information from log output."
@@ -422,8 +443,7 @@ The changes are between FIRST-VERSION and SECOND-VERSION."
              (list "-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.
-                      (fboundp 'start-process))))
+                      (or oldvers newvers)))) ; Svn diffs those locally.
       (apply 'vc-svn-command buffer
             (if async 'async 0)
             files "diff"
@@ -531,7 +551,7 @@ and that it passes `vc-svn-global-switches' to it before FLAGS."
           (re-search-forward "^<<<<<<< " nil t))
         ;; There are conflict markers.
         (progn
-          (smerge-mode 1)
+          (smerge-start-session)
           (add-hook 'after-save-hook 'vc-svn-resolve-when-done nil t))
       ;; There are no conflict markers.  This is problematic: maybe it means
       ;; the conflict has been resolved and we should immediately call "svn
@@ -548,15 +568,16 @@ information about FILENAME and return its status."
   (let (file status)
     (goto-char (point-min))
     (while (re-search-forward
-            ;; Ignore the files with status in [IX?].
-           "^[ ACDGMR!~][ MC][ L][ +][ S]..\\([ *]\\) +\\([-0-9]+\\) +\\([0-9?]+\\) +\\([^ ]+\\) +" nil t)
+            ;; Ignore the files with status X.
+           "^\\(\\?\\|[ ACDGIMR!~][ MC][ L][ +][ S]..\\([ *]\\) +\\([-0-9]+\\) +\\([0-9?]+\\) +\\([^ ]+\\)\\) +" nil t)
       ;; If the username contains spaces, the output format is ambiguous,
       ;; so don't trust the output's filename unless we have to.
       (setq file (or filename
                      (expand-file-name
                       (buffer-substring (point) (line-end-position)))))
       (setq status (char-after (line-beginning-position)))
-      (unless (eq status ??)
+      (if (eq status ??)
+         (vc-file-setprop file 'vc-state 'unregistered)
        ;; `vc-BACKEND-registered' must not set vc-backend,
        ;; which is instead set in vc-registered.
        (unless filename (vc-file-setprop file 'vc-backend 'SVN))
@@ -578,11 +599,15 @@ information about FILENAME and return its status."
           ;; If the file was actually copied, (match-string 2) is "-".
           (vc-file-setprop file 'vc-working-revision "0")
           (vc-file-setprop file 'vc-checkout-time 0)
-          'edited)
+          'added)
          ((memq status '(?M ?C))
           (if (eq (char-after (match-beginning 1)) ?*)
               'needs-merge
             'edited))
+         ((eq status ?I)
+          (vc-file-setprop file 'vc-state 'ignored))
+         ((eq status ?R)
+          (vc-file-setprop file 'vc-state 'removed))
          (t 'edited)))))
     (if filename (vc-file-getprop filename 'vc-state))))