]> git.decadent.org.uk Git - dak.git/blob - dak/bts_categorize.py
Merge commit 'stew/categorize-bts' into merge
[dak.git] / dak / bts_categorize.py
1 #!/usr/bin/python
2
3 """
4 bts -- manage bugs filed against ftp.debian.org
5
6 Copyright 2009 Mike O'Connor <stew@vireo.org>
7 """
8
9 #  This program is free software; you can redistribute it and/or modify it
10 #  under the terms of the GNU General Public License as published by the
11 #  Free Software Foundation; either version 2, or (at your option) any
12 #  later version.
13 #
14 #  This program is distributed in the hope that it will be useful,
15 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 #  GNU General Public License for more details.
18 #
19 #  You should have received a copy of the GNU General Public License
20 #  along with this program; if not, write to the Free Software
21 #  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
22 #  USA.
23
24 ################################################################################
25 ################################################################################
26
27 import sys
28 import re
29 import logging
30 log = logging.getLogger()
31
32 import apt_pkg
33 from daklib import utils
34 from btsutils.debbugs import debbugs
35
36 def usage():
37     print """
38 SYNOPSIS
39     dak bts-categorize [options]
40
41 OPTIONS
42     -s
43     --simulate
44         Don't send email, instead output the lines that would be sent to
45         control@b.d.o.
46
47     -v
48     --verbose
49         Print more informational log messages
50
51     -q
52     --quiet
53         Suppress informational messages
54
55     -h
56     --help
57         Print this documentation.
58 """
59
60 arguments = [('s','simulate','BtsCategorize::Options::Simulate'),
61              ('v', 'verbose', 'BtsCategorize::Options::Verbose'),
62              ('q', 'quiet', 'BtsCategorize::Options::Quiet'),
63              ('h', 'help', 'BtsCategorize::Options::Help')]
64
65 class BugClassifier(object):
66     """
67     classify bugs using usertags based on the bug subject lines
68
69     >>> BugClassifier.rm_re.match( "RM: asdf" ) != None
70     True
71     >>> BugClassifier.rm_re.match( "[dak] Packages.diff/Index broken" ) != None
72     False
73     >>> BugClassifier.dak_re.match( "[dak] Packages.diff/Index broken" ) != None
74     True
75     """
76     rm_re = re.compile( "^RM" )
77     dak_re = re.compile( "^\[dak\]" )
78     arch_re = re.compile( "^\[Architectures\]" )
79
80     classifiers = { rm_re: 'remove',
81                     dak_re: 'dak',
82                     arch_re: 'archs'}
83
84     def __init__( self ):
85         self.bts = debbugs()
86         self.bts.setUsers(['ftp.debian.org@packages.debian.org'])
87
88
89     def unclassified_bugs(self):
90         """
91         Returns a list of open bugs which have not yet been classified
92         by one of our usertags.
93         """
94         return [ bug for bug in self.bts.query("pkg:ftp.debian.org") \
95                      if bug.status=='pending' and not bug.usertags ]
96
97
98     def classify_bug(self, bug):
99         """
100         if any of our classifiers match, return a newline terminated
101         command to set an appropriate usertag, otherwise return an
102         empty string
103         """
104         retval = ""
105
106         for classifier in self.classifiers.keys():
107             if classifier.match(bug.summary):
108                 retval = "usertag %s %s\n" % (bug.bug,
109                                             self.classifiers[classifier])
110                 break
111
112         if retval:
113             log.info(retval)
114         else:
115             log.debug("Unmatched: [%s] %s" % (bug.bug, bug.summary))
116
117         return retval
118
119     def email_text(self):
120         controls = ""
121
122         bc = BugClassifier()
123         for bug in bc.unclassified_bugs():
124             controls += bc.classify_bug(bug)
125
126         return controls
127
128 def send_email(commands, simulate=False):
129     global Cnf
130
131     Subst = {'__COMMANDS__' : commands,
132              "__DAK_ADDRESS__": Cnf["Dinstall::MyAdminAddress"]}
133
134     bts_mail_message = utils.TemplateSubst(
135         Subst,Cnf["Dir::Templates"]+"/bts-categorize")
136
137     if simulate:
138         print bts_mail_message
139     else:
140         utils.send_mail( bts_mail_message )
141
142 def main():
143     """
144     for now, we just dump a list of commands that could be sent for
145     control@b.d.o
146     """
147     global Cnf
148     Cnf = utils.get_conf()
149
150     for arg in arguments:
151         opt = "BtsCategorize::Options::%s" % arg[1]
152         if not Cnf.has_key(opt):
153             Cnf[opt] = ""
154
155     packages = apt_pkg.ParseCommandLine(Cnf, arguments, sys.argv)
156     Options = Cnf.SubTree('BtsCategorize::Options')
157
158     if Options["Help"]:
159         usage()
160         sys.exit( 0 )
161
162     if Options["Quiet"]:
163         level=logging.ERROR
164
165     elif Options["Verbose"]:
166         level=logging.DEBUG
167
168     else:
169         level=logging.INFO
170
171     logging.basicConfig( level=level,
172                          format='%(asctime)s %(levelname)s %(message)s',
173                          stream = sys.stderr )
174
175     body = BugClassifier().email_text()
176
177     if body:
178         send_email(body, Options["Simulate"])
179
180     else:
181         log.info( "nothing to do" )
182
183
184 if __name__ == '__main__':
185 #    import doctest
186 #    doctest.testmod()
187     main()