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 

30 

31import apt_pkg 

32 

33from daklib import daklog, utils 

34from daklib.config import Config 

35from daklib.dbconn import ( 

36 DBConn, 

37 get_override_type, 

38 get_priority, 

39 get_section, 

40 get_suite, 

41) 

42 

43################################################################################ 

44 

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

46 

47 

48def game_over(): 

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

50 if answer != "y": 

51 print("Aborted.") 

52 sys.exit(1) 

53 

54 

55def usage(exit_code=0): 

56 print( 

57 """Usage: dak override [OPTIONS] package [section] [priority] 

58Make microchanges or microqueries of the binary overrides 

59 

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

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

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

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

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

65""" 

66 ) 

67 sys.exit(exit_code) 

68 

69 

70def main(): 

71 cnf = Config() 

72 

73 Arguments = [ 

74 ("h", "help", "Override::Options::Help"), 

75 ("c", "check", "Override::Options::Check"), 

76 ("d", "done", "Override::Options::Done", "HasArg"), 

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

78 ("s", "suite", "Override::Options::Suite", "HasArg"), 

79 ] 

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

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

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

83 cnf[key] = "" 

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

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

86 

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

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

89 

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

91 usage() 

92 

93 session = DBConn().session() 

94 

95 if not arguments: 

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

97 

98 package = arguments.pop(0) 

99 suite_name = Options["Suite"] 

100 if arguments and len(arguments) > 2: 

101 utils.fubar("Too many arguments") 

102 

103 suite = get_suite(suite_name, session) 

104 if suite is None: 

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

106 

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

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

109 arg = arguments.pop() 

110 q = session.execute( 

111 """ 

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

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

114 """, 

115 {"arg": arg}, 

116 ) 

117 r = q.fetchall() 

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

119 arguments = (arg, ".") 

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

121 arguments = (".", arg) 

122 else: 

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

124 

125 # Retrieve current section/priority... 

126 oldsection, oldsourcesection, oldpriority = None, None, None 

127 for packagetype in ["source", "binary"]: 

128 eqdsc = "!=" 

129 if packagetype == "source": 

130 eqdsc = "=" 

131 q = session.execute( 

132 """ 

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

134 FROM override, priority, section, suite, override_type 

135 WHERE override.priority = priority.id 

136 AND override.type = override_type.id 

137 AND override_type.type %s 'dsc' 

138 AND override.section = section.id 

139 AND override.package = :package 

140 AND override.suite = suite.id 

141 AND suite.suite_name = :suite_name 

142 """ 

143 % (eqdsc), 

144 {"package": package, "suite_name": suite_name}, 

145 ) 

146 

147 if q.rowcount == 0: 

148 continue 

149 if q.rowcount > 1: 

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

151 

152 r = q.fetchone() 

153 if packagetype == "binary": 

154 oldsection = r[1] 

155 oldpriority = r[0] 

156 else: 

157 oldsourcesection = r[1] 

158 oldpriority = "optional" 

159 

160 if not oldpriority and not oldsourcesection: 

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

162 

163 if oldsection and oldsourcesection and oldsection != oldsourcesection: 

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

165 utils.warn( 

166 "Source is in section '%s' instead of '%s'" % (oldsourcesection, oldsection) 

167 ) 

168 

169 if not oldsection: 

170 oldsection = oldsourcesection 

171 

172 if not arguments: 

173 print( 

174 "%s is in section '%s' at priority '%s'" 

175 % (package, oldsection, oldpriority) 

176 ) 

177 sys.exit(0) 

178 

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

180 newsection, newpriority = arguments 

181 

182 if newsection == ".": 

183 newsection = oldsection 

184 if newpriority == ".": 

185 newpriority = oldpriority 

186 

187 s = get_section(newsection, session) 

188 if s is None: 

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

190 newsecid = s.section_id 

191 

192 p = get_priority(newpriority, session) 

193 if p is None: 

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

195 newprioid = p.priority_id 

196 

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

198 print("I: Doing nothing") 

199 sys.exit(0) 

200 

201 if Options["Check"]: 

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

203 

204 # If we're in no-action mode 

205 if Options["No-Action"]: 

206 if newpriority != oldpriority: 

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

208 if newsection != oldsection: 

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

210 if "Done" in Options: 

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

212 

213 sys.exit(0) 

214 

215 if newpriority != oldpriority: 

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

217 

218 if newsection != oldsection: 

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

220 

221 if "Done" not in Options: 

222 pass 

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

224 else: 

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

226 

227 game_over() 

228 

229 Logger = daklog.Logger("override") 

230 

231 dsc_otype_id = get_override_type("dsc").overridetype_id 

232 

233 # We're already in a transaction 

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

235 if newpriority != oldpriority: 

236 session.execute( 

237 """ 

238 UPDATE override 

239 SET priority = :newprioid 

240 WHERE package = :package 

241 AND override.type != :otypedsc 

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

243 { 

244 "newprioid": newprioid, 

245 "package": package, 

246 "otypedsc": dsc_otype_id, 

247 "suite_name": suite_name, 

248 }, 

249 ) 

250 

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

252 

253 if newsection != oldsection: 

254 q = session.execute( 

255 """ 

256 UPDATE override 

257 SET section = :newsecid 

258 WHERE package = :package 

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

260 {"newsecid": newsecid, "package": package, "suite_name": suite_name}, 

261 ) 

262 

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

264 

265 session.commit() 

266 

267 if "Done" in Options: 

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

269 utils.warn( 

270 "Asked to send Done message but Dinstall::BugServer is not configured" 

271 ) 

272 Logger.close() 

273 return 

274 

275 Subst = {} 

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

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

278 bcc = [] 

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

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

281 if bcc: 

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

283 else: 

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

285 if "Dinstall::PackagesServer" in cnf: 

286 Subst["__CC__"] = ( 

287 "Cc: " 

288 + package 

289 + "@" 

290 + cnf["Dinstall::PackagesServer"] 

291 + "\nX-DAK: dak override" 

292 ) 

293 else: 

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

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

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

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

298 Subst["__SOURCE__"] = package 

299 

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

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

302 if newpriority != oldpriority: 

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

304 if newsection != oldsection: 

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

306 Subst["__SUMMARY__"] = summary 

307 

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

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

310 Subst["__BUG_NUMBER__"] = bug 

311 mail_message = utils.TemplateSubst(Subst, template) 

312 utils.send_mail(mail_message) 

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

314 

315 Logger.close() 

316 

317 

318################################################################################# 

319 

320 

321if __name__ == "__main__": 

322 main()