1#! /usr/bin/env python3
3"""Configure dak parameters in the database"""
4# Copyright (C) 2009 Mark Hymers <mhy@debian.org>
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.
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.
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
20################################################################################
22import collections
23import json
24import sys
25from collections.abc import Callable, Sequence
26from dataclasses import dataclass
27from typing import Any, NoReturn, Optional
29import apt_pkg
30from sqlalchemy.exc import IntegrityError, SQLAlchemyError
31from sqlalchemy.orm.exc import NoResultFound
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)
63################################################################################
65dispatch = {}
66dryrun = False
68################################################################################
71def warn(msg: str) -> None:
72 print(msg, file=sys.stderr)
75def die(msg: str, exit_code: int = 1) -> NoReturn:
76 print(msg, file=sys.stderr)
77 sys.exit(exit_code)
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)
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
96def usage(exit_code: int = 0) -> NoReturn:
97 """Perform administrative work on the dak database."""
99 print(
100 """Usage: dak admin COMMAND
101Perform administrative work on the dak database.
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).
107 Commands can use a long or abbreviated form:
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
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
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
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.
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)
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
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)
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)
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.
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
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
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.
217 forget-signature FILE: forget that we saw FILE
218"""
219 )
220 sys.exit(exit_code)
223################################################################################
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)
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]))
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])
287def architecture(args):
288 d = DBConn()
290 die_arglen(args, 2, "E: architecture needs at least a command")
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")
303dispatch["architecture"] = architecture
304dispatch["a"] = architecture
306################################################################################
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))
315def component_add(args):
316 (name, description, ordering) = args[0:3]
318 attributes = dict(
319 component_name=name,
320 description=description,
321 ordering=ordering,
322 )
324 for option in args[3:]:
325 (key, value) = option.split("=")
326 attributes[key] = value
328 session = DBConn().session()
330 component = Component()
331 for key, value in attributes.items():
332 setattr(component, key, value)
334 session.add(component)
335 session.flush()
337 if dryrun:
338 session.rollback()
339 else:
340 session.commit()
343def component_rm(name: str) -> None:
344 session = DBConn().session()
345 component = get_component(name, session)
346 session.delete(component)
347 session.flush()
349 if dryrun:
350 session.rollback()
351 else:
352 session.commit()
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()
361 if dryrun:
362 session.rollback()
363 else:
364 session.commit()
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")
381dispatch["component"] = component
383################################################################################
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))
400def __suite_show(d, args):
401 if len(args) < 2:
402 die("E: showing an suite entry requires a suite")
404 su = get_suite_or_die(args[2])
406 print(su.details())
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:])
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
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))
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)
468 print("Architectures %s added to %s" % (",".join(arches), suite_name))
470 s.commit()
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))
494def __suite_add_build_queue(d, args):
495 session = d.session()
497 die_arglen(args, 6, "E: Adding a build queue needs four parameters.")
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))
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
529 # Do not accept direct uploads to the build queue
530 s.accept_source_uploads = False
531 s.accept_binary_uploads = False
533 s.archive = build_queue_archive
534 s.architectures.extend(suite.architectures)
535 s.components.extend(suite.components)
536 s.srcformats.extend(suite.srcformats)
538 session.add(s)
539 session.flush()
541 bq = BuildQueue()
542 bq.queue_name = build_queue_codename
543 bq.suite = s
545 session.add(bq)
546 session.flush()
548 suite.copy_queues.append(bq)
550 session.commit()
553def suite(args):
554 d = DBConn()
556 die_arglen(args, 2, "E: suite needs at least a command")
558 mode = args[1].lower()
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")
576dispatch["suite"] = suite
577dispatch["s"] = suite
579################################################################################
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]))
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)
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)
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")
610 s = d.session()
612 suite = get_suite_or_die(args[2], s)
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())
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 )
633 print(
634 "Added suite-architecture entry for %s, %s" % (args[2].lower(), arch_name)
635 )
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()
640 s.close()
643def __suite_architecture_rm(d, args):
644 if len(args) < 3:
645 die("E: removing an suite-architecture entry requires a suite and arch")
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 )
672 print(
673 "Removed suite-architecture entry for %s, %s"
674 % (args[2].lower(), args[3].lower())
675 )
678def suite_architecture(args):
679 d = DBConn()
681 die_arglen(args, 2, "E: suite-architecture needs at least a command")
683 mode = args[1].lower()
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")
699dispatch["suite-architecture"] = suite_architecture
700dispatch["s-a"] = suite_architecture
702################################################################################
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]))
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)
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)
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")
732 s = d.session()
734 suite = get_suite_or_die(args[2], s)
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())
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 )
755 print(
756 "Added suite-component entry for %s, %s" % (args[2].lower(), component_name)
757 )
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()
764def __suite_component_rm(d, args):
765 if len(args) < 3:
766 die("E: removing an suite-component entry requires a suite and component")
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 )
793 print(
794 "Removed suite-component entry for %s, %s" % (args[2].lower(), args[3].lower())
795 )
798def suite_component(args):
799 d = DBConn()
801 die_arglen(args, 2, "E: suite-component needs at least a command")
803 mode = args[1].lower()
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")
819dispatch["suite-component"] = suite_component
820dispatch["s-c"] = suite_component
823################################################################################
825# Sentinel for detecting read-only configurations
826SUITE_CONFIG_READ_ONLY = object()
827SUITE_CONFIG_WRITABLE_ONLY_VIA_JSON = object()
830@dataclass
831class SuiteConfigSerializer:
832 db_name: str
833 serialize: Callable[[Any], str]
834 deserialize: Optional[Callable[[str], Any]]
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
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
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
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
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
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}
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}
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)
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)
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))
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()
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
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)))
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 )
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()
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 = {}
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))
1116def suite_config(args):
1117 d = DBConn()
1119 die_arglen(args, 2, "E: suite-config needs a command")
1120 mode = args[1].lower()
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")
1145dispatch["suite-config"] = suite_config
1146dispatch["suite-cfg"] = suite_config
1147dispatch["s-cfg"] = suite_config
1150################################################################################
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 )
1163def archive_add(args):
1164 (name, path, description) = args[0:3]
1166 attributes = dict(
1167 archive_name=name,
1168 path=path,
1169 description=description,
1170 )
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
1176 session = DBConn().session()
1178 archive = Archive()
1179 for key, value in attributes.items():
1180 setattr(archive, key, value)
1182 session.add(archive)
1183 session.flush()
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()
1191def archive_rm(name):
1192 session = DBConn().session()
1193 archive = get_archive(name, session)
1194 session.delete(archive)
1195 session.flush()
1197 if dryrun:
1198 session.rollback()
1199 else:
1200 session.commit()
1203def archive_rename(oldname, newname):
1204 session = DBConn().session()
1205 archive = get_archive(oldname, session)
1206 archive.archive_name = newname
1207 session.flush()
1209 if dryrun:
1210 session.rollback()
1211 else:
1212 session.commit()
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")
1229dispatch["archive"] = archive
1231################################################################################
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)
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))
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 )
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()
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 )
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.")
1284def version_check(args):
1285 d = DBConn()
1287 die_arglen(args, 2, "E: version-check needs at least a command")
1288 mode = args[1].lower()
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")
1308dispatch["version-check"] = version_check
1309dispatch["v-c"] = version_check
1311################################################################################
1314def show_config(args):
1315 cnf = utils.get_conf()
1317 die_arglen(args, 2, "E: config needs at least a command")
1319 mode = args[1].lower()
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)
1364dispatch["config"] = show_config
1365dispatch["c"] = show_config
1367################################################################################
1370def show_keyring(args):
1371 die_arglen(args, 2, "E: keyring needs at least a command")
1373 mode = args[1].lower()
1375 d = DBConn()
1377 q = d.session().query(Keyring).filter(Keyring.active == True) # noqa:E712
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")
1388 for k in q.all():
1389 print(k.keyring_name)
1392def keyring_add_buildd(command):
1393 name = command[2]
1394 arch_names = command[3:]
1396 session = DBConn().session()
1397 arches = session.query(Architecture).filter(
1398 Architecture.arch_string.in_(arch_names)
1399 )
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)
1410 k = Keyring()
1411 k.keyring_name = name
1412 k.acl = acl
1413 k.priority = 10
1414 session.add(k)
1416 session.commit()
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")
1428dispatch["keyring"] = keyring
1429dispatch["k"] = keyring
1431################################################################################
1434def change_component_source(transaction, suite, component, source_names):
1435 session = transaction.session
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()
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)
1459def change_component_binary(transaction, suite, component, binary_names):
1460 session = transaction.session
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()
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
1489def change_component(args):
1490 with daklib.archive.ArchiveTransaction() as transaction:
1491 session = transaction.session
1493 suite = session.query(Suite).filter_by(suite_name=args[1]).one()
1494 component = session.query(Component).filter_by(component_name=args[2]).one()
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]))
1503 transaction.commit()
1506dispatch["change-component"] = change_component
1508################################################################################
1511def forget_signature(args):
1512 filename = args[1]
1513 with open(filename, "rb") as fh:
1514 data = fh.read()
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()
1533dispatch["forget-signature"] = forget_signature
1535################################################################################
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] = ""
1551 arguments = apt_pkg.parse_commandline(Cnf, arguments, sys.argv)
1553 options = Cnf.subtree("Admin::Options")
1554 if options["Help"] or len(arguments) < 1:
1555 usage()
1556 if options["Dry-Run"]:
1557 dryrun = True
1559 subcommand = arguments[0]
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")
1567################################################################################
1570if __name__ == "__main__":
1571 main()