]> code.delx.au - gnu-emacs/blobdiff - lisp/version.el
Update docs for `customize-mode'
[gnu-emacs] / lisp / version.el
index 75763b3f68221cb2d4363e91bba05772a01f987b..77188a51ee3b03e5f5895b85a2a89fe406805937 100644 (file)
@@ -1,6 +1,6 @@
 ;;; version.el --- record version number of Emacs
 
-;; Copyright (C) 1985, 1992, 1994-1995, 1999-2015 Free Software
+;; Copyright (C) 1985, 1992, 1994-1995, 1999-2016 Free Software
 ;; Foundation, Inc.
 
 ;; Maintainer: emacs-devel@gnu.org
@@ -41,12 +41,15 @@ This variable first existed in version 19.23.")
 (defconst emacs-build-time (current-time)
   "Time at which Emacs was dumped out.")
 
+;; I think this should be obsoleted/removed.  It's just one more meaningless
+;; difference between different builds.  It's usually not even an fqdn.
 (defconst emacs-build-system (system-name)
   "Name of the system on which Emacs was built.")
 
 (defvar motif-version-string)
 (defvar gtk-version-string)
 (defvar ns-version-string)
+(defvar cairo-version-string)
 
 (defun emacs-version (&optional here)
   "Return string describing the version of Emacs that is running.
@@ -56,8 +59,8 @@ to the system configuration; look at `system-configuration' instead."
   (interactive "P")
   (let ((version-string
          (format (if (not (called-interactively-p 'interactive))
-                    "GNU Emacs %s (%s%s%s)\n of %s on %s"
-                  "GNU Emacs %s (%s%s%s) of %s on %s")
+                    "GNU Emacs %s (%s%s%s%s)\n of %s"
+                  "GNU Emacs %s (%s%s%s%s) of %s")
                  emacs-version
                 system-configuration
                 (cond ((featurep 'motif)
@@ -68,13 +71,15 @@ to the system configuration; look at `system-configuration' instead."
                       ((featurep 'ns)
                        (format ", NS %s" ns-version-string))
                       (t ""))
+                (if (featurep 'cairo)
+                    (format ", cairo version %s" cairo-version-string)
+                  "")
                 (if (and (boundp 'x-toolkit-scroll-bars)
                          (memq x-toolkit-scroll-bars '(xaw xaw3d)))
                     (format ", %s scroll bars"
                             (capitalize (symbol-name x-toolkit-scroll-bars)))
                   "")
-                (format-time-string "%Y-%m-%d" emacs-build-time)
-                 emacs-build-system)))
+                (format-time-string "%Y-%m-%d" emacs-build-time))))
     (if here
         (insert version-string)
       (if (called-interactively-p 'interactive)
@@ -93,44 +98,33 @@ 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-version-git (dir)
+  "Ask git itself for the version information for directory DIR."
+  (message "Waiting for git...")
+  (with-temp-buffer
+    (let ((default-directory (file-name-as-directory dir)))
+      (and (eq 0
+              (with-demoted-errors "Error running git rev-parse: %S"
+                (call-process "git" nil '(t nil) nil "rev-parse" "HEAD")))
+          (progn (goto-char (point-min))
+                 (looking-at "[0-9a-fA-F]\\{40\\}"))
+          (match-string 0)))))
+
+(defun emacs-repository--version-git-1 (file dir)
+  "Internal subroutine of `emacs-repository-get-version'."
+  (when (file-readable-p file)
+    (with-temp-buffer
+      (insert-file-contents file)
+      (cond ((looking-at "[0-9a-fA-F]\\{40\\}")
+             (match-string 0))
+            ((looking-at "ref: \\(.*\\)")
+             (emacs-repository--version-git-1
+              (expand-file-name (match-string 1) dir)
+              dir))))))
+
 (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.
@@ -139,59 +133,43 @@ 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."
+Optional argument DIR is a directory to use instead of `source-directory'.
+Optional argument EXTERNAL non-nil means to just ask the VCS itself,
+if the sources appear to be under version control.  Otherwise only ask
+the VCS if we cannot find any information ourselves."
   (or dir (setq dir source-directory))
-  (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 "rev-parse"
-                                       "HEAD")
-                       (error nil)))
-                 (not (zerop (buffer-size)))
-                 (replace-regexp-in-string "\n" "" (buffer-string))))))))
+  (let* ((base-dir (expand-file-name ".git" dir))
+         (in-main-worktree (file-directory-p base-dir))
+         (in-linked-worktree nil)
+         sub-dir)
+    ;; If the sources are in a linked worktree, .git is a file that points to
+    ;; the location of the main worktree and the repo's administrative files.
+    (when (and (not in-main-worktree)
+               (file-regular-p base-dir)
+               (file-readable-p base-dir))
+      (with-temp-buffer
+        (insert-file-contents base-dir)
+        (when (looking-at "gitdir: \\(.*\.git\\)\\(.*\\)$")
+          (setq base-dir (match-string 1)
+                sub-dir (concat base-dir (match-string 2))
+                in-linked-worktree t))))
+    ;; We've found a worktree, either main or linked.
+    (when (or in-main-worktree in-linked-worktree)
+      (if external
+          (emacs-repository-version-git dir)
+        (or (if in-linked-worktree
+                (emacs-repository--version-git-1
+                 (expand-file-name "HEAD" sub-dir) base-dir)
+              (let ((files '("HEAD" "refs/heads/master"))
+                    file rev)
+                (while (and (not rev)
+                            (setq file (car files)))
+                  (setq file (expand-file-name file base-dir)
+                        files (cdr files)
+                        rev (emacs-repository--version-git-1 file base-dir)))
+                rev))
+            ;; AFAICS this doesn't work during dumping (bug#20799).
+            (emacs-repository-version-git dir))))))
 
 ;; 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))