[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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



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)



Reply to: