]> code.delx.au - gnu-emacs/blobdiff - admin/admin.el
gnus-start.el (gnus-clean-old-newsrc): Always remove 'unexist' marks if `gnus-newsrc...
[gnu-emacs] / admin / admin.el
index c71e6539413c85253003901ce75c5db191e81222..927f68e978a3427670d85e860800b5878646a6b2 100644 (file)
@@ -1,6 +1,6 @@
 ;;; admin.el --- utilities for Emacs administration
 
-;; Copyright (C) 2001-201 Free Software Foundation, Inc.
+;; Copyright (C) 2001-2013 Free Software Foundation, Inc.
 
 ;; This file is part of GNU Emacs.
 
 
 (defvar add-log-time-format)           ; in add-log
 
-(defun add-release-logs (root version)
+;; 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.
-Root must be the root of an Emacs source tree."
-  (interactive "DEmacs root directory: \nNVersion number: ")
+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: ")
+                    (read-string "Version number: "
+                                 (format "%s.%s" emacs-major-version
+                                         emacs-minor-version))
+                    (read-string "Release date: "
+                                 (progn (require 'add-log)
+                                        (let ((add-log-time-zone-rule t))
+                                          (funcall add-log-time-format))))))
   (setq root (expand-file-name root))
   (unless (file-exists-p (expand-file-name "src/emacs.c" root))
     (error "%s doesn't seem to be the root of an Emacs source tree" root))
   (require 'add-log)
+  (or date (setq date (let ((add-log-time-zone-rule t))
+                       (funcall add-log-time-format))))
   (let* ((logs (process-lines "find" root "-name" "ChangeLog"))
         (entry (format "%s  %s  <%s>\n\n\t* Version %s released.\n\n"
-                       (funcall add-log-time-format)
+                       date
                        (or add-log-full-name (user-full-name))
                        (or add-log-mailing-address user-mail-address)
                        version)))
     (dolist (log logs)
-      (unless (string-match "/gnus/" log)
-       (find-file log)
-       (goto-char (point-min))
-       (insert entry)))))
+      (find-file log)
+      (goto-char (point-min))
+      (insert entry))))
 
 (defun set-version-in-file (root file version rx)
   (find-file (expand-file-name file root))
@@ -158,6 +171,10 @@ Root must be the root of an Emacs source tree."
   (set-version-in-file root "configure.ac" copyright
                       (rx (and bol "copyright" (0+ (not (in ?\")))
                                ?\" (submatch (1+ (not (in ?\")))) ?\")))
+  (set-version-in-file root "msdos/sed2v2.inp" 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)
@@ -176,54 +193,82 @@ Root must be the root of an Emacs source tree."
 
 ;;; Various bits of magic for generating the web manuals
 
-(defun make-manuals (root)
-  "Generate the web manuals for the Emacs webpage."
-  (interactive "DEmacs root directory: ")
+(defun manual-misc-manuals (root)
+  "Return doc/misc manuals as list of strings."
+  ;; Like `make -C doc/misc echo-info', but works if unconfigured.
+  (with-temp-buffer
+    (insert-file-contents (expand-file-name "doc/misc/Makefile.in" root))
+    (search-forward "INFO_TARGETS = ")
+    (let ((start (point))
+         res)
+      (end-of-line)
+      (while (and (looking-back "\\\\")
+                 (zerop (forward-line 1)))
+       (end-of-line))
+      (split-string (replace-regexp-in-string
+                    "\\(\\\\\\|\\.info\\)" ""
+                    (buffer-substring start (point)))))))
+
+(defun make-manuals (root &optional type)
+  "Generate the web manuals for the Emacs webpage.
+Interactively with a prefix argument, prompt for TYPE.
+Optional argument TYPE is type of output (nil means all)."
+  (interactive (let ((root (read-directory-name "Emacs root directory: "
+                                               source-directory nil t)))
+                (list root
+                      (if current-prefix-arg
+                          (completing-read
+                           "Type: "
+                           (append
+                            '("misc" "pdf" "ps")
+                            (let (res)
+                              (dolist (i '("emacs" "elisp" "eintr") res)
+                                (dolist (j '("" "-mono" "-node" "-ps" "-pdf"))
+                                  (push (concat i j) res))))
+                            (manual-misc-manuals root)))))))
   (let* ((dest (expand-file-name "manual" root))
         (html-node-dir (expand-file-name "html_node" dest))
         (html-mono-dir (expand-file-name "html_mono" dest))
-        (txt-dir (expand-file-name "text" dest))
-        (dvi-dir (expand-file-name "dvi" dest))
-        (ps-dir (expand-file-name "ps" dest)))
+        (ps-dir (expand-file-name "ps" dest))
+        (pdf-dir (expand-file-name "pdf" dest))
+        (emacs (expand-file-name "doc/emacs/emacs.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)))
+    ;; TODO this makes it non-continuable.
+    ;; Instead, delete the individual dest directory each time.
     (when (file-directory-p dest)
-      (if (y-or-n-p (format "Directory %s exists, delete it first?" dest))
+      (if (y-or-n-p (format "Directory %s exists, delete it first? " dest))
          (delete-directory dest t)
-       (error "Aborted")))
-    (make-directory dest)
-    (make-directory html-node-dir)
-    (make-directory html-mono-dir)
-    (make-directory txt-dir)
-    (make-directory dvi-dir)
-    (make-directory ps-dir)
-    ;; Emacs manual
-    (let ((texi (expand-file-name "doc/emacs/emacs.texi" root)))
-      (manual-html-node texi (expand-file-name "emacs" html-node-dir))
-      (manual-html-mono texi (expand-file-name "emacs.html" html-mono-dir))
-      (manual-txt texi (expand-file-name "emacs.txt" txt-dir))
-      (manual-pdf texi (expand-file-name "emacs.pdf" dest))
-      (manual-dvi texi (expand-file-name "emacs.dvi" dvi-dir)
-                 (expand-file-name "emacs.ps" ps-dir)))
-    ;; Lisp manual
-    (let ((texi (expand-file-name "doc/lispref/elisp.texi" root)))
-      (manual-html-node texi (expand-file-name "elisp" html-node-dir))
-      (manual-html-mono texi (expand-file-name "elisp.html" html-mono-dir))
-      (manual-txt texi (expand-file-name "elisp.txt" txt-dir))
-      (manual-pdf texi (expand-file-name "elisp.pdf" dest))
-      (manual-dvi texi (expand-file-name "elisp.dvi" dvi-dir)
-                 (expand-file-name "elisp.ps" ps-dir)))
+       (user-error "Aborted")))
+    (if (member type '(nil "emacs" "emacs-node"))
+       (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)))
+    (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"))
+       (manual-html-mono elisp (expand-file-name "elisp.html" html-mono-dir)))
+    (if (member type '(nil "elisp" "elisp-pdf" "pdf"))
+       (manual-pdf elisp (expand-file-name "elisp.pdf" pdf-dir)))
+    (if (member type '(nil "elisp" "elisp-ps" "ps"))
+       (manual-ps elisp (expand-file-name "elisp.ps" ps-dir)))
+    (if (member type '(nil "eintr" "eintr-node"))
+       (manual-html-node eintr (expand-file-name "eintr" html-node-dir)))
+    (if (member type '(nil "eintr" "eintr-node"))
+       (manual-html-mono eintr (expand-file-name "eintr.html" html-mono-dir)))
+    (if (member type '(nil "eintr" "eintr-pdf" "pdf"))
+       (manual-pdf eintr (expand-file-name "eintr.pdf" pdf-dir)))
+    (if (member type '(nil "eintr" "eintr-ps" "ps"))
+       (manual-ps eintr (expand-file-name "eintr.ps" ps-dir)))
     ;; Misc manuals
-    (let ((manuals '("ada-mode" "auth" "autotype" "calc" "cc-mode"
-                    "cl" "dbus" "dired-x" "ebrowse" "ede" "ediff"
-                    "edt" "eieio" "emacs-mime" "epa" "erc" "ert"
-                    "eshell" "eudc" "faq" "flymake" "forms"
-                    "gnus" "emacs-gnutls" "idlwave" "info"
-                    "mairix-el" "message" "mh-e" "newsticker"
-                    "nxml-mode" "org" "pcl-cvs" "pgg" "rcirc"
-                    "remember" "reftex" "sasl" "sc" "semantic"
-                    "ses" "sieve" "smtpmail" "speedbar" "tramp"
-                    "url" "vip" "viper" "widget" "woman")))
-      (dolist (manual manuals)
-       (manual-misc-html manual root html-node-dir html-mono-dir)))
+    (dolist (manual misc)
+      (if (member type `(nil ,manual "misc"))
+         (manual-misc-html manual root html-node-dir html-mono-dir)))
     (message "Manuals created in %s" dest)))
 
 (defconst manual-doctype-string
@@ -238,10 +283,15 @@ Root must be the root of an Emacs source tree."
 <meta name=\"DC.title\" content=\"gnu.org\">\n\n")
 
 (defconst manual-style-string "<style type=\"text/css\">
-@import url('/style.css');\n</style>\n")
+@import url('/s/emacs/manual.css');\n</style>\n")
 
 (defun manual-misc-html (name root html-node-dir html-mono-dir)
-  (let ((texi (expand-file-name (format "doc/misc/%s.texi" name) root)))
+  ;; Hack to deal with the cases where .texi creates a different .info.
+  ;; Blech.  TODO Why not just rename the .texi files?
+  (let* ((texiname (cond ((equal name "ccmode") "cc-mode")
+                        ((equal name "efaq") "faq")
+                        (t name)))
+        (texi (expand-file-name (format "doc/misc/%s.texi" texiname) root)))
     (manual-html-node texi (expand-file-name name html-node-dir))
     (manual-html-mono texi (expand-file-name (concat name ".html")
                                             html-mono-dir))))
@@ -251,7 +301,13 @@ Root must be the root of an Emacs source tree."
 This function also edits the HTML files so that they validate as
 HTML 4.01 Transitional, and pulls in the gnu.org stylesheet using
 the @import directive."
+  (make-directory (or (file-name-directory dest) ".") t)
   (call-process "makeinfo" nil nil nil
+               "-D" "WWW_GNU_ORG"
+               "-I" (expand-file-name "../emacs"
+                                      (file-name-directory texi-file))
+               "-I" (expand-file-name "../misc"
+                                      (file-name-directory texi-file))
                "--html" "--no-split" texi-file "-o" dest)
   (with-temp-buffer
     (insert-file-contents dest)
@@ -272,7 +328,13 @@ HTML 4.01 Transitional, and pulls in the gnu.org stylesheet using
 the @import directive."
   (unless (file-exists-p texi-file)
     (error "Manual file %s not found" texi-file))
+  (make-directory dir t)
   (call-process "makeinfo" nil nil nil
+               "-D" "WWW_GNU_ORG"
+               "-I" (expand-file-name "../emacs"
+                                      (file-name-directory texi-file))
+               "-I" (expand-file-name "../misc"
+                                      (file-name-directory texi-file))
                "--html" texi-file "-o" dir)
   ;; Loop through the node files, fixing them up.
   (dolist (f (directory-files dir nil "\\.html\\'"))
@@ -301,23 +363,25 @@ the @import directive."
            (manual-html-fix-node-div))
          (save-buffer))))))
 
-(defun manual-txt (texi-file dest)
-  "Run Makeinfo on TEXI-FILE, emitting plaintext output to DEST."
-  (call-process "makeinfo" nil nil nil
-               "--plaintext" "--no-split" texi-file "-o" dest)
-  (shell-command (concat "gzip -c " dest " > " (concat dest ".gz"))))
-
 (defun manual-pdf (texi-file dest)
-  "Run texi2pdf on TEXI-FILE, emitting plaintext output to DEST."
-  (call-process "texi2pdf" nil nil nil texi-file "-o" dest))
-
-(defun manual-dvi (texi-file dest ps-dest)
-  "Run texi2dvi on TEXI-FILE, emitting dvi output to DEST.
-Also generate PostScript output in PS-DEST."
-  (call-process "texi2dvi" nil nil nil texi-file "-o" dest)
-  (call-process "dvips" nil nil nil dest "-o" ps-dest)
-  (call-process "gzip" nil nil nil dest)
-  (call-process "gzip" nil nil nil ps-dest))
+  "Run texi2pdf on TEXI-FILE, emitting pdf output to DEST."
+  (make-directory (or (file-name-directory dest) ".") t)
+  (let ((default-directory (file-name-directory texi-file)))
+    (call-process "texi2pdf" nil nil nil
+                 "-I" "../emacs" "-I" "../misc"
+                 texi-file "-o" dest)))
+
+(defun manual-ps (texi-file dest)
+  "Generate a PostScript version of TEXI-FILE as DEST."
+  (make-directory (or (file-name-directory dest) ".") t)
+  (let ((dvi-dest (concat (file-name-sans-extension dest) ".dvi"))
+       (default-directory (file-name-directory texi-file)))
+    (call-process "texi2dvi" nil nil nil
+                 "-I" "../emacs" "-I" "../misc"
+                 texi-file "-o" dvi-dest)
+    (call-process "dvips" nil nil nil dvi-dest "-o" dest)
+    (delete-file dvi-dest)
+    (call-process "gzip" nil nil nil dest)))
 
 (defun manual-html-fix-headers ()
   "Fix up HTML headers for the Emacs manual in the current buffer."
@@ -421,7 +485,8 @@ Also generate PostScript output in PS-DEST."
        (setq done t))
        (t
        (if (eobp)
-           (error "Parse error in %s" f)) ; f is bound in manual-html-node
+           (error "Parse error in %s"
+                  (file-name-nondirectory buffer-file-name)))
        (unless open-td
          (setq done t))))
       (forward-line 1))))
@@ -442,8 +507,10 @@ If optional OLD is non-nil, also include defvars."
                                     ))
                 "{}" "+"))
 
-;; TODO if a defgroup with a version tag, apply to all customs in that
-;; group (eg for new files).
+(defvar cusver-new-version (format "%s.%s" emacs-major-version
+                                  (1+ emacs-minor-version))
+  "Version number that new defcustoms should have.")
+
 (defun cusver-scan (file &optional old)
   "Scan FILE for `defcustom' calls.
 Return a list with elements of the form (VAR . VER),
@@ -452,8 +519,8 @@ a :version tag having value VER (may be nil).
 If optional argument OLD is non-nil, also scan for defvars."
   (let ((m (format "Scanning %s..." file))
        (re (format "^[ \t]*\\((def%s\\)[ \t\n]"
-                   (if old "\\(?:custom\\|var\\)" "custom")))
-        alist var ver form)
+                   (if old "\\(custom\\|var\\)" "\\(custom\\|group\\)")))
+        alist var ver form glist grp)
     (message "%s" m)
     (with-temp-buffer
       (insert-file-contents file)
@@ -461,15 +528,42 @@ If optional argument OLD is non-nil, also scan for defvars."
       (while (re-search-forward re nil t)
         (goto-char (match-beginning 1))
         (if (and (setq form (ignore-errors (read (current-buffer))))
-                 (setq var (car-safe (cdr-safe form)))
+                (setq var (car-safe (cdr-safe form)))
                 ;; Exclude macros, eg (defcustom ,varname ...).
                 (symbolp var))
-            (setq ver (car (cdr-safe (memq :version form)))
-                  alist (cons (cons var ver) alist))
+           (progn
+             (setq ver (car (cdr-safe (memq :version form))))
+             (if (equal "group" (match-string 2))
+                 ;; Group :version could be old.
+                 (if (equal ver cusver-new-version)
+                     (setq glist (cons (cons var ver) glist)))
+               ;; If it specifies a group and the whole group has a
+               ;; version. use that.
+               (unless ver
+                 (setq grp (car (cdr-safe (memq :group form))))
+                 (and grp
+                      (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)))))
     (message "%sdone" m)
     alist))
 
+(defun cusver-scan-cus-start (file)
+  "Scan cus-start.el and return an alist with elements (VAR . VER)."
+  (if (file-readable-p file)
+      (with-temp-buffer
+       (insert-file-contents file)
+       (when (search-forward "(let ((all '(" nil t)
+         (backward-char 1)
+         (let (var ver alist)
+           (dolist (elem (ignore-errors (read (current-buffer))))
+             (when (symbolp (setq var (car-safe elem)))
+               (or (stringp (setq ver (nth 3 elem)))
+                   (setq ver nil))
+               (setq alist (cons (cons var ver) alist))))
+           alist)))))
+
 (define-button-type 'cusver-xref 'action #'cusver-goto-xref)
 
 (defun cusver-goto-xref (button)
@@ -485,12 +579,10 @@ If optional argument OLD is non-nil, also scan for defvars."
        (pop-to-buffer (current-buffer))))))
 
 ;; You should probably at least do a grep over the old directory
-;; to check the results of this look sensible.  Eg cus-start if
-;; something moved from C to Lisp.
-;; TODO handle renamed things with aliases to the old names.
-;; What to do about new files?  Does everything in there need a :version,
-;; or eg just the defgroup?
-(defun cusver-check (newdir olddir)
+;; to check the results of this look sensible.
+;; TODO Check cus-start if something moved from C to Lisp.
+;; TODO Handle renamed things with aliases to the old names.
+(defun cusver-check (newdir olddir version)
   "Check that defcustoms have :version tags where needed.
 NEWDIR is the current lisp/ directory, OLDDIR is that from the previous
 release.  A defcustom that is only in NEWDIR should have a :version
@@ -499,11 +591,16 @@ just converting a defvar to a defcustom does not require a :version bump.
 
 Note that a :version tag should also be added if the value of a defcustom
 changes (in a non-trivial way).  This function does not check for that."
-  (interactive "DNew Lisp directory: \nDOld Lisp directory: ")
+  (interactive (list (read-directory-name "New Lisp directory: ")
+                    (read-directory-name "Old Lisp directory: ")
+                    (number-to-string
+                     (read-number "New version number: "
+                                  (string-to-number cusver-new-version)))))
   (or (file-directory-p (setq newdir (expand-file-name newdir)))
       (error "Directory `%s' not found" newdir))
   (or (file-directory-p (setq olddir (expand-file-name olddir)))
       (error "Directory `%s' not found" olddir))
+  (setq cusver-new-version version)
   (let* ((newfiles (progn (message "Finding new files with defcustoms...")
                          (cusver-find-files newdir)))
         (oldfiles (progn (message "Finding old files with defcustoms...")
@@ -516,6 +613,8 @@ changes (in a non-trivial way).  This function does not check for that."
     (message "Reading old defcustoms...")
     (dolist (file oldfiles)
       (setq oldcus (append oldcus (cusver-scan file t))))
+    (setq oldcus (append oldcus (cusver-scan-cus-start
+                                (expand-file-name "cus-start.el" olddir))))
     ;; newcus has elements (FILE (VAR VER) ... ).
     ;; oldcus just (VAR . VER).
     (message "Checking for version tags...")