Subject: dpkg-changelog-mode (dpkg-changelog.el)

From: Ian Jackson <[email-masked]>
Date: Tue, 6 Aug 96 20:09 BST

My upload of dpkg 1.3.0 didn't include the file below.  It is an Emacs
mode for editing the changelogs that dpkg-parsechangelog understands.

Try it (on your own packages or on the changelog from hello 1.3-7) and
let me know what you think.

When I know where to put the autoload definitions I'll release a dpkg
version with this file.  I don't propose to use the auto-mode-alist:
the file is named simply `changelog' because it is in the `debian'
subdirectory of the source tree, and binding that filename to
dpkg-changelog-mode would IMO be too obnoxious.  Instead people can
perhaps use a local variables clause to set the mode.

There are facilities in dpkg 1.3.0 for defining a parser for a
different changelog format.  I put this in because people seemed so
hung up on the Emacs format, which I think is dreadful.  However, if
someone defines a standard way of representing the required
information in an Emacs-style changelog and writes the parser for it
I'll distribute it.

Of course I'd be far happier if there were a (possibly rough)
consensus that we should stick to my format so that I can write that
into the policy manual, but for the moment I'll just mandate that you
have to use a format that the latest dpkg supports (so that people
don't need to find your home-grown parser to build your package).

Ian.

;; dpkg-changelog.el --- change log maintenance for dpkg-style changelogs

;; Keywords: maint

;; Copyright (C) 1996 Ian Jackson
;; This file is part of dpkg.
;;
;; It is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;;
;; dpkg 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
;; along with your Debian installation, in /usr/doc/copyright/GPL.
;; If not, write to the Free Software Foundation, 675 Mass Ave,
;; Cambridge, MA 02139, USA.

(require 'add-log)

(defvar dpkg-changelog-urgencies
  '((?l."LOW") (?m."MEDIUM") (?h."HIGH"))
  "alist of keystrokes vs. urgency values dpkg-changelog-urgency ^c^u.")

(defvar dpkg-changelog-distributions
  '((?s."stable") (?u."unstable") (?c."contrib") (?n."non-free") (?e."experimental"))
  "alist of keystrokes vs. distribution values for dpkg-changelog-distribution ^c^d.")

(defvar dpkg-changelog-mode-map nil
  "Keymap for dpkg changelog major mode.")
(if dpkg-changelog-mode-map
    nil
  (setq dpkg-changelog-mode-map (make-sparse-keymap))
  (define-key dpkg-changelog-mode-map "\C-c\C-a" 'dpkg-changelog-add-entry)
  (define-key dpkg-changelog-mode-map "\C-c\C-f" 'dpkg-changelog-finalise-last-version)
  (define-key dpkg-changelog-mode-map "\C-c\C-c" 'dpkg-changelog-finalise-and-save)
  (define-key dpkg-changelog-mode-map "\C-c\C-v" 'dpkg-changelog-add-version)
  (define-key dpkg-changelog-mode-map "\C-c\C-d" 'dpkg-changelog-distribution)
  (define-key dpkg-changelog-mode-map "\C-c\C-u" 'dpkg-changelog-urgency)
  (define-key dpkg-changelog-mode-map "\C-c\C-e"
    'dpkg-changelog-unfinalise-last-version))

(defun dpkg-changelog-add-entry ()
  "Add a new change entry to a dpkg-style changelog."
  (interactive)
  (if (eq (dpkg-changelog-finalised-p) t)
      (error "most recent version has been finalised - use ^c^e or ^c^v"))
  (goto-char (point-min))
  (re-search-forward "\n --")
  (backward-char 5)
  (if (prog1 (looking-at "\n") (forward-char 1))
      nil
    (insert "\n"))
  (insert "  * ")
  (save-excursion (insert "\n")))

(defun dpkg-changelog-headervalue (arg re alist)
  (let (a b v k
        (lineend (save-excursion (end-of-line) (point))))
    (save-excursion
      (goto-char (point-min))
      (re-search-forward re lineend)
      (setq a (match-beginning 1)
            b (match-end 1))
      (goto-char a)
      (if arg nil
        (message (mapconcat
                  (function (lambda (x) (format "%c:%s" (car x) (cdr x))))
                  alist " "))
        (while (not v)
          (setq k (read-char))
          (setq v (assoc k alist))))
      (delete-region a b)
      (if arg nil (insert (cdr v))))
    (if arg (goto-char a))))

(defun dpkg-changelog-urgency (arg)
  "Without argument, prompt for a key for a new urgency value (using
dpkg-changelog-urgencies).  With argument, delete the current urgency
and position the cursor to type a new one."
  (interactive "P")
  (dpkg-changelog-headervalue
   arg
   "\\;[^\n]* urgency=\\(\\sw+\\)"
   dpkg-changelog-urgencies))

(defun dpkg-changelog-distribution (arg)
  "Without argument, prompt for a key for a new distribution value (using
dpkg-changelog-distributions).  With argument, delete the current distribution
and position the cursor to type a new one."
  (interactive "P")
  (dpkg-changelog-headervalue
   arg
   ") \\(.*\\)\\;"
   dpkg-changelog-distributions))

(defun dpkg-changelog-finalised-p ()
  "Check whether the most recent dpkg-style changelog entry is
finalised yet (ie, has a maintainer name and email address and a
release date."
  (save-excursion
    (goto-char (point-min))
    (if (re-search-forward "\n\\S-" (point-max) t) nil
      (goto-char (point-max)))
    (if (re-search-backward "\n --" (point-min) t)
        (forward-char 4)
      (beginning-of-line)
      (insert " --\n\n")
      (backward-char 2))
    (cond
     ((looking-at "[ \n]+\\S-[^\n\t]+\\S- <[^ \t\n<>]+>  \\S-[^\t\n]+\\S-[ \t]*\n")
      t)
     ((looking-at "[ \t]*\n")
      nil)
     ("finalisation line has bad format (not ` -- maintainer <email>  date')"))))

(defun dpkg-changelog-add-version ()
  "Add a new version section to a dpkg-style changelog file."
  (interactive)
  (let ((f (dpkg-changelog-finalised-p)))
    (and (stringp f) (error f))
    (or f (error "previous version not yet finalised")))
  (goto-char (point-min))
  (let ((headstring
         (if (looking-at "\\(\\S-+ ([^()\n\t ]*[^0-9\n\t()]\\)\\([0-9]+\\)\\()[^\n]*\\)")
             (concat (match-string 1)
                     (number-to-string (+ 1 (string-to-number (match-string 2))))
                     (match-string 3))
           (let ((pkg (read-string "Package name: "))
                 (ver (read-version "New version (including any revision): ")))
             (concat pkg " (" ver ") unstable; urgency="
                     (cdr (car dpkg-changelog-urgencies)))))))
    (insert headstring "\n\n  * ")
    (save-excursion
      (if (re-search-backward "\;[^\n]* urgency=\\(\\sw+\\)" (point-min) t)
          (progn (goto-char (match-beginning 1))
                 (delete-region (point) (match-end 1))
                 (insert (cdr (car dpkg-changelog-urgencies))))))
    (save-excursion (insert "\n\n --\n\n"))))

(defun dpkg-changelog-finalise-and-save ()
  "Finalise, if necessary, and then save a dpkg-style changelog file."
  (interactive)
  (let ((f (dpkg-changelog-finalised-p)))
    (and (stringp f) (error f))
    (or f (dpkg-changelog-finalise-last-version)))
  (save-buffer))

(defun dpkg-changelog-finalise-last-version ()
  "Remove the `finalisation' information (maintainer's name and email
address and release date) so that new entries can be made."
  (interactive)
  (or add-log-full-name (setq add-log-full-name (user-full-name)))
  (or add-log-mailing-address (setq add-log-mailing-address user-mail-address))
  (and (dpkg-changelog-finalised-p) (dpkg-changelog-unfinalise-last-version))
  (save-excursion
    (goto-char (point-min))
    (re-search-forward "\n --\\([ \t]*\\)")
    (delete-region (match-beginning 1) (match-end 1))
    (insert " " add-log-full-name " <" add-log-mailing-address ">  ")
    (let* ((dp "822-date")
           (r (call-process dp nil t)))
      (or (= r 0) (error (concat dp " returned error status " (prin1-to-string r)))))
    (backward-char)
    (or (looking-at "\n")
        (error (concat "expected newline after date from " dp)))
    (delete-char 1)))

(defun dpkg-changelog-unfinalise-last-version ()
  "Remove the `finalisation' information (maintainer's name and email
address and release date) so that new entries can be made."
  (interactive)
  (if (dpkg-changelog-finalised-p) nil
    (error "most recent version is not finalised"))
  (save-excursion
    (goto-char (point-min))
    (re-search-forward "\n --")
    (let ((dels (point)))
      (end-of-line)
      (delete-region dels (point)))))

(defun dpkg-changelog-mode ()
  "Major mode for editing dpkg-style change logs.
Runs `dpkg-changelog-mode-hook'."
  (interactive)
  (kill-all-local-variables)
  (text-mode)
  (setq major-mode 'dpkg-changelog-mode
	mode-name "dpkg changelog"
        left-margin 2
	fill-prefix "    "
	fill-column 74)
  (use-local-map dpkg-changelog-mode-map)
  ;; Let each entry behave as one paragraph:
  (set (make-local-variable 'paragraph-start) "\\*")
  (set (make-local-variable 'paragraph-separate) "\\*\\|\\s-*$|\\S-")
  ;; Let each version behave as one page.
  ;; Match null string on the heading line so that the heading line
  ;; is grouped with what follows.
  (set (make-local-variable 'page-delimiter) "^\\<")
  (set (make-local-variable 'version-control) 'never)
  (run-hooks 'dpkg-changelog-mode-hook))

(provide 'dpkg-changelog)

---

From: Michael Meskes <[email-masked]>
Date: Wed, 7 Aug 1996 11:52:33 +0200 (MET DST)

> mode for editing the changelogs that dpkg-parsechangelog understands.

Do we have an official look the changelog has to have? If so how should it
look?

I won't be able to test your emacs style since I don't use emacs.

Michael
-- 
Michael Meskes                   |    _____ ________ __  ____
[email-masked] |   / ___// ____/ // / / __ \___  __________
[email-masked]                  |   \__ \/ /_  / // /_/ /_/ / _ \/ ___/ ___/
[email-masked]                |  ___/ / __/ /__  __/\__, /  __/ /  (__  )
Use Debian Linux!                | /____/_/      /_/  /____/\___/_/  /____/

---

From: Ian Jackson <[email-masked]>
Date: Fri, 9 Aug 96 21:19 BST

> I won't be able to test your emacs style since I don't use emacs.

Yes, we do.  An example (from dpkg) is below.  This is documented both
by example in hello and dpkg and by specification in the new manual.

Ian.

dpkg (1.3.1) experimental; urgency=LOW

  * manpage for dpkg-source et al now available.
  * dpkg-changelog-mode.el installed in site-lisp, but still no autoload.

  * dpkg-source prints correct string for not-understood tar -vvt output.
  * dpkg-source parsing of tar -vvt output made more robust.

  * dpkg-buildpackage prints usage message on usage error.
  * dpkg-gencontrol can print usage message.
  * -T<varlistfile> option added to dpkg-source.
  * Description of -f<fileslistfile> corrected in dpkg-distaddfile usage.
  * -m<maintainer> synopsis changed in dpkg-genchanges usage.
  * debian/substvars may now contain blank lines.

 -- Ian Jackson <[email-masked]>  Thu, 8 Aug 1996 02:36:04 +0100