]> git.decadent.org.uk Git - dak.git/blob - dak/admin.py
allow adding multiple architectures and components to a suite at the same time
[dak.git] / dak / admin.py
1 #!/usr/bin/env python
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
22 import sys
23
24 import apt_pkg
25
26 from daklib import utils
27 from daklib.dbconn import *
28 from sqlalchemy.orm.exc import NoResultFound
29
30 ################################################################################
31
32 dispatch = {}
33 dryrun = False
34
35 ################################################################################
36 def warn(msg):
37     print >> sys.stderr, msg
38
39 def die(msg, exit_code=1):
40     print >> sys.stderr, msg
41     sys.exit(exit_code)
42
43 def die_arglen(args, args_needed, msg):
44     if len(args) < args_needed:
45         die(msg)
46
47 def usage(exit_code=0):
48     """Perform administrative work on the dak database."""
49
50     print """Usage: dak admin COMMAND
51 Perform administrative work on the dak database.
52
53   -h, --help          show this help and exit.
54   -n, --dry-run       don't do anything, just show what would have been done
55                       (only applies to add or rm operations).
56
57   Commands can use a long or abbreviated form:
58
59   config / c:
60      c db                   show db config
61      c db-shell             show db config in a usable form for psql
62      c NAME                 show option NAME as set in configuration table
63
64   keyring / k:
65      k list-all             list all keyrings
66      k list-binary          list all keyrings with a NULL source acl
67      k list-source          list all keyrings with a non NULL source acl
68      k add-buildd NAME ARCH...   add buildd keyring with upload permission
69                                  for the given architectures
70
71   architecture / a:
72      a list                 show a list of architectures
73      a rm ARCH              remove an architecture (will only work if
74                             no longer linked to any suites)
75      a add ARCH DESCRIPTION [SUITELIST]
76                             add architecture ARCH with DESCRIPTION.
77                             If SUITELIST is given, add to each of the
78                             suites at the same time
79
80   component:
81      component list         show a list of components
82      component rm COMPONENT remove a component (will only work if
83                             empty)
84      component add NAME DESCRIPTION ORDERING
85                             add component NAME with DESCRIPTION.
86                             Ordered at ORDERING.
87
88   suite / s:
89      s list [--print-archive]
90                             show a list of suites
91      s show SUITE           show config details for a suite
92      s add SUITE VERSION [ label=LABEL ] [ description=DESCRIPTION ]
93                          [ origin=ORIGIN ] [ codename=CODENAME ]
94                          [ signingkey=SIGNINGKEY ] [ archive=ARCHIVE ]
95                             add suite SUITE, version VERSION.
96                             label, description, origin, codename
97                             and signingkey are optional.
98
99      s add-all-arches SUITE VERSION... as "s add" but adds suite-architecture
100                             relationships for all architectures
101
102   suite-architecture / s-a:
103      s-a list               show the architectures for all suites
104      s-a list-suite ARCH    show the suites an ARCH is in
105      s-a list-arch SUITE    show the architectures in a SUITE
106      s-a add SUITE ARCH     add ARCH to suite
107      s-a rm SUITE ARCH      remove ARCH from suite (will only work if
108                             no packages remain for the arch in the suite)
109
110   suite-component / s-c:
111      s-c list               show the architectures for all suites
112      s-c list-suite COMPONENT
113                             show the suites a COMPONENT is in
114      s-c list-component SUITE
115                             show the components in a SUITE
116      s-c add SUITE COMPONENT
117                             add COMPONENT to suite
118      s-c rm SUITE COMPONENT remove component from suite (will only work if
119                             no packages remain for the component in the suite)
120
121   archive:
122      archive list           list all archives
123      archive add NAME ROOT DESCRIPTION [primary-mirror=MIRROR] [tainted=1]
124                             add archive NAME with path ROOT,
125                             primary mirror MIRROR.
126      archive rm NAME        remove archive NAME (will only work if there are
127                             no files and no suites in the archive)
128      archive rename OLD NEW rename archive OLD to NEW
129
130   version-check / v-c:
131      v-c list                        show version checks for all suites
132      v-c list-suite SUITE            show version checks for suite SUITE
133      v-c add SUITE CHECK REFERENCE   add a version check for suite SUITE
134      v-c rm SUITE CHECK REFERENCE    remove a version check
135        where
136          CHECK     is one of Enhances, MustBeNewerThan, MustBeOlderThan
137          REFERENCE is another suite name
138 """
139     sys.exit(exit_code)
140
141 ################################################################################
142
143 def __architecture_list(d, args):
144     q = d.session().query(Architecture).order_by(Architecture.arch_string)
145     for j in q.all():
146         # HACK: We should get rid of source from the arch table
147         if j.arch_string == 'source': continue
148         print j.arch_string
149     sys.exit(0)
150
151 def __architecture_add(d, args):
152     die_arglen(args, 4, "E: adding an architecture requires a name and a description")
153     print "Adding architecture %s" % args[2]
154     suites = [str(x) for x in args[4:]]
155     if len(suites) > 0:
156         print "Adding to suites %s" % ", ".join(suites)
157     if not dryrun:
158         try:
159             s = d.session()
160             a = Architecture()
161             a.arch_string = str(args[2]).lower()
162             a.description = str(args[3])
163             s.add(a)
164             for sn in suites:
165                 su = get_suite(sn, s)
166                 if su is not None:
167                     a.suites.append(su)
168                 else:
169                     warn("W: Cannot find suite %s" % su)
170             s.commit()
171         except IntegrityError as e:
172             die("E: Integrity error adding architecture %s (it probably already exists)" % args[2])
173         except SQLAlchemyError as e:
174             die("E: Error adding architecture %s (%s)" % (args[2], e))
175     print "Architecture %s added" % (args[2])
176
177 def __architecture_rm(d, args):
178     die_arglen(args, 3, "E: removing an architecture requires at least a name")
179     print "Removing architecture %s" % args[2]
180     if not dryrun:
181         try:
182             s = d.session()
183             a = get_architecture(args[2].lower(), s)
184             if a is None:
185                 die("E: Cannot find architecture %s" % args[2])
186             s.delete(a)
187             s.commit()
188         except IntegrityError as e:
189             die("E: Integrity error removing architecture %s (suite-arch entries probably still exist)" % args[2])
190         except SQLAlchemyError as e:
191             die("E: Error removing architecture %s (%s)" % (args[2], e))
192     print "Architecture %s removed" % args[2]
193
194 def architecture(command):
195     args = [str(x) for x in command]
196     Cnf = utils.get_conf()
197     d = DBConn()
198
199     die_arglen(args, 2, "E: architecture needs at least a command")
200
201     mode = args[1].lower()
202     if mode == 'list':
203         __architecture_list(d, args)
204     elif mode == 'add':
205         __architecture_add(d, args)
206     elif mode == 'rm':
207         __architecture_rm(d, args)
208     else:
209         die("E: architecture command unknown")
210
211 dispatch['architecture'] = architecture
212 dispatch['a'] = architecture
213
214 ################################################################################
215
216 def component_list():
217     session = DBConn().session()
218     for component in session.query(Component).order_by(Component.component_name):
219         print "{0} ordering={1}".format(component.component_name, component.ordering)
220
221 def component_add(args):
222     (name, description, ordering) = args[0:3]
223
224     attributes = dict(
225         component_name=name,
226         description=description,
227         ordering=ordering,
228         )
229
230     for option in args[3:]:
231         (key, value) = option.split('=')
232         attributes[key] = value
233
234     session = DBConn().session()
235
236     component = Component()
237     for key, value in attributes.iteritems():
238         setattr(component, key, value)
239
240     session.add(component)
241     session.flush()
242
243     if dryrun:
244         session.rollback()
245     else:
246         session.commit()
247
248 def component_rm(name):
249     session = DBConn().session()
250     component = get_component(name, session)
251     session.delete(component)
252     session.flush()
253
254     if dryrun:
255         session.rollback()
256     else:
257         session.commit()
258
259 def component_rename(oldname, newname):
260     session = DBConn().session()
261     component = get_component(oldname, session)
262     component.component_name = newname
263     session.flush()
264
265     if dryrun:
266         session.rollback()
267     else:
268         session.commit()
269
270 def component(command):
271     mode = command[1]
272     if mode == 'list':
273         component_list()
274     elif mode == 'rename':
275         component_rename(command[2], command[3])
276     elif mode == 'add':
277         component_add(command[2:])
278     elif mode == 'rm':
279         component_rm(command[2])
280     else:
281         die("E: component command unknown")
282
283 dispatch['component'] = component
284
285 ################################################################################
286
287 def __suite_list(d, args):
288     s = d.session()
289     for j in s.query(Suite).join(Suite.archive).order_by(Archive.archive_name, Suite.suite_name).all():
290         if len(args) > 2 and args[2] == "--print-archive":
291             print "{0} {1}".format(j.archive.archive_name, j.suite_name)
292         else:
293             print "{0}".format(j.suite_name)
294
295 def __suite_show(d, args):
296     if len(args) < 2:
297         die("E: showing an suite entry requires a suite")
298
299     s = d.session()
300     su = get_suite(args[2].lower())
301     if su is None:
302         die("E: can't find suite entry for %s" % (args[2].lower()))
303
304     print su.details()
305
306 def __suite_add(d, args, addallarches=False):
307     die_arglen(args, 4, "E: adding a suite requires at least a name and a version")
308     suite_name = args[2].lower()
309     version = args[3]
310     rest = args[3:]
311
312     def get_field(field):
313         for varval in args:
314             if varval.startswith(field + '='):
315                 return varval.split('=')[1]
316         return None
317
318     print "Adding suite %s" % suite_name
319     if not dryrun:
320         try:
321             s = d.session()
322             suite = Suite()
323             suite.suite_name = suite_name
324             suite.overridecodename = suite_name
325             suite.version = version
326             suite.label = get_field('label')
327             suite.description = get_field('description')
328             suite.origin = get_field('origin')
329             suite.codename = get_field('codename')
330             signingkey = get_field('signingkey')
331             if signingkey is not None:
332                 suite.signingkeys = [signingkey.upper()]
333             archive_name = get_field('archive')
334             if archive_name is not None:
335                 suite.archive = get_archive(archive_name, s)
336             else:
337                 suite.archive = s.query(Archive).filter(~Archive.archive_name.in_(['build-queues', 'new', 'policy'])).one()
338             suite.srcformats = s.query(SrcFormat).all()
339             s.add(suite)
340             s.flush()
341         except IntegrityError as e:
342             die("E: Integrity error adding suite %s (it probably already exists)" % suite_name)
343         except SQLAlchemyError as e:
344             die("E: Error adding suite %s (%s)" % (suite_name, e))
345     print "Suite %s added" % (suite_name)
346
347     if addallarches:
348         arches = []
349         q = s.query(Architecture).order_by(Architecture.arch_string)
350         for arch in q.all():
351             suite.architectures.append(arch)
352             arches.append(arch.arch_string)
353
354         print "Architectures %s added to %s" % (','.join(arches), suite_name)
355
356     s.commit()
357
358 def __suite_rm(d, args):
359     die_arglen(args, 3, "E: removing a suite requires at least a name")
360     name = args[2]
361     print "Removing suite {0}".format(name)
362     if not dryrun:
363         try:
364             s = d.session()
365             su = get_suite(name.lower())
366             if su is None:
367                 die("E: Cannot find suite {0}".format(name))
368             s.delete(su)
369             s.commit()
370         except IntegrityError as e:
371             die("E: Integrity error removing suite {0} (suite-arch entries probably still exist)".format(name))
372         except SQLAlchemyError as e:
373             die("E: Error removing suite {0} ({1})".format(name, e))
374     print "Suite {0} removed".format(name)
375
376 def suite(command):
377     args = [str(x) for x in command]
378     Cnf = utils.get_conf()
379     d = DBConn()
380
381     die_arglen(args, 2, "E: suite needs at least a command")
382
383     mode = args[1].lower()
384
385     if mode == 'list':
386         __suite_list(d, args)
387     elif mode == 'show':
388         __suite_show(d, args)
389     elif mode == 'rm':
390         __suite_rm(d, args)
391     elif mode == 'add':
392         __suite_add(d, args, False)
393     elif mode == 'add-all-arches':
394         __suite_add(d, args, True)
395     else:
396         die("E: suite command unknown")
397
398 dispatch['suite'] = suite
399 dispatch['s'] = suite
400
401 ################################################################################
402
403 def __suite_architecture_list(d, args):
404     s = d.session()
405     for j in s.query(Suite).order_by(Suite.suite_name):
406         architectures = j.get_architectures(skipsrc = True, skipall = True)
407         print j.suite_name + ': ' + \
408               ', '.join([a.arch_string for a in architectures])
409
410 def __suite_architecture_listarch(d, args):
411     die_arglen(args, 3, "E: suite-architecture list-arch requires a suite")
412     suite = get_suite(args[2].lower(), d.session())
413     if suite is None:
414         die('E: suite %s is invalid' % args[2].lower())
415     a = suite.get_architectures(skipsrc = True, skipall = True)
416     for j in a:
417         print j.arch_string
418
419
420 def __suite_architecture_listsuite(d, args):
421     die_arglen(args, 3, "E: suite-architecture list-suite requires an arch")
422     architecture = get_architecture(args[2].lower(), d.session())
423     if architecture is None:
424         die("E: architecture %s is invalid" % args[2].lower())
425     for j in architecture.suites:
426         print j.suite_name
427
428
429 def __suite_architecture_add(d, args):
430     if len(args) < 3:
431         die("E: adding a suite-architecture entry requires a suite and arch")
432
433     s = d.session()
434
435     suite = get_suite(args[2].lower(), s)
436     if suite is None: die("E: Can't find suite %s" % args[2].lower())
437
438     for arch_name in args[3:]:
439         arch = get_architecture(arch_name.lower(), s)
440         if arch is None: die("E: Can't find architecture %s" % args[3].lower())
441
442         try:
443             suite.architectures.append(arch)
444             s.flush()
445         except IntegrityError as e:
446             die("E: Can't add suite-architecture entry (%s, %s) - probably already exists" % (args[2].lower(), arch_name))
447         except SQLAlchemyError as e:
448             die("E: Can't add suite-architecture entry (%s, %s) - %s" % (args[2].lower(), arch_name, e))
449
450         print "Added suite-architecture entry for %s, %s" % (args[2].lower(), arch_name)
451
452     if not dryrun:
453         s.commit()
454
455     s.close()
456
457 def __suite_architecture_rm(d, args):
458     if len(args) < 3:
459         die("E: removing an suite-architecture entry requires a suite and arch")
460
461     s = d.session()
462     if not dryrun:
463         try:
464             suite_name = args[2].lower()
465             suite = get_suite(suite_name, s)
466             if suite is None:
467                 die('E: no such suite %s' % suite_name)
468             arch_string = args[3].lower()
469             architecture = get_architecture(arch_string, s)
470             if architecture not in suite.architectures:
471                 die("E: architecture %s not found in suite %s" % (arch_string, suite_name))
472             suite.architectures.remove(architecture)
473             s.commit()
474         except IntegrityError as e:
475             die("E: Can't remove suite-architecture entry (%s, %s) - it's probably referenced" % (args[2].lower(), args[3].lower()))
476         except SQLAlchemyError as e:
477             die("E: Can't remove suite-architecture entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
478
479     print "Removed suite-architecture entry for %s, %s" % (args[2].lower(), args[3].lower())
480
481
482 def suite_architecture(command):
483     args = [str(x) for x in command]
484     Cnf = utils.get_conf()
485     d = DBConn()
486
487     die_arglen(args, 2, "E: suite-architecture needs at least a command")
488
489     mode = args[1].lower()
490
491     if mode == 'list':
492         __suite_architecture_list(d, args)
493     elif mode == 'list-arch':
494         __suite_architecture_listarch(d, args)
495     elif mode == 'list-suite':
496         __suite_architecture_listsuite(d, args)
497     elif mode == 'add':
498         __suite_architecture_add(d, args)
499     elif mode == 'rm':
500         __suite_architecture_rm(d, args)
501     else:
502         die("E: suite-architecture command unknown")
503
504 dispatch['suite-architecture'] = suite_architecture
505 dispatch['s-a'] = suite_architecture
506
507 ################################################################################
508
509 def __suite_component_list(d, args):
510     s = d.session()
511     for j in s.query(Suite).order_by(Suite.suite_name):
512         components = j.components
513         print j.suite_name + ': ' + \
514               ', '.join([c.component_name for c in components])
515
516
517 def __suite_component_listcomponent(d, args):
518      die_arglen(args, 3, "E: suite-component list-component requires a suite")
519      suite = get_suite(args[2].lower(), d.session())
520      if suite is None:
521          die('E: suite %s is invalid' % args[2].lower())
522      for c in suite.components:
523          print c.component_name
524
525
526 def __suite_component_listsuite(d, args):
527      die_arglen(args, 3, "E: suite-component list-suite requires an component")
528      component = get_component(args[2].lower(), d.session())
529      if component is None:
530          die("E: component %s is invalid" % args[2].lower())
531      for s in component.suites:
532          print s.suite_name
533
534
535 def __suite_component_add(d, args):
536      if len(args) < 3:
537          die("E: adding a suite-component entry requires a suite and component")
538
539      s = d.session()
540
541      suite = get_suite(args[2].lower(), s)
542      if suite is None: die("E: Can't find suite %s" % args[2].lower())
543
544      for component_name in args[3:]:
545          component = get_component(component_name.lower(), s)
546          if component is None: die("E: Can't find component %s" % args[3].lower())
547
548          try:
549              suite.components.append(component)
550              s.flush()
551          except IntegrityError as e:
552              die("E: Can't add suite-component entry (%s, %s) - probably already exists" % (args[2].lower(), component_name))
553          except SQLAlchemyError as e:
554              die("E: Can't add suite-component entry (%s, %s) - %s" % (args[2].lower(), component_name, e))
555
556          print "Added suite-component entry for %s, %s" % (args[2].lower(), component_name)
557
558      if not dryrun:
559          s.commit()
560      s.close()
561
562 def __suite_component_rm(d, args):
563      if len(args) < 3:
564          die("E: removing an suite-component entry requires a suite and component")
565
566      s = d.session()
567      if not dryrun:
568          try:
569              suite_name = args[2].lower()
570              suite = get_suite(suite_name, s)
571              if suite is None:
572                  die('E: no such suite %s' % suite_name)
573              component_string = args[3].lower()
574              component = get_component(arch_string, s)
575              if component not in suite.components:
576                  die("E: component %s not found in suite %s" % (component_string, suite_name))
577              suite.components.remove(component)
578              s.commit()
579          except IntegrityError as e:
580              die("E: Can't remove suite-component entry (%s, %s) - it's probably referenced" % (args[2].lower(), args[3].lower()))
581          except SQLAlchemyError as e:
582              die("E: Can't remove suite-component entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
583
584      print "Removed suite-component entry for %s, %s" % (args[2].lower(), args[3].lower())
585
586
587 def suite_component(command):
588     args = [str(x) for x in command]
589     Cnf = utils.get_conf()
590     d = DBConn()
591
592     die_arglen(args, 2, "E: suite-component needs at least a command")
593
594     mode = args[1].lower()
595
596     if mode == 'list':
597         __suite_component_list(d, args)
598     elif mode == 'list-component':
599         __suite_component_listcomponent(d, args)
600     elif mode == 'list-suite':
601         __suite_component_listsuite(d, args)
602     elif mode == 'add':
603         __suite_component_add(d, args)
604     # elif mode == 'rm':
605     #     __suite_architecture_rm(d, args)
606     else:
607         die("E: suite-component command unknown")
608
609 dispatch['suite-component'] = suite_component
610 dispatch['s-c'] = suite_component
611
612 ################################################################################
613
614 def archive_list():
615     session = DBConn().session()
616     for archive in session.query(Archive).order_by(Archive.archive_name):
617         print "{0} path={1} description={2} tainted={3}".format(archive.archive_name, archive.path, archive.description, archive.tainted)
618
619 def archive_add(args):
620     (name, path, description) = args[0:3]
621
622     attributes = dict(
623         archive_name=name,
624         path=path,
625         description=description,
626         )
627
628     for option in args[3:]:
629         (key, value) = option.split('=')
630         attributes[key] = value
631
632     session = DBConn().session()
633
634     archive = Archive()
635     for key, value in attributes.iteritems():
636         setattr(archive, key, value)
637
638     session.add(archive)
639     session.flush()
640
641     if dryrun:
642         session.rollback()
643     else:
644         session.commit()
645
646 def archive_rm(name):
647     session = DBConn().session()
648     archive = get_archive(name, session)
649     session.delete(archive)
650     session.flush()
651
652     if dryrun:
653         session.rollback()
654     else:
655         session.commit()
656
657 def archive_rename(oldname, newname):
658     session = DBConn().session()
659     archive = get_archive(oldname, session)
660     archive.archive_name = newname
661     session.flush()
662
663     if dryrun:
664         session.rollback()
665     else:
666         session.commit()
667
668 def archive(command):
669     mode = command[1]
670     if mode == 'list':
671         archive_list()
672     elif mode == 'rename':
673         archive_rename(command[2], command[3])
674     elif mode == 'add':
675         archive_add(command[2:])
676     elif mode == 'rm':
677         archive_rm(command[2])
678     else:
679         die("E: archive command unknown")
680
681 dispatch['archive'] = archive
682
683 ################################################################################
684
685 def __version_check_list(d):
686     session = d.session()
687     for s in session.query(Suite).order_by(Suite.suite_name):
688         __version_check_list_suite(d, s.suite_name)
689
690 def __version_check_list_suite(d, suite_name):
691     vcs = get_version_checks(suite_name)
692     for vc in vcs:
693         print "%s %s %s" % (suite_name, vc.check, vc.reference.suite_name)
694
695 def __version_check_add(d, suite_name, check, reference_name):
696     suite = get_suite(suite_name)
697     if not suite:
698         die("E: Could not find suite %s." % (suite_name))
699     reference = get_suite(reference_name)
700     if not reference:
701         die("E: Could not find reference suite %s." % (reference_name))
702
703     session = d.session()
704     vc = VersionCheck()
705     vc.suite = suite
706     vc.check = check
707     vc.reference = reference
708     session.add(vc)
709     session.commit()
710
711 def __version_check_rm(d, suite_name, check, reference_name):
712     suite = get_suite(suite_name)
713     if not suite:
714         die("E: Could not find suite %s." % (suite_name))
715     reference = get_suite(reference_name)
716     if not reference:
717         die("E: Could not find reference suite %s." % (reference_name))
718
719     session = d.session()
720     try:
721       vc = session.query(VersionCheck).filter_by(suite=suite, check=check, reference=reference).one()
722       session.delete(vc)
723       session.commit()
724     except NoResultFound:
725       print "W: version-check not found."
726
727 def version_check(command):
728     args = [str(x) for x in command]
729     Cnf = utils.get_conf()
730     d = DBConn()
731
732     die_arglen(args, 2, "E: version-check needs at least a command")
733     mode = args[1].lower()
734
735     if mode == 'list':
736         __version_check_list(d)
737     elif mode == 'list-suite':
738         if len(args) != 3:
739             die("E: version-check list-suite needs a single parameter")
740         __version_check_list_suite(d, args[2])
741     elif mode == 'add':
742         if len(args) != 5:
743             die("E: version-check add needs three parameters")
744         __version_check_add(d, args[2], args[3], args[4])
745     elif mode == 'rm':
746         if len(args) != 5:
747             die("E: version-check rm needs three parameters")
748         __version_check_rm(d, args[2], args[3], args[4])
749     else:
750         die("E: version-check command unknown")
751
752 dispatch['version-check'] = version_check
753 dispatch['v-c'] = version_check
754
755 ################################################################################
756
757 def show_config(command):
758     args = [str(x) for x in command]
759     cnf = utils.get_conf()
760
761     die_arglen(args, 2, "E: config needs at least a command")
762
763     mode = args[1].lower()
764
765     if mode == 'db':
766         connstr = ""
767         if cnf.has_key("DB::Service"):
768             # Service mode
769             connstr = "postgresql://service=%s" % cnf["DB::Service"]
770         elif cnf.has_key("DB::Host"):
771             # TCP/IP
772             connstr = "postgres://%s" % cnf["DB::Host"]
773             if cnf.has_key("DB::Port") and cnf["DB::Port"] != "-1":
774                 connstr += ":%s" % cnf["DB::Port"]
775             connstr += "/%s" % cnf["DB::Name"]
776         else:
777             # Unix Socket
778             connstr = "postgres:///%s" % cnf["DB::Name"]
779             if cnf["DB::Port"] and cnf["DB::Port"] != "-1":
780                 connstr += "?port=%s" % cnf["DB::Port"]
781         print connstr
782     elif mode == 'db-shell':
783         e = []
784         if cnf.has_key("DB::Service"):
785             e.append('PGSERVICE')
786             print "PGSERVICE=%s" % cnf["DB::Service"]
787         if cnf.has_key("DB::Name"):
788             e.append('PGDATABASE')
789             print "PGDATABASE=%s" % cnf["DB::Name"]
790         if cnf.has_key("DB::Host"):
791             print "PGHOST=%s" % cnf["DB::Host"]
792             e.append('PGHOST')
793         if cnf.has_key("DB::Port") and cnf["DB::Port"] != "-1":
794             print "PGPORT=%s" % cnf["DB::Port"]
795             e.append('PGPORT')
796         print "export " + " ".join(e)
797     elif mode == 'get':
798         print cnf.get(args[2])
799     else:
800         session = DBConn().session()
801         try:
802             o = session.query(DBConfig).filter_by(name = mode).one()
803             print o.value
804         except NoResultFound:
805             print "W: option '%s' not set" % mode
806
807 dispatch['config'] = show_config
808 dispatch['c'] = show_config
809
810 ################################################################################
811
812 def show_keyring(command):
813     args = [str(x) for x in command]
814     cnf = utils.get_conf()
815
816     die_arglen(args, 2, "E: keyring needs at least a command")
817
818     mode = args[1].lower()
819
820     d = DBConn()
821
822     q = d.session().query(Keyring).filter(Keyring.active == True)
823
824     if mode == 'list-all':
825         pass
826     elif mode == 'list-binary':
827         q = q.join(Keyring.acl).filter(ACL.allow_source == False)
828     elif mode == 'list-source':
829         q = q.join(Keyring.acl).filter(ACL.allow_source == True)
830     else:
831         die("E: keyring command unknown")
832
833     for k in q.all():
834         print k.keyring_name
835
836 def keyring_add_buildd(command):
837     name = command[2]
838     arch_names = command[3:]
839
840     session = DBConn().session()
841     arches = session.query(Architecture).filter(Architecture.arch_string.in_(arch_names))
842
843     acl = ACL()
844     acl.name = 'buildd-{0}'.format('+'.join(arch_names))
845     acl.architectures.update(arches)
846     acl.allow_new = True
847     acl.allow_binary = True
848     acl.allow_binary_only = True
849     acl.allow_hijack = True
850     session.add(acl)
851
852     k = Keyring()
853     k.keyring_name = name
854     k.acl = acl
855     k.priority = 10
856     session.add(k)
857
858     session.commit()
859
860 def keyring(command):
861     if command[1].startswith('list-'):
862         show_keyring(command)
863     elif command[1] == 'add-buildd':
864         keyring_add_buildd(command)
865     else:
866         die("E: keyring command unknown")
867
868 dispatch['keyring'] = keyring
869 dispatch['k'] = keyring
870
871 ################################################################################
872
873 def main():
874     """Perform administrative work on the dak database"""
875     global dryrun
876     Cnf = utils.get_conf()
877     arguments = [('h', "help", "Admin::Options::Help"),
878                  ('n', "dry-run", "Admin::Options::Dry-Run")]
879     for i in [ "help", "dry-run" ]:
880         if not Cnf.has_key("Admin::Options::%s" % (i)):
881             Cnf["Admin::Options::%s" % (i)] = ""
882
883     arguments = apt_pkg.parse_commandline(Cnf, arguments, sys.argv)
884
885     options = Cnf.subtree("Admin::Options")
886     if options["Help"] or len(arguments) < 1:
887         usage()
888     if options["Dry-Run"]:
889         dryrun = True
890
891     subcommand = str(arguments[0])
892
893     if subcommand in dispatch.keys():
894         dispatch[subcommand](arguments)
895     else:
896         die("E: Unknown command")
897
898 ################################################################################
899
900 if __name__ == '__main__':
901     main()