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 

30from sqlalchemy.exc import IntegrityError, SQLAlchemyError 

31from sqlalchemy.orm.exc import NoResultFound 

32 

33import daklib.archive 

34import daklib.gpg 

35from daklib import utils 

36from daklib.dbconn import ( 

37 ACL, 

38 Architecture, 

39 Archive, 

40 BuildQueue, 

41 Component, 

42 DBBinary, 

43 DBConfig, 

44 DBConn, 

45 DBSource, 

46 Keyring, 

47 Override, 

48 OverrideType, 

49 PolicyQueue, 

50 SignatureHistory, 

51 SrcFormat, 

52 Suite, 

53 VersionCheck, 

54 get_architecture, 

55 get_archive, 

56 get_component, 

57 get_policy_queue, 

58 get_suite, 

59 get_version_checks, 

60 session_wrapper, 

61) 

62 

63################################################################################ 

64 

65dispatch = {} 

66dryrun = False 

67 

68################################################################################ 

69 

70 

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

72 print(msg, file=sys.stderr) 

73 

74 

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

76 print(msg, file=sys.stderr) 

77 sys.exit(exit_code) 

78 

79 

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

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

82 die(msg) 

83 

84 

85def get_suite_or_die( 

86 suite_name: str, 

87 session=None, 

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

89) -> Suite: 

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

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

92 die(error_message % {"suite_name": suite_name}) 

93 return suite 

94 

95 

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

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

98 

99 print( 

100 """Usage: dak admin COMMAND 

101Perform administrative work on the dak database. 

102 

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

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

105 (only applies to add or rm operations). 

106 

107 Commands can use a long or abbreviated form: 

108 

109 config / c: 

110 c db show db config 

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

112 c NAME show option NAME as set in configuration table 

113 

114 keyring / k: 

115 k list-all list all keyrings 

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

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

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

119 for the given architectures 

120 

121 architecture / a: 

122 a list show a list of architectures 

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

124 no longer linked to any suites) 

125 a add ARCH DESCRIPTION [SUITELIST] 

126 add architecture ARCH with DESCRIPTION. 

127 If SUITELIST is given, add to each of the 

128 suites at the same time 

129 

130 component: 

131 component list show a list of components 

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

133 empty) 

134 component add NAME DESCRIPTION ORDERING 

135 add component NAME with DESCRIPTION. 

136 Ordered at ORDERING. 

137 

138 suite / s: 

139 s list [--print-archive] 

140 show a list of suites 

141 s show SUITE show config details for a suite 

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

143 [ origin=ORIGIN ] [ codename=CODENAME ] 

144 [ signingkey=SIGNINGKEY ] [ archive=ARCHIVE ] 

145 add suite SUITE, version VERSION. 

146 label, description, origin, codename 

147 and signingkey are optional. 

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

149 

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

151 relationships for all architectures 

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

153 add a build queue for an existing suite 

154 

155 suite-architecture / s-a: 

156 s-a list show the architectures for all suites 

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

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

159 s-a add SUITE ARCH add ARCH to suite 

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

161 no packages remain for the arch in the suite) 

162 

163 suite-component / s-c: 

164 s-c list show the architectures for all suites 

165 s-c list-suite COMPONENT 

166 show the suites a COMPONENT is in 

167 s-c list-component SUITE 

168 show the components in a SUITE 

169 s-c add SUITE COMPONENT 

170 add COMPONENT to suite 

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

172 no packages remain for the component in the suite) 

173 

174 suite-config / suite-cfg / s-cfg: 

175 s-cfg list show the names of the configurations 

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

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

178 s-cfg get SUITE NAME ... 

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

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

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

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

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

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

185 set NAME to VALUE in SUITE 

186 s-cfg set-json SUITE 

187 s-cfg set-json SUITE FILENAME 

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

189 and update all configurations listed to match the 

190 value in the JSON. 

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

192 

193 archive: 

194 archive list list all archives 

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

196 add archive NAME with path ROOT, 

197 primary mirror MIRROR. 

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

199 no files and no suites in the archive) 

200 archive rename OLD NEW rename archive OLD to NEW 

201 

202 version-check / v-c: 

203 v-c list show version checks for all suites 

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

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

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

207 where 

208 CHECK is one of Enhances, MustBeNewerThan, MustBeOlderThan 

209 REFERENCE is another suite name 

210 

211 change-component: 

212 change-component SUITE COMPONENT source SOURCE... 

213 change-component SUITE COMPONENT binary BINARY... 

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

215 associated files and changing the overrides. 

216 

217 forget-signature FILE: forget that we saw FILE 

218""" 

219 ) 

220 sys.exit(exit_code) 

221 

222 

223################################################################################ 

224 

225 

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

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

228 for j in q.all(): 

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

230 if j.arch_string == "source": 

231 continue 

