Initial import from tla sources
[slh] / pkg-build.el
1 ;;; pkg-build.el --- Automate building XEmacs packages for release.
2
3 ;; Copyright (C) 2002 Steve Youngs
4
5 ;; RCS: $Id: pkg-build.el,v 1.26 2004/03/15 22:55:33 youngs Exp $
6 ;; Author:        Steve Youngs <youngs@xemacs.org>
7 ;; Maintainer:    Steve Youngs <youngs@xemacs.org>
8 ;; Created:       2002-04-07
9 ;; Last-Modified: <2004-03-16 08:14:03 (steve)>
10 ;; Keywords:      maint packages
11
12 ;; This file is part of XEmacs
13
14 ;; XEmacs is free software; you can redistribute it and/or modify
15 ;; it under the terms of the GNU General Public License as published by
16 ;; the Free Software Foundation; either version 2 of the License, or
17 ;; (at your option) any later version.
18
19 ;; XEmacs is distributed in the hope that it will be useful,
20 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 ;; GNU General Public License for more details.
23
24 ;; You should have received a copy of the GNU General Public License
25 ;; along with this program; if not, write to the Free Software
26 ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
27
28
29 ;;; Commentary:
30 ;;
31 ;;  This is far from finished.  The intention here is to automate as
32 ;;  much as possible the work of the XEmacs Package Release Manager.
33
34 ;;; Currently implemented features:
35 ;;
36 ;;     - Increment Makefile $VERSION.
37 ;;     - Write ChangeLog entry for incremented Makefile $VERSION.
38 ;;     - Write ChangeLog entry in toplevel directory listing released
39 ;;       packages.
40 ;;     - Commit changed files to CVS.
41 ;;     - Build single or multiple packages,
42 ;;     - Do a 'cvs tag pkgname-x_xx' for each package built.
43 ;;     - GnuPG sign package-index file.
44 ;;     - Upload packages to FTP site.
45 ;;     - Handle Sumo packages.  Building, tagging, uploading.
46 ;;     - Keep a "packages to be released later" file
47 ;;     - Release packages using above file as input.
48 ;;
49 ;;##################### W A R N I N G ################################
50 ;;                                                         
51 ;;              DANGER Will Robinson! DANGER!!
52 ;;
53 ;; This will *NOT* run out of the box.  You *MUST* customise it to
54 ;; suit first.  And while on the subject of warnings... If you don't
55 ;; have commit access to the entire packages CVS repository, this file
56 ;; is not for you.  If you don't have an account on gwyn.tux.org, this
57 ;; file is not for you.  If you are not the XEmacs Packages Release
58 ;; Manager, this file is not for you.  Pretty God damned restrictive,
59 ;; huh.
60 ;;
61 ;;####################################################################
62 ;;
63 ;; OK, warnings over, now Setup and Usage:
64 ;;
65 ;;   1) Stick this file somewhere in your load-path and byte-compile
66 ;;      it.  And then add: (require 'pkg-build) to ~/.xemacs/init.el
67 ;;      (or similar).  A better way to do this is left as an exercise
68 ;;      for the reader.
69 ;;
70 ;;   2) Run 'M-x pkg-customize'  (remember those big fat warnings?)
71 ;;
72 ;;   3) The only functions you need to worry about are:
73 ;;      - `pkg-release-packages'
74 ;;      - `pkg-release-packages-from-file'
75 ;;      - `pkg-release-packages-later'
76 ;;      - `pkg-release-sumo'
77 ;;
78 ;; A Note About GnuPG Comments:
79 ;;
80 ;; Since this file switched over to using PGG instead of gpg.el,
81 ;; setting your GnuPG comment field in this file is no longer
82 ;; supported.  If you want to set the comment field, do so in your
83 ;; `~/.gnupg/gpg.conf' file: `comment "Comment Here"'.
84
85 ;;; Todo:
86 ;;
87 ;;     - Automated release announcements.
88 ;;     - Lots and lots of code clean up.
89 ;;
90
91 ;;; History:
92 ;;
93 ;;  Go look at the ChangeLog, this is just here so `pkg-commentary'
94 ;;  works.
95
96
97 ;;; Code:
98 (eval-and-compile
99   (require 'add-log)
100   (require 'dired)
101   (require 'pgg)
102   (require 'package-get)
103   (autoload 'lm-commentary "lisp-mnt")
104   (autoload 'customize-group "cus-edit")
105   (autoload 'with-electric-help "ehelp"))
106
107
108 (defconst pkg-build-version "3.0.5"
109   "The version of pkg-build.")
110
111 (defgroup pkg-build nil
112   "Preparing XEmacs packages for release."
113   :prefix "pkg-"
114   :group 'package-tools)
115
116 (defgroup pkg-directory nil
117   "The directories associated with building packages."
118   :prefix "pkg-"
119   :group 'pkg-build)
120
121 (defgroup pkg-remote nil
122   "Remote host options associated with building packages."
123   :prefix "pkg-"
124   :group 'pkg-build)
125
126 (defgroup pkg-sumo nil
127   "Sumo options."
128   :prefix "pkg-"
129   :group 'pkg-build)
130
131 (defcustom pkg-std-packages
132   '("Sun" "ada" "apel" "auctex" "bbdb" "build" "c-support" "calc"
133     "calendar" "cc-mode" "clearcase" "cookie" "crisp" "debug" "dictionary"
134     "dired" "docbookide" "ecb" "ecrypto" "edebug" "ediff" "edit-utils"
135     "edt" "efs" "eieio" "elib" "emerge" "erc" "escreen" "eshell" "ess" 
136     "eterm" "eudc" "footnote" "forms" "fortran-modes" "frame-icon" "fsf-compat"
137     "games" "general-docs" "gnats" "gnus" "haskell-mode" "hm--html-menus"
138     "hyperbole" "ibuffer" "idlwave" "igrep" "ilisp" "ispell" "jde" "liece"
139     "mail-lib" "mailcrypt" "mew" "mh-e" "mine" "misc-games" "mmm-mode"
140     "net-utils" "ocaml" "oo-browser" "os-utils" "pc" "pcl-cvs" "pcomplete"
141     "perl-modes" "pgg" "prog-modes" "ps-print" "psgml" "psgml-dtds" 
142     "python-modes" "reftex" "riece" "rmail" "ruby-modes" "sasl" "scheme"
143     "semantic" "sgml" "sh-script" "sieve" "slider" "sml-mode" "sounds-au"
144     "sounds-wav" "speedbar" "strokes" "supercite" "texinfo" "text-modes"
145     "textools" "time" "tm" "tooltalk" "tpu" "tramp" "vc" "vc-cc" "vhdl"
146     "view-process" "viper" "vm" "w3" "x-symbol" "xemacs-base" "xemacs-devel"
147     "xlib" "xslide" "xslt-process" "xwem" "zenirc")
148   "*A list of all standard (non-Mule) packages."
149   :group 'pkg-build
150   :type '(repeat string)
151   :tag "Standard Packages"
152   :link '(info-link "(xemacs)Available Packages"))
153
154 (defcustom pkg-mule-packages
155   '("edict" "egg-its" "latin-unity" "leim" "locale" "lookup"
156     "mule-base" "mule-ucs" "skk")
157   "*A list of all Mule packages."
158   :group 'pkg-build
159   :type '(repeat string)
160   :link '(info-link "(xemacs)Available Packages"))
161
162 (defcustom pkg-log-buffer "*Pkg Build Log*"
163   "*The buffer that logs all the goings on from building packages."
164   :group 'pkg-build
165   :type 'string)
166
167 (defcustom pkg-log-entry-inc-ver "\"Increment VERSION in Makefile\""
168   "*CVS commit log entry.
169
170 It is used when committing a package's Makefile & ChangeLog after
171 incrementing $VERSION."
172   :group 'pkg-build
173   :type 'string)
174
175 (defcustom pkg-copy-cmd "cp -a"
176   "*The command used to copy a package into the working directory.
177
178 This command MUST do a recursive copy."
179   :group 'pkg-build
180   :type 'string)
181
182 (defcustom pkg-copy-glob "*"
183   "*A shell wildcard that means \"All files in the directory\".
184
185 This is used in conjuction with `pkg-copy-cmd'."
186   :group 'pkg-build
187   :type '(choice 
188           (const :tag "GNU/Linux (\"*\")" "*")
189           (const :tag "FreeBSD (Nothing)" nil)
190           (string :tag "Other" "")))
191
192 (defcustom pkg-make-program (executable-find "gmake")
193   "*The \"make\" program used to build packages.
194
195 The XEmacs packages need GNU/make to build."
196   :group 'pkg-build
197   :type '(file :must-match t))
198
199 (defcustom pkg-make-targets `((all    . ,(concat pkg-make-program " all"))
200                               (aload  . ,(concat pkg-make-program " autoloads"))
201                               (bdist  . ,(concat pkg-make-program " bindist"))
202                               (clean  . ,(concat pkg-make-program " clean"))
203                               (dclean . ,(concat pkg-make-program " distclean"))
204                               (eclean . ,(concat pkg-make-program " extraclean"))
205                               (html   . ,(concat pkg-make-program " html"))
206                               (inst   . ,(concat pkg-make-program " install"))
207                               (insth  . ,(concat pkg-make-program " install-html"))
208                               (insto  . ,(concat pkg-make-program " install-only")))
209   "*An alist of makefile targets used in building packages."
210   :group 'pkg-build
211   :type 'alist)
212
213 ;;;###autoload
214 (defcustom pkg-packages-to-release-file
215   (expand-file-name ".pkg-todo" (getenv "HOME"))
216   "*A list of package names to be released at a later date."
217   :group 'pkg-build
218   :type 'file)
219
220 (defcustom pkg-clear-release-file t
221   "*If non-nil, erase the contents of `pkg-packages-to-release-file'.
222
223 The file is cleared after the packages are released.  Defaults to
224 non-nil so that the same set of packages aren't released multiple
225 times with multiple release runs."
226   :group 'pkg-build
227   :type 'boolean)
228           
229 (defcustom pkg-base-directory
230   (file-name-as-directory 
231    (expand-file-name "programming/XEmacs/packages"
232                      (getenv "HOME")))
233   "*Base directory of the XEmacs packages source."
234   :group 'pkg-directory
235   :type 'directory)
236
237 (defcustom pkg-std-directory
238   (file-name-as-directory
239    (expand-file-name "xemacs-packages" pkg-base-directory))
240   "*Parent directory of standard packages."
241   :group 'pkg-directory
242   :type 'directory)
243
244 (defcustom pkg-mule-directory
245   (file-name-as-directory
246    (expand-file-name "mule-packages" pkg-base-directory))
247   "*Parent directory of Mule packages."
248   :group 'pkg-directory
249   :type 'directory)
250
251 (defcustom pkg-working-base-directory
252   (file-name-as-directory
253    (expand-file-name "test-it/build/packages"
254                      (getenv "HOME")))
255   "*Base directory of the XEmacs packages source.
256
257 The `pkg-working-*-directory' are where the packages are actually
258 built.  I use a different directory from the checked out CVS source
259 just in case something goes wrong."
260   :group 'pkg-directory
261   :type 'directory)
262
263 (defcustom pkg-working-std-directory
264   (file-name-as-directory
265    (expand-file-name "xemacs-packages" pkg-working-base-directory))
266   "*Parent directory of standard packages.
267
268 The `pkg-working-*-directory' are where the packages are actually
269 built.  I use a different directory from the checked out CVS source
270 just in case something goes wrong."
271   :group 'pkg-directory
272   :type 'directory)
273
274 (defcustom pkg-working-mule-directory
275   (file-name-as-directory
276    (expand-file-name "mule-packages" pkg-working-base-directory))
277   "*Parent directory of Mule packages.
278
279 The `pkg-working-*-directory' are where the packages are actually
280 built.  I use a different directory from the checked out CVS source
281 just in case something goes wrong."
282   :group 'pkg-directory
283   :type 'directory)
284
285 (defcustom pkg-staging-directory 
286   (file-name-as-directory
287    (expand-file-name "staging" (getenv "HOME")))
288   "*This is the directory whereto make bindist puts its products."
289   :group 'pkg-directory
290   :type 'directory)
291
292 (defcustom pkg-upload-directory 
293   (file-name-as-directory
294    (expand-file-name "upload" (getenv "HOME")))
295   "*This is the directory from where the packages get uploaded from.
296
297 WARNING! DANGER! *EVERYTHING* in this directory may deleted!  DON'T use
298 it for any other purpose.  You have been warned!!"
299   :group 'pkg-directory
300   :type 'directory)
301
302 (defcustom pkg-packages-omit-sumo '("Sun")
303   "*A list of packages to NOT include in the SUMO packages."
304   :group 'pkg-sumo
305   :type '(repeat string))
306
307 (defcustom pkg-sumo-tarball-directory
308   (file-name-as-directory
309    (expand-file-name "Sumo"
310                      pkg-staging-directory))
311   "*The top level Sumo directory.
312
313 Under this directory is where all the packages are installed to in
314 readiness for creating the Sumo package tarballs."
315   :group 'pkg-sumo
316   :type 'directory)
317
318 (defcustom pkg-std-sumo-install-directory
319   (file-name-as-directory
320    (expand-file-name "xemacs-packages"
321                      pkg-sumo-tarball-directory))
322   "*The directory where the standard packages are installed for Sumo creation."
323   :group 'pkg-sumo
324   :type 'directory)
325
326 (defcustom pkg-mule-sumo-install-directory
327   (file-name-as-directory
328    (expand-file-name "mule-packages"
329                      pkg-sumo-tarball-directory))
330   "*The directory where the mule packages are installed for Sumo creation."
331   :group 'pkg-sumo
332   :type 'directory)
333
334 (defcustom pkg-std-sumo-build-flags
335   (format "NONMULE_INSTALLED_PACKAGES_ROOT=%s"
336           pkg-std-sumo-install-directory)
337   "*Args to pass to make when building the standard Sumo."
338   :group 'pkg-sumo
339   :type 'string)
340
341 (defcustom pkg-mule-sumo-build-flags
342   (format "MULE_INSTALLED_PACKAGES_ROOT=%s"
343           pkg-mule-sumo-install-directory)
344   "*Args to pass to make when building the Mule Sumo."
345   :group 'pkg-sumo
346   :type 'string)
347
348 (defcustom pkg-sumo-tar-gzip
349   "tar --create --owner=0 --group=0 --use-compress-program=gzip --file"
350   "*The program and flags used to build the tar.gz Sumo tarballs."
351   :group 'pkg-sumo
352   :type 'string)
353
354 (defcustom pkg-sumo-tar-bzip
355   "tar --create --owner=0 --group=0 --use-compress-program=bzip2 --file"
356   "*The program and flags used to build the tar.bz2 Sumo tarballs."
357   :group 'pkg-sumo
358   :type 'string)
359
360 (defcustom pkg-online-status-file "/var/run/ppp0.pid"
361   "*This file must exist for CVS tagging and commits to happen."
362   :group 'pkg-remote
363   :type 'file)
364
365 (defcustom pkg-upload-command "scp -qC"
366   "*Program to use for uploading packages & Sumo's to the FTP site."
367   :group 'pkg-remote
368   :type 'string)
369
370 (defcustom pkg-remote-path "youngs@ftp.xemacs.org:pkgtmp/"
371   "*Path where packages get uploaded to.
372
373 This path is compatible with \"scp\" and includes a user name."
374   :group 'pkg-remote
375   :type 'string)
376
377 ;;;###autoload
378 (defun pkg-customize ()
379   "Convenience function to customise pkg-build."
380   (interactive)
381   (customize-group 'pkg-build))
382
383 ;;;###autoload
384 (defun pkg-version (&optional arg)
385   "Print the current version of pkg-build.
386
387 With prefix arg ARG, insert version string at point."
388   (interactive "P")
389   (if arg
390       (insert (format "Pkg Build v%s" pkg-build-version))
391     (message (format "Pkg Build v%s" pkg-build-version))))
392
393 ;;;###autoload
394 (defun pkg-commentary ()
395   "Display the commentary section from pkg-build.el."
396   (interactive)
397   ;; Yeah, yeah, I know there is `finder-commentary', but this is
398   ;; better.
399   (with-electric-help
400    '(lambda ()
401       (insert
402        (with-temp-buffer
403          (erase-buffer)
404          (insert (lm-commentary (locate-library "pkg-build.el")))
405          (goto-char (point-min))
406          (while (re-search-forward "^;+ ?" nil t)
407            (replace-match "" nil nil))
408          (buffer-string (current-buffer)))))))
409
410 (defsubst pkg-call-process (command &optional buffer displayp)
411   "Call a shell process executing COMMAND with output to BUFFER.
412
413 Argument COMMAND is a string.
414 Optional argument BUFFER if omitted will be the current buffer.
415 Optional argument DISPLAYP if non-nil update the output buffer on the
416 fly instead of just when command finishes."
417   (apply 'call-process shell-file-name nil (or buffer t) displayp
418          shell-command-switch (list command)))
419
420 (defun pkg-make-bindist (pkg type)
421   "Build a binary distribution for package PKG.
422
423 Argument TYPE is a string of either \"standard\" or \"mule\".
424
425 This function is called from `pkg-release-packages'.  It copies the
426 package's source files from the CVS checkout directory to a working
427 directory.  And then does a \"make distclean\", \"make autoloads\",
428 and a \"make bindist\".
429
430 The output from the compilations is appended to `pkg-log-buffer'."
431   (let (copy-dest)
432     ;; Mule or Standard.
433     (cond
434      ((string= type "standard")
435       (setq default-directory 
436             (file-name-as-directory 
437              (expand-file-name pkg pkg-std-directory))
438             copy-dest
439             (file-name-as-directory
440              (expand-file-name pkg pkg-working-std-directory))))
441      ((string= type "mule")
442       (setq default-directory 
443             (file-name-as-directory 
444              (expand-file-name pkg pkg-mule-directory))
445             copy-dest
446             (file-name-as-directory
447              (expand-file-name pkg pkg-working-mule-directory))))
448      (t
449       (error 'wrong-type-argument
450              (format "Type: %s is not valid for package: %s" type pkg))))
451     ;; Copy the package to the working directory
452     (shell-command
453      (concat
454       pkg-copy-cmd " " default-directory pkg-copy-glob " " copy-dest))
455     ;; Set the default directory to the working directory
456     (setq default-directory copy-dest)
457     ;; make distclean.
458     (pkg-call-process 
459      (cdr (assq 'dclean pkg-make-targets)) pkg-log-buffer t)
460     ;; make autoloads.
461     (pkg-call-process 
462      (cdr (assq 'aload pkg-make-targets)) pkg-log-buffer t)
463     ;; make all
464     (pkg-call-process
465      (cdr (assq 'all pkg-make-targets)) pkg-log-buffer t)
466     ;; make bindist.
467     (pkg-call-process
468      (cdr (assq 'bdist pkg-make-targets)) pkg-log-buffer t)))
469
470 (defun pkg-commit-inc-ver (pkg type)
471   "Commit the ChangeLog & Makefile of package PKG.
472
473 Argument TYPE is a string of either \"standard\" or \"mule\".
474
475 Once $VERSION in Makefile has been incremented and a ChangeLog entry
476 written, this function commits the Makefile & ChangeLog to CVS."
477   (let ((files "ChangeLog Makefile")
478         (cvs-cmd "cvs commit -m"))
479     ;; Mule or Standard.
480     (cond
481      ((string= type "standard")
482       (setq default-directory 
483             (file-name-as-directory (expand-file-name pkg pkg-std-directory))))
484      ((string= type "mule")
485       (setq default-directory 
486             (file-name-as-directory (expand-file-name pkg pkg-mule-directory))))
487      (t
488       (error 'wrong-type-argument
489              (format "Type: %s is not valid for package: %s" type pkg))))
490     (pkg-call-process
491      (concat cvs-cmd " " pkg-log-entry-inc-ver " " files)
492      pkg-log-buffer t)))
493
494 (defun pkg-tag-package (pkg version type)
495   "Run \"cvs tag package-x_xx\" for package PKG.
496
497 Argument PKG is the name of the package to tag (a string).
498 Argument VERSION is the version number of the package to tag.
499 Argument TYPE is a string of either \"standard\" or \"mule\"."
500   (let ((tag-name))
501     (with-temp-buffer
502       (erase-buffer)
503       (insert (concat pkg "-" (format "%.2f" version)))
504       (while (re-search-backward "\\." nil t)
505         (replace-match "_" nil nil))
506       (goto-char (point-min))
507       (re-search-forward ".*$" (eolp) t)
508       (setq tag-name (match-string 0)))
509     (cond
510      ((string= type "standard")
511       (setq default-directory
512             (file-name-as-directory (expand-file-name pkg pkg-std-directory)))
513       (pkg-call-process (concat "cvs tag " tag-name) pkg-log-buffer t))
514      ((string= type "mule")
515       (setq default-directory
516             (file-name-as-directory (expand-file-name pkg pkg-mule-directory)))
517       (pkg-call-process (concat "cvs tag " tag-name) pkg-log-buffer t))
518      (t
519       (error 'wrong-type-argument
520              (format "Type: %s is not valid for package: %s" type pkg))))))
521
522 (defun pkg-upload-packages (pkgs)
523   "Upload compiled XEmacs packages to the FTP site.
524
525 Argument PKGS is a list of filenames to upload."
526   (let* ((staging (file-name-as-directory pkg-staging-directory))
527          (oldfilelist (directory-files pkg-upload-directory nil nil nil t))
528          (pgg-output-buffer "package-index.gpg"))
529     (setq default-directory staging)
530     (loop for each in '("package-index"
531                         "package-index.gpg")
532       do (find-file-noselect each))
533     (erase-buffer "package-index.gpg")
534     (with-current-buffer "package-index"
535       (pgg-sign-region (point-min) (point-max) 'cleartext)
536       (kill-buffer (current-buffer)))
537     (with-current-buffer pgg-output-buffer
538       (save-buffer)
539       (kill-buffer (current-buffer)))
540     (loop for each in '("package-index"
541                         "package-index.gpg"
542                         "setup-packages.ini")
543       do (setq pkgs (push each pkgs)))
544     ;; DANGER Will Robinson! Delete anything that is in
545     ;; `pkg-upload-directory'.
546     (if (yes-or-no-p "DELETE upload/* BEFORE we copy files into it? ")
547         (let* ((default-directory pkg-upload-directory))
548           (while oldfilelist
549             (delete-file (car oldfilelist))
550             (setq oldfilelist (cdr oldfilelist)))))
551     (while pkgs
552       (copy-file (expand-file-name (car pkgs) staging) pkg-upload-directory)
553       (setq pkgs (cdr pkgs)))
554     (start-process-shell-command "Package Upload"
555                                  pkg-log-buffer
556                                  (concat pkg-upload-command " "
557                                          (expand-file-name "*"
558                                                            pkg-upload-directory)
559                                          " "
560                                          pkg-remote-path))))
561
562 ;;;###autoload
563 (defun pkg-release-packages (packages)
564   "Prepare PACKAGES for release.
565
566 Argument PACKAGES is a list of one or more XEmacs packages to
567 operate on.  They must be members of either `pkg-std-packages' or
568 `pkg-mule-packages'.
569
570 It increments $VERSION in the Makefile and writes a new ChangeLog
571 entry, commits those changes to CVS, and start the ball rolling on
572 tagging the CVS repository, building the binary distribution, and
573 upload them to the FTP site."
574   (interactive "sWhitespace separated list of 1 or more packages: ")
575   (when (not (featurep 'mule))
576     (error 'unimplemented
577            "`mule': It is best to build packages with a Mule-enabled XEmacs"))
578   (let* ((pkg-list (with-temp-buffer
579                      (insert packages)
580                      (remove-if (lambda (s) (string= "" s))
581                                 (split-string 
582                                  (buffer-string (current-buffer))))))
583          (changelog (expand-file-name "ChangeLog" pkg-base-directory))
584          (log-entry "\"Package release\"")
585          (ci-top-changelog (concat "cvs commit -m "
586                                    log-entry " ChangeLog"))
587          packages type tarball-name all-tarballs)
588     (setq packages pkg-list)
589     (switch-to-buffer (get-buffer-create pkg-log-buffer))
590     (insert
591      (format "Releasing the following packages:\n\t%s" packages))
592     (insert "\n===================================================\n")
593     ;; Add a ChangeLog entry in the top level ChangeLog and commit
594     ;; that to CVS if we're online.
595     (save-excursion
596       (find-file changelog)
597       (add-change-log-entry nil nil nil t)
598       (insert
599        (format "Packages released: %s." packages))
600       (while (re-search-backward "(\\|)" nil t)
601         (replace-match "" nil nil))
602       (fill-paragraph 1)
603       (change-log-exit))
604     (if (file-readable-p pkg-online-status-file)
605         (progn
606           (setq default-directory pkg-base-directory)
607           (pkg-call-process ci-top-changelog pkg-log-buffer t))
608       (save-excursion
609         (set-buffer pkg-log-buffer)
610         (insert-string "\n*** OFFLINE *** Commit toplevel ChangeLog manually.\n")))
611     ;; Increment $VERSION for each package and write a ChangeLog entry
612     ;; for it.
613     (while packages
614       ;; Standard or Mule.
615       (cond
616        ((member (car packages) pkg-std-packages)
617         (set-buffer (find-file (expand-file-name 
618                                 "Makefile"
619                                 (file-name-as-directory
620                                  (expand-file-name (car packages)
621                                                    pkg-std-directory)))))
622         (setq type "standard"))
623        ((member (car packages) pkg-mule-packages)
624         (set-buffer (find-file (expand-file-name 
625                                 "Makefile"
626                                 (file-name-as-directory
627                                  (expand-file-name (car packages)
628                                                    pkg-mule-directory)))))
629         (setq type "mule"))
630        (t
631         (error 'invalid-argument
632                (format "%s is not a valid package" (car packages)))))
633       (goto-char (point-min))
634       (re-search-forward "^VERSION = " nil t)
635       (re-search-forward ".*$" (eolp) t)
636       (let* ((oldver (match-string 0))
637              (incver (+ 0.01 (string-to-number oldver))))
638         (replace-match (format "%.2f" incver))
639         (save-buffer (current-buffer))
640         (add-change-log-entry nil nil nil t)
641         (insert
642          (format "XEmacs package %.2f released." incver))
643         (change-log-exit)
644         (kill-buffer (current-buffer))
645         (pkg-make-bindist (car packages) type)
646         (setq tarball-name (concat (car packages) "-"
647                                    (format "%.2f" incver)
648                                    "-pkg.tar.gz"))
649         (setq all-tarballs (push tarball-name all-tarballs))
650         ;; If online, commit the Makefile & ChangeLog, and tag CVS.
651         (if (file-readable-p pkg-online-status-file)
652             (progn
653               (pkg-commit-inc-ver (car packages) type)
654               (pkg-tag-package (car packages) incver type))
655           (save-excursion
656             (set-buffer pkg-log-buffer)
657             (insert
658              (format
659               "\n*** OFFLINE *** Commit changes and tag tree for %s manually.\n"
660               (car packages)))))
661       (setq packages (cdr packages))))
662     ;; If online, upload the package tarballs.
663     (if (file-readable-p pkg-online-status-file)
664         (pkg-upload-packages all-tarballs)
665       (save-excursion
666         (set-buffer pkg-log-buffer)
667         (insert
668          (format
669           "\n*** OFFLINE *** Upload these packages manually:\n\t%s"
670           (cl-prettyprint (symbol-value 'all-tarballs))))))))
671   
672 ;;;###autoload
673 (defun pkg-release-packages-from-file (&optional file arg)
674   "Call `pkg-release-packages' using FILE as input.
675
676 Optional Argument FILE is a file to use.  It must contain a single
677 line that is a whitespace separated list of package names.
678
679 With Prefix Argument ARG, prompt for a file to use.
680
681 The default is to use `pkg-packages-to-release-file', but if that
682 doesn't exist, prompt for a file to use."
683   (interactive "i\nP")
684   (let* ((list-file (if file
685                         file
686                       (if (or arg
687                               (not (file-exists-p pkg-packages-to-release-file)))
688                           (expand-file-name
689                            (read-file-name "Package list file: " nil nil t))
690                         pkg-packages-to-release-file)))
691          (buf (find-file-noselect list-file))
692          (pkg-list (buffer-string buf)))
693     (when (not (file-readable-p list-file))
694       (error 'file-error 
695              "Release file not readable or nonexistent"))
696     (pkg-release-packages pkg-list)
697     (save-excursion
698       (switch-to-buffer buf)
699       (when pkg-clear-release-file
700         (erase-buffer buf))
701       (save-buffer)
702       (kill-buffer buf))))
703
704 ;;;###autoload
705 (defun pkg-release-packages-later (packages &optional now)
706   "Create or add to a list of packages to release.
707
708 The list is kept in the file, `pkg-packages-to-release-file'.
709
710 Argument PACKAGES is a whitespace separated list of package names.
711
712 With Optional prefix Argument NOW, release the packages instead
713 of keeping a list to do later."
714   (interactive "sWhitespace separated list of packages: \nP")
715   (if now
716       (pkg-release-packages packages)
717     (let ((buf (find-file-noselect pkg-packages-to-release-file)))
718       (save-excursion
719         (switch-to-buffer (get-buffer buf))
720         (when (y-or-n-p "Erase any previous entries first? ")
721           (erase-buffer buf))
722         (insert (concat packages " "))
723         (save-buffer)
724         (kill-buffer buf)))))
725
726 ;;;###autoload
727 (defun pkg-release-sumo ()
728   "Builds the SUMO packages."
729   (interactive)
730   (when (not (featurep 'mule))
731     (error 'unimplemented
732            "`mule': Sumos built with a non-Mule XEmacs is discouraged"))
733   (switch-to-buffer (get-buffer-create pkg-log-buffer))
734   (let ((sumo-std (reverse pkg-std-packages))
735         (sumo-mule pkg-mule-packages)
736         (sumo-pkgs))
737     (while sumo-std
738       (setq sumo-pkgs (push (car sumo-std) sumo-mule))
739       (setq sumo-std (cdr sumo-std)))
740     ;; Do a 'make autoloads' just to be on the safe side.
741     (setq default-directory pkg-working-base-directory)
742     (pkg-call-process 
743      (cdr (assq 'aload pkg-make-targets)) pkg-log-buffer t)
744     ;; Build each package.
745     (while sumo-pkgs
746       (unless (member (car sumo-pkgs) pkg-packages-omit-sumo)
747         (cond
748          ((member (car sumo-pkgs) pkg-std-packages)
749           (setq default-directory (file-name-as-directory
750                                    (expand-file-name (car sumo-pkgs)
751                                                      pkg-working-std-directory)))
752           (pkg-call-process 
753            (cdr (assq 'all pkg-make-targets)) pkg-log-buffer t)
754           (pkg-call-process 
755            (concat (cdr (assq 'inst pkg-make-targets))
756                    " "
757                    pkg-std-sumo-build-flags) pkg-log-buffer t))
758          ((member (car sumo-pkgs) pkg-mule-packages)
759           (setq default-directory (file-name-as-directory
760                                    (expand-file-name (car sumo-pkgs)
761                                                      pkg-working-mule-directory)))
762           (pkg-call-process 
763            (cdr (assq 'all pkg-make-targets)) pkg-log-buffer t)
764           (pkg-call-process 
765            (concat (cdr (assq 'inst pkg-make-targets))
766                    " "
767                    pkg-mule-sumo-build-flags) pkg-log-buffer t))
768          (t
769           (error 'invalid-argument
770                  (format "%s is not a valid package" (car sumo-pkgs))))))
771       (setq sumo-pkgs (cdr sumo-pkgs))))
772   ;; Add a ChangeLog entry to say that a Sumo package has been released.
773   (save-excursion
774     (find-file (expand-file-name "ChangeLog" pkg-base-directory))
775     (add-change-log-entry nil nil nil t)
776     (insert-string "Sumo packages released.")
777     (change-log-exit))
778   (let ((log-msg "\"Sumo packages released\"")
779         (tag (format-time-string "sumo-%Y-%m-%d"))
780         (sumo-build-directory pkg-sumo-tarball-directory))
781     (if (file-readable-p pkg-online-status-file)
782         (progn
783           ;; Commit the ChangeLog.
784           (setq default-directory pkg-base-directory)
785           (pkg-call-process (concat "cvs commit -m "
786                                     log-msg
787                                     " ChangeLog")
788                             pkg-log-buffer t)
789           ;; Tag the tree.
790           (pkg-call-process (concat "cvs tag " tag) pkg-log-buffer t)
791           (pkg-call-process "cvs tag -F sumo-current" pkg-log-buffer t))
792       (save-excursion
793         (set-buffer pkg-log-buffer)
794         (insert
795          (format
796           "\n*** OFFLINE *** Manually commit ChangeLog and tag tree as: %s.\n"
797           tag))))
798     ;; Build the tarballs.
799     (setq default-directory sumo-build-directory)
800     (pkg-call-process (concat pkg-sumo-tar-gzip " "
801                               (format-time-string
802                                "./xemacs-sumo-%Y-%m-%d.tar.gz")
803                                " ./xemacs-packages/")
804                       pkg-log-buffer t)
805     (pkg-call-process (concat pkg-sumo-tar-gzip " "
806                               (format-time-string
807                                "./xemacs-mule-sumo-%Y-%m-%d.tar.gz")
808                                " ./mule-packages/")
809                       pkg-log-buffer t)
810     (pkg-call-process (concat pkg-sumo-tar-bzip " "
811                               (format-time-string
812                                "./xemacs-sumo-%Y-%m-%d.tar.bz2")
813                                " ./xemacs-packages/")
814                       pkg-log-buffer t)
815     (pkg-call-process (concat pkg-sumo-tar-bzip " "
816                               (format-time-string
817                                "./xemacs-mule-sumo-%Y-%m-%d.tar.bz2")
818                                " ./mule-packages/")
819                       pkg-log-buffer t)
820     ;; Upload them if we're online.
821     (if (file-readable-p pkg-online-status-file)
822         (start-process-shell-command "Sumo Upload"
823                                      pkg-log-buffer
824                                      (concat pkg-upload-command " "
825                                              "*-sumo-*.tar.* "
826                                              pkg-remote-path))
827       (save-excursion
828         (set-buffer pkg-log-buffer)
829         (insert-string "\n*** OFFLINE *** Upload Sumo tarballs manually.\n")))))
830
831 (provide 'pkg-build)
832
833 ;;; pkg-build.el ends here
834
835 ;Local Variables:
836 ;time-stamp-start: "Last-Modified:[     ]+\\\\?[\"<]+"
837 ;time-stamp-end: "\\\\?[\">]"
838 ;time-stamp-line-limit: 10
839 ;time-stamp-format: "%4y-%02m-%02d %02H:%02M:%02S (%u)"
840 ;End: