Coverage for dak/control_overrides.py: 59%

177 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2025-08-26 22:11 +0000

1#! /usr/bin/env python3 

2 

3"""Bulk manipulation of the overrides""" 

4# Copyright (C) 2000, 2001, 2002, 2003, 2006 James Troup <james@nocrew.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# On 30 Nov 1998, James Troup wrote: 

23# 

24# > James Troup<2> <troup2@debian.org> 

25# > 

26# > James is a clone of James; he's going to take over the world. 

27# > After he gets some sleep. 

28# 

29# Could you clone other things too? Sheep? Llamas? Giant mutant turnips? 

30# 

31# Your clone will need some help to take over the world, maybe clone up an 

32# army of penguins and threaten to unleash them on the world, forcing 

33# governments to sway to the new James' will! 

34# 

35# Yes, I can envision a day when James' duplicate decides to take a horrific 

36# vengance on the James that spawned him and unleashes his fury in the form 

37# of thousands upon thousands of chickens that look just like Captin Blue 

38# Eye! Oh the horror. 

39# 

40# Now you'll have to were name tags to people can tell you apart, unless of 

41# course the new clone is truely evil in which case he should be easy to 

42# identify! 

43# 

44# Jason 

45# Chicken. Black. Helicopters. 

46# Be afraid. 

47 

48# <Pine.LNX.3.96.981130011300.30365Z-100000@wakko> 

49 

50################################################################################ 

51 

52import sys 

53import time 

54 

55import apt_pkg 

56 

57from daklib import daklog, utils 

58from daklib.config import Config 

59from daklib.dbconn import ( 

60 DBConn, 

61 get_component, 

62 get_override_type, 

63 get_priorities, 

64 get_sections, 

65 get_suite, 

66) 

67from daklib.regexes import re_comments 

68 

69################################################################################ 

70 

71Logger = None 

72 

73################################################################################ 

74 

75 

76def usage(exit_code=0): 

77 print( 

78 """Usage: dak control-overrides [OPTIONS] 

79 -h, --help print this help and exit 

80 

81 -c, --component=CMPT list/set overrides by component 

82 (contrib,*main,non-free) 

83 -s, --suite=SUITE list/set overrides by suite 

84 (experimental,stable,testing,*unstable) 

85 -t, --type=TYPE list/set overrides by type 

86 (*deb,dsc,udeb) 

87 

88 -a, --add add overrides (changes and deletions are ignored) 

89 -S, --set set overrides 

90 -C, --change change overrides (additions and deletions are ignored) 

91 -l, --list list overrides 

92 

93 -q, --quiet be less verbose 

94 -n, --no-action only list the action that would have been done 

95 -f, --force also work on untouchable suites 

96 

97 starred (*) values are default""" 

98 ) 

99 sys.exit(exit_code) 

100 

101 

102################################################################################ 

103 

104 

105def process_file(file, suite, component, otype, mode, action, session): 

106 cnf = Config() 

107 

108 s = get_suite(suite, session=session) 

109 if s is None: 109 ↛ 110line 109 didn't jump to line 110, because the condition on line 109 was never true

110 utils.fubar("Suite '%s' not recognised." % (suite)) 

111 suite_id = s.suite_id 

112 

113 c = get_component(component, session=session) 

114 if c is None: 114 ↛ 115line 114 didn't jump to line 115, because the condition on line 114 was never true

115 utils.fubar("Component '%s' not recognised." % (component)) 

116 component_id = c.component_id 

117 

118 o = get_override_type(otype) 

119 if o is None: 119 ↛ 120line 119 didn't jump to line 120, because the condition on line 119 was never true

120 utils.fubar( 

121 "Type '%s' not recognised. (Valid types are deb, udeb and dsc.)" % (otype) 

122 ) 

123 type_id = o.overridetype_id 

124 

125 # --set is done mostly internal for performance reasons; most 

126 # invocations of --set will be updates and making people wait 2-3 

127 # minutes while 6000 select+inserts are run needlessly isn't cool. 

128 

129 original = {} 

130 new = {} 

131 c_skipped = 0 

132 c_added = 0 

133 c_updated = 0 

134 c_removed = 0 

135 c_error = 0 

136 

137 q = session.execute( 

138 """SELECT o.package, o.priority, o.section, o.maintainer, p.priority, s.section 

139 FROM override o, priority p, section s 

140 WHERE o.suite = :suiteid AND o.component = :componentid AND o.type = :typeid 

141 and o.priority = p.id and o.section = s.id""", 

142 {"suiteid": suite_id, "componentid": component_id, "typeid": type_id}, 

143 ) 