232 print(j.arch_string) 

233 sys.exit(0) 

234 

235 

236def __architecture_add(d, args): 

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

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

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

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

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

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

243 try: 

244 s = d.session() 

245 a = Architecture() 

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

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

248 s.add(a) 

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

250 su = get_suite(sn, s) 

251 if su is not None: 

252 a.suites.append(su) 

253 else: 

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

255 s.commit() 

256 except IntegrityError: 

257 die( 

258 "E: Integrity error adding architecture %s (it probably already exists)" 

259 % args[2] 

260 ) 

261 except SQLAlchemyError as e: 

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

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

264 

265 

266def __architecture_rm(d, args): 

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

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

269 if not dryrun: 

270 try: 

271 s = d.session() 

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

273 if a is None: 

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

275 s.delete(a) 

276 s.commit() 

277 except IntegrityError: 

278 die( 

279 "E: Integrity error removing architecture %s (suite-arch entries probably still exist)" 

280 % args[2] 

281 ) 

282 except SQLAlchemyError as e: 

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

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

285 

286 

287def architecture(args): 

288 d = DBConn() 

289 

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

291 

292 mode = args[1].lower() 

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

294 __architecture_list(d, args) 

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

296 __architecture_add(d, args) 

297 elif mode == "rm": 

298 __architecture_rm(d, args) 

299 else: 

300 die("E: architecture command unknown") 

301 

302 

303dispatch["architecture"] = architecture 

304dispatch["a"] = architecture 

305 

306################################################################################ 

307 

308 

309def component_list(): 

310 session = DBConn().session() 

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

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

313 

314 

315def component_add(args): 

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

317 

318 attributes = dict( 

319 component_name=name, 

320 description=description, 

321 ordering=ordering, 

322 ) 

323 

324 for option in args[3:]: 

325 (key, value) = option.split("=") 

326 attributes[key] = value 

327 

328 session = DBConn().session() 

329 

330 component = Component() 

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

332 setattr(component, key, value) 

333 

334 session.add(component) 

335 session.flush() 

336 

337 if dryrun: 

338 session.rollback() 

339 else: 

340 session.commit() 

341 

342 

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

344 session = DBConn().session() 

345 component = get_component(name, session) 

346 session.delete(component) 

347 session.flush() 

348 

349 if dryrun: 

350 session.rollback() 

351 else: 

352 session.commit() 

353 

354 

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

356 session = DBConn().session() 

357 component = get_component(oldname, session) 

358 component.component_name = newname 

359 session.flush() 

360 

361 if dryrun: 

362 session.rollback() 

363 else: 

364 session.commit() 

365 

366 

367def component(command): 

368 mode = command[1] 

369 if mode == "list": 

370 component_list() 

371 elif mode == "rename": 

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

373 elif mode == "add": 

374 component_add(command[2:]) 

375 elif mode == "rm": 

376 component_rm(command[2]) 

377 else: 

378 die("E: component command unknown") 

379 

380 

381dispatch["component"] = component 

382 

383################################################################################ 

384 

385 

386def __suite_list(d, args): 

387 s = d.session() 

388 for j in ( 

389 s.query(Suite) 

390 .join(Suite.archive) 

391 .order_by(Archive.archive_name, Suite.suite_name) 

392 .all() 

393 ): 

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

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

396 else: 

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

398 

399 

400def __suite_show(d, args): 

401 if len(args) < 2: 

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

403 

404 su = get_suite_or_die(args[2]) 

405 

406 print(su.details()) 

407 

408 

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

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

411 suite_name = args[2].lower() 

412 version = args[3] 

413 kvpairs = __suite_config_set_confing_args_as_dict(args[4:]) 

414 

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

416 version = None 

417 

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

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

420 try: 

421 s = d.session() 

422 suite = Suite() 

423 suite.suite_name = suite_name 

424 suite.overridecodename = None 

425 suite.version = version or None 

426 # Most configurations will be handled by 

427 # __suite_config_internal_set. However, a few are managed 

428 # manually here because __suite_config_internal_set cannot 

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

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

431 suite.codename = kvpairs.pop("codename", None) 

432 signingkey = kvpairs.pop("signingkey", None) 

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

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

435 archive_name = kvpairs.pop("archive", None) 

436 if archive_name is not None: 

437 suite.archive = get_archive(archive_name, s) 

438 else: 

439 suite.archive = ( 

440 s.query(Archive) 

441 .filter( 

442 ~Archive.archive_name.in_(["build-queues", "new", "policy"]) 

443 ) 

444 .one() 

445 ) 

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

447 __suite_config_internal_set( 

448 suite, suite_name, kvpairs, print_config_set=False 

449 ) 

450 s.add(suite) 

451 s.flush() 

452 except IntegrityError: 

453 die( 

454 "E: Integrity error adding suite %s (it probably already exists)" 

455 % suite_name 

456 ) 

