version.el 7.47 KB
Newer Older
1
;;; version.el --- record version number of Emacs
Dave Love's avatar
#  
Dave Love committed
2

3
;; Copyright (C) 1985, 1992, 1994-1995, 1999-2014 Free Software
4
;; Foundation, Inc.
Dave Love's avatar
#  
Dave Love committed
5 6 7

;; Maintainer: FSF
;; Keywords: internal
8
;; Package: emacs
Dave Love's avatar
#  
Dave Love committed
9 10 11

;; This file is part of GNU Emacs.

12
;; GNU Emacs is free software: you can redistribute it and/or modify
Dave Love's avatar
#  
Dave Love committed
13
;; it under the terms of the GNU General Public License as published by
14 15
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
Dave Love's avatar
#  
Dave Love committed
16 17 18 19 20 21 22

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
23
;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
Dave Love's avatar
#  
Dave Love committed
24

25 26
;;; Commentary:

Dave Love's avatar
#  
Dave Love committed
27 28
;;; Code:

29 30 31 32
(defconst emacs-major-version
  (progn (string-match "^[0-9]+" emacs-version)
         (string-to-number (match-string 0 emacs-version)))
  "Major version number of this version of Emacs.
Dave Love's avatar
#  
Dave Love committed
33 34
This variable first existed in version 19.23.")

35 36 37 38
(defconst emacs-minor-version
  (progn (string-match "^[0-9]+\\.\\([0-9]+\\)" emacs-version)
         (string-to-number (match-string 1 emacs-version)))
  "Minor version number of this version of Emacs.
Dave Love's avatar
#  
Dave Love committed
39 40
This variable first existed in version 19.23.")

41 42
(defconst emacs-build-time (current-time)
  "Time at which Emacs was dumped out.")
Dave Love's avatar
#  
Dave Love committed
43

44 45
(defconst emacs-build-system (system-name)
  "Name of the system on which Emacs was built.")
Dave Love's avatar
#  
Dave Love committed
46

47 48 49 50
(defvar motif-version-string)
(defvar gtk-version-string)
(defvar ns-version-string)

51 52
(defun emacs-version (&optional here)
  "Return string describing the version of Emacs that is running.
Dave Love's avatar
#  
Dave Love committed
53 54 55 56
If optional argument HERE is non-nil, insert string at point.
Don't use this function in programs to choose actions according
to the system configuration; look at `system-configuration' instead."
  (interactive "P")
57
  (let ((version-string
58
         (format (if (not (called-interactively-p 'interactive))
59 60
		     "GNU Emacs %s (%s%s%s)\n of %s on %s"
		   "GNU Emacs %s (%s%s%s) of %s on %s")
Dave Love's avatar
#  
Dave Love committed
61 62
                 emacs-version
		 system-configuration
63
		 (cond ((featurep 'motif)
64
			(concat ", " (substring motif-version-string 4)))
65 66
		       ((featurep 'gtk)
			(concat ", GTK+ Version " gtk-version-string))
67
		       ((featurep 'x-toolkit) ", X toolkit")
Dan Nicolaescu's avatar
Dan Nicolaescu committed
68
		       ((featurep 'ns)
69
			(format ", NS %s" ns-version-string))
Dave Love's avatar
#  
Dave Love committed
70
		       (t ""))
71 72 73 74 75
		 (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)))
		   "")
76
		 (format-time-string "%Y-%m-%d" emacs-build-time)
Dave Love's avatar
#  
Dave Love committed
77
                 emacs-build-system)))
78
    (if here
Dave Love's avatar
#  
Dave Love committed
79
        (insert version-string)
80
      (if (called-interactively-p 'interactive)
Dave Love's avatar
#  
Dave Love committed
81 82 83
          (message "%s" version-string)
        version-string))))

Stefan Monnier's avatar
Stefan Monnier committed
84
;; We hope that this alias is easier for people to find.
Dave Love's avatar
#  
Dave Love committed
85 86
(defalias 'version 'emacs-version)

Glenn Morris's avatar
Glenn Morris committed
87
;; Set during dumping, this is a defvar so that it can be setq'd.
88 89
(defvar emacs-bzr-version nil
  "String giving the bzr revision from which this Emacs was built.
90
The format is: [revno] revision_id, where revno may be absent.
91
Value is nil if Emacs was not built from a bzr checkout, or if we could
Glenn Morris's avatar
Glenn Morris committed
92 93
not determine the revision.")

94 95 96 97 98 99 100 101 102 103 104 105 106
(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))))))

107
(defun emacs-bzr-version-bzr (_dir)
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
  "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))))

(defun emacs-bzr-get-version (&optional dir external)
130 131
  "Try to return as a string the bzr revision of the Emacs sources.
The format is: [revno] revision_id, where revno may be absent.
132
Value is nil if the sources do not seem to be under bzr, or if we could
Glenn Morris's avatar
Glenn Morris committed
133
not determine the revision.  Note that this reports on the current state
Glenn Morris's avatar
Glenn Morris committed
134 135
of the sources, which may not correspond to the running Emacs.

136 137 138 139
Optional argument DIR is a directory to use instead of `source-directory'.
Optional argument EXTERNAL non-nil means to maybe ask `bzr' itself,
if the sources appear to be under bzr.  If `force', always ask bzr.
Otherwise only ask bzr if we cannot find any information ourselves."
Glenn Morris's avatar
Glenn Morris committed
140
  (or dir (setq dir source-directory))
141
  (when (file-directory-p (expand-file-name ".bzr/branch" dir))
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
    (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 the 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-bzr-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)))))))
Glenn Morris's avatar
Glenn Morris committed
175

Richard M. Stallman's avatar
Richard M. Stallman committed
176
;; We put version info into the executable in the form that `ident' uses.
177 178
(purecopy (concat "\n$Id: " (subst-char-in-string ?\n ?\s (emacs-version))
		  " $\n"))
Dave Love's avatar
#  
Dave Love committed
179 180

;;; version.el ends here