144 for i in q.fetchall(): 

145 original[i[0]] = i[1:] 

146 

147 start_time = time.time() 

148 

149 section_cache = get_sections(session) 

150 priority_cache = get_priorities(session) 

151 

152 # Our session is already in a transaction 

153 

154 for line in file.readlines(): 

155 line = re_comments.sub("", line).strip() 

156 if line == "": 156 ↛ 157line 156 didn't jump to line 157, because the condition on line 156 was never true

157 continue 

158 

159 maintainer_override = None 

160 if otype == "dsc": 

161 split_line = line.split(None, 2) 

162 if len(split_line) == 2: 162 ↛ 164line 162 didn't jump to line 164, because the condition on line 162 was never false

163 (package, section) = split_line 

164 elif len(split_line) == 3: 

165 (package, section, maintainer_override) = split_line 

166 else: 

167 utils.warn( 

168 "'%s' does not break into 'package section [maintainer-override]'." 

169 % (line) 

170 ) 

171 c_error += 1 

172 continue 

173 priority = "optional" 

174 else: # binary or udeb 

175 split_line = line.split(None, 3) 

176 if len(split_line) == 3: 176 ↛ 178line 176 didn't jump to line 178, because the condition on line 176 was never false

177 (package, priority, section) = split_line 

178 elif len(split_line) == 4: 

179 (package, priority, section, maintainer_override) = split_line 

180 else: 

181 utils.warn( 

182 "'%s' does not break into 'package priority section [maintainer-override]'." 

183 % (line) 

184 ) 

185 c_error += 1 

186 continue 

187 

188 if section not in section_cache: 188 ↛ 189line 188 didn't jump to line 189, because the condition on line 188 was never true

189 utils.warn( 

190 "'%s' is not a valid section. ['%s' in suite %s, component %s]." 

191 % (section, package, suite, component) 

192 ) 

193 c_error += 1 

194 continue 

195 

196 section_id = section_cache[section] 

197 

198 if priority not in priority_cache: 198 ↛ 199line 198 didn't jump to line 199, because the condition on line 198 was never true

199 utils.warn( 

200 "'%s' is not a valid priority. ['%s' in suite %s, component %s]." 

201 % (priority, package, suite, component) 

202 ) 

203 c_error += 1 

204 continue 

205 

206 priority_id = priority_cache[priority] 

207 

208 if package in new: 208 ↛ 209line 208 didn't jump to line 209, because the condition on line 208 was never true

209 utils.warn( 

210 "Can't insert duplicate entry for '%s'; ignoring all but the first. [suite %s, component %s]" 

211 % (package, suite, component) 

212 ) 

213 c_error += 1 

214 continue 

215 new[package] = "" 

216 

217 if package in original: 217 ↛ 218line 217 didn't jump to line 218

218 ( 

219 old_priority_id, 

220 old_section_id, 

221 old_maintainer_override, 

222 old_priority, 

223 old_section, 

224 ) = original[package] 

225 if ( 

226 mode == "add" 

227 or old_priority_id == priority_id 

228 and old_section_id == section_id 

229 and old_maintainer_override == maintainer_override 

230 ): 

231 # If it's unchanged or we're in 'add only' mode, ignore it 

232 c_skipped += 1 

233 continue 

234 else: 

235 # If it's changed, delete the old one so we can 

236 # reinsert it with the new information 

237 c_updated += 1 

238 if action: 

239 session.execute( 

240 """DELETE FROM override WHERE suite = :suite AND component = :component 

241 AND package = :package AND type = :typeid""", 

242 { 

243 "suite": suite_id, 

244 "component": component_id, 

245 "package": package, 

246 "typeid": type_id, 

247 }, 

248 ) 

249 

250 # Log changes 

251 if old_priority_id != priority_id: 

252 Logger.log(["changed priority", package, old_priority, priority]) 

253 if old_section_id != section_id: 

254 Logger.log(["changed section", package, old_section, section]) 

255 if old_maintainer_override != maintainer_override: 

256 Logger.log( 

257 [ 

258 "changed maintainer override", 

259 package, 

260 old_maintainer_override, 

261 maintainer_override, 

262 ] 

263 ) 

264 update_p = 1 

265 elif mode == "change": 265 ↛ 267line 265 didn't jump to line 267, because the condition on line 265 was never true