457 except SQLAlchemyError as e: 

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

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

460 

461 if addallarches: 

462 arches = [] 

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

464 for arch in q.all(): 

465 suite.architectures.append(arch) 

466 arches.append(arch.arch_string) 

467 

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

469 

470 s.commit() 

471 

472 

473def __suite_rm(d, args): 

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

475 name = args[2] 

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

477 if not dryrun: 

478 try: 

479 s = d.session() 

480 su = get_suite_or_die(name, s) 

481 s.delete(su) 

482 s.commit() 

483 except IntegrityError: 

484 die( 

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

486 name 

487 ) 

488 ) 

489 except SQLAlchemyError as e: 

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

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

492 

493 

494def __suite_add_build_queue(d, args): 

495 session = d.session() 

496 

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

498 

499 suite_name = args[2] 

500 build_queue_name = args[3] 

501 build_queue_codename = args[4] 

502 build_queue_archive_name = args[5] 

503 try: 

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

505 except NoResultFound: 

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

507 try: 

508 build_queue_archive = ( 

509 session.query(Archive) 

510 .filter_by(archive_name=build_queue_archive_name) 

511 .one() 

512 ) 

513 except NoResultFound: 

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

515 

516 # Create suite 

517 s = Suite() 

518 s.suite_name = build_queue_name 

519 s.origin = suite.origin 

520 s.label = suite.label 

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

522 s.codename = build_queue_codename 

523 s.notautomatic = suite.notautomatic 

524 s.overridesuite = suite.overridesuite or suite.suite_name 

525 s.butautomaticupgrades = suite.butautomaticupgrades 

526 s.signingkeys = suite.signingkeys 

527 s.include_long_description = False 

528 

529 # Do not accept direct uploads to the build queue 

530 s.accept_source_uploads = False 

531 s.accept_binary_uploads = False 

532 

533 s.archive = build_queue_archive 

534 s.architectures.extend(suite.architectures) 

535 s.components.extend(suite.components) 

536 s.srcformats.extend(suite.srcformats) 

537 

538 session.add(s) 

539 session.flush() 

540 

541 bq = BuildQueue() 

542 bq.queue_name = build_queue_codename 

543 bq.suite = s 

544 

545 session.add(bq) 

546 session.flush() 

547 

548 suite.copy_queues.append(bq) 

549 

550 session.commit() 

551 

552 

553def suite(args): 

554 d = DBConn() 

555 

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

557 

558 mode = args[1].lower() 

559 

560 if mode == "list": 

561 __suite_list(d, args) 

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

563 __suite_show(d, args) 

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

565 __suite_rm(d, args) 

566 elif mode == "add": 

567 __suite_add(d, args, False) 

568 elif mode == "add-all-arches": 

569 __suite_add(d, args, True) 

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

571 __suite_add_build_queue(d, args) 

572 else: 

573 die("E: suite command unknown") 

574 

575 

576dispatch["suite"] = suite 

577dispatch["s"] = suite 

578 

579################################################################################ 

580 

581 

582def __suite_architecture_list(d, args): 

583 s = d.session() 

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

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

586 print(j.suite_name + ": " + ", ".join([a.arch_string for a in architectures])) 

587 

588 

589def __suite_architecture_listarch(d, args): 

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

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

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

593 for j in a: 

594 print(j.arch_string) 

595 

596 

597def __suite_architecture_listsuite(d, args): 

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

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

600 if architecture is None: 

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

602 for j in architecture.suites: 

603 print(j.suite_name) 

604 

605 

606def __suite_architecture_add(d, args): 

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

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

609 

610 s = d.session() 

611 

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

613 

614 for arch_name in args[3:]: 

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

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

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

618 

619 try: 

620 suite.architectures.append(arch) 

621 s.flush() 

622 except IntegrityError: 

623 die( 

624 "E: Can't add suite-architecture entry (%s, %s) - probably already exists" 

625 % (args[2].lower(), arch_name) 

626 ) 

627 except SQLAlchemyError as e: 

628 die( 

629 "E: Can't add suite-architecture entry (%s, %s) - %s" 

630 % (args[2].lower(), arch_name, e) 

631 ) 

632 

633 print( 

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

635 ) 

636 

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

638 s.commit() 

639 

640 s.close() 

641 

642 

643def __suite_architecture_rm(d, args): 

644 if len(args) < 3: 

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

646 

647 s = d.session() 

648 if not dryrun: 

649 try: 

650 suite_name = args[2].lower() 

651 suite = get_suite_or_die(suite_name, s) 

652 arch_string = args[3].lower() 

653 architecture = get_architecture(arch_string, s) 

654 if architecture not in suite.architectures: 

655 die( 

656 "E: architecture %s not found in suite %s" 

657 % (arch_string, suite_name) 

658 ) 

