1#! /usr/bin/env python3 

2 

3"""Configure dak parameters in the database""" 

4# Copyright (C) 2009 Mark Hymers <mhy@debian.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 

22import collections 

23import json 

24import sys 

25from collections.abc import Callable, Sequence 

26from dataclasses import dataclass 

27from typing import Any, NoReturn, Optional 

28 

29import apt_pkg 

30 

31import daklib.archive 

32import daklib.gpg 

33 

34from daklib import utils 

35from daklib.dbconn import * 

36from sqlalchemy.orm.exc import NoResultFound 

37 

38################################################################################ 

39 

40dispatch = {} 

41dryrun = False 

42 

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

44 

45 

46def warn(msg: str) -> None: 

47 print(msg, file=sys.stderr) 

48 

49 

50def die(msg: str, exit_code: int = 1) -> NoReturn: 

51 print(msg, file=sys.stderr) 

52 sys.exit(exit_code) 

53 

54 

55def die_arglen(args: Sequence, args_needed: int, msg: str) -> None: 

56 if len(args) < args_needed: 56 ↛ 57line 56 didn't jump to line 57, because the condition on line 56 was never true

57 die(msg) 

58 

59 

60def get_suite_or_die( 

61 suite_name: str, 

62 session=None, 

63 error_message="E: Invalid/unknown suite %(suite_name)s", 

64) -> Suite: 

65 suite = get_suite(suite_name.lower(), session=session) 

66 if suite is None: 66 ↛ 67line 66 didn't jump to line 67, because the condition on line 66 was never true

67 die(error_message % {'suite_name': suite_name}) 

68 return suite 

69 

70 

71def usage(exit_code: int = 0) -> NoReturn: 

72 """Perform administrative work on the dak database.""" 

73 

74 print("""Usage: dak admin COMMAND 

75Perform administrative work on the dak database. 

76 

77 -h, --help show this help and exit. 

78 -n, --dry-run don't do anything, just show what would have been done 

79 (only applies to add or rm operations). 

80 

81 Commands can use a long or abbreviated form: 

82 

83 config / c: 

84 c db show db config 

85 c db-shell show db config in a usable form for psql 

86 c NAME show option NAME as set in configuration table 

87 

88 keyring / k: 

89 k list-all list all keyrings 

90 k list-binary list all keyrings with a NULL source acl 

91 k list-source list all keyrings with a non NULL source acl 

92 k add-buildd NAME ARCH... add buildd keyring with upload permission 

93 for the given architectures 

94 

95 architecture / a: 

96 a list show a list of architectures 

97 a rm ARCH remove an architecture (will only work if 

98 no longer linked to any suites) 

99 a add ARCH DESCRIPTION [SUITELIST] 

100 add architecture ARCH with DESCRIPTION. 

101 If SUITELIST is given, add to each of the 

102 suites at the same time 

103 

104 component: 

105 component list show a list of components 

106 component rm COMPONENT remove a component (will only work if 

107 empty) 

108 component add NAME DESCRIPTION ORDERING 

109 add component NAME with DESCRIPTION. 

110 Ordered at ORDERING. 

111 

112 suite / s: 

113 s list [--print-archive] 

114 show a list of suites 

115 s show SUITE show config details for a suite 

116 s add SUITE VERSION [ label=LABEL ] [ description=DESCRIPTION ] 

117 [ origin=ORIGIN ] [ codename=CODENAME ] 

118 [ signingkey=SIGNINGKEY ] [ archive=ARCHIVE ] 

119 add suite SUITE, version VERSION. 

120 label, description, origin, codename 

121 and signingkey are optional. 

122 s rm SUITE remove a suite (will only work if empty) 

123 

124 s add-all-arches SUITE VERSION... as "s add" but adds suite-architecture 

125 relationships for all architectures 

126 s add-build-queue SUITE BUILD-QUEUE BUILD-QUEUE-CODENAME BUILD-QUEUE-ARCHIVE 

127 add a build queue for an existing suite 

128 

129 suite-architecture / s-a: 

130 s-a list show the architectures for all suites 

131 s-a list-suite ARCH show the suites an ARCH is in 

132 s-a list-arch SUITE show the architectures in a SUITE 

133 s-a add SUITE ARCH add ARCH to suite 

134 s-a rm SUITE ARCH remove ARCH from suite (will only work if 

135 no packages remain for the arch in the suite) 

136 

137 suite-component / s-c: 

138 s-c list show the architectures for all suites 

139 s-c list-suite COMPONENT 

140 show the suites a COMPONENT is in 

141 s-c list-component SUITE 

142 show the components in a SUITE 

143 s-c add SUITE COMPONENT 

144 add COMPONENT to suite 

145 s-c rm SUITE COMPONENT remove component from suite (will only work if 

146 no packages remain for the component in the suite) 

147 

148 suite-config / suite-cfg / s-cfg: 

149 s-cfg list show the names of the configurations 

150 s-cfg list SUITE show the configuration values for SUITE 

151 s-cfg list-json SUITE show the configuration values for SUITE in JSON format 

152 s-cfg get SUITE NAME ... 

153 show the value for NAME in SUITE (format: NAME=VALUE) 

154 s-cfg get-value SUITE NAME ... 

155 show the value for NAME in SUITE (format: VALUE) 

156 s-cfg get-json SUITE NAME ... 

157 show the value for NAME in SUITE (format: JSON object) 

158 s-cfg set SUITE NAME=VALUE ... 

159 set NAME to VALUE in SUITE 

160 s-cfg set-json SUITE 

161 s-cfg set-json SUITE FILENAME 

162 parse FILENAME (if absent or "-", then stdin) as JSON 

163 and update all configurations listed to match the 

164 value in the JSON. 

165 Uses the same format as list-json or get-json outputs. 

166 

167 archive: 

168 archive list list all archives 

169 archive add NAME ROOT DESCRIPTION [primary-mirror=MIRROR] [tainted=1] 

170 add archive NAME with path ROOT, 

171 primary mirror MIRROR. 

172 archive rm NAME remove archive NAME (will only work if there are 

173 no files and no suites in the archive) 

174 archive rename OLD NEW rename archive OLD to NEW 

175 

176 version-check / v-c: 

177 v-c list show version checks for all suites 

178 v-c list-suite SUITE show version checks for suite SUITE 

179 v-c add SUITE CHECK REFERENCE add a version check for suite SUITE 

180 v-c rm SUITE CHECK REFERENCE remove a version check 

181 where 

182 CHECK is one of Enhances, MustBeNewerThan, MustBeOlderThan 

183 REFERENCE is another suite name 

184 

185 change-component: 

186 change-component SUITE COMPONENT source SOURCE... 

187 change-component SUITE COMPONENT binary BINARY... 

188 Move source or binary packages to a different component by copying 

189 associated files and changing the overrides. 

190 

191 forget-signature FILE: forget that we saw FILE 

192""") 

193 sys.exit(exit_code) 

194 

195################################################################################ 

196 

197 

198def __architecture_list(d, args) -> NoReturn: 

199 q = d.session().query(Architecture).order_by(Architecture.arch_string) 

200 for j in q.all(): 