266 # Ignore additions in 'change only' mode 

267 c_skipped += 1 

268 continue 

269 else: 

270 c_added += 1 

271 update_p = 0 

272 

273 if action: 273 ↛ 295line 273 didn't jump to line 295, because the condition on line 273 was never false

274 if not maintainer_override: 274 ↛ 277line 274 didn't jump to line 277, because the condition on line 274 was never false

275 m_o = None 

276 else: 

277 m_o = maintainer_override 

278 session.execute( 

279 """INSERT INTO override (suite, component, type, package, 

280 priority, section, maintainer) 

281 VALUES (:suiteid, :componentid, :typeid, 

282 :package, :priorityid, :sectionid, 

283 :maintainer)""", 

284 { 

285 "suiteid": suite_id, 

286 "componentid": component_id, 

287 "typeid": type_id, 

288 "package": package, 

289 "priorityid": priority_id, 

290 "sectionid": section_id, 

291 "maintainer": m_o, 

292 }, 

293 ) 

294 

295 if not update_p: 295 ↛ 154line 295 didn't jump to line 154, because the condition on line 295 was never false

296 Logger.log( 

297 [ 

298 "new override", 

299 suite, 

300 component, 

301 otype, 

302 package, 

303 priority, 

304 section, 

305 maintainer_override, 

306 ] 

307 ) 

308 

309 if mode == "set": 309 ↛ 311line 309 didn't jump to line 311, because the condition on line 309 was never true

310 # Delete any packages which were removed 

311 for package in original.keys(): 

312 if package not in new: 

313 if action: 

314 session.execute( 

315 """DELETE FROM override 

316 WHERE suite = :suiteid AND component = :componentid 

317 AND package = :package AND type = :typeid""", 

318 { 

319 "suiteid": suite_id, 

320 "componentid": component_id, 

321 "package": package, 

322 "typeid": type_id, 

323 }, 

324 ) 

325 c_removed += 1 

326 Logger.log(["removed override", suite, component, otype, package]) 

327 

328 if action: 328 ↛ 331line 328 didn't jump to line 331, because the condition on line 328 was never false

329 session.commit() 

330 

331 if not cnf["Control-Overrides::Options::Quiet"]: 331 ↛ 344line 331 didn't jump to line 344, because the condition on line 331 was never false

332 print( 

333 "Done in %d seconds. [Updated = %d, Added = %d, Removed = %d, Skipped = %d, Errors = %d]" 

334 % ( 

335 int(time.time() - start_time), 

336 c_updated, 

337 c_added, 

338 c_removed, 

339 c_skipped, 

340 c_error, 

341 ) 

342 ) 

343 

344 Logger.log(["set complete", c_updated, c_added, c_removed, c_skipped, c_error]) 

345 

346 

347################################################################################ 

348 

349 

350def list_overrides(suite, component, otype, session): 

351 dat = {} 

352 s = get_suite(suite, session) 

353 if s is None: 353 ↛ 354line 353 didn't jump to line 354, because the condition on line 353 was never true

354 utils.fubar("Suite '%s' not recognised." % (suite)) 

355 

356 dat["suiteid"] = s.suite_id 

357 

358 c = get_component(component, session) 

359 if c is None: 359 ↛ 360line 359 didn't jump to line 360, because the condition on line 359 was never true

360 utils.fubar("Component '%s' not recognised." % (component)) 

361 

362 dat["componentid"] = c.component_id 

363 

364 o = get_override_type(otype) 

365 if o is None: 365 ↛ 366line 365 didn't jump to line 366, because the condition on line 365 was never true

366 utils.fubar( 

367 "Type '%s' not recognised. (Valid types are deb, udeb and dsc)" % (otype) 

368 ) 

369 

370 dat["typeid"] = o.overridetype_id 

371 

372 if otype == "dsc": 372 ↛ 373line 372 didn't jump to line 373, because the condition on line 372 was never true

373 q = session.execute( 

374 """SELECT o.package, s.section, o.maintainer FROM override o, section s 

375 WHERE o.suite = :suiteid AND o.component = :componentid 

376 AND o.type = :typeid AND o.section = s.id 

377 ORDER BY s.section, o.package""", 

378 dat, 

379 ) 

380 for i in q.fetchall(): 

381 print(utils.result_join(i)) 

382 else: 