659 suite.architectures.remove(architecture) 

660 s.commit() 

661 except IntegrityError: 

662 die( 

663 "E: Can't remove suite-architecture entry (%s, %s) - it's probably referenced" 

664 % (args[2].lower(), args[3].lower()) 

665 ) 

666 except SQLAlchemyError as e: 

667 die( 

668 "E: Can't remove suite-architecture entry (%s, %s) - %s" 

669 % (args[2].lower(), args[3].lower(), e) 

670 ) 

671 

672 print( 

673 "Removed suite-architecture entry for %s, %s" 

674 % (args[2].lower(), args[3].lower()) 

675 ) 

676 

677 

678def suite_architecture(args): 

679 d = DBConn() 

680 

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

682 

683 mode = args[1].lower() 

684 

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

686 __suite_architecture_list(d, args) 

687 elif mode == "list-arch": 

688 __suite_architecture_listarch(d, args) 

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

690 __suite_architecture_listsuite(d, args) 

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

692 __suite_architecture_add(d, args) 

693 elif mode == "rm": 

694 __suite_architecture_rm(d, args) 

695 else: 

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

697 

698 

699dispatch["suite-architecture"] = suite_architecture 

700dispatch["s-a"] = suite_architecture 

701 

702################################################################################ 

703 

704 

705def __suite_component_list(d, args): 

706 s = d.session() 

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

708 components = j.components 

709 print(j.suite_name + ": " + ", ".join([c.component_name for c in components])) 

710 

711 

712def __suite_component_listcomponent(d, args): 

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

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

715 for c in suite.components: 

716 print(c.component_name) 

717 

718 

719def __suite_component_listsuite(d, args): 

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

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

722 if component is None: 

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

724 for s in component.suites: 

725 print(s.suite_name) 

726 

727 

728def __suite_component_add(d, args): 

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

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

731 

732 s = d.session() 

733 

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

735 

736 for component_name in args[3:]: 

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

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

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

740 

741 try: 

742 suite.components.append(component) 

743 s.flush() 

744 except IntegrityError: 

745 die( 

746 "E: Can't add suite-component entry (%s, %s) - probably already exists" 

747 % (args[2].lower(), component_name) 

748 ) 

749 except SQLAlchemyError as e: 

750 die( 

751 "E: Can't add suite-component entry (%s, %s) - %s" 

752 % (args[2].lower(), component_name, e) 

753 ) 

754 

755 print( 

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

757 ) 

758 

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

760 s.commit() 

761 s.close() 

762 

763 

764def __suite_component_rm(d, args): 

765 if len(args) < 3: 

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

767 

768 s = d.session() 

769 if not dryrun: 

770 try: 

771 suite_name = args[2].lower() 

772 suite = get_suite_or_die(suite_name, s) 

773 component_string = args[3].lower() 

774 component = get_component(component_string, s) 

775 if component not in suite.components: 

776 die( 

777 "E: component %s not found in suite %s" 

778 % (component_string, suite_name) 

779 ) 

780 suite.components.remove(component) 

781 s.commit() 

782 except IntegrityError: 

783 die( 

784 "E: Can't remove suite-component entry (%s, %s) - it's probably referenced" 

785 % (args[2].lower(), args[3].lower()) 

786 ) 

787 except SQLAlchemyError as e: 

788 die( 

789 "E: Can't remove suite-component entry (%s, %s) - %s" 

790 % (args[2].lower(), args[3].lower(), e) 

791 ) 

792 

793 print( 

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

795 ) 

796 

797 

798def suite_component(args): 

799 d = DBConn() 

800 

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

802 

803 mode = args[1].lower() 

804 

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

806 __suite_component_list(d, args) 

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

808 __suite_component_listcomponent(d, args) 

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

810 __suite_component_listsuite(d, args) 

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

812 __suite_component_add(d, args) 

813 # elif mode == 'rm': 

814 # __suite_architecture_rm(d, args) 

815 else: 

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

817 

818 

819dispatch["suite-component"] = suite_component 

820dispatch["s-c"] = suite_component 

821 

822 

823################################################################################ 

824 

825# Sentinel for detecting read-only configurations 

826SUITE_CONFIG_READ_ONLY = object() 

827SUITE_CONFIG_WRITABLE_ONLY_VIA_JSON = object() 

828 

829 

830@dataclass 

831class SuiteConfigSerializer: 

832 db_name: str 

833 serialize: Callable[[Any], str] 

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

835 

836 

837def _serialize_suite(x): 

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

839 return None 

840 return Suite.get(x).suite_name 

841 

842 

843def _deserialize_suite(x): 

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

845 return None 

846 return get_suite_or_die(x).suite_id 

847 

848 

849@session_wrapper 

850def _serialize_policy_queue(x, session=None): 

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

852 return None 

853 try: 

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

855 except NoResultFound: 

