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