1#! /usr/bin/env python3 

2 

3""" 

4bts -- 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@copyright: 2010 Alexander Reichle-Schmehl <tolimar@debian.org> 

9@license: GNU General Public License version 2 or later 

10""" 

11 

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. 

26 

27################################################################################ 

28################################################################################ 

29 

30import sys 

31import re 

32import logging 

33log = logging.getLogger() 

34 

35import apt_pkg 

36from daklib import utils 

37import debianbts as bts 

38 

39 

40def usage(): 

41 print(""" 

42SYNOPSIS 

43 dak bts-categorize [options] 

44 

45OPTIONS 

46 -s 

47 --simulate 

48 Don't send email, instead output the lines that would be sent to 

49 control@b.d.o. 

50 

51 -v 

52 --verbose 

53 Print more informational log messages 

54 

55 -q 

56 --quiet 

57 Suppress informational messages 

58 

59 -h 

60 --help 

61 Print this documentation. 

62""") 

63 

64 

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')] 

70 

71 

72class BugClassifier: 

73 """ 

74 classify bugs using usertags based on the bug subject lines 

75 

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") 

87 

88 classifiers = {rm_re: 'remove', 

89 dak_re: 'dak', 

90 arch_re: 'archs', 

91 override_re: 'override'} 

92 

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 """ 

98 

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] 

103 

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] 

106 

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 = "" 

114 

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 

120 

121 if retval: 

122 log.info(retval) 

123 else: 

124 log.debug("Unmatched: [%s] %s" % (bug.bug_num, bug.subject)) 

125 

126 return retval 

127 

128 def email_text(self): 

129 controls = "" 

130 

131 bc = BugClassifier() 

132 try: 

133 for bug in bc.unclassified_bugs(): 

134 controls += bc.classify_bug(bug) 

135 

136 return controls 

137 except: 

138 log.error("couldn't retrieve bugs from soap interface: %s" % sys.exc_info()[0]) 

139 return None 

140 

141 

142def send_email(commands, simulate=False): 

143 global Cnf 

144 

145 Subst = {'__COMMANDS__': commands, 

146 "__DAK_ADDRESS__": Cnf["Dinstall::MyAdminAddress"]} 

147 

148 bts_mail_message = utils.TemplateSubst( 

149 Subst, Cnf["Dir::Templates"] + "/bts-categorize") 

150 

151 if simulate: 

152 print(bts_mail_message) 

153 else: 

154 utils.send_mail(bts_mail_message) 

155 

156 

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() 

164 

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] = "" 

169 

170 packages = apt_pkg.parse_commandline(Cnf, arguments, sys.argv) 

171 Options = Cnf.subtree('BtsCategorize::Options') 

172 

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) 

176 

177 if Options["Quiet"]: 

178 level = logging.ERROR 

179 

180 elif Options["Verbose"]: 

181 level = logging.DEBUG 

182 

183 else: 

184 level = logging.INFO 

185 

186 logging.basicConfig(level=level, 

187 format='%(asctime)s %(levelname)s %(message)s', 

188 stream=sys.stderr) 

189 

190 body = BugClassifier().email_text() 

191 

192 if body: 

193 send_email(body, Options["Simulate"]) 

194 

195 else: 

196 log.info("nothing to do") 

197 

198 

199if __name__ == '__main__': 

200 # import doctest 

201 # doctest.testmod() 

202 main()