856 return None 

857 return policy_obj.queue_name 

858 

859 

860def _deserialize_policy_queue(x): 

861 if x is None: 

862 return None 

863 policy_queue = get_policy_queue(x) 

864 if policy_queue is None: 

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

866 return policy_queue.policy_queue_id 

867 

868 

869@session_wrapper 

870def _serialize_archive(x, session=None): 

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

872 return None 

873 try: 

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

875 except NoResultFound: 

876 return None 

877 return archive_obj.archive_name 

878 

879 

880CUSTOM_SUITE_CONFIG_SERIALIZERS = { 

881 "archive": SuiteConfigSerializer( 

882 db_name="archive_id", serialize=_serialize_archive, deserialize=None 

883 ), 

884 "debugsuite": SuiteConfigSerializer( 

885 db_name="debugsuite_id", 

886 serialize=_serialize_suite, 

887 deserialize=_deserialize_suite, 

888 ), 

889 "new_queue": SuiteConfigSerializer( 

890 db_name="new_queue_id", 

891 serialize=_serialize_policy_queue, 

892 deserialize=_deserialize_policy_queue, 

893 ), 

894 "policy_queue": SuiteConfigSerializer( 

895 db_name="policy_queue_id", 

896 serialize=_serialize_policy_queue, 

897 deserialize=_deserialize_policy_queue, 

898 ), 

899} 

900 

901 

902ALLOWED_SUITE_CONFIGS = { 

903 "accept_binary_uploads": utils.parse_boolean_from_user, 

904 "accept_source_uploads": utils.parse_boolean_from_user, 

905 "allowcsset": utils.parse_boolean_from_user, 

906 "announce": SUITE_CONFIG_WRITABLE_ONLY_VIA_JSON, 

907 "archive": SUITE_CONFIG_READ_ONLY, 

908 "butautomaticupgrades": utils.parse_boolean_from_user, 

909 "byhash": utils.parse_boolean_from_user, 

910 "changelog": str, 

911 "changelog_url": str, 

912 "checksums": SUITE_CONFIG_WRITABLE_ONLY_VIA_JSON, 

913 "close_bugs": utils.parse_boolean_from_user, 

914 "codename": SUITE_CONFIG_READ_ONLY, 

915 "debugsuite": str, 

916 "description": str, 

917 "include_long_description": utils.parse_boolean_from_user, 

918 "indices_compression": SUITE_CONFIG_WRITABLE_ONLY_VIA_JSON, 

919 "label": str, 

920 "mail_whitelist": str, 

921 "merged_pdiffs": utils.parse_boolean_from_user, 

922 "new_queue": str, 

923 "notautomatic": utils.parse_boolean_from_user, 

924 "origin": str, 

925 "overridecodename": str, 

926 "overrideorigin": str, 

927 "overrideprocess": utils.parse_boolean_from_user, 

928 "overridesuite": str, 

929 "policy_queue": str, 

930 "priority": int, 

931 "separate_contents_architecture_all": utils.parse_boolean_from_user, 

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

933 "separate_packages_architecture_all": SUITE_CONFIG_READ_ONLY, 

934 "signingkeys": SUITE_CONFIG_WRITABLE_ONLY_VIA_JSON, 

935 "suite_name": SUITE_CONFIG_READ_ONLY, 

936 "untouchable": utils.parse_boolean_from_user, 

937 "validtime": int, 

938} 

939 

940 

941def _get_suite_value(suite, conf_name): 

942 serial_config = CUSTOM_SUITE_CONFIG_SERIALIZERS.get(conf_name) 

943 if serial_config is None: 

944 return getattr(suite, conf_name) 

945 db_value = getattr(suite, serial_config.db_name) 

946 return serial_config.serialize(db_value) 

947 

948 

949def _set_suite_value(suite, conf_name, new_value): 

950 serial_config = CUSTOM_SUITE_CONFIG_SERIALIZERS.get(conf_name) 

951 db_name = conf_name 

952 if serial_config is not None: 

953 assert serial_config.deserialize is not None, ( 

954 "Changing %s is not supported!" % conf_name 

955 ) 

956 new_value = serial_config.deserialize(new_value) 

957 db_name = serial_config.db_name 

958 setattr(suite, db_name, new_value) 

959 

960 

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

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

963 session = d.session() 

964 suite_name = args[2] 

965 suite = get_suite_or_die(suite_name, session) 

966 values = {} 

967 for arg in args[3:]: 

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

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

970 value = _get_suite_value(suite, arg) 

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

972 values[arg] = value 

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

974 print(value) 

975 else: 

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

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

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

979 

980 

981def __suite_config_set(d, args): 

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

983 session = d.session() 

984 suite_name = args[2] 

985 suite = get_suite_or_die(suite_name, session) 

986 args_as_kvpairs = __suite_config_set_confing_args_as_dict(args[3:]) 

