]> code.delx.au - gnu-emacs-elpa/blobdiff - packages/debbugs/debbugs-gnu.el
Merge branch 'master' of github.com:leoliu/ggtags
[gnu-emacs-elpa] / packages / debbugs / debbugs-gnu.el
index ca4d73c470b052b45ff4b22d5db6365bf9557b5e..4d7ab2404737cbd2ca05cc37da8be8e3726e9471 100644 (file)
@@ -1,20 +1,21 @@
 ;;; debbugs-gnu.el --- interface for the GNU bug tracker
 
-;; Copyright (C) 2011, 2012 Free Software Foundation, Inc.
+;; Copyright (C) 2011-2014 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;;         Michael Albinus <michael.albinus@gmx.org>
 ;; Keywords: comm, hypermedia, maint
 ;; Package: debbugs
-;; Version: 0.3
+;; Version: 0.6
 
-;; This file is part of GNU Emacs.
+;; This file is not part of GNU Emacs.
 
-;; GNU Emacs is free software: you can redistribute it and/or modify
+;; This program 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 3 of the License, or
 ;; (at your option) any later version.
 
-;; GNU Emacs is distributed in the hope that it will be useful,
+;; This program 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.
@@ -34,6 +35,8 @@
 ;;
 ;;   (autoload 'debbugs-gnu "debbugs-gnu" "" 'interactive)
 ;;   (autoload 'debbugs-gnu-search "debbugs-gnu" "" 'interactive)
+;;   (autoload 'debbugs-gnu-usertags "debbugs-gnu" "" 'interactive)
+;;   (autoload 'debbugs-gnu-bugs "debbugs-gnu" "" 'interactive)
 
 ;; The bug tracker is called interactively by
 ;;
 ;; used, although configured on the GNU bug tracker.  If no severity
 ;; is given, all bugs are selected.
 
