1#! /usr/bin/env python3
3"""
4bts -- manage bugs filed against ftp.debian.org
6@contact: Debian FTP Master <ftpmaster@debian.org>
7@copyright: 2009 Mike O'Connor <stew@vireo.org>
8@copyright: 2010 Alexander Reichle-Schmehl <tolimar@debian.org>
9@license: GNU General Public License version 2 or later
10"""
12# This program is free software; you can redistribute it and/or modify it
13# under the terms of the GNU General Public License as published by the
14# Free Software Foundation; either version 2, or (at your option) any
15# later version.
16#
17# This program is distributed in the hope that it will be useful,
18# but WITHOUT ANY WARRANTY; without even the implied warranty of
19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20# GNU General Public License for more details.
21#
22# You should have received a copy of the GNU General Public License
23# along with this program; if not, write to the Free Software
24# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
25# USA.
27################################################################################
28################################################################################
30import sys
31import re
32import logging
33log = logging.getLogger()
35import apt_pkg
36from daklib import utils
37import debianbts as bts
40def usage():
41 print("""
42SYNOPSIS
43 dak bts-categorize [options]
45OPTIONS
46 -s
47 --simulate
48 Don't send email, instead output the lines that would be sent to
49 control@b.d.o.
51 -v
52 --verbose
53 Print more informational log messages
55 -q
56 --quiet
57 Suppress informational messages
59 -h
60 --help
61 Print this documentation.
62""")
65arguments = [('s', 'simulate', 'BtsCategorize::Options::Simulate'),
66 ('v', 'verbose', 'BtsCategorize::Options::Verbose'),
67 ('q', 'quiet', 'BtsCategorize::Options::Quiet'),
68 ('h', 'help', 'BtsCategorize::Options::Help'),
69 ('o', 'option', '', 'ArbItem')]
72class BugClassifier:
73 """
74 classify bugs using usertags based on the bug subject lines
76 >>> BugClassifier.rm_re.match( "RM: asdf" ) != None
77 True
78 >>> BugClassifier.rm_re.match( "[dak] Packages.diff/Index broken" ) != None
79 False
80 >>> BugClassifier.dak_re.match( "[dak] Packages.diff/Index broken" ) != None
81 True
82 """
83 rm_re = re.compile("^RM")
84 dak_re = re.compile(r"^\[dak\]")
85 arch_re = re.compile(r"^\[Architectures\]")
86 override_re = re.compile("^override")
88 classifiers = {rm_re: 'remove',
89 dak_re: 'dak',
90 arch_re: 'archs',
91 override_re: 'override'}
93 def unclassified_bugs(self):
94 """
95 Returns a list of open bugs which have not yet been classified
96 by one of our usertags.
97 """
99 tagged_bugs = bts.get_usertag('ftp.debian.org@packages.debian.org')
100 tagged_bugs_ftp = []
101 for tags in tagged_bugs.keys():
102 tagged_bugs_ftp += tagged_bugs[tags]
104 return [bug for bug in bts.get_status(bts.get_bugs(package="ftp.debian.org"))
105 if bug.pending == 'pending' and bug.bug_num not in tagged_bugs_ftp]
107 def classify_bug(self, bug):
108 """
109 if any of our classifiers match, return a newline terminated
110 command to set an appropriate usertag, otherwise return an
111 empty string
112 """
113 retval = ""
115 for classifier in self.classifiers.keys():
116 if classifier.match(bug.subject):
117 retval = "usertag %s %s\n" % (bug.bug_num,
118 self.classifiers[classifier])
119 break
121 if retval:
122 log.info(retval)
123 else:
124 log.debug("Unmatched: [%s] %s" % (bug.bug_num, bug.subject))
126 return retval
128 def email_text(self):
129 controls = ""
131 bc = BugClassifier()
132 try:
133 for bug in bc.unclassified_bugs():
134 controls += bc.classify_bug(bug)
136 return controls
137 except:
138 log.error("couldn't retrieve bugs from soap interface: %s" % sys.exc_info()[0])
139 return None
142def send_email(commands, simulate=False):
143 global Cnf
145 Subst = {'__COMMANDS__': commands,
146 "__DAK_ADDRESS__": Cnf["Dinstall::MyAdminAddress"]}
148 bts_mail_message = utils.TemplateSubst(
149 Subst, Cnf["Dir::Templates"] + "/bts-categorize")
151 if simulate:
152 print(bts_mail_message)
153 else:
154 utils.send_mail(bts_mail_message)
157def main():
158 """
159 for now, we just dump a list of commands that could be sent for
160 control@b.d.o
161 """
162 global Cnf
163 Cnf = utils.get_conf()
165 for arg in arguments:
166 opt = "BtsCategorize::Options::%s" % arg[1]
167 if opt not in Cnf: 167 ↛ 165line 167 didn't jump to line 165, because the condition on line 167 was never false
168 Cnf[opt] = ""
170 packages = apt_pkg.parse_commandline(Cnf, arguments, sys.argv)
171 Options = Cnf.subtree('BtsCategorize::Options')
173 if Options["Help"]: 173 ↛ 177line 173 didn't jump to line 177, because the condition on line 173 was never false
174 usage()
175 sys.exit(0)
177 if Options["Quiet"]:
178 level = logging.ERROR
180 elif Options["Verbose"]:
181 level = logging.DEBUG
183 else:
184 level = logging.INFO
186 logging.basicConfig(level=level,
187 format='%(asctime)s %(levelname)s %(message)s',
188 stream=sys.stderr)
190 body = BugClassifier().email_text()
192 if body:
193 send_email(body, Options["Simulate"])
195 else:
196 log.info("nothing to do")
199if __name__ == '__main__':
200 # import doctest
201 # doctest.testmod()
202 main()