987 __suite_config_internal_set( 

988 suite, suite_name, args_as_kvpairs, print_config_set=True 

989 ) 

990 if dryrun: 

991 session.rollback() 

992 print() 

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

994 else: 

995 session.commit() 

996 

997 

998def __suite_config_set_confing_args_as_dict(args): 

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

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

1001 kvpairs = collections.OrderedDict() 

1002 for arg in args: 

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

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

1005 conf_name, new_value_str = arg.split("=", 1) 

1006 kvpairs[conf_name] = new_value_str 

1007 return kvpairs 

1008 

1009 

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

1011 for kvpair in kvpairs.items(): 

1012 conf_name, new_value_str = kvpair 

1013 cli_parser = ALLOWED_SUITE_CONFIGS.get(conf_name) 

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

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

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

1017 if cli_parser == SUITE_CONFIG_WRITABLE_ONLY_VIA_JSON: 

1018 msg = ( 

1019 "Cannot parse value for %s" 

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

1021 ) 

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

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

1024 try: 

1025 new_value = cli_parser(new_value_str) 

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

1027 warn( 

1028 "Could not parse new value for %s (given: %s)" 

1029 % (conf_name, new_value_str) 

1030 ) 

1031 raise e 

1032 try: 

1033 _set_suite_value(suite, conf_name, new_value) 

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

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

1036 raise e 

1037 if print_config_set: 

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

1039 

1040 

1041def __suite_config_set_json(d, args): 

1042 session = d.session() 

1043 suite_name = args[2] 

1044 suite = get_suite_or_die(suite_name, session) 

1045 filename = "-" 

1046 if len(args) > 3: 

1047 if len(args) > 4: 

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

1049 filename = args[3] 

1050 if filename != "-": 

1051 with open(filename) as fd: 

1052 update_config = json.load(fd) 

1053 else: 

1054 update_config = json.load(sys.stdin) 

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

1056 die( 

1057 "E: suite-config set-json expects a dictionary (json object), got %s" 

1058 % type(update_config) 

1059 ) 

1060 

1061 for conf_name in sorted(update_config): 

1062 new_value = update_config[conf_name] 

1063 cli_parser = ALLOWED_SUITE_CONFIGS.get(conf_name) 

1064 if cli_parser is None: 

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

1066 if cli_parser is SUITE_CONFIG_READ_ONLY: 

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

1068 try: 

1069 _set_suite_value(suite, conf_name, new_value) 

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

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

1072 raise e 

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

1074 if dryrun: 

1075 session.rollback() 

1076 print() 

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

1078 else: 

1079 session.commit() 

1080 

1081 

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

1083 suite = None 

1084 session = d.session() 

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

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

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

1088 suite_name = args[2] 

1089 suite = get_suite_or_die(suite_name, session) 

1090 else: 

1091 if json_format: 

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

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

1094 print() 

1095 values = {} 

1096 

1097 for arg in sorted(ALLOWED_SUITE_CONFIGS): 

1098 mode = "writable" 

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

1100 value = _get_suite_value(suite, arg) 

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

1102 values[arg] = value 

1103 else: 

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

1105 else: 

1106 converter = ALLOWED_SUITE_CONFIGS[arg] 

1107 if converter is SUITE_CONFIG_READ_ONLY: 

1108 mode = "read-only" 

1109 elif converter is SUITE_CONFIG_WRITABLE_ONLY_VIA_JSON: 

1110 mode = "writeable (via set-json only)" 

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

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

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

1114 

1115 

1116def suite_config(args): 

1117 d = DBConn() 

1118 

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

1120 mode = args[1].lower() 

1121 

1122 if mode in {"get", "get-value", "get-json"}: 

1123 direct_value = False 

1124 json_format = mode == "get-json" 

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

1126 direct_value = True 

1127 if len(args) > 4: 

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

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

1130 elif mode == "set": 

1131 __suite_config_set(d, args) 

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

1133 __suite_config_set_json(d, args) 

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

1135 json_format = mode == "list-json" 

1136 __suite_config_list(d, args, json_format=json_format) 

1137 else: 

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

1139 if suite is not None: 

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

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

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

1143 

1144 

1145dispatch["suite-config"] = suite_config 

1146dispatch["suite-cfg"] = suite_config 

1147dispatch["s-cfg"] = suite_config 

1148 

1149 

1150################################################################################ 

1151 

1152 

1153def archive_list(): 

1154 session = DBConn().session() 

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

1156 print( 

1157 "{0} path={1} description={2} tainted={3}".format( 

1158 archive.archive_name, archive.path, archive.description, archive.tainted 

1159 ) 

1160 ) 

1161 

1162 

1163def archive_add(args): 

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

1165 

1166 attributes = dict( 

1167 archive_name=name, 

1168 path=path, 

1169 description=description, 

1170 ) 