383 q = session.execute( 

384 """SELECT o.package, p.priority, s.section, o.maintainer, p.level 

385 FROM override o, priority p, section s 

386 WHERE o.suite = :suiteid AND o.component = :componentid 

387 AND o.type = :typeid AND o.priority = p.id AND o.section = s.id 

388 ORDER BY s.section, p.level, o.package""", 

389 dat, 

390 ) 

391 for i in q.fetchall(): 391 ↛ 392line 391 didn't jump to line 392, because the loop on line 391 never started

392 print(utils.result_join(i[:-1])) 

393 

394 

395################################################################################ 

396 

397 

398def main(): 

399 global Logger 

400 

401 cnf = Config() 

402 Arguments = [ 

403 ("a", "add", "Control-Overrides::Options::Add"), 

404 ("c", "component", "Control-Overrides::Options::Component", "HasArg"), 

405 ("h", "help", "Control-Overrides::Options::Help"), 

406 ("l", "list", "Control-Overrides::Options::List"), 

407 ("q", "quiet", "Control-Overrides::Options::Quiet"), 

408 ("s", "suite", "Control-Overrides::Options::Suite", "HasArg"), 

409 ("S", "set", "Control-Overrides::Options::Set"), 

410 ("C", "change", "Control-Overrides::Options::Change"), 

411 ("n", "no-action", "Control-Overrides::Options::No-Action"), 

412 ("t", "type", "Control-Overrides::Options::Type", "HasArg"), 

413 ("f", "force", "Control-Overrides::Options::Force"), 

414 ] 

415 

416 # Default arguments 

417 for i in ["add", "help", "list", "quiet", "set", "change", "no-action"]: 

418 key = "Control-Overrides::Options::%s" % i 

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

420 cnf[key] = "" 

421 if "Control-Overrides::Options::Component" not in cnf: 421 ↛ 423line 421 didn't jump to line 423, because the condition on line 421 was never false

422 cnf["Control-Overrides::Options::Component"] = "main" 

423 if "Control-Overrides::Options::Suite" not in cnf: 423 ↛ 425line 423 didn't jump to line 425, because the condition on line 423 was never false

424 cnf["Control-Overrides::Options::Suite"] = "unstable" 

425 if "Control-Overrides::Options::Type" not in cnf: 425 ↛ 428line 425 didn't jump to line 428, because the condition on line 425 was never false

426 cnf["Control-Overrides::Options::Type"] = "deb" 

427 

428 file_list = apt_pkg.parse_commandline(cnf.Cnf, Arguments, sys.argv) 

429 

430 if cnf["Control-Overrides::Options::Help"]: 

431 usage() 

432 

433 session = DBConn().session() 

434 

435 mode = None 

436 for i in ["add", "list", "set", "change"]: 

437 if cnf["Control-Overrides::Options::%s" % (i)]: 

438 if mode: 438 ↛ 439line 438 didn't jump to line 439, because the condition on line 438 was never true

439 utils.fubar("Can not perform more than one action at once.") 

440 mode = i 

441 

442 # Need an action... 

443 if mode is None: 443 ↛ 444line 443 didn't jump to line 444, because the condition on line 443 was never true

444 utils.fubar("No action specified.") 

445 

446 (suite, component, otype) = ( 

447 cnf["Control-Overrides::Options::Suite"], 

448 cnf["Control-Overrides::Options::Component"], 

449 cnf["Control-Overrides::Options::Type"], 

450 ) 

451 

452 if mode == "list": 

453 list_overrides(suite, component, otype, session) 

454 else: 

455 if ( 455 ↛ 459line 455 didn't jump to line 459

456 get_suite(suite).untouchable 

457 and not cnf["Control-Overrides::Options::Force"] 

458 ): 

459 utils.fubar("%s: suite is untouchable" % suite) 

460 

461 action = True 

462 if cnf["Control-Overrides::Options::No-Action"]: 462 ↛ 463line 462 didn't jump to line 463, because the condition on line 462 was never true

463 utils.warn("In No-Action Mode") 

464 action = False 

465 

466 Logger = daklog.Logger("control-overrides", mode) 

467 if file_list: 467 ↛ 468line 467 didn't jump to line 468, because the condition on line 467 was never true

468 for f in file_list: 

469 process_file(open(f), suite, component, otype, mode, action, session) 

470 else: 

471 process_file(sys.stdin, suite, component, otype, mode, action, session) 

472 Logger.close() 

473 

474 

475####################################################################################### 

476 

477 

478if __name__ == "__main__": 

479 main()