;;; admin.el --- utilities for Emacs administration
-;; Copyright (C) 2001-2015 Free Software Foundation, Inc.
+;; Copyright (C) 2001-2016 Free Software Foundation, Inc.
;; This file is part of GNU Emacs.
(defvar add-log-time-format) ; in add-log
-;; Does this information need to be in every ChangeLog, as opposed to
-;; just the top-level one? Only if you allow changes the same
-;; day as the release.
-;; http://lists.gnu.org/archive/html/emacs-devel/2013-03/msg00161.html
(defun add-release-logs (root version &optional date)
"Add \"Version VERSION released.\" change log entries in ROOT.
+Also update the etc/HISTORY file.
Root must be the root of an Emacs source tree.
Optional argument DATE is the release date, default today."
(interactive (list (read-directory-name "Emacs root directory: ")
emacs-minor-version))
(read-string "Release date: "
(progn (require 'add-log)
- (let ((add-log-time-zone-rule t))
- (funcall add-log-time-format))))))
+ (funcall add-log-time-format nil t)))))
(setq root (expand-file-name root))
(unless (file-exists-p (expand-file-name "src/emacs.c" root))
(user-error "%s doesn't seem to be the root of an Emacs source tree" root))
+ (let ((clog (expand-file-name "ChangeLog" root)))
+ (if (file-exists-p clog)
+ ;; Basic check that a ChangeLog that exists is not your personal one.
+ ;; TODO Perhaps we should move any existing file and unconditionally
+ ;; call make ChangeLog? Or make ChangeLog CHANGELOG=temp and compare
+ ;; with the existing?
+ (with-temp-buffer
+ (insert-file-contents clog)
+ (or (re-search-forward "^[ \t]*Copyright.*Free Software" nil t)
+ (user-error "ChangeLog looks like a personal one - remove it?")))
+ (or
+ (zerop (call-process "make" nil nil nil "-C" root "ChangeLog"))
+ (error "Problem generating ChangeLog"))))
(require 'add-log)
- (or date (setq date (let ((add-log-time-zone-rule t))
- (funcall add-log-time-format))))
+ (or date (setq date (funcall add-log-time-format nil t)))
(let* ((logs (process-lines "find" root "-name" "ChangeLog"))
(entry (format "%s %s <%s>\n\n\t* Version %s released.\n\n"
date
(dolist (log logs)
(find-file log)
(goto-char (point-min))
- (insert entry))))
+ (insert entry)))
+ (let ((histfile (expand-file-name "etc/HISTORY" root)))
+ (unless (file-exists-p histfile)
+ (error "%s not present" histfile))
+ (find-file histfile)
+ (goto-char (point-max))
+ (search-backward "\f")
+ (insert (format "GNU Emacs %s (%s) emacs-%s\n\n" version date version))))
(defun set-version-in-file (root file version rx)
"Subroutine of `set-version' and `set-copyright'."
(rx (and "AC_INIT" (1+ (not (in ?,)))
?, (0+ space)
(submatch (1+ (in "0-9."))))))
- ;; No longer used, broken in multiple ways, updating version seems pointless.
- (set-version-in-file root "nt/config.nt" version
- (rx (and bol "#" (0+ blank) "define" (1+ blank)
- "VERSION" (1+ blank) "\""
- (submatch (1+ (in "0-9."))))))
;; TODO: msdos could easily extract the version number from
;; configure.ac with sed, rather than duplicating the information.
(set-version-in-file root "msdos/sed2v2.inp" version
(rx (and bol "/^#undef " (1+ not-newline)
"define VERSION" (1+ space) "\""
(submatch (1+ (in "0-9."))))))
- ;; No longer used, broken in multiple ways, updating version seems pointless.
- (set-version-in-file root "nt/makefile.w32-in" version
- (rx (and "VERSION" (0+ space) "=" (0+ space)
- (submatch (1+ (in "0-9."))))))
;; Major version only.
(when (string-match "\\([0-9]\\{2,\\}\\)" version)
- (setq version (match-string 1 version))
- (set-version-in-file root "src/msdos.c" version
- (rx (and "Vwindow_system_version" (1+ not-newline)
- ?\( (submatch (1+ (in "0-9"))) ?\))))
- (set-version-in-file root "etc/refcards/ru-refcard.tex" version
- "\\\\newcommand{\\\\versionemacs}\\[0\\]\
-{\\([0-9]\\{2,\\}\\)}.+%.+version of Emacs"))
+ (let ((newmajor (match-string 1 version)))
+ (set-version-in-file root "src/msdos.c" newmajor
+ (rx (and "Vwindow_system_version" (1+ not-newline)
+ ?\( (submatch (1+ (in "0-9"))) ?\))))
+ (set-version-in-file root "etc/refcards/ru-refcard.tex" newmajor
+ "\\\\newcommand{\\\\versionemacs}\\[0\\]\
+{\\([0-9]\\{2,\\}\\)}.+%.+version of Emacs")))
+ (let* ((oldversion
+ (with-temp-buffer
+ (insert-file-contents (expand-file-name "README" root))
+ (if (re-search-forward "version \\([0-9.]*\\)" nil t)
+ (version-to-list (match-string 1)))))
+ (oldmajor (if oldversion (car oldversion)))
+ (newversion (version-to-list version))
+ (newmajor (car newversion))
+ (newshort (format "%s.%s" newmajor
+ (+ (cadr newversion)
+ (if (eq 2 (length newversion)) 0 1))))
+ (majorbump (and oldversion (not (equal oldmajor newmajor))))
+ (minorbump (and oldversion (not majorbump)
+ (not (equal (cadr oldversion) (cadr newversion)))))
+ (newsfile (expand-file-name "etc/NEWS" root))
+ (oldnewsfile (expand-file-name (format "etc/NEWS.%s" oldmajor) root)))
+ (when (and majorbump
+ (not (file-exists-p oldnewsfile)))
+ (rename-file newsfile oldnewsfile)
+ (find-file oldnewsfile) ; to prompt you to commit it
+ (copy-file oldnewsfile newsfile)
+ (with-temp-buffer
+ (insert-file-contents newsfile)
+ (re-search-forward "is about changes in Emacs version \\([0-9]+\\)")
+ (replace-match (number-to-string newmajor) nil nil nil 1)
+ (re-search-forward "^See files \\(NEWS\\)")
+ (replace-match (format "NEWS.%s, NEWS" oldmajor) nil nil nil 1)
+ (let ((start (line-beginning-position)))
+ (search-forward "in older Emacs versions")
+ (or (equal start (line-beginning-position))
+ (fill-region start (line-beginning-position 2))))
+ (re-search-forward "^\f$")
+ (forward-line -1)
+ (let ((start (point)))
+ (goto-char (point-max))
+ (re-search-backward "^\f$" nil nil 2)
+ (delete-region start (line-beginning-position 0)))
+ (write-region nil nil newsfile)))
+ (when (or majorbump minorbump)
+ (find-file newsfile)
+ (goto-char (point-min))
+ (if (re-search-forward (format "^\\* .*in Emacs %s" newshort) nil t)
+ (progn
+ (kill-buffer)
+ (message "No need to update etc/NEWS"))
+ (goto-char (point-min))
+ (re-search-forward "^\f$")
+ (forward-line -1)
+ (dolist (s '("Installation Changes" "Startup Changes" "Changes"
+ "Editing Changes"
+ "Changes in Specialized Modes and Packages"
+ "New Modes and Packages"
+ "Incompatible Lisp Changes"
+ "Lisp Changes"))
+ (insert (format "\n\f\n* %s in Emacs %s\n" s newshort)))
+ (insert (format "\n\f\n* Changes in Emacs %s on \
+Non-Free Operating Systems\n" newshort)))
+ ;; Because we skip "bump version" commits when merging between branches.
+ ;; Probably doesn't matter in practice, because NEWS changes
+ ;; will only happen on master anyway.
+ (message "Commit any NEWS changes separately")))
(message "Setting version numbers...done"))
;; Note this makes some assumptions about form of short copyright.
(rx (and bol "/^#undef " (1+ not-newline)
"define COPYRIGHT" (1+ space)
?\" (submatch (1+ (not (in ?\")))) ?\")))
- (set-version-in-file root "nt/config.nt" copyright
- (rx (and bol "#" (0+ blank) "define" (1+ blank)
- "COPYRIGHT" (1+ blank)
- ?\" (submatch (1+ (not (in ?\")))) ?\")))
(set-version-in-file root "lib-src/rcs2log" copyright
(rx (and "Copyright" (0+ space) ?= (0+ space)
?\' (submatch (1+ nonl)))))
(ps-dir (expand-file-name "ps" dest))
(pdf-dir (expand-file-name "pdf" dest))
(emacs (expand-file-name "doc/emacs/emacs.texi" root))
+ (emacs-xtra (expand-file-name "doc/emacs/emacs-xtra.texi" root))
(elisp (expand-file-name "doc/lispref/elisp.texi" root))
(eintr (expand-file-name "doc/lispintro/emacs-lisp-intro.texi" root))
(misc (manual-misc-manuals root)))
(manual-html-node emacs (expand-file-name "emacs" html-node-dir)))
(if (member type '(nil "emacs" "emacs-mono"))
(manual-html-mono emacs (expand-file-name "emacs.html" html-mono-dir)))
- (if (member type '(nil "emacs" "emacs-pdf" "pdf"))
- (manual-pdf emacs (expand-file-name "emacs.pdf" pdf-dir)))
- (if (member type '(nil "emacs" "emacs-ps" "ps"))
- (manual-ps emacs (expand-file-name "emacs.ps" ps-dir)))
+ (when (member type '(nil "emacs" "emacs-pdf" "pdf"))
+ (manual-pdf emacs (expand-file-name "emacs.pdf" pdf-dir))
+ ;; emacs-xtra exists only in pdf/ps format.
+ ;; In other formats it is included in the Emacs manual.
+ (manual-pdf emacs-xtra (expand-file-name "emacs-xtra.pdf" pdf-dir)))
+ (when (member type '(nil "emacs" "emacs-ps" "ps"))
+ (manual-ps emacs (expand-file-name "emacs.ps" ps-dir))
+ (manual-ps emacs-xtra (expand-file-name "emacs-xtra.ps" ps-dir)))
(if (member type '(nil "elisp" "elisp-node"))
(manual-html-node elisp (expand-file-name "elisp" html-node-dir)))
(if (member type '(nil "elisp" "elisp-mono"))
(defconst manual-meta-string
"<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">
-<link rev=\"made\" href=\"mailto:webmasters@gnu.org\">
+<link rev=\"made\" href=\"mailto:bug-gnu-emacs@gnu.org\">
<link rel=\"icon\" type=\"image/png\" href=\"/graphics/gnu-head-mini.png\">
<meta name=\"ICBM\" content=\"42.256233,-71.006581\">
<meta name=\"DC.title\" content=\"gnu.org\">\n\n")
(copy-file "../doc/misc/texinfo.tex" stem)
(or (equal type "emacs") (copy-file "../doc/emacs/emacsver.texi" stem))
(dolist (file (directory-files (format "../doc/%s" type) t))
- (if (or (string-match-p "\\(\\.texi\\'\\|/ChangeLog\\|/README\\'\\)" file)
+ (if (or (string-match-p "\\(\\.texi\\'\\|/README\\'\\)" file)
(and (equal type "lispintro")
(string-match-p "\\.\\(eps\\|pdf\\)\\'" file)))
(copy-file file stem)))
(and (not old)
(equal "custom" (match-string 2))
(not (memq :type form))
- (display-warning 'custom
- (format "Missing type in: `%s'" form)))
+ (display-warning
+ 'custom (format-message "Missing type in: `%s'" form)))
(setq ver (car (cdr-safe (memq :version form))))
(if (equal "group" (match-string 2))
;; Group :version could be old.
(setq grp (car (cdr-safe grp))) ; (quote foo) -> foo
(setq ver (assq grp glist))))
(setq alist (cons (cons var ver) alist))))
- (if form (message "Malformed defcustom: `%s'" form)))))
+ (if form (format-message "Malformed defcustom: `%s'" form)))))
(message "%sdone" m)
alist))
(message "No missing :version tags")
(pop-to-buffer "*cusver*")
(erase-buffer)
- (insert "These `defcustom's might be missing :version tags:\n\n")
+ (insert (substitute-command-keys
+ "These `defcustom's might be missing :version tags:\n\n"))
(dolist (elem result)
(let* ((str (file-relative-name (car elem) newdir))
(strlen (length str)))