1171 

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

1173 (key, value) = option.split("=") 

1174 attributes[key] = value 

1175 

1176 session = DBConn().session() 

1177 

1178 archive = Archive() 

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

1180 setattr(archive, key, value) 

1181 

1182 session.add(archive) 

1183 session.flush() 

1184 

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

1186 session.rollback() 

1187 else: 

1188 session.commit() 

1189 

1190 

1191def archive_rm(name): 

1192 session = DBConn().session() 

1193 archive = get_archive(name, session) 

1194 session.delete(archive) 

1195 session.flush() 

1196 

1197 if dryrun: 

1198 session.rollback() 

1199 else: 

1200 session.commit() 

1201 

1202 

1203def archive_rename(oldname, newname): 

1204 session = DBConn().session() 

1205 archive = get_archive(oldname, session) 

1206 archive.archive_name = newname 

1207 session.flush() 

1208 

1209 if dryrun: 

1210 session.rollback() 

1211 else: 

1212 session.commit() 

1213 

1214 

1215def archive(command): 

1216 mode = command[1] 

1217 if mode == "list": 

1218 archive_list() 

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

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

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

1222 archive_add(command[2:]) 

1223 elif mode == "rm": 

1224 archive_rm(command[2]) 

1225 else: 

1226 die("E: archive command unknown") 

1227 

1228 

1229dispatch["archive"] = archive 

1230 

1231################################################################################ 

1232 

1233 

1234def __version_check_list(d): 

1235 session = d.session() 

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

1237 __version_check_list_suite(d, s.suite_name) 

1238 

1239 

1240def __version_check_list_suite(d, suite_name): 

1241 vcs = get_version_checks(suite_name) 

1242 for vc in vcs: 

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

1244 

1245 

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

1247 suite = get_suite_or_die( 

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

1249 ) 

1250 reference = get_suite_or_die( 

1251 reference_name, error_message="E: Could not find reference suite %(suite_name)s" 

1252 ) 

1253 

1254 session = d.session() 

1255 vc = VersionCheck() 

1256 vc.suite = suite 

1257 vc.check = check 

1258 vc.reference = reference 

1259 session.add(vc) 

1260 session.commit() 

1261 

1262 

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

1264 suite = get_suite_or_die( 

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

1266 ) 

1267 reference = get_suite_or_die( 

1268 reference_name, error_message="E: Could not find reference suite %(suite_name)s" 

1269 ) 

1270 

1271 session = d.session() 

1272 try: 

1273 vc = ( 

1274 session.query(VersionCheck) 

1275 .filter_by(suite=suite, check=check, reference=reference) 

1276 .one() 

1277 ) 

1278 session.delete(vc) 

1279 session.commit() 

1280 except NoResultFound: 

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

1282 

1283 

1284def version_check(args): 

1285 d = DBConn() 

1286 

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

1288 mode = args[1].lower() 

1289 

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

1291 __version_check_list(d) 

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

1293 if len(args) != 3: 

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

1295 __version_check_list_suite(d, args[2]) 

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

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

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

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

1300 elif mode == "rm": 

1301 if len(args) != 5: 

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

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

1304 else: 

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

1306 

1307 

1308dispatch["version-check"] = version_check 

1309dispatch["v-c"] = version_check 

1310 

1311################################################################################ 

1312 

1313 

1314def show_config(args): 

1315 cnf = utils.get_conf() 

1316 

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

1318 

1319 mode = args[1].lower() 

1320 

1321 if mode == "db": 

1322 connstr = "" 

1323 if "DB::Service" in cnf: 

1324 # Service mode 

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

1326 elif "DB::Host" in cnf: 

1327 # TCP/IP 

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

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

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

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

1332 else: 

1333 # Unix Socket 

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

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

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

1337 print(connstr) 

1338 elif mode == "db-shell": 

1339 e = [] 

1340 if "DB::Service" in cnf: 

1341 e.append("PGSERVICE") 

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

1343 if "DB::Name" in cnf: 

1344 e.append("PGDATABASE") 

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

1346 if "DB::Host" in cnf: 

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

1348 e.append("PGHOST") 

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

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

1351 e.append("PGPORT") 

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

1353 elif mode == "get": 

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

1355 else: 

1356 session = DBConn().session() 

1357 try: 

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

1359 print(o.value) 

1360 except NoResultFound: 

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

1362 

1363 

1364dispatch["config"] = show_config 

1365dispatch["c"] = show_config 

1366 

1367################################################################################ 

1368 

1369 

1370def show_keyring(args): 

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

1372 

1373 mode = args[1].lower() 

1374 

1375 d = DBConn() 

1376 

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

1378 

1379 if mode == "list-all": 

1380 pass 

1381 elif mode == "list-binary": 

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

1383 elif mode == "list-source": 

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

