Replace "Maintainer: FSF" with the emacs-devel mailing address
[bpt/emacs.git] / lisp / version.el
index e63c51d..68b502c 100644 (file)
@@ -1,9 +1,9 @@
 ;;; version.el --- record version number of Emacs
 
-;; Copyright (C) 1985, 1992, 1994-1995, 1999-2012
-;;   Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1992, 1994-1995, 1999-2014 Free Software
+;; Foundation, Inc.
 
-;; Maintainer: FSF
+;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: internal
 ;; Package: emacs
 
@@ -85,42 +85,113 @@ to the system configuration; look at `system-configuration' instead."
 (defalias 'version 'emacs-version)
 
 ;; Set during dumping, this is a defvar so that it can be setq'd.
-(defvar emacs-bzr-version nil
-  "String giving the bzr revision from which this Emacs was built.
-Value is the bzr revision number and a revision ID separated by a blank.
-Value is nil if Emacs was not built from a bzr checkout, or if we could
-not determine the revision.")
-
-(defun emacs-bzr-get-version (&optional dir)
-  "Try to return as a string the bzr revision number of the Emacs sources.
-Value is the bzr revision number and a revision ID separated by a blank.
-Value is nil if the sources do not seem to be under bzr, or if we could
-not determine the revision.  Note that this reports on the current state
-of the sources, which may not correspond to the running Emacs.
-
-Optional argument DIR is a directory to use instead of `source-directory'."
+(defvar emacs-repository-version nil
+  "String giving the repository revision from which this Emacs was built.
+Value is nil if Emacs was not built from a repository checkout,
+or if we could not determine the revision.")
+
+(define-obsolete-variable-alias 'emacs-bzr-version
+                                'emacs-repository-version "24.4")
+
+(defun emacs-bzr-version-dirstate (dir)
+  "Try to return as a string the bzr revision ID of directory DIR.
+This uses the dirstate file's parent revision entry.
+Returns nil if unable to find this information."
+  (let ((file (expand-file-name ".bzr/checkout/dirstate" dir)))
+    (when (file-readable-p file)
+      (with-temp-buffer
+        (insert-file-contents file)
+        (and (looking-at "#bazaar dirstate flat format 3")
+             (forward-line 3)
+             (looking-at "[0-9]+\0\\([^\0\n]+\\)\0")
+             (match-string 1))))))
+
+(defun emacs-bzr-version-bzr (dir)
+  "Ask bzr itself for the version information for directory DIR."
+  ;; Comments on `bzr version-info':
+  ;; i) Unknown files also cause clean != 1.
+  ;; ii) It can be slow, contacting the upstream repo to get the
+  ;; branch nick if one is not set locally, even with a custom
+  ;; template that is not asking for the nick (as used here).  You'd
+  ;; think the latter part would be trivial to fix:
+  ;; https://bugs.launchpad.net/bzr/+bug/882541/comments/3
+  ;; https://bugs.launchpad.net/bzr/+bug/629150
+  ;; You can set the nick locally with `bzr nick ...', which speeds
+  ;; things up enormously.  `bzr revno' does not have this issue, but
+  ;; has no way to print the revision_id AFAICS.
+  (message "Waiting for bzr...")
+  (with-temp-buffer
+    (if (zerop
+         (call-process "bzr" nil '(t nil) nil "version-info"
+                       "--custom"
+                       "--template={revno} {revision_id} (clean = {clean})"
+                       dir))
+        (buffer-string))))
+
+(define-obsolete-function-alias 'emacs-bzr-get-version
+                                'emacs-repository-get-version "24.4")
+
+(defun emacs-repository-get-version (&optional dir external)
+  "Try to return as a string the repository revision of the Emacs sources.
+The format of the returned string is dependent on the VCS in use.
+Value is nil if the sources do not seem to be under version
+control, or if we could not determine the revision.  Note that
+this reports on the current state of the sources, which may not
+correspond to the running Emacs.
+
+Optional argument DIR is a directory to use instead of
+`source-directory'.  Optional argument EXTERNAL non-nil means to
+maybe ask the VCS itself, if the sources appear to be under
+version control.  If `force', always ask.  the VCS. Otherwise
+only ask the VCS if we cannot find any information ourselves."
   (or dir (setq dir source-directory))
-  (when (file-directory-p (setq dir (expand-file-name ".bzr/branch" dir)))
-    (let (file loc)
-      (cond ((file-readable-p
-              (setq file (expand-file-name "last-revision" dir)))
-             (with-temp-buffer
-               (insert-file-contents file)
-               (goto-char (point-max))
-               (if (looking-back "\n")
-                   (delete-char -1))
-               (buffer-string)))
-            ;; OK, no last-revision.  Is it a lightweight checkout?
-            ((file-readable-p
-              (setq file (expand-file-name "location" dir)))
-             ;; If the parent branch is local, try looking there for the revid.
-             (if (setq loc (with-temp-buffer
-                             (insert-file-contents file)
-                             (if (looking-at "file://\\(.*\\)")
-                                 (match-string 1))))
-                 (emacs-bzr-get-version loc)))
-            ;; Could fall back to eg `bzr testament' at this point.
-            ))))
+  (cond ((file-directory-p (expand-file-name ".bzr/branch" dir))
+        (if (eq external 'force)
+            (emacs-bzr-version-bzr dir)
+          (let (file loc rev)
+            (cond ((file-readable-p
+                    (setq file (expand-file-name
+                                ".bzr/branch/last-revision" dir)))
+                   (with-temp-buffer
+                     (insert-file-contents file)
+                     (goto-char (point-max))
+                     (if (looking-back "\n")
+                         (delete-char -1))
+                     (buffer-string)))
+                  ;; OK, no last-revision.  Is it a lightweight checkout?
+                  ((file-readable-p
+                    (setq file (expand-file-name ".bzr/branch/location" dir)))
+                   (setq rev (emacs-bzr-version-dirstate dir))
+                   ;; If parent branch is local, try looking there for the rev.
+                   ;; Note: there is no guarantee that the parent branch's rev
+                   ;; corresponds to this branch.  This branch could have
+                   ;; been made with a specific -r revno argument, or the
+                   ;; parent could have been updated since this branch was
+                   ;; created.
+                   ;; To try and detect this, we check the dirstate revids
+                   ;; to see if they match.
+                   (if (and (setq loc (with-temp-buffer
+                                        (insert-file-contents file)
+                                        (if (looking-at "file://\\(.*\\)")
+                                            (match-string 1))))
+                            (equal rev (emacs-bzr-version-dirstate loc)))
+                       (emacs-repository-get-version loc)
+                     ;; If parent does not match, the best we can do without
+                     ;; calling external commands is to use the dirstate rev.
+                     rev))
+                  (external
+                   (emacs-bzr-version-bzr dir))))))
+       ((file-directory-p (expand-file-name ".git" dir))
+        (message "Waiting for git...")
+        (with-temp-buffer
+          (let ((default-directory (file-name-as-directory dir)))
+            (and (eq 0
+                     (condition-case nil
+                         (call-process "git" nil '(t nil) nil "log"
+                                       "-1" "--pretty=format:%N")
+                       (error nil)))
+                 (not (zerop (buffer-size)))
+                 (replace-regexp-in-string "\n" "" (buffer-string))))))))
 
 ;; We put version info into the executable in the form that `ident' uses.
 (purecopy (concat "\n$Id: " (subst-char-in-string ?\n ?\s (emacs-version))