201 # HACK: We should get rid of source from the arch table 

202 if j.arch_string == 'source': 

203 continue 

204 print(j.arch_string) 

205 sys.exit(0) 

206 

207 

208def __architecture_add(d, args): 

209 die_arglen(args, 4, "E: adding an architecture requires a name and a description") 

210 print("Adding architecture %s" % args[2]) 

211 suites = [str(x) for x in args[4:]] 

212 if len(suites) > 0: 212 ↛ 213line 212 didn't jump to line 213, because the condition on line 212 was never true

213 print("Adding to suites %s" % ", ".join(suites)) 

214 if not dryrun: 214 ↛ 232line 214 didn't jump to line 232, because the condition on line 214 was never false

215 try: 

216 s = d.session() 

217 a = Architecture() 

218 a.arch_string = str(args[2]).lower() 

219 a.description = str(args[3]) 

220 s.add(a) 

221 for sn in suites: 221 ↛ 222line 221 didn't jump to line 222, because the loop on line 221 never started

222 su = get_suite(sn, s) 

223 if su is not None: 

224 a.suites.append(su) 

225 else: 

226 warn("W: Cannot find suite %s" % su) 

227 s.commit() 

228 except IntegrityError as e: 

229 die("E: Integrity error adding architecture %s (it probably already exists)" % args[2]) 

230 except SQLAlchemyError as e: 

231 die("E: Error adding architecture %s (%s)" % (args[2], e)) 

232 print("Architecture %s added" % (args[2])) 

233 

234 

235def __architecture_rm(d, args): 

236 die_arglen(args, 3, "E: removing an architecture requires at least a name") 

237 print("Removing architecture %s" % args[2]) 

238 if not dryrun: 

239 try: 

240 s = d.session() 

241 a = get_architecture(args[2].lower(), s) 

242 if a is None: 

243 die("E: Cannot find architecture %s" % args[2]) 

244 s.delete(a) 

245 s.commit() 

246 except IntegrityError as e: 

247 die("E: Integrity error removing architecture %s (suite-arch entries probably still exist)" % args[2]) 

248 except SQLAlchemyError as e: 

249 die("E: Error removing architecture %s (%s)" % (args[2], e)) 

250 print("Architecture %s removed" % args[2]) 

251 

252 

253def architecture(args): 

254 Cnf = utils.get_conf() 

255 d = DBConn() 

256 

257 die_arglen(args, 2, "E: architecture needs at least a command") 

258 

259 mode = args[1].lower() 

260 if mode == 'list': 260 ↛ 261line 260 didn't jump to line 261, because the condition on line 260 was never true

261 __architecture_list(d, args) 

262 elif mode == 'add': 262 ↛ 264line 262 didn't jump to line 264, because the condition on line 262 was never false

263 __architecture_add(d, args) 

264 elif mode == 'rm': 

265 __architecture_rm(d, args) 

266 else: 

267 die("E: architecture command unknown") 

268 

269 

270dispatch['architecture'] = architecture 

271dispatch['a'] = architecture 

272 

273################################################################################ 

274 

275 

276def component_list(): 

277 session = DBConn().session() 

278 for component in session.query(Component).order_by(Component.component_name): 

279 print("{0} ordering={1}".format(component.component_name, component.ordering)) 

280 

281 

282def component_add(args): 

283 (name, description, ordering) = args[0:3] 

284 

285 attributes = dict( 

286 component_name=name, 

287 description=description, 

288 ordering=ordering, 

289 ) 

290 

291 for option in args[3:]: 

292 (key, value) = option.split('=') 

293 attributes[key] = value 

294 

295 session = DBConn().session() 

296 

297 component = Component() 

298 for key, value in attributes.items(): 

299 setattr(component, key, value) 

300 

301 session.add(component) 

302 session.flush() 

303 

304 if dryrun: 

305 session.rollback() 

306 else: 

307 session.commit() 

308 

309 

310def component_rm(name: str) -> None: 

311 session = DBConn().session() 

312 component = get_component(name, session) 

313 session.delete(component) 

314 session.flush() 

315 

316 if dryrun: 

317 session.rollback() 

318 else: 

319 session.commit() 

320 

321 

322def component_rename(oldname: str, newname: str) -> None: 

323 session = DBConn().session() 

324 component = get_component(oldname, session) 

325 component.component_name = newname 

326 session.flush() 

327 

328 if dryrun: 

329 session.rollback() 

330 else: 

331 session.commit() 

332 

333 

334def component(command): 

335 mode = command[1] 

336 if mode == 'list': 

337 component_list() 

338 elif mode == 'rename': 

339 component_rename(command[2], command[3]) 

340 elif mode == 'add': 

341 component_add(command[2:]) 

342 elif mode == 'rm': 

343 component_rm(command[2]) 

344 else: 

345 die("E: component command unknown") 

346 

347 

348dispatch['component'] = component 

349 

350################################################################################ 

351 

352 

353def __suite_list(d, args): 

354 s = d.session() 

355 for j in s.query(Suite).join(Suite.archive).order_by(Archive.archive_name, Suite.suite_name).all(): 

356 if len(args) > 2 and args[2] == "--print-archive": 356 ↛ 357line 356 didn't jump to line 357, because the condition on line 356 was never true

357 print("{0} {1}".format(j.archive.archive_name, j.suite_name)) 

358 else: 

359 print("{0}".format(j.suite_name)) 

360 

361 

362def __suite_show(d, args): 

363 if len(args) < 2: 

364 die("E: showing an suite entry requires a suite") 

365 

366 s = d.session() 

367 su = get_suite_or_die(args[2]) 

368 

369 print(su.details()) 

370 

371 

372def __suite_add(d, args, addallarches=False) -> None: 

373 die_arglen(args, 4, "E: adding a suite requires at least a name and a version") 

374 suite_name = args[2].lower() 

375 version = args[3] 

376 kvpairs = __suite_config_set_confing_args_as_dict(args[4:]) 

377 

378 if len(version) == 0: 378 ↛ 381line 378 didn't jump to line 381, because the condition on line 378 was never false

379 version = None 

380 

381 print("Adding suite %s" % suite_name) 

382 if not dryrun: 382 ↛ 412line 382 didn't jump to line 412, because the condition on line 382 was never false

383 try: 

384 s = d.session() 

385 suite = Suite() 

386 suite.suite_name = suite_name 

387 suite.overridecodename = None 

388 suite.version = version or None 

389 # Most configurations will be handled by 

390 # __suite_config_internal_set. However, a few are managed 

391 # manually here because __suite_config_internal_set cannot 

392 # handle them. Either because they are create-only or 

393 # because suite-add handled them different (historically) 

394 suite.codename = kvpairs.pop('codename', None) 

395 signingkey = kvpairs.pop('signingkey', None) 

396 if signingkey is not None: 396 ↛ 397line 396 didn't jump to line 397, because the condition on line 396 was never true

397 suite.signingkeys = [signingkey.upper()] 

398 archive_name = kvpairs.pop('archive', None) 

399 if archive_name is not None: 

400 suite.archive = get_archive(archive_name, s) 

401 else: 

402 suite.archive = s.query(Archive).filter(~Archive.archive_name.in_(['build-queues', 'new', 'policy'])).one() 

403 suite.srcformats = s.query(SrcFormat).all() 

404 __suite_config_internal_set(suite, suite_name, kvpairs, 

405 print_config_set=False) 

406 s.add(suite) 

407 s.flush() 

408 except IntegrityError as e: 

409 die("E: Integrity error adding suite %s (it probably already exists)" % suite_name) 

410 except SQLAlchemyError as e: 

411 die("E: Error adding suite %s (%s)" % (suite_name, e)) 

412 print("Suite %s added" % (suite_name)) 

413 

414 if addallarches: 

415 arches = [] 

416 q = s.query(Architecture).order_by(Architecture.arch_string) 

417 for arch in q.all(): 

418 suite.architectures.append(arch) 

419 arches.append(arch.arch_string) 

420 

421 print("Architectures %s added to %s" % (','.join(arches), suite_name)) 

422 

423 s.commit() 

424 

425 

426def __suite_rm(d, args): 

427 die_arglen(args, 3, "E: removing a suite requires at least a name") 

428 name = args[2] 

429 print("Removing suite {0}".format(name)) 

430 if not dryrun: 

431 try: 

432 s = d.session() 

433 su = get_suite_or_die(name, s) 

434 s.delete(su) 

435 s.commit() 

436 except IntegrityError as e: 

437 die("E: Integrity error removing suite {0} (suite-arch entries probably still exist)".format(name)) 

438 except SQLAlchemyError as e: 

439 die("E: Error removing suite {0} ({1})".format(name, e)) 

440 print("Suite {0} removed".format(name)) 

441 

442 

443def __suite_add_build_queue(d, args): 

444 session = d.session() 

445 

446 die_arglen(args, 6, "E: Adding a build queue needs four parameters.") 

447 

448 suite_name = args[2] 

449 build_queue_name = args[3] 

450 build_queue_codename = args[4] 

451 build_queue_archive_name = args[5] 

452 try: 

453 suite = session.query(Suite).filter_by(suite_name=suite_name).one() 

454 except NoResultFound: 

455 die("E: Unknown suite '{0}'".format(suite_name)) 

456 try: 

457 build_queue_archive = session.query(Archive).filter_by(archive_name=build_queue_archive_name).one() 

458 except NoResultFound: 

459 die("E: Unknown archive '{0}'".format(build_queue_archive_name)) 

460 

461 # Create suite 

462 s = Suite() 

463 s.suite_name = build_queue_name 

464 s.origin = suite.origin 

465 s.label = suite.label 

466 s.description = "buildd {0} incoming".format(suite_name) 

467 s.codename = build_queue_codename 

468 s.notautomatic = suite.notautomatic 

469 s.overridesuite = suite.overridesuite or suite.suite_name 

470 s.butautomaticupgrades = suite.butautomaticupgrades 

471 s.signingkeys = suite.signingkeys 

472 s.include_long_description = False 

473 

474 # Do not accept direct uploads to the build queue 

475 s.accept_source_uploads = False 

476 s.accept_binary_uploads = False 

477 

478 s.archive = build_queue_archive 

479 s.architectures.extend(suite.architectures) 

480 s.components.extend(suite.components) 

481 s.srcformats.extend(suite.srcformats) 

482 

483 session.add(s) 

484 session.flush() 

485 

486 bq = BuildQueue() 

487 bq.queue_name = build_queue_codename 

488 bq.suite = s 

489 

490 session.add(bq) 

491 session.flush() 

492 

493 suite.copy_queues.append(bq) 

494 

495 session.commit() 

496 

497 

498def suite(args): 

499 Cnf = utils.get_conf() 

500 d = DBConn() 

501 

502 die_arglen(args, 2, "E: suite needs at least a command") 

503 

504 mode = args[1].lower() 

505 

506 if mode == 'list': 

507 __suite_list(d, args) 

508 elif mode == 'show': 508 ↛ 509line 508 didn't jump to line 509, because the condition on line 508 was never true

509 __suite_show(d, args) 

510 elif mode == 'rm': 510 ↛ 511line 510 didn't jump to line 511, because the condition on line 510 was never true

511 __suite_rm(d, args) 

512 elif mode == 'add': 

513 __suite_add(d, args, False) 

514 elif mode == 'add-all-arches': 

515 __suite_add(d, args, True) 

516 elif mode == 'add-build-queue': 516 ↛ 519line 516 didn't jump to line 519, because the condition on line 516 was never false

517 __suite_add_build_queue(d, args) 

518 else: 

519 die("E: suite command unknown") 

520 

521 

522dispatch['suite'] = suite 

523dispatch['s'] = suite 

524 

525################################################################################ 

526 

527 

528def __suite_architecture_list(d, args): 

529 s = d.session() 

530 for j in s.query(Suite).order_by(Suite.suite_name): 

531 architectures = j.get_architectures(skipsrc=True, skipall=True) 

532 print(j.suite_name + ': ' 

533 + ', '.join([a.arch_string for a in architectures])) 

534 

535 

536def __suite_architecture_listarch(d, args): 

537 die_arglen(args, 3, "E: suite-architecture list-arch requires a suite") 

538 suite = get_suite_or_die(args[2], d.session()) 

539 a = suite.get_architectures(skipsrc=True, skipall=True) 

540 for j in a: 

541 print(j.arch_string) 

542 

543 

544def __suite_architecture_listsuite(d, args): 

545 die_arglen(args, 3, "E: suite-architecture list-suite requires an arch") 

546 architecture = get_architecture(args[2].lower(), d.session()) 

547 if architecture is None: 

548 die("E: architecture %s is invalid" % args[2].lower()) 

549 for j in architecture.suites: 

550 print(j.suite_name) 

551 

552 

553def __suite_architecture_add(d, args): 

554 if len(args) < 3: 554 ↛ 555line 554 didn't jump to line 555, because the condition on line 554 was never true

555 die("E: adding a suite-architecture entry requires a suite and arch") 

556 

557 s = d.session() 

558 

559 suite = get_suite_or_die(args[2], s) 

560 

561 for arch_name in args[3:]: 

562 arch = get_architecture(arch_name.lower(), s) 

563 if arch is None: 563 ↛ 564line 563 didn't jump to line 564, because the condition on line 563 was never true

564 die("E: Can't find architecture %s" % args[3].lower()) 

565 

566 try: 

567 suite.architectures.append(arch) 

568 s.flush() 

569 except IntegrityError as e: 

570 die("E: Can't add suite-architecture entry (%s, %s) - probably already exists" % (args[2].lower(), arch_name)) 

571 except SQLAlchemyError as e: 

572 die("E: Can't add suite-architecture entry (%s, %s) - %s" % (args[2].lower(), arch_name, e)) 

573 

574 print("Added suite-architecture entry for %s, %s" % (args[2].lower(), arch_name)) 

575 

576 if not dryrun: 576 ↛ 579line 576 didn't jump to line 579, because the condition on line 576 was never false

577 s.commit() 

578 

579 s.close() 

580 

581 

582def __suite_architecture_rm(d, args): 

