]> git.decadent.org.uk Git - dak.git/blob - dak/bts_categorize.py
Merge branch 'psycopg2' into content_generation
[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         for bug in bc.unclassified_bugs():
126             controls += bc.classify_bug(bug)
127
128         return controls
129
130 def send_email(commands, simulate=False):
131     global Cnf
132
133     Subst = {'__COMMANDS__' : commands,
134              "__DAK_ADDRESS__": Cnf["Dinstall::MyAdminAddress"]}
135
136     bts_mail_message = utils.TemplateSubst(
137         Subst,Cnf["Dir::Templates"]+"/bts-categorize")
138
139     if simulate:
140         print bts_mail_message
141     else:
142         utils.send_mail( bts_mail_message )
143
144 def main():
145     """
146     for now, we just dump a list of commands that could be sent for
147     control@b.d.o
148     """
149     global Cnf
150     Cnf = utils.get_conf()
151
152     for arg in arguments:
153         opt = "BtsCategorize::Options::%s" % arg[1]
154         if not Cnf.has_key(opt):
155             Cnf[opt] = ""
156
157     packages = apt_pkg.ParseCommandLine(Cnf, arguments, sys.argv)
158     Options = Cnf.SubTree('BtsCategorize::Options')
159
160     if Options["Help"]:
161         usage()
162         sys.exit( 0 )
163
164     if Options["Quiet"]:
165         level=logging.ERROR
166
167     elif Options["Verbose"]:
168         level=logging.DEBUG
169
170     else:
171         level=logging.INFO
172
173     logging.basicConfig( level=level,
174                          format='%(asctime)s %(levelname)s %(message)s',
175                          stream = sys.stderr )
176
177     body = BugClassifier().email_text()
178
179     if body:
180         send_email(body, Options["Simulate"])
181
182     else:
183         log.info( "nothing to do" )
184
185
186 if __name__ == '__main__':
187 #    import doctest
188 #    doctest.testmod()
189     main()