1385 else: 

1386 die("E: keyring command unknown") 

1387 

1388 for k in q.all(): 

1389 print(k.keyring_name) 

1390 

1391 

1392def keyring_add_buildd(command): 

1393 name = command[2] 

1394 arch_names = command[3:] 

1395 

1396 session = DBConn().session() 

1397 arches = session.query(Architecture).filter( 

1398 Architecture.arch_string.in_(arch_names) 

1399 ) 

1400 

1401 acl = ACL() 

1402 acl.name = "buildd-{0}".format("+".join(arch_names)) 

1403 acl.architectures.update(arches) 

1404 acl.allow_new = True 

1405 acl.allow_binary = True 

1406 acl.allow_binary_only = True 

1407 acl.allow_hijack = True 

1408 session.add(acl) 

1409 

1410 k = Keyring() 

1411 k.keyring_name = name 

1412 k.acl = acl 

1413 k.priority = 10 

1414 session.add(k) 

1415 

1416 session.commit() 

1417 

1418 

1419def keyring(command): 

1420 if command[1].startswith("list-"): 

1421 show_keyring(command) 

1422 elif command[1] == "add-buildd": 

1423 keyring_add_buildd(command) 

1424 else: 

1425 die("E: keyring command unknown") 

1426 

1427 

1428dispatch["keyring"] = keyring 

1429dispatch["k"] = keyring 

1430 

1431################################################################################ 

1432 

1433 

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

1435 session = transaction.session 

1436 

1437 overrides = ( 

1438 session.query(Override) 

1439 .filter(Override.package.in_(source_names)) 

1440 .filter_by(suite=suite) 

1441 .join(OverrideType) 

1442 .filter_by(overridetype="dsc") 

1443 ) 

1444 for override in overrides: 

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

1446 override.component = component 

1447 session.flush() 

1448 

1449 sources = ( 

1450 session.query(DBSource) 

1451 .filter(DBSource.source.in_(source_names)) 

1452 .filter(DBSource.suites.contains(suite)) 

1453 ) 

1454 for source in sources: 

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

1456 transaction.copy_source(source, suite, component) 

1457 

1458 

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

1460 session = transaction.session 

1461 

1462 overrides = ( 

1463 session.query(Override) 

1464 .filter(Override.package.in_(binary_names)) 

1465 .filter_by(suite=suite) 

1466 .join(OverrideType) 

1467 .filter(OverrideType.overridetype.in_(["deb", "udeb"])) 

1468 ) 

1469 for override in overrides: 

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

1471 override.component = component 

1472 session.flush() 

1473 

1474 binaries = ( 

1475 session.query(DBBinary) 

1476 .filter(DBBinary.package.in_(binary_names)) 

1477 .filter(DBBinary.suites.contains(suite)) 

1478 ) 

1479 for binary in binaries: 

1480 print( 

1481 "Copying {0}={1} [{2}]".format( 

1482 binary.package, binary.version, binary.architecture.arch_string 

1483 ) 

1484 ) 

1485 transaction.copy_binary(binary, suite, component) 

1486 pass 

1487 

1488 

1489def change_component(args): 

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

1491 session = transaction.session 

1492 

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

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

1495 

1496 if args[3] == "source": 

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

1498 elif args[3] == "binary": 

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

1500 else: 

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

1502 

1503 transaction.commit() 

1504 

1505 

1506dispatch["change-component"] = change_component 

1507 

1508################################################################################ 

1509 

1510 

1511def forget_signature(args): 

1512 filename = args[1] 

1513 with open(filename, "rb") as fh: 

1514 data = fh.read() 

1515 

1516 session = DBConn().session() 

1517 keyrings = [ 

1518 k.keyring_name 

1519 for k in session.query(Keyring) 

1520 .filter_by(active=True) 

1521 .order_by(Keyring.priority) 

1522 ] 

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

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

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

1526 session.delete(history) 

1527 session.commit() 

1528 else: 

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

1530 session.rollback() 

1531 

1532 

1533dispatch["forget-signature"] = forget_signature 

1534 

1535################################################################################ 

1536 

1537 

1538def main(): 

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

1540 global dryrun 

1541 Cnf = utils.get_conf() 

1542 arguments = [ 

1543 ("h", "help", "Admin::Options::Help"), 

1544 ("n", "dry-run", "Admin::Options::Dry-Run"), 

1545 ] 

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

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

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

1549 Cnf[key] = "" 

1550 

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

1552 

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

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

1555 usage() 

1556 if options["Dry-Run"]: 

1557 dryrun = True 

1558 

1559 subcommand = arguments[0] 

1560 

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

1562 dispatch[subcommand](arguments) 

1563 else: 

1564 die("E: Unknown command") 

1565 

1566 

1567################################################################################ 

1568 

1569 

1570if __name__ == "__main__": 

1571 main()