583 if len(args) < 3: 

584 die("E: removing an suite-architecture entry requires a suite and arch") 

585 

586 s = d.session() 

587 if not dryrun: 

588 try: 

589 suite_name = args[2].lower() 

590 suite = get_suite_or_die(suite_name, s) 

591 arch_string = args[3].lower() 

592 architecture = get_architecture(arch_string, s) 

593 if architecture not in suite.architectures: 

594 die("E: architecture %s not found in suite %s" % (arch_string, suite_name)) 

595 suite.architectures.remove(architecture) 

596 s.commit() 

597 except IntegrityError as e: 

598 die("E: Can't remove suite-architecture entry (%s, %s) - it's probably referenced" % (args[2].lower(), args[3].lower())) 

599 except SQLAlchemyError as e: 

600 die("E: Can't remove suite-architecture entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e)) 

601 

602 print("Removed suite-architecture entry for %s, %s" % (args[2].lower(), args[3].lower())) 

603 

604 

605def suite_architecture(args): 

606 Cnf = utils.get_conf() 

607 d = DBConn() 

608 

609 die_arglen(args, 2, "E: suite-architecture needs at least a command") 

610 

611 mode = args[1].lower() 

612 

613 if mode == 'list': 613 ↛ 614line 613 didn't jump to line 614, because the condition on line 613 was never true

614 __suite_architecture_list(d, args) 

615 elif mode == 'list-arch': 

616 __suite_architecture_listarch(d, args) 

617 elif mode == 'list-suite': 617 ↛ 618line 617 didn't jump to line 618, because the condition on line 617 was never true

618 __suite_architecture_listsuite(d, args) 

619 elif mode == 'add': 619 ↛ 621line 619 didn't jump to line 621, because the condition on line 619 was never false

620 __suite_architecture_add(d, args) 

621 elif mode == 'rm': 

622 __suite_architecture_rm(d, args) 

623 else: 

624 die("E: suite-architecture command unknown") 

625 

626 

627dispatch['suite-architecture'] = suite_architecture 

628dispatch['s-a'] = suite_architecture 

629 

630################################################################################ 

631 

632 

633def __suite_component_list(d, args): 

634 s = d.session() 

635 for j in s.query(Suite).order_by(Suite.suite_name): 

636 components = j.components 

637 print(j.suite_name + ': ' 

638 + ', '.join([c.component_name for c in components])) 

639 

640 

641def __suite_component_listcomponent(d, args): 

642 die_arglen(args, 3, "E: suite-component list-component requires a suite") 

643 suite = get_suite_or_die(args[2], d.session()) 

644 for c in suite.components: 

645 print(c.component_name) 

646 

647 

648def __suite_component_listsuite(d, args): 

649 die_arglen(args, 3, "E: suite-component list-suite requires an component") 

650 component = get_component(args[2].lower(), d.session()) 

651 if component is None: 

652 die("E: component %s is invalid" % args[2].lower()) 

653 for s in component.suites: 

654 print(s.suite_name) 

655 

656 

657def __suite_component_add(d, args): 

658 if len(args) < 3: 658 ↛ 659line 658 didn't jump to line 659, because the condition on line 658 was never true

659 die("E: adding a suite-component entry requires a suite and component") 

660 

661 s = d.session() 

662 

663 suite = get_suite_or_die(args[2], s) 

664 

665 for component_name in args[3:]: 

666 component = get_component(component_name.lower(), s) 

667 if component is None: 667 ↛ 668line 667 didn't jump to line 668, because the condition on line 667 was never true

668 die("E: Can't find component %s" % args[3].lower()) 

669 

670 try: 

671 suite.components.append(component) 

672 s.flush() 

673 except IntegrityError as e: 

674 die("E: Can't add suite-component entry (%s, %s) - probably already exists" % (args[2].lower(), component_name)) 

675 except SQLAlchemyError as e: 

676 die("E: Can't add suite-component entry (%s, %s) - %s" % (args[2].lower(), component_name, e)) 

677 

678 print("Added suite-component entry for %s, %s" % (args[2].lower(), component_name)) 

679 

680 if not dryrun: 680 ↛ 682line 680 didn't jump to line 682, because the condition on line 680 was never false

681 s.commit() 

682 s.close() 

683 

684 

685def __suite_component_rm(d, args): 

686 if len(args) < 3: 

687 die("E: removing an suite-component entry requires a suite and component") 

688 

689 s = d.session() 

690 if not dryrun: 

691 try: 

692 suite_name = args[2].lower() 

693 suite = get_suite_or_die(suite_name, s) 

694 component_string = args[3].lower() 

695 component = get_component(component_string, s) 

696 if component not in suite.components: 

697 die("E: component %s not found in suite %s" % (component_string, suite_name)) 

698 suite.components.remove(component) 

699 s.commit() 

700 except IntegrityError as e: 

701 die("E: Can't remove suite-component entry (%s, %s) - it's probably referenced" % (args[2].lower(), args[3].lower())) 

702 except SQLAlchemyError as e: 

703 die("E: Can't remove suite-component entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e)) 

704 

705 print("Removed suite-component entry for %s, %s" % (args[2].lower(), args[3].lower())) 

706 

707 

708def suite_component(args): 

709 Cnf = utils.get_conf() 

710 d = DBConn() 

711 

712 die_arglen(args, 2, "E: suite-component needs at least a command") 

713 

714 mode = args[1].lower() 

715 

716 if mode == 'list': 716 ↛ 717line 716 didn't jump to line 717, because the condition on line 716 was never true

717 __suite_component_list(d, args) 

718 elif mode == 'list-component': 718 ↛ 719line 718 didn't jump to line 719, because the condition on line 718 was never true

719 __suite_component_listcomponent(d, args) 

720 elif mode == 'list-suite': 720 ↛ 721line 720 didn't jump to line 721, because the condition on line 720 was never true

721 __suite_component_listsuite(d, args) 

722 elif mode == 'add': 722 ↛ 727line 722 didn't jump to line 727, because the condition on line 722 was never false

723 __suite_component_add(d, args) 

724 # elif mode == 'rm': 

725 # __suite_architecture_rm(d, args) 

726 else: 

727 die("E: suite-component command unknown") 

728 

729 

730dispatch['suite-component'] = suite_component 

731dispatch['s-c'] = suite_component 

732 

733 

734################################################################################ 

735 

736# Sentinel for detecting read-only configurations 

737SUITE_CONFIG_READ_ONLY = object() 

738SUITE_CONFIG_WRITABLE_ONLY_VIA_JSON = object() 

739 

740 

741@dataclass 

742class SuiteConfigSerializer: 

743 db_name: str 

744 serialize: Callable[[Any], str] 

745 deserialize: Optional[Callable[[str], Any]] 

746 

747 

748def _serialize_suite(x): 

749 if x is None: 749 ↛ 751line 749 didn't jump to line 751, because the condition on line 749 was never false

750 return None 

751 return Suite.get(x).suite_name 

752 

753 

754def _deserialize_suite(x): 

755 if x is None: 755 ↛ 756line 755 didn't jump to line 756, because the condition on line 755 was never true

756 return None 

757 return get_suite_or_die(x).suite_id 

758 

759 

760@session_wrapper 

761def _serialize_policy_queue(x, session=None): 

762 if x is None: 762 ↛ 764line 762 didn't jump to line 764, because the condition on line 762 was never false

763 return None 

764 try: 

765 policy_obj = session.query(PolicyQueue).filter_by(policy_queue_id=x).one() 

766 except NoResultFound: 

767 return None 

768 return policy_obj.queue_name 

769 

770 

771def _deserialize_policy_queue(x): 

772 if x is None: 

773 return None 

774 policy_queue = get_policy_queue(x) 

775 if policy_queue is None: 

776 raise ValueError("There is no policy queue with name %s" % x) 

777 return policy_queue.policy_queue_id 

778 

779 

780@session_wrapper 

781def _serialize_archive(x, session=None): 

782 if x is None: 782 ↛ 783line 782 didn't jump to line 783, because the condition on line 782 was never true

783 return None 

784 try: 

785 archive_obj = session.query(Archive).filter_by(archive_id=x).one() 

786 except NoResultFound: 

787 return None 

788 return archive_obj.archive_name 

789 

790 

791CUSTOM_SUITE_CONFIG_SERIALIZERS = { 

792 'archive': SuiteConfigSerializer(db_name='archive_id', serialize=_serialize_archive, 

793 deserialize=None), 

794 'debugsuite': SuiteConfigSerializer(db_name='debugsuite_id', serialize=_serialize_suite, 

795 deserialize=_deserialize_suite), 

796 'new_queue': SuiteConfigSerializer(db_name='new_queue_id', serialize=_serialize_policy_queue, 

797 deserialize=_deserialize_policy_queue), 

798 'policy_queue': SuiteConfigSerializer(db_name='policy_queue_id', serialize=_serialize_policy_queue, 

799 deserialize=_deserialize_policy_queue), 

800} 

801 

802 

803ALLOWED_SUITE_CONFIGS = { 

804 'accept_binary_uploads': utils.parse_boolean_from_user, 

805 'accept_source_uploads': utils.parse_boolean_from_user, 

806 'allowcsset': utils.parse_boolean_from_user, 

807 'announce': SUITE_CONFIG_WRITABLE_ONLY_VIA_JSON, 

808 'archive': SUITE_CONFIG_READ_ONLY, 

809 'butautomaticupgrades': utils.parse_boolean_from_user, 

810 'byhash': utils.parse_boolean_from_user, 

811 'changelog': str, 

812 'changelog_url': str, 

813 'checksums': SUITE_CONFIG_WRITABLE_ONLY_VIA_JSON, 

814 'close_bugs': utils.parse_boolean_from_user, 

815 'codename': SUITE_CONFIG_READ_ONLY, 

816 'debugsuite': str, 

817 'description': str, 

818 'include_long_description': utils.parse_boolean_from_user, 

819 'indices_compression': SUITE_CONFIG_WRITABLE_ONLY_VIA_JSON, 

820 'label': str, 

821 'mail_whitelist': str, 

822 'merged_pdiffs': utils.parse_boolean_from_user, 

823 'new_queue': str, 

824 'notautomatic': utils.parse_boolean_from_user, 

825 'origin': str, 

826 'overridecodename': str, 

827 'overrideorigin': str, 

828 'overrideprocess': utils.parse_boolean_from_user, 

829 'overridesuite': str, 

830 'policy_queue': str, 

831 'priority': int, 

832 'separate_contents_architecture_all': utils.parse_boolean_from_user, 

833 # We do not support separate Packages-all, so do not let people set it. 

834 'separate_packages_architecture_all': SUITE_CONFIG_READ_ONLY, 

835 'signingkeys': SUITE_CONFIG_WRITABLE_ONLY_VIA_JSON, 

836 'suite_name': SUITE_CONFIG_READ_ONLY, 

837 'untouchable': utils.parse_boolean_from_user, 

838 'validtime': int, 

839} 

840 

841 

842def _get_suite_value(suite, conf_name): 

843 serial_config = CUSTOM_SUITE_CONFIG_SERIALIZERS.get(conf_name) 

844 if serial_config is None: 

845 return getattr(suite, conf_name) 

846 db_value = getattr(suite, serial_config.db_name) 

847 return serial_config.serialize(db_value) 

848 

849 

850def _set_suite_value(suite, conf_name, new_value): 

851 serial_config = CUSTOM_SUITE_CONFIG_SERIALIZERS.get(conf_name) 

852 db_name = conf_name 

853 if serial_config is not None: 

854 assert serial_config.deserialize is not None, "Changing %s is not supported!" % conf_name 

855 new_value = serial_config.deserialize(new_value) 

856 db_name = serial_config.db_name 

857 setattr(suite, db_name, new_value) 

858 

859 

860def __suite_config_get(d, args, direct_value=False, json_format=False): 

861 die_arglen(args, 4, "E: suite-config get needs the name of a configuration") 

862 session = d.session() 

863 suite_name = args[2] 

864 suite = get_suite_or_die(suite_name, session) 

865 values = {} 

866 for arg in args[3:]: 

867 if arg not in ALLOWED_SUITE_CONFIGS: 867 ↛ 868line 867 didn't jump to line 868, because the condition on line 867 was never true

868 die("Unknown (or unsupported) suite configuration variable") 

869 value = _get_suite_value(suite, arg) 

870 if json_format: 870 ↛ 871line 870 didn't jump to line 871, because the condition on line 870 was never true

871 values[arg] = value 

872 elif direct_value: 872 ↛ 873line 872 didn't jump to line 873, because the condition on line 872 was never true

873 print(value) 

874 else: 

875 print("%s=%s" % (arg, value)) 

876 if json_format: 876 ↛ 877line 876 didn't jump to line 877, because the condition on line 876 was never true

877 print(json.dumps(values, indent=2, sort_keys=True)) 

878 

879 

880def __suite_config_set(d, args): 

881 die_arglen(args, 4, "E: suite-config set needs the name of a configuration") 

882 session = d.session() 

883 suite_name = args[2] 

884 suite = get_suite_or_die(suite_name, session) 

885 args_as_kvpairs = __suite_config_set_confing_args_as_dict(args[3:]) 

886 __suite_config_internal_set(suite, suite_name, args_as_kvpairs, 

887 print_config_set=True 

888 ) 

889 if dryrun: 

890 session.rollback() 

891 print() 

892 print("This was a dryrun; changes have been rolled back") 

893 else: 

894 session.commit() 

895 

896 

897def __suite_config_set_confing_args_as_dict(args): 

898 # Use OrderedDict to preserve order (makes "dak admin suite-config set ..." 

899 # less confusing when things are processed in the input order) 

900 kvpairs = collections.OrderedDict() 

901 for arg in args: 

902 if '=' not in arg: 902 ↛ 903line 902 didn't jump to line 903, because the condition on line 902 was never true

903 die("Missing value for configuration %s: Use key=value format" % arg) 

904 conf_name, new_value_str = arg.split('=', 1) 

905 kvpairs[conf_name] = new_value_str 

906 return kvpairs 

907 

908 

909def __suite_config_internal_set(suite, suite_name, kvpairs, print_config_set=True): 

910 for kvpair in kvpairs.items(): 

911 conf_name, new_value_str = kvpair 

912 cli_parser = ALLOWED_SUITE_CONFIGS.get(conf_name) 

913 if cli_parser is None: 913 ↛ 914line 913 didn't jump to line 914, because the condition on line 913 was never true

914 die("Unknown (or unsupported) suite configuration variable") 

915 if cli_parser in (SUITE_CONFIG_READ_ONLY, SUITE_CONFIG_WRITABLE_ONLY_VIA_JSON): 915 ↛ 916line 915 didn't jump to line 916, because the condition on line 915 was never true

916 if cli_parser == SUITE_CONFIG_WRITABLE_ONLY_VIA_JSON: 

917 msg = "Cannot parse value for %s" \ 

918 ''' - set via echo '{"%s": <...>}' | dak suite-config set-json %s instead''' 

919 warn(msg % (conf_name, conf_name, suite_name)) 

920 die("Cannot change %s from the command line" % conf_name) 

921 try: 

922 new_value = cli_parser(new_value_str) 

923 except (RuntimeError, ValueError, TypeError) as e: 

924 warn("Could not parse new value for %s (given: %s)" % (conf_name, new_value_str)) 

925 raise e 

926 try: 

927 _set_suite_value(suite, conf_name, new_value) 

928 except (RuntimeError, ValueError, TypeError) as e: 

929 warn("Could not set new value for %s (given: %s)" % (conf_name, new_value)) 

930 raise e 

931 if print_config_set: 

932 print("%s=%s" % (conf_name, _get_suite_value(suite, conf_name))) 

933 

934 

935def __suite_config_set_json(d, args): 

936 session = d.session() 

937 suite_name = args[2] 

938 suite = get_suite_or_die(suite_name, session) 

939 filename = '-' 

940 if len(args) > 3: 

941 if len(args) > 4: 

942 warn("W: Ignoring extra argument after the json file name") 

943 filename = args[3] 

944 if filename != '-': 

945 with open(filename) as fd: 

946 update_config = json.load(fd) 

947 else: 

948 update_config = json.load(sys.stdin) 

949 if update_config is None or not isinstance(update_config, dict): 

950 die("E: suite-config set-json expects a dictionary (json object), got %s" % type(update_config)) 

951 

952 for conf_name in sorted(update_config): 

953 new_value = update_config[conf_name] 

954 cli_parser = ALLOWED_SUITE_CONFIGS.get(conf_name) 

955 if cli_parser is None: 

956 die("Unknown (or unsupported) suite configuration variable: %s" % conf_name) 

957 if cli_parser is SUITE_CONFIG_READ_ONLY: 

958 die("Cannot change %s via JSON" % conf_name) 

959 try: 

960 _set_suite_value(suite, conf_name, new_value) 

961 except (RuntimeError, ValueError, TypeError) as e: 

962 warn("Could not set new value for %s (given: %s)" % (conf_name, new_value)) 

963 raise e 

964 print("%s=%s" % (conf_name, _get_suite_value(suite, conf_name))) 

965 if dryrun: 

966 session.rollback() 

967 print() 

968 print("This was a dryrun; changes have been rolled back") 

969 else: 

970 session.commit() 

971 

972 

973def __suite_config_list(d, args, json_format=False): 

974 suite = None 

975 session = d.session() 

976 if len(args) > 3: 976 ↛ 977line 976 didn't jump to line 977, because the condition on line 976 was never true

977 warn("W: Ignoring extra argument after the suite name") 

978 if len(args) == 3: 978 ↛ 982line 978 didn't jump to line 982, because the condition on line 978 was never false

979 suite_name = args[2] 

980 suite = get_suite_or_die(suite_name, session) 

981 else: 

982 if json_format: 

983 die("E: suite-config list-json requires a suite name!") 

984 print("Valid suite-config options manageable by this command:") 

985 print() 

986 values = {} 

987 

988 for arg in sorted(ALLOWED_SUITE_CONFIGS): 

989 mode = 'writable' 

990 if suite is not None: 990 ↛ 997line 990 didn't jump to line 997, because the condition on line 990 was never false

991 value = _get_suite_value(suite, arg) 

992 if json_format: 992 ↛ 993line 992 didn't jump to line 993, because the condition on line 992 was never true

993 values[arg] = value 

994 else: 

995 print("%s=%s" % (arg, value)) 

996 else: 

997 converter = ALLOWED_SUITE_CONFIGS[arg] 

998 if converter is SUITE_CONFIG_READ_ONLY: 

999 mode = 'read-only' 

1000 elif converter is SUITE_CONFIG_WRITABLE_ONLY_VIA_JSON: 

1001 mode = 'writeable (via set-json only)' 

1002 print(" * %s (%s)" % (arg, mode)) 

1003 if json_format: 1003 ↛ 1004line 1003 didn't jump to line 1004, because the condition on line 1003 was never true

1004 print(json.dumps(values, indent=2, sort_keys=True)) 

1005 

1006 

1007def suite_config(args): 

1008 Cnf = utils.get_conf() 

1009 d = DBConn() 

1010 

1011 die_arglen(args, 2, "E: suite-config needs a command") 

1012 mode = args[1].lower() 

1013 

1014 if mode in {'get', 'get-value', 'get-json'}: 

1015 direct_value = False 

1016 json_format = mode == 'get-json' 

1017 if mode == 'get-value': 1017 ↛ 1018line 1017 didn't jump to line 1018, because the condition on line 1017 was never true

1018 direct_value = True 

1019 if len(args) > 4: 

1020 die("E: get-value must receive exactly one key to lookup") 

1021 __suite_config_get(d, args, direct_value=direct_value, json_format=json_format) 

1022 elif mode == 'set': 

1023 __suite_config_set(d, args) 

1024 elif mode == 'set-json': 1024 ↛ 1025line 1024 didn't jump to line 1025, because the condition on line 1024 was never true

1025 __suite_config_set_json(d, args) 

1026 elif mode in {'list', 'list-json'}: 1026 ↛ 1030line 1026 didn't jump to line 1030, because the condition on line 1026 was never false

1027 json_format = mode == 'list-json' 

1028 __suite_config_list(d, args, json_format=json_format) 

1029 else: 

1030 suite = get_suite(mode, d.session()) 

1031 if suite is not None: 

1032 warn("Did you get the order of the suite and the subcommand wrong?") 

1033 warn("Syntax: dak admin %s {get,set,...} <suite>" % args[0]) 

1034 die("E: suite-config command unknown") 

1035 

1036 

1037dispatch['suite-config'] = suite_config 

1038dispatch['suite-cfg'] = suite_config 

1039dispatch['s-cfg'] = suite_config 

1040 

1041 

1042################################################################################ 

1043 

1044 

1045def archive_list(): 

1046 session = DBConn().session() 

1047 for archive in session.query(Archive).order_by(Archive.archive_name): 

1048 print("{0} path={1} description={2} tainted={3}".format(archive.archive_name, archive.path, archive.description, archive.tainted)) 

1049 

1050 

1051def archive_add(args): 

1052 (name, path, description) = args[0:3] 

1053 

1054 attributes = dict( 

1055 archive_name=name, 

1056 path=path, 

1057 description=description, 

1058 ) 

1059 

1060 for option in args[3:]: 1060 ↛ 1061line 1060 didn't jump to line 1061, because the loop on line 1060 never started

1061 (key, value) = option.split('=') 

1062 attributes[key] = value 

1063 

1064 session = DBConn().session() 

1065 

1066 archive = Archive() 

1067 for key, value in attributes.items(): 

1068 setattr(archive, key, value) 

1069 

1070 session.add(archive) 

1071 session.flush() 

1072 

1073 if dryrun: 1073 ↛ 1074line 1073 didn't jump to line 1074, because the condition on line 1073 was never true

1074 session.rollback() 

1075 else: 

1076 session.commit() 

1077 

1078 

1079def archive_rm(name): 

1080 session = DBConn().session() 

1081 archive = get_archive(name, session) 

1082 session.delete(archive) 

1083 session.flush() 

1084 

1085 if dryrun: 

1086 session.rollback() 

1087 else: 

1088 session.commit() 

1089 

1090 

1091def archive_rename(oldname, newname): 

1092 session = DBConn().session() 

1093 archive = get_archive(oldname, session) 

1094 archive.archive_name = newname 

1095 session.flush() 

1096 

1097 if dryrun: 

1098 session.rollback() 

1099 else: 

1100 session.commit() 

1101 

1102 

1103def archive(command): 

1104 mode = command[1] 

1105 if mode == 'list': 

1106 archive_list() 

1107 elif mode == 'rename': 1107 ↛ 1108line 1107 didn't jump to line 1108, because the condition on line 1107 was never true

1108 archive_rename(command[2], command[3]) 

1109 elif mode == 'add': 1109 ↛ 1111line 1109 didn't jump to line 1111, because the condition on line 1109 was never false

1110 archive_add(command[2:]) 

1111 elif mode == 'rm': 

1112 archive_rm(command[2]) 

1113 else: 

1114 die("E: archive command unknown") 

1115 

1116 

1117dispatch['archive'] = archive 

1118 

1119################################################################################ 

1120 

1121 

1122def __version_check_list(d): 

1123 session = d.session() 

1124 for s in session.query(Suite).order_by(Suite.suite_name): 

1125 __version_check_list_suite(d, s.suite_name) 

1126 

1127 

1128def __version_check_list_suite(d, suite_name): 

1129 vcs = get_version_checks(suite_name) 

1130 for vc in vcs: 

1131 print("%s %s %s" % (suite_name, vc.check, vc.reference.suite_name)) 

1132 

1133 

1134def __version_check_add(d, suite_name, check, reference_name): 

1135 suite = get_suite_or_die(suite_name, 

1136 error_message="E: Could not find suite %(suite_name)s") 

1137 reference = get_suite_or_die(reference_name, 

1138 error_message="E: Could not find reference suite %(suite_name)s") 

1139 

1140 session = d.session() 

1141 vc = VersionCheck() 

1142 vc.suite = suite 

1143 vc.check = check 

1144 vc.reference = reference 

1145 session.add(vc) 

1146 session.commit() 

1147 

1148 

1149def __version_check_rm(d, suite_name, check, reference_name): 

1150 suite = get_suite_or_die(suite_name, 

1151 error_message="E: Could not find suite %(suite_name)s") 

1152 reference = get_suite_or_die(reference_name, 

1153 error_message="E: Could not find reference suite %(suite_name)s") 

1154 

1155 session = d.session() 

1156 try: 

1157 vc = session.query(VersionCheck).filter_by(suite=suite, check=check, reference=reference).one() 

1158 session.delete(vc) 

1159 session.commit() 

1160 except NoResultFound: 

1161 print("W: version-check not found.") 

1162 

1163 

1164def version_check(args): 

1165 Cnf = utils.get_conf() 

1166 d = DBConn() 

1167 

1168 die_arglen(args, 2, "E: version-check needs at least a command") 

1169 mode = args[1].lower() 

1170 

1171 if mode == 'list': 1171 ↛ 1172line 1171 didn't jump to line 1172, because the condition on line 1171 was never true

1172 __version_check_list(d) 

1173 elif mode == 'list-suite': 1173 ↛ 1174line 1173 didn't jump to line 1174, because the condition on line 1173 was never true

1174 if len(args) != 3: 

1175 die("E: version-check list-suite needs a single parameter") 

1176 __version_check_list_suite(d, args[2]) 

1177 elif mode == 'add': 1177 ↛ 1181line 1177 didn't jump to line 1181, because the condition on line 1177 was never false

1178 if len(args) != 5: 1178 ↛ 1179line 1178 didn't jump to line 1179, because the condition on line 1178 was never true

1179 die("E: version-check add needs three parameters") 

1180 __version_check_add(d, args[2], args[3], args[4]) 

1181 elif mode == 'rm': 

1182 if len(args) != 5: 

1183 die("E: version-check rm needs three parameters") 

1184 __version_check_rm(d, args[2], args[3], args[4]) 

1185 else: 

1186 die("E: version-check command unknown") 

1187 

1188 

1189dispatch['version-check'] = version_check 

1190dispatch['v-c'] = version_check 

1191 

1192################################################################################ 

1193 

1194 

1195def show_config(args): 

1196 cnf = utils.get_conf() 

1197 

1198 die_arglen(args, 2, "E: config needs at least a command") 

1199 

1200 mode = args[1].lower() 

1201 

1202 if mode == 'db': 

1203 connstr = "" 

1204 if "DB::Service" in cnf: 

1205 # Service mode 

1206 connstr = "postgresql://service=%s" % cnf["DB::Service"] 

1207 elif "DB::Host" in cnf: 

1208 # TCP/IP 

1209 connstr = "postgresql://%s" % cnf["DB::Host"] 

1210 if "DB::Port" in cnf and cnf["DB::Port"] != "-1": 

1211 connstr += ":%s" % cnf["DB::Port"] 

1212 connstr += "/%s" % cnf["DB::Name"] 

1213 else: 

1214 # Unix Socket 

1215 connstr = "postgresql:///%s" % cnf["DB::Name"] 

1216 if cnf["DB::Port"] and cnf["DB::Port"] != "-1": 

1217 connstr += "?port=%s" % cnf["DB::Port"] 

1218 print(connstr) 

1219 elif mode == 'db-shell': 

1220 e = [] 

1221 if "DB::Service" in cnf: 

1222 e.append('PGSERVICE') 

1223 print("PGSERVICE=%s" % cnf["DB::Service"]) 

1224 if "DB::Name" in cnf: 

1225 e.append('PGDATABASE') 

1226 print("PGDATABASE=%s" % cnf["DB::Name"]) 

1227 if "DB::Host" in cnf: 

1228 print("PGHOST=%s" % cnf["DB::Host"]) 

1229 e.append('PGHOST') 

1230 if "DB::Port" in cnf and cnf["DB::Port"] != "-1": 

1231 print("PGPORT=%s" % cnf["DB::Port"]) 

1232 e.append('PGPORT') 

1233 print("export " + " ".join(e)) 

1234 elif mode == 'get': 

1235 print(cnf.get(args[2])) 

1236 else: 

1237 session = DBConn().session() 

1238 try: 

1239 o = session.query(DBConfig).filter_by(name=mode).one() 

1240 print(o.value) 

1241 except NoResultFound: 

1242 print("W: option '%s' not set" % mode) 

1243 

1244 

1245dispatch['config'] = show_config 

1246dispatch['c'] = show_config 

1247 

1248################################################################################ 

1249 

1250 

1251def show_keyring(args): 

1252 cnf = utils.get_conf() 

1253 

1254 die_arglen(args, 2, "E: keyring needs at least a command") 

1255 

1256 mode = args[1].lower() 

1257 

1258 d = DBConn() 

1259 

1260 q = d.session().query(Keyring).filter(Keyring.active == True) # noqa:E712 

1261 

1262 if mode == 'list-all': 

1263 pass 

1264 elif mode == 'list-binary': 

1265 q = q.join(Keyring.acl).filter(ACL.allow_source == False) # noqa:E712 

1266 elif mode == 'list-source': 

1267 q = q.join(Keyring.acl).filter(ACL.allow_source == True) # noqa:E712 

1268 else: 

1269 die("E: keyring command unknown") 

1270 

1271 for k in q.all(): 

1272 print(k.keyring_name) 

1273 

1274 

1275def keyring_add_buildd(command): 

1276 name = command[2] 

1277 arch_names = command[3:] 

1278 

1279 session = DBConn().session() 

1280 arches = session.query(Architecture).filter(Architecture.arch_string.in_(arch_names)) 

1281 

1282 acl = ACL() 

1283 acl.name = 'buildd-{0}'.format('+'.join(arch_names)) 

1284 acl.architectures.update(arches) 

1285 acl.allow_new = True 

1286 acl.allow_binary = True 

1287 acl.allow_binary_only = True 

1288 acl.allow_hijack = True 

1289 session.add(acl) 

1290 

1291 k = Keyring() 

1292 k.keyring_name = name 

1293 k.acl = acl 

1294 k.priority = 10 

1295 session.add(k) 

1296 

1297 session.commit() 

1298 

1299 

1300def keyring(command): 

1301 if command[1].startswith('list-'): 

1302 show_keyring(command) 

1303 elif command[1] == 'add-buildd': 

1304 keyring_add_buildd(command) 

1305 else: 

1306 die("E: keyring command unknown") 

1307 

1308 

1309dispatch['keyring'] = keyring 

1310dispatch['k'] = keyring 

1311 

1312################################################################################ 

1313 

1314 

1315def change_component_source(transaction, suite, component, source_names): 

1316 session = transaction.session 

1317 

1318 overrides = session.query(Override).filter(Override.package.in_(source_names)).filter_by(suite=suite).join(OverrideType).filter_by(overridetype='dsc') 

1319 for override in overrides: 

1320 print("Changing override for {0}".format(override.package)) 

1321 override.component = component 

1322 session.flush() 

1323 

1324 sources = session.query(DBSource).filter(DBSource.source.in_(source_names)).filter(DBSource.suites.contains(suite)) 

1325 for source in sources: 

1326 print("Copying {0}={1}".format(source.source, source.version)) 

1327 transaction.copy_source(source, suite, component) 

1328 

1329 

1330def change_component_binary(transaction, suite, component, binary_names): 

1331 session = transaction.session 

1332 

1333 overrides = session.query(Override).filter(Override.package.in_(binary_names)).filter_by(suite=suite).join(OverrideType).filter(OverrideType.overridetype.in_(['deb', 'udeb'])) 

1334 for override in overrides: 

1335 print("Changing override for {0}".format(override.package)) 

1336 override.component = component 

1337 session.flush() 

1338 

1339 binaries = session.query(DBBinary).filter(DBBinary.package.in_(binary_names)).filter(DBBinary.suites.contains(suite)) 

1340 for binary in binaries: 

1341 print("Copying {0}={1} [{2}]".format(binary.package, binary.version, binary.architecture.arch_string)) 

1342 transaction.copy_binary(binary, suite, component) 

1343 pass 

1344 

1345 

1346def change_component(args): 

1347 with daklib.archive.ArchiveTransaction() as transaction: 

1348 session = transaction.session 

1349 

1350 suite = session.query(Suite).filter_by(suite_name=args[1]).one() 

1351 component = session.query(Component).filter_by(component_name=args[2]).one() 

1352 

1353 if args[3] == 'source': 

1354 change_component_source(transaction, suite, component, args[4:]) 

1355 elif args[3] == 'binary': 

1356 change_component_binary(transaction, suite, component, args[4:]) 

1357 else: 

1358 raise Exception("Can only move source or binary, not {0}".format(args[3])) 

1359 

1360 transaction.commit() 

1361 

1362 

1363dispatch['change-component'] = change_component 

1364 

1365################################################################################ 

1366 

1367 

1368def forget_signature(args): 

1369 filename = args[1] 

1370 with open(filename, 'rb') as fh: 

1371 data = fh.read() 

1372 

1373 session = DBConn().session() 

1374 keyrings = [k.keyring_name for k in session.query(Keyring).filter_by(active=True).order_by(Keyring.priority)] 

1375 signed_file = daklib.gpg.SignedFile(data, keyrings) 

1376 history = SignatureHistory.from_signed_file(signed_file).query(session) 

1377 if history is not None: 1377 ↛ 1381line 1377 didn't jump to line 1381, because the condition on line 1377 was never false

1378 session.delete(history) 

1379 session.commit() 

1380 else: 

1381 print("Signature was not known to dak.") 

1382 session.rollback() 

1383 

1384 

1385dispatch['forget-signature'] = forget_signature 

1386 

1387################################################################################ 

1388 

1389 

1390def main(): 

1391 """Perform administrative work on the dak database""" 

1392 global dryrun 

1393 Cnf = utils.get_conf() 

1394 arguments = [('h', "help", "Admin::Options::Help"), 

1395 ('n', "dry-run", "Admin::Options::Dry-Run")] 

1396 for i in ["help", "dry-run"]: 

1397 key = "Admin::Options::%s" % i 

1398 if key not in Cnf: 1398 ↛ 1396line 1398 didn't jump to line 1396, because the condition on line 1398 was never false

1399 Cnf[key] = "" 

1400 

1401 arguments = apt_pkg.parse_commandline(Cnf, arguments, sys.argv) 

1402 

1403 options = Cnf.subtree("Admin::Options") 

1404 if options["Help"] or len(arguments) < 1: 

1405 usage() 

1406 if options["Dry-Run"]: 

1407 dryrun = True 

1408 

1409 subcommand = arguments[0] 

1410 

1411 if subcommand in dispatch: 1411 ↛ 1414line 1411 didn't jump to line 1414, because the condition on line 1411 was never false

1412 dispatch[subcommand](arguments) 

1413 else: 

1414 die("E: Unknown command") 

1415 

1416################################################################################ 

1417 

1418 

1419if __name__ == '__main__': 

1420 main()