-;; There is also the pseudo severity "tagged", which selects locally
-;; tagged bugs.
+;; There is also the pseudo severity "tagged".  When it is used, the
+;; function will ask for user tags (a comma separated list), and shows
+;; just the bugs which are tagged with them.  In general, user tags
+;; shall be strings denoting to subprojects of the package, like
+;; "cedet" or "tramp" of the package "emacs".  If no user tag is
+;; given, locally tagged bugs are shown.
 
 ;; If a prefix is given to the command, more search parameters are
 ;; asked for, like packages (also a comma separated list, "emacs" is
 ;; happens as expected for the respective column; sorting in the Title
 ;; column is depending on whether you are the owner of a bug.
 
+;; Another approach for listing bugs is calling the command
+;;
+;;   M-x debbugs-gnu-usertags
+
+;; This command shows you all existing user tags for the packages
+;; defined in `debbugs-gnu-default-packages'.  A prefix for the
+;; command allows you to use other packe names, or an arbitrary string
+;; for a user who has tagged bugs.  The command returns the list of
+;; existing user tags for the given user(s) or package name(s),
+;; respectively.  Applying RET on a user tag, all bugs tagged with
+;; this user tag are shown.
+
+;; Unfortunately, it is not possible with the SOAP interface to show
+;; all users who have tagged bugs.  This list can be retrieved via
+;; <http://debbugs.gnu.org/cgi/pkgindex.cgi?indexon=users>.
+
+;; Finally, if you simply want to list some bugs with known bug
+;; numbers, call the command
+;;
+;;   M-x debbugs-gnu-bugs
+
+;; The bug numbers to be shown shall be entered as comma separated list.
+
 ;;; Code:
 
 (require 'debbugs)
 (require 'widget)
+(require 'wid-edit)
 (require 'tabulated-list)
 (eval-when-compile (require 'cl))
 
-(autoload 'widget-convert "wid-edit.el")
 (autoload 'gnus-read-ephemeral-emacs-bug-group "gnus-group")
 (autoload 'mail-header-subject "nnheader")
 (autoload 'gnus-summary-article-header "gnus-sum")
              (const "tagged"))
   :version "24.1")
 
+(defconst debbugs-gnu-all-severities
+  (mapcar 'cadr (cdr (get 'debbugs-gnu-default-severities 'custom-type)))
+  "*List of all possible severities.")
+
 (defcustom debbugs-gnu-default-packages '("emacs")
   "*The list of packages to be searched for."
   ;; <http://debbugs.gnu.org/Packages.html>
+  ;; <http://debbugs.gnu.org/cgi/pkgindex.cgi>
   :group 'debbugs-gnu
-  :type '(set (const "automake")
+  :type '(set (const "auctex")
+             (const "automake")
+             (const "cc-mode")
              (const "coreutils")
+             (const "cppi")
              (const "debbugs.gnu.org")
+             (const "diffutils")
              (const "emacs")
              (const "emacs-xwidgets")
              (const "fm")
              (const "gnus")
+             (const "grep")
              (const "guile")
+             (const "guix")
+             (const "gzip")
+             (const "idutils")
              (const "libtool")
+             (const "mh-e")
+             (const "org-mode")
+             (const "parted")
+             (const "vc-dwim")
              (const "woodchuck"))
-  :version "24.1")
+  :version "24.4")
+
+(defconst debbugs-gnu-all-packages
+  (mapcar 'cadr (cdr (get 'debbugs-gnu-default-packages 'custom-type)))
+  "*List of all possible package names.")
 
 (defcustom debbugs-gnu-default-hits-per-page 500
   "*The number of bugs shown per page."
@@ -191,7 +242,6 @@ suppressed bugs is toggled by `debbugs-gnu-toggle-suppress'."
 (defvar debbugs-gnu-widget-map
   (let ((map (make-sparse-keymap)))
     (define-key map "\r" 'widget-button-press)
-    (define-key map [mouse-1] 'widget-button-press)
     (define-key map [mouse-2] 'widget-button-press)
     map))
 
@@ -281,20 +331,15 @@ marked as \"client-side filter\"."
              (setq
               severities
               (completing-read-multiple
-               "Enter severities: "
-               (mapcar
-                'cadr (cdr (get 'debbugs-gnu-default-severities 'custom-type)))
-               nil t
+               "Enter severities: " debbugs-gnu-all-severities nil t
                (mapconcat 'identity debbugs-gnu-default-severities ","))))
 
             ((equal key "package")
              (setq
               packages
               (completing-read-multiple
-               "Enter packages: "
-               (mapcar
-                'cadr (cdr (get 'debbugs-gnu-default-packages 'custom-type)))
-               nil t (mapconcat 'identity debbugs-gnu-default-packages ","))))
+               "Enter packages: " debbugs-gnu-all-packages nil t
+               (mapconcat 'identity debbugs-gnu-default-packages ","))))
 
             ((equal key "archive")
              ;; We simplify, by assuming just archived bugs are requested.
@@ -317,8 +362,8 @@ marked as \"client-side filter\"."
               val1
               (completing-read "Enter status: " '("done" "forwarded" "open")))
              (when (not (zerop (length val1)))
-           (add-to-list
-            'debbugs-gnu-current-query (cons (intern key) val1))))
+               (add-to-list
+                'debbugs-gnu-current-query (cons (intern key) val1))))
 
             ;; Client-side filters.
             ((member key '("date" "log_modified" "last_modified"
@@ -382,26 +427,28 @@ marked as \"client-side filter\"."
          debbugs-gnu-current-filter nil)))
 
 ;;;###autoload
-(defun debbugs-gnu (severities &optional packages archivedp suppress)
-  "List all outstanding Emacs bugs."
+(defun debbugs-gnu (severities &optional packages archivedp suppress tags)
+  "List all outstanding bugs."
   (interactive
-   (let (archivedp)
+   (let (severities archivedp)
      (list
-      (completing-read-multiple
-       "Severities: "
-       (mapcar 'cadr (cdr (get 'debbugs-gnu-default-severities 'custom-type)))
-       nil t (mapconcat 'identity debbugs-gnu-default-severities ","))
-      ;; The optional parameters are asked only when there is a prefix.
+      (setq severities
+           (completing-read-multiple
+            "Severities: " debbugs-gnu-all-severities nil t
+            (mapconcat 'identity debbugs-gnu-default-severities ",")))
+      ;; The next parameters are asked only when there is a prefix.
       (if current-prefix-arg
          (completing-read-multiple
-          "Packages: "
-          (mapcar 'cadr (cdr (get 'debbugs-gnu-default-packages 'custom-type)))
-          nil t (mapconcat 'identity debbugs-gnu-default-packages ","))
+          "Packages: " debbugs-gnu-all-packages nil t
+          (mapconcat 'identity debbugs-gnu-default-packages ","))
        debbugs-gnu-default-packages)
       (when current-prefix-arg
        (setq archivedp (y-or-n-p "Show archived bugs?")))
       (when (and current-prefix-arg (not archivedp))
-       (y-or-n-p "Suppress unwanted bugs?")))))
+       (y-or-n-p "Suppress unwanted bugs?"))
+      ;; This one must be asked for severity "tagged".
+      (when (member "tagged" severities)
+       (split-string (read-string "User tag(s): ") "," t)))))
 
   ;; Initialize variables.
   (when (and (file-exists-p debbugs-gnu-persistency-file)
@@ -420,6 +467,12 @@ marked as \"client-side filter\"."
       (add-to-list 'debbugs-gnu-current-query (cons 'package package))))
   (when archivedp
     (add-to-list 'debbugs-gnu-current-query '(archive . "1")))
+  (when suppress
+    (add-to-list 'debbugs-gnu-current-query '(status . "open"))
+    (add-to-list 'debbugs-gnu-current-query '(status . "forwarded")))
+  (dolist (tag (if (consp tags) tags (list tags)))
+    (when (not (zerop (length tag)))
+      (add-to-list 'debbugs-gnu-current-query (cons 'tag tag))))
 
   (unwind-protect
       (let ((hits debbugs-gnu-default-hits-per-page)
@@ -478,13 +531,14 @@ marked as \"client-side filter\"."
 
 (defun debbugs-gnu-get-bugs (query)
   "Retrieve bugs numbers from debbugs.gnu.org according search criteria."
-  (let ((debbugs-port "gnu.org")
-       (tagged (when (member '(severity . "tagged") query)
-                 (copy-sequence debbugs-gnu-local-tags)))
-       (phrase (assoc 'phrase query))
-       args)
+  (let* ((debbugs-port "gnu.org")
+        (bugs (assoc 'bugs query))
+        (tags (assoc 'tag query))
+        (local-tags (and (member '(severity . "tagged") query) (not tags)))
+        (phrase (assoc 'phrase query))
+        args)
     ;; Compile query arguments.
-    (unless query
+    (unless (or query tags)
       (dolist (elt debbugs-gnu-default-packages)
        (setq args (append args (list :package elt)))))
     (dolist (elt query)
@@ -505,35 +559,42 @@ marked as \"client-side filter\"."
                 (list (intern (concat ":" (symbol-name (car elt))))
                       (cdr elt)))))))
 
-    (cond
-     ;; If the query contains only the pseudo-severity "tagged", we
-     ;; return just the local tagged bugs.
-     ((and tagged (not (memq :severity args)))
-      (sort tagged '<))
-     ;; A full text query.
-     (phrase
-      (append
+    (sort
+     (cond
+      ;; If the query is just a list of bug numbers, we return them.
+      (bugs (cdr bugs))
+      ;; If the query contains the pseudo-severity "tagged", we return
+      ;; just the local tagged bugs.
+      (local-tags (copy-sequence debbugs-gnu-local-tags))
+      ;; A full text query.
+      (phrase
        (mapcar
        (lambda (x) (cdr (assoc "id" x)))
-       (apply 'debbugs-search-est args))
-       tagged))
-     ;; Otherwise, we retrieve the bugs from the server.
-     (t (sort (append (apply 'debbugs-get-bugs args) tagged) '<)))))
+       (apply 'debbugs-search-est args)))
+      ;; User tags.
+      (tags
+       (setq args (mapcar (lambda (x) (if (eq x :package) :user x)) args))
+       (apply 'debbugs-get-usertag args))
+      ;; Otherwise, we retrieve the bugs from the server.
+      (t (apply 'debbugs-get-bugs args)))
+     ;; Sort function.
+     '<)))
 
 (defvar debbugs-gnu-current-widget nil)
 (defvar debbugs-gnu-current-limit nil)
 
-(defvar widget-mouse-face)
-
 (defun debbugs-gnu-show-reports (widget)
   "Show bug reports as given in WIDGET property :bug-ids."
+  ;; The tabulated mode sets several local variables.  We must get rid
+  ;; of them.
+  (when (get-buffer (widget-get widget :buffer-name))
+    (kill-buffer (widget-get widget :buffer-name)))
   (pop-to-buffer (get-buffer-create (widget-get widget :buffer-name)))
   (debbugs-gnu-mode)
   (let ((inhibit-read-only t)
        (debbugs-port "gnu.org"))
     (erase-buffer)
-    (set (make-local-variable 'debbugs-gnu-current-widget)
-        widget)
+    (set (make-local-variable 'debbugs-gnu-current-widget) widget)
 
     (dolist (status (apply 'debbugs-get-status (widget-get widget :bug-ids)))
       (let* ((id (cdr (assq 'id status)))
@@ -930,13 +991,21 @@ Subject fields."
 (defun debbugs-gnu-current-status ()
   (get-text-property (line-beginning-position) 'tabulated-list-id))
 
-(defun debbugs-gnu-display-status (status)
-  "Display the status of the report on the current line."
-  (interactive (list (debbugs-gnu-current-status)))
+(defun debbugs-gnu-current-query ()
+  (widget-get debbugs-gnu-current-widget :query))
+
+(defun debbugs-gnu-display-status (query status)
+  "Display the query and status of the report on the current line."
+  (interactive (list (debbugs-gnu-current-query)
+                    (debbugs-gnu-current-status)))
   (pop-to-buffer "*Bug Status*")
-  (erase-buffer)
-  (pp status (current-buffer))
-  (goto-char (point-min)))
+  (let ((inhibit-read-only t))
+    (erase-buffer)
+    (when query (pp query (current-buffer)))
+    (when status (pp status (current-buffer)))
+    (goto-char (point-min)))
+  (set-buffer-modified-p nil)
+  (special-mode))
 
 (defun debbugs-gnu-select-report ()
   "Select the report on the current line."
@@ -1021,7 +1090,8 @@ removed instead."
            "invalid"
            "reassign"
            "patch" "wontfix" "moreinfo" "unreproducible" "fixed" "notabug"
-           "pending" "help" "security" "confirmed")
+           "pending" "help" "security" "confirmed"
+           "usertag")
          nil t)
         current-prefix-arg))
   (let* ((id (or debbugs-gnu-bug-number        ; Set on group entry.
@@ -1073,12 +1143,121 @@ removed instead."
               ((equal message "invalid")
                (format "tags %d notabug\ntags %d wontfix\nclose %d\n"
                        id id id))
+              ((equal message "usertag")
+               (format "user %s\nusertag %d %s\n"
+                       (completing-read
+                        "Package name or email address: "
+                        (append
+                         debbugs-gnu-all-packages (list user-mail-address))
+                        nil nil (car debbugs-gnu-default-packages))
+                       id (read-string "User tag: ")))
               (t
                (format "tags %d%s %s\n"
                        id (if reverse " -" "")
                        message))))
       (funcall send-mail-function))))
 
+(defvar debbugs-gnu-usertags-mode-map
+  (let ((map (make-sparse-keymap)))
+    (set-keymap-parent map tabulated-list-mode-map)
+    (define-key map "\r" 'debbugs-gnu-select-usertag)
+    (define-key map [mouse-1] 'debbugs-gnu-select-usertag)
+    (define-key map [mouse-2] 'debbugs-gnu-select-usertag)
+    map))
+
+(define-derived-mode debbugs-gnu-usertags-mode tabulated-list-mode "Usertags"
+  "Major mode for listing user tags.
+
+All normal editing commands are switched off.
+\\<debbugs-gnu-usertags-mode-map>
+
+The following commands are available:
+
+\\{debbugs-gnu-usertags-mode-map}"
+  (buffer-disable-undo)
+  (setq truncate-lines t)
+  (setq buffer-read-only t))
+
+;;;###autoload
+(defun debbugs-gnu-usertags (&rest users)
+  "List all user tags for USERS, which is \(\"emacs\"\) by default."
+  (interactive
+   (if current-prefix-arg
+       (completing-read-multiple
+       "Package name(s) or email address: "
+       (append debbugs-gnu-all-packages (list user-mail-address)) nil nil
+       (mapconcat 'identity debbugs-gnu-default-packages ","))
+     debbugs-gnu-default-packages))
+
+  (unwind-protect
+      (let ((inhibit-read-only t)
+           (debbugs-port "gnu.org")
+           (buffer-name "*Emacs User Tags*")
+           (user-tab-length
+            (1+ (apply 'max (length "User") (mapcar 'length users)))))
+
+       ;; Initialize variables.
+       (when (and (file-exists-p debbugs-gnu-persistency-file)
+                  (not debbugs-gnu-local-tags))
+         (with-temp-buffer
+           (insert-file-contents debbugs-gnu-persistency-file)
+           (eval (read (current-buffer)))))
+
+       ;; Create buffer.
+       (when (get-buffer buffer-name)
+         (kill-buffer buffer-name))
+       (pop-to-buffer (get-buffer-create buffer-name))
+       (debbugs-gnu-usertags-mode)
+       (setq tabulated-list-format `[("User" ,user-tab-length t)
+                                     ("Tag"  10 t)])
+       (setq tabulated-list-sort-key (cons "User" nil))
+       ;(setq tabulated-list-printer 'debbugs-gnu-print-entry)
+       (erase-buffer)
+
+       ;; Retrieve user tags.
+       (dolist (user users)
+         (dolist (tag (sort (debbugs-get-usertag :user user) 'string<))
+           (add-to-list
+            'tabulated-list-entries
+            ;; `tabulated-list-id' is the parameter list for `debbugs-gnu'.
+            `((("tagged") (,user) nil nil (,tag))
+              ,(vector (propertize user 'mouse-face widget-mouse-face)
+                       (propertize tag 'mouse-face widget-mouse-face)))
+            'append)))
+
+       ;; Add local tags.
+       (when debbugs-gnu-local-tags
+         (add-to-list
+            'tabulated-list-entries
+            `((("tagged"))
+              ,(vector "" (propertize "(local tags)"
+                                      'mouse-face widget-mouse-face)))))
+
+       ;; Show them.
+       (tabulated-list-init-header)
+       (tabulated-list-print)
+
+       (set-buffer-modified-p nil)
+       (goto-char (point-min)))))
+
+(defun debbugs-gnu-select-usertag ()
+  "Select the user tag on the current line."
+  (interactive)
+  ;; We open the bug reports.
+  (let ((args (get-text-property (line-beginning-position) 'tabulated-list-id)))
+    (when args (apply 'debbugs-gnu args))))
+
+;;;###autoload
+(defun debbugs-gnu-bugs (&rest bugs)
+  "List all BUGS, a list of bug numbers."
+  (interactive
+   (mapcar 'string-to-number
+          (completing-read-multiple "Bug numbers: " nil 'natnump)))
+  (dolist (elt bugs)
+    (unless (natnump elt) (signal 'wrong-type-argument (list 'natnump elt))))
+  (add-to-list 'debbugs-gnu-current-query (cons 'bugs bugs))
+  (debbugs-gnu nil))
+
 (provide 'debbugs-gnu)
 
 ;;; TODO: