1#! /usr/bin/env python3 

2 

3""" Microscopic modification and query tool for overrides in projectb """ 

4# Copyright (C) 2004, 2006 Daniel Silverstone <dsilvers@digital-scurf.org> 

5 

6# This program is free software; you can redistribute it and/or modify 

7# it under the terms of the GNU General Public License as published by 

8# the Free Software Foundation; either version 2 of the License, or 

9# (at your option) any later version. 

10 

11# This program is distributed in the hope that it will be useful, 

12# but WITHOUT ANY WARRANTY; without even the implied warranty of 

13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

14# GNU General Public License for more details. 

15 

16# You should have received a copy of the GNU General Public License 

17# along with this program; if not, write to the Free Software 

18# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 

19 

20 

21################################################################################ 

22## So line up your soldiers and she'll shoot them all down 

23## Coz Alisha Rules The World 

24## You think you found a dream, then it shatters and it seems, 

25## That Alisha Rules The World 

26################################################################################ 

27 

28import os 

29import sys 

30import apt_pkg 

31 

32from daklib.config import Config 

33from daklib.dbconn import * 

34from daklib import daklog 

35from daklib import utils 

36 

37################################################################################ 

38 

39# Shamelessly stolen from 'dak rm'. Should probably end up in utils.py 

40 

41 

42def game_over(): 

43 answer = utils.input_or_exit("Continue (y/N)? ").lower() 

44 if answer != "y": 

45 print("Aborted.") 

46 sys.exit(1) 

47 

48 

49def usage(exit_code=0): 

50 print("""Usage: dak override [OPTIONS] package [section] [priority] 

51Make microchanges or microqueries of the binary overrides 

52 

53 -h, --help show this help and exit 

54 -c, --check check override compliance (deprecated) 

55 -d, --done=BUG# send priority/section change as closure to bug# 

56 -n, --no-action don't do anything 

57 -s, --suite specify the suite to use 

58""") 

59 sys.exit(exit_code) 

60 

61 

62def main(): 

63 cnf = Config() 

64 

65 Arguments = [('h', "help", "Override::Options::Help"), 

66 ('c', "check", "Override::Options::Check"), 

67 ('d', "done", "Override::Options::Done", "HasArg"), 

68 ('n', "no-action", "Override::Options::No-Action"), 

69 ('s', "suite", "Override::Options::Suite", "HasArg"), 

70 ] 

71 for i in ["help", "check", "no-action"]: 

72 key = "Override::Options::%s" % i 

73 if key not in cnf: 73 ↛ 71line 73 didn't jump to line 71, because the condition on line 73 was never false

74 cnf[key] = "" 

75 if "Override::Options::Suite" not in cnf: 75 ↛ 78line 75 didn't jump to line 78, because the condition on line 75 was never false

76 cnf["Override::Options::Suite"] = "unstable" 

77 

78 arguments = apt_pkg.parse_commandline(cnf.Cnf, Arguments, sys.argv) 

79 Options = cnf.subtree("Override::Options") 

80 

81 if Options["Help"]: 81 ↛ 84line 81 didn't jump to line 84, because the condition on line 81 was never false

82 usage() 

83 

84 session = DBConn().session() 

85 

86 if not arguments: 

87 utils.fubar("package name is a required argument.") 

88 

89 package = arguments.pop(0) 

90 suite_name = Options["Suite"] 

91 if arguments and len(arguments) > 2: 

92 utils.fubar("Too many arguments") 

93 

94 suite = get_suite(suite_name, session) 

95 if suite is None: 

96 utils.fubar("Unknown suite '{0}'".format(suite_name)) 

97 

98 if arguments and len(arguments) == 1: 

99 # Determine if the argument is a priority or a section... 

100 arg = arguments.pop() 

101 q = session.execute(""" 

102 SELECT ( SELECT COUNT(*) FROM section WHERE section = :arg ) AS secs, 

103 ( SELECT COUNT(*) FROM priority WHERE priority = :arg ) AS prios 

104 """, {'arg': arg}) 

105 r = q.fetchall() 

106 if r[0][0] == 1: 

107 arguments = (arg, ".") 

108 elif r[0][1] == 1: 

109 arguments = (".", arg) 

110 else: 

111 utils.fubar("%s is not a valid section or priority" % (arg)) 

112 

113 # Retrieve current section/priority... 

114 oldsection, oldsourcesection, oldpriority = None, None, None 

115 for packagetype in ['source', 'binary']: 

116 eqdsc = '!=' 

117 if packagetype == 'source': 

118 eqdsc = '=' 

119 q = session.execute(""" 

120 SELECT priority.priority AS prio, section.section AS sect, override_type.type AS type 

121 FROM override, priority, section, suite, override_type 

122 WHERE override.priority = priority.id 

123 AND override.type = override_type.id 

124 AND override_type.type %s 'dsc' 

125 AND override.section = section.id 

126 AND override.package = :package 

127 AND override.suite = suite.id 

128 AND suite.suite_name = :suite_name 

129 """ % (eqdsc), {'package': package, 'suite_name': suite_name}) 

130 

131 if q.rowcount == 0: 

132 continue 

133 if q.rowcount > 1: 

134 utils.fubar("%s is ambiguous. Matches %d packages" % (package, q.rowcount)) 

135 

136 r = q.fetchone() 

137 if packagetype == 'binary': 

138 oldsection = r[1] 

139 oldpriority = r[0] 

140 else: 

141 oldsourcesection = r[1] 

142 oldpriority = 'optional' 

143 

144 if not oldpriority and not oldsourcesection: 

145 utils.fubar("Unable to find package %s" % (package)) 

146 

147 if oldsection and oldsourcesection and oldsection != oldsourcesection: 

148 # When setting overrides, both source & binary will become the same section 

149 utils.warn("Source is in section '%s' instead of '%s'" % (oldsourcesection, oldsection)) 

150 

151 if not oldsection: 

152 oldsection = oldsourcesection 

153 

154 if not arguments: 

155 print("%s is in section '%s' at priority '%s'" % ( 

156 package, oldsection, oldpriority)) 

157 sys.exit(0) 

158 

159 # At this point, we have a new section and priority... check they're valid... 

160 newsection, newpriority = arguments 

161 

162 if newsection == ".": 

163 newsection = oldsection 

164 if newpriority == ".": 

165 newpriority = oldpriority 

166 

167 s = get_section(newsection, session) 

168 if s is None: 

169 utils.fubar("Supplied section %s is invalid" % (newsection)) 

170 newsecid = s.section_id 

171 

172 p = get_priority(newpriority, session) 

173 if p is None: 

174 utils.fubar("Supplied priority %s is invalid" % (newpriority)) 

175 newprioid = p.priority_id 

176 

177 if newpriority == oldpriority and newsection == oldsection: 

178 print("I: Doing nothing") 

179 sys.exit(0) 

180 

181 if Options["Check"]: 

182 print("WARNING: Check option is deprecated by Debian Policy 4.0.1") 

183 

184 # If we're in no-action mode 

185 if Options["No-Action"]: 

186 if newpriority != oldpriority: 

187 print("I: Would change priority from %s to %s" % (oldpriority, newpriority)) 

188 if newsection != oldsection: 

189 print("I: Would change section from %s to %s" % (oldsection, newsection)) 

190 if "Done" in Options: 

191 print("I: Would also close bug(s): %s" % (Options["Done"])) 

192 

193 sys.exit(0) 

194 

195 if newpriority != oldpriority: 

196 print("I: Will change priority from %s to %s" % (oldpriority, newpriority)) 

197 

198 if newsection != oldsection: 

199 print("I: Will change section from %s to %s" % (oldsection, newsection)) 

200 

201 if "Done" not in Options: 

202 pass 

203 # utils.warn("No bugs to close have been specified. Noone will know you have done this.") 

204 else: 

205 print("I: Will close bug(s): %s" % (Options["Done"])) 

206 

207 game_over() 

208 

209 Logger = daklog.Logger("override") 

210 

211 dsc_otype_id = get_override_type('dsc').overridetype_id 

212 

213 # We're already in a transaction 

214 # We're in "do it" mode, we have something to do... do it 

215 if newpriority != oldpriority: 

216 session.execute(""" 

217 UPDATE override 

218 SET priority = :newprioid 

219 WHERE package = :package 

220 AND override.type != :otypedsc 

221 AND suite = (SELECT id FROM suite WHERE suite_name = :suite_name)""", 

222 {'newprioid': newprioid, 'package': package, 

223 'otypedsc': dsc_otype_id, 'suite_name': suite_name}) 

224 

225 Logger.log(["changed priority", package, oldpriority, newpriority]) 

226 

227 if newsection != oldsection: 

228 q = session.execute(""" 

229 UPDATE override 

230 SET section = :newsecid 

231 WHERE package = :package 

232 AND suite = (SELECT id FROM suite WHERE suite_name = :suite_name)""", 

233 {'newsecid': newsecid, 'package': package, 

234 'suite_name': suite_name}) 

235 

236 Logger.log(["changed section", package, oldsection, newsection]) 

237 

238 session.commit() 

239 

240 if "Done" in Options: 

241 if "Dinstall::BugServer" not in cnf: 

242 utils.warn("Asked to send Done message but Dinstall::BugServer is not configured") 

243 Logger.close() 

244 return 

245 

246 Subst = {} 

247 Subst["__OVERRIDE_ADDRESS__"] = cnf["Dinstall::MyEmailAddress"] 

248 Subst["__BUG_SERVER__"] = cnf["Dinstall::BugServer"] 

249 bcc = [] 

250 if cnf.find("Dinstall::Bcc") != "": 

251 bcc.append(cnf["Dinstall::Bcc"]) 

252 if bcc: 

253 Subst["__BCC__"] = "Bcc: " + ", ".join(bcc) 

254 else: 

255 Subst["__BCC__"] = "X-Filler: 42" 

256 if "Dinstall::PackagesServer" in cnf: 

257 Subst["__CC__"] = "Cc: " + package + "@" + cnf["Dinstall::PackagesServer"] + "\nX-DAK: dak override" 

258 else: 

259 Subst["__CC__"] = "X-DAK: dak override" 

260 Subst["__ADMIN_ADDRESS__"] = cnf["Dinstall::MyAdminAddress"] 

261 Subst["__DISTRO__"] = cnf["Dinstall::MyDistribution"] 

262 Subst["__WHOAMI__"] = utils.whoami() 

263 Subst["__SOURCE__"] = package 

264 

265 summary = "Concerning package %s...\n" % (package) 

266 summary += "Operating on the %s suite\n" % (suite_name) 

267 if newpriority != oldpriority: 

268 summary += "Changed priority from %s to %s\n" % (oldpriority, newpriority) 

269 if newsection != oldsection: 

270 summary += "Changed section from %s to %s\n" % (oldsection, newsection) 

271 Subst["__SUMMARY__"] = summary 

272 

273 template = os.path.join(cnf["Dir::Templates"], "override.bug-close") 

274 for bug in utils.split_args(Options["Done"]): 

275 Subst["__BUG_NUMBER__"] = bug 

276 mail_message = utils.TemplateSubst(Subst, template) 

277 utils.send_mail(mail_message) 

278 Logger.log(["closed bug", bug]) 

279 

280 Logger.close() 

281 

282################################################################################# 

283 

284 

285if __name__ == '__main__': 

286 main()