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 

96 starred (*) values are default""" 

97 ) 

98 sys.exit(exit_code) 

99 

100 

101################################################################################ 

102 

103 

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

105 cnf = Config() 

106 

107 s = get_suite(suite, session=session) 

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

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

110 suite_id = s.suite_id 

111 

112 c = get_component(component, session=session) 

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

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

115 component_id = c.component_id 

116 

117 o = get_override_type(otype) 

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

119 utils.fubar( 

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

121 ) 

122 type_id = o.overridetype_id 

123 

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

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

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

127 

128 original = {} 

129 new = {} 

130 c_skipped = 0 

131 c_added = 0 

132 c_updated = 0 

133 c_removed = 0 

134 c_error = 0 

135 

136 q = session.execute( 

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

138 FROM override o, priority p, section s 

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

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

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

142 ) 

143 for i in q.fetchall(): 

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

145 

146 start_time = time.time() 

147 

148 section_cache = get_sections(session) 

149 priority_cache = get_priorities(session) 

150 

151 # Our session is already in a transaction 

152 

153 for line in file.readlines(): 

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

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

156 continue 

157 

158 maintainer_override = None 

159 if otype == "dsc": 

160 split_line = line.split(None, 2) 

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

162 (package, section) = split_line 

163 elif len(split_line) == 3: 

164 (package, section, maintainer_override) = split_line 

165 else: 

166 utils.warn( 

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

168 % (line) 

169 ) 

170 c_error += 1 

171 continue 

172 priority = "optional" 

173 else: # binary or udeb 

174 split_line = line.split(None, 3) 

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

176 (package, priority, section) = split_line 

177 elif len(split_line) == 4: 

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

179 else: 

180 utils.warn( 

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

182 % (line) 

183 ) 

184 c_error += 1 

185 continue 

186 

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

188 utils.warn( 

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

190 % (section, package, suite, component) 

191 ) 

192 c_error += 1 

193 continue 

194 

195 section_id = section_cache[section] 

196 

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

198 utils.warn( 

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

200 % (priority, package, suite, component) 

201 ) 

202 c_error += 1 

203 continue 

204 

205 priority_id = priority_cache[priority] 

206 

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

208 utils.warn( 

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

210 % (package, suite, component) 

211 ) 

212 c_error += 1 

213 continue 

214 new[package] = "" 

215 

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

217 ( 

218 old_priority_id, 

219 old_section_id, 

220 old_maintainer_override, 

221 old_priority, 

222 old_section, 

223 ) = original[package] 

224 if ( 

225 mode == "add" 

226 or old_priority_id == priority_id 

227 and old_section_id == section_id 

228 and old_maintainer_override == maintainer_override 

229 ): 

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

231 c_skipped += 1 

232 continue 

233 else: 

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

235 # reinsert it with the new information 

236 c_updated += 1 

237 if action: 

238 session.execute( 

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

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

241 { 

242 "suite": suite_id, 

243 "component": component_id, 

244 "package": package, 

245 "typeid": type_id, 

246 }, 

247 ) 

248 

249 # Log changes 

250 if old_priority_id != priority_id: 

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

252 if old_section_id != section_id: 

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

254 if old_maintainer_override != maintainer_override: 

255 Logger.log( 

256 [ 

257 "changed maintainer override", 

258 package, 

259 old_maintainer_override, 

260 maintainer_override, 

261 ] 

262 ) 

263 update_p = 1 

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

265 # Ignore additions in 'change only' mode 

266 c_skipped += 1 

267 continue 

268 else: 

269 c_added += 1 

270 update_p = 0 

271 

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

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

274 m_o = None 

275 else: 

276 m_o = maintainer_override 

277 session.execute( 

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

279 priority, section, maintainer) 

280 VALUES (:suiteid, :componentid, :typeid, 

281 :package, :priorityid, :sectionid, 

282 :maintainer)""", 

283 { 

284 "suiteid": suite_id, 

285 "componentid": component_id, 

286 "typeid": type_id, 

287 "package": package, 

288 "priorityid": priority_id, 

289 "sectionid": section_id, 

290 "maintainer": m_o, 

291 }, 

292 ) 

293 

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

295 Logger.log( 

296 [ 

297 "new override", 

298 suite, 

299 component, 

300 otype, 

301 package, 

302 priority, 

303 section, 

304 maintainer_override, 

305 ] 

306 ) 

307 

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

309 # Delete any packages which were removed 

310 for package in original.keys(): 

311 if package not in new: 

312 if action: 

313 session.execute( 

314 """DELETE FROM override 

315 WHERE suite = :suiteid AND component = :componentid 

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

317 { 

318 "suiteid": suite_id, 

319 "componentid": component_id, 

320 "package": package, 

321 "typeid": type_id, 

322 }, 

323 ) 

324 c_removed += 1 

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

326 

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

328 session.commit() 

329 

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

331 print( 

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

333 % ( 

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

335 c_updated, 

336 c_added, 

337 c_removed, 

338 c_skipped, 

339 c_error, 

340 ) 

341 ) 

342 

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

344 

345 

346################################################################################ 

347 

348 

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

350 dat = {} 

351 s = get_suite(suite, session) 

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

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

354 

355 dat["suiteid"] = s.suite_id 

356 

357 c = get_component(component, session) 

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

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

360 

361 dat["componentid"] = c.component_id 

362 

363 o = get_override_type(otype) 

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

365 utils.fubar( 

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

367 ) 

368 

369 dat["typeid"] = o.overridetype_id 

370 

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

372 q = session.execute( 

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

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

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

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

377 dat, 

378 ) 

379 for i in q.fetchall(): 

380 print(utils.result_join(i)) 

381 else: 

382 q = session.execute( 

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

384 FROM override o, priority p, section s 

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

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

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

388 dat, 

389 ) 

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

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

392 

393 

394################################################################################ 

395 

396 

397def main(): 

398 global Logger 

399 

400 cnf = Config() 

401 Arguments = [ 

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

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

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

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

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

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

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

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

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

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

412 ] 

413 

414 # Default arguments 

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

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

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

418 cnf[key] = "" 

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

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

421 if "Control-Overrides::Options::Suite" 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::Suite"] = "unstable" 

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

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

425 

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

427 

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

429 usage() 

430 

431 session = DBConn().session() 

432 

433 mode = None 

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

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

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

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

438 mode = i 

439 

440 # Need an action... 

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

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

443 

444 (suite, component, otype) = ( 

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

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

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

448 ) 

449 

450 if mode == "list": 

451 list_overrides(suite, component, otype, session) 

452 else: 

453 if get_suite(suite).untouchable: 453 ↛ 454line 453 didn't jump to line 454, because the condition on line 453 was never true

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

455 

456 action = True 

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

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

459 action = False 

460 

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

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

463 for f in file_list: 

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

465 else: 

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

467 Logger.close() 

468 

469 

470####################################################################################### 

471 

472 

473if __name__ == "__main__": 

474 main()