]> git.decadent.org.uk Git - dak.git/blob - dak/admin.py
dak/admin.py: Add commands to manipulate the suite-component mapping
[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     arch = get_architecture(args[3].lower(), s)
439     if arch is None: die("E: Can't find architecture %s" % args[3].lower())
440
441     if not dryrun:
442         try:
443             suite.architectures.append(arch)
444             s.commit()
445         except IntegrityError as e:
446             die("E: Can't add suite-architecture entry (%s, %s) - probably already exists" % (args[2].lower(), args[3].lower()))
447         except SQLAlchemyError as e:
448             die("E: Can't add suite-architecture entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
449
450     print "Added suite-architecture entry for %s, %s" % (args[2].lower(), args[3].lower())
451
452
453 def __suite_architecture_rm(d, args):
454     if len(args) < 3:
455         die("E: removing an suite-architecture entry requires a suite and arch")
456
457     s = d.session()
458     if not dryrun:
459         try:
460             suite_name = args[2].lower()
461             suite = get_suite(suite_name, s)
462             if suite is None:
463                 die('E: no such suite %s' % suite_name)
464             arch_string = args[3].lower()
465             architecture = get_architecture(arch_string, s)
466             if architecture not in suite.architectures:
467                 die("E: architecture %s not found in suite %s" % (arch_string, suite_name))
468             suite.architectures.remove(architecture)
469             s.commit()
470         except IntegrityError as e:
471             die("E: Can't remove suite-architecture entry (%s, %s) - it's probably referenced" % (args[2].lower(), args[3].lower()))
472         except SQLAlchemyError as e:
473             die("E: Can't remove suite-architecture entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
474
475     print "Removed suite-architecture entry for %s, %s" % (args[2].lower(), args[3].lower())
476
477
478 def suite_architecture(command):
479     args = [str(x) for x in command]
480     Cnf = utils.get_conf()
481     d = DBConn()
482
483     die_arglen(args, 2, "E: suite-architecture needs at least a command")
484
485     mode = args[1].lower()
486
487     if mode == 'list':
488         __suite_architecture_list(d, args)
489     elif mode == 'list-arch':
490         __suite_architecture_listarch(d, args)
491     elif mode == 'list-suite':
492         __suite_architecture_listsuite(d, args)
493     elif mode == 'add':
494         __suite_architecture_add(d, args)
495     elif mode == 'rm':
496         __suite_architecture_rm(d, args)
497     else:
498         die("E: suite-architecture command unknown")
499
500 dispatch['suite-architecture'] = suite_architecture
501 dispatch['s-a'] = suite_architecture
502
503 ################################################################################
504
505 def __suite_component_list(d, args):
506     s = d.session()
507     for j in s.query(Suite).order_by(Suite.suite_name):
508         components = j.components
509         print j.suite_name + ': ' + \
510               ', '.join([c.component_name for c in components])
511
512
513 def __suite_component_listcomponent(d, args):
514      die_arglen(args, 3, "E: suite-component list-component requires a suite")
515      suite = get_suite(args[2].lower(), d.session())
516      if suite is None:
517          die('E: suite %s is invalid' % args[2].lower())
518      for c in suite.components:
519          print c.component_name
520
521
522 def __suite_component_listsuite(d, args):
523      die_arglen(args, 3, "E: suite-component list-suite requires an component")
524      component = get_component(args[2].lower(), d.session())
525      if component is None:
526          die("E: component %s is invalid" % args[2].lower())
527      for s in component.suites:
528          print s.suite_name
529
530
531 def __suite_component_add(d, args):
532      if len(args) < 3:
533          die("E: adding a suite-component entry requires a suite and component")
534
535      s = d.session()
536
537      suite = get_suite(args[2].lower(), s)
538      if suite is None: die("E: Can't find suite %s" % args[2].lower())
539
540      component = get_component(args[3].lower(), s)
541      if component is None: die("E: Can't find component %s" % args[3].lower())
542
543      if not dryrun:
544          try:
545              suite.components.append(component)
546              s.commit()
547          except IntegrityError as e:
548              die("E: Can't add suite-component entry (%s, %s) - probably already exists" % (args[2].lower(), args[3].lower()))
549          except SQLAlchemyError as e:
550              die("E: Can't add suite-component entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
551
552      print "Added suite-component entry for %s, %s" % (args[2].lower(), args[3].lower())
553
554
555 def __suite_component_rm(d, args):
556      if len(args) < 3:
557          die("E: removing an suite-component entry requires a suite and component")
558
559      s = d.session()
560      if not dryrun:
561          try:
562              suite_name = args[2].lower()
563              suite = get_suite(suite_name, s)
564              if suite is None:
565                  die('E: no such suite %s' % suite_name)
566              component_string = args[3].lower()
567              component = get_component(arch_string, s)
568              if component not in suite.components:
569                  die("E: component %s not found in suite %s" % (component_string, suite_name))
570              suite.components.remove(component)
571              s.commit()
572          except IntegrityError as e:
573              die("E: Can't remove suite-component entry (%s, %s) - it's probably referenced" % (args[2].lower(), args[3].lower()))
574          except SQLAlchemyError as e:
575              die("E: Can't remove suite-component entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
576
577      print "Removed suite-component entry for %s, %s" % (args[2].lower(), args[3].lower())
578
579
580 def suite_component(command):
581     args = [str(x) for x in command]
582     Cnf = utils.get_conf()
583     d = DBConn()
584
585     die_arglen(args, 2, "E: suite-component needs at least a command")
586
587     mode = args[1].lower()
588
589     if mode == 'list':
590         __suite_component_list(d, args)
591     elif mode == 'list-component':
592         __suite_component_listcomponent(d, args)
593     elif mode == 'list-suite':
594         __suite_component_listsuite(d, args)
595     elif mode == 'add':
596         __suite_component_add(d, args)
597     # elif mode == 'rm':
598     #     __suite_architecture_rm(d, args)
599     else:
600         die("E: suite-component command unknown")
601
602 dispatch['suite-component'] = suite_component
603 dispatch['s-c'] = suite_component
604
605 ################################################################################
606
607 def archive_list():
608     session = DBConn().session()
609     for archive in session.query(Archive).order_by(Archive.archive_name):
610         print "{0} path={1} description={2} tainted={3}".format(archive.archive_name, archive.path, archive.description, archive.tainted)
611
612 def archive_add(args):
613     (name, path, description) = args[0:3]
614
615     attributes = dict(
616         archive_name=name,
617         path=path,
618         description=description,
619         )
620
621     for option in args[3:]:
622         (key, value) = option.split('=')
623         attributes[key] = value
624
625     session = DBConn().session()
626
627     archive = Archive()
628     for key, value in attributes.iteritems():
629         setattr(archive, key, value)
630
631     session.add(archive)
632     session.flush()
633
634     if dryrun:
635         session.rollback()
636     else:
637         session.commit()
638
639 def archive_rm(name):
640     session = DBConn().session()
641     archive = get_archive(name, session)
642     session.delete(archive)
643     session.flush()
644
645     if dryrun:
646         session.rollback()
647     else:
648         session.commit()
649
650 def archive_rename(oldname, newname):
651     session = DBConn().session()
652     archive = get_archive(oldname, session)
653     archive.archive_name = newname
654     session.flush()
655
656     if dryrun:
657         session.rollback()
658     else:
659         session.commit()
660
661 def archive(command):
662     mode = command[1]
663     if mode == 'list':
664         archive_list()
665     elif mode == 'rename':
666         archive_rename(command[2], command[3])
667     elif mode == 'add':
668         archive_add(command[2:])
669     elif mode == 'rm':
670         archive_rm(command[2])
671     else:
672         die("E: archive command unknown")
673
674 dispatch['archive'] = archive
675
676 ################################################################################
677
678 def __version_check_list(d):
679     session = d.session()
680     for s in session.query(Suite).order_by(Suite.suite_name):
681         __version_check_list_suite(d, s.suite_name)
682
683 def __version_check_list_suite(d, suite_name):
684     vcs = get_version_checks(suite_name)
685     for vc in vcs:
686         print "%s %s %s" % (suite_name, vc.check, vc.reference.suite_name)
687
688 def __version_check_add(d, suite_name, check, reference_name):
689     suite = get_suite(suite_name)
690     if not suite:
691         die("E: Could not find suite %s." % (suite_name))
692     reference = get_suite(reference_name)
693     if not reference:
694         die("E: Could not find reference suite %s." % (reference_name))
695
696     session = d.session()
697     vc = VersionCheck()
698     vc.suite = suite
699     vc.check = check
700     vc.reference = reference
701     session.add(vc)
702     session.commit()
703
704 def __version_check_rm(d, suite_name, check, reference_name):
705     suite = get_suite(suite_name)
706     if not suite:
707         die("E: Could not find suite %s." % (suite_name))
708     reference = get_suite(reference_name)
709     if not reference:
710         die("E: Could not find reference suite %s." % (reference_name))
711
712     session = d.session()
713     try:
714       vc = session.query(VersionCheck).filter_by(suite=suite, check=check, reference=reference).one()
715       session.delete(vc)
716       session.commit()
717     except NoResultFound:
718       print "W: version-check not found."
719
720 def version_check(command):
721     args = [str(x) for x in command]
722     Cnf = utils.get_conf()
723     d = DBConn()
724
725     die_arglen(args, 2, "E: version-check needs at least a command")
726     mode = args[1].lower()
727
728     if mode == 'list':
729         __version_check_list(d)
730     elif mode == 'list-suite':
731         if len(args) != 3:
732             die("E: version-check list-suite needs a single parameter")
733         __version_check_list_suite(d, args[2])
734     elif mode == 'add':
735         if len(args) != 5:
736             die("E: version-check add needs three parameters")
737         __version_check_add(d, args[2], args[3], args[4])
738     elif mode == 'rm':
739         if len(args) != 5:
740             die("E: version-check rm needs three parameters")
741         __version_check_rm(d, args[2], args[3], args[4])
742     else:
743         die("E: version-check command unknown")
744
745 dispatch['version-check'] = version_check
746 dispatch['v-c'] = version_check
747
748 ################################################################################
749
750 def show_config(command):
751     args = [str(x) for x in command]
752     cnf = utils.get_conf()
753
754     die_arglen(args, 2, "E: config needs at least a command")
755
756     mode = args[1].lower()
757
758     if mode == 'db':
759         connstr = ""
760         if cnf.has_key("DB::Service"):
761             # Service mode
762             connstr = "postgresql://service=%s" % cnf["DB::Service"]
763         elif cnf.has_key("DB::Host"):
764             # TCP/IP
765             connstr = "postgres://%s" % cnf["DB::Host"]
766             if cnf.has_key("DB::Port") and cnf["DB::Port"] != "-1":
767                 connstr += ":%s" % cnf["DB::Port"]
768             connstr += "/%s" % cnf["DB::Name"]
769         else:
770             # Unix Socket
771             connstr = "postgres:///%s" % cnf["DB::Name"]
772             if cnf["DB::Port"] and cnf["DB::Port"] != "-1":
773                 connstr += "?port=%s" % cnf["DB::Port"]
774         print connstr
775     elif mode == 'db-shell':
776         e = []
777         if cnf.has_key("DB::Service"):
778             e.append('PGSERVICE')
779             print "PGSERVICE=%s" % cnf["DB::Service"]
780         if cnf.has_key("DB::Name"):
781             e.append('PGDATABASE')
782             print "PGDATABASE=%s" % cnf["DB::Name"]
783         if cnf.has_key("DB::Host"):
784             print "PGHOST=%s" % cnf["DB::Host"]
785             e.append('PGHOST')
786         if cnf.has_key("DB::Port") and cnf["DB::Port"] != "-1":
787             print "PGPORT=%s" % cnf["DB::Port"]
788             e.append('PGPORT')
789         print "export " + " ".join(e)
790     elif mode == 'get':
791         print cnf.get(args[2])
792     else:
793         session = DBConn().session()
794         try:
795             o = session.query(DBConfig).filter_by(name = mode).one()
796             print o.value
797         except NoResultFound:
798             print "W: option '%s' not set" % mode
799
800 dispatch['config'] = show_config
801 dispatch['c'] = show_config
802
803 ################################################################################
804
805 def show_keyring(command):
806     args = [str(x) for x in command]
807     cnf = utils.get_conf()
808
809     die_arglen(args, 2, "E: keyring needs at least a command")
810
811     mode = args[1].lower()
812
813     d = DBConn()
814
815     q = d.session().query(Keyring).filter(Keyring.active == True)
816
817     if mode == 'list-all':
818         pass
819     elif mode == 'list-binary':
820         q = q.join(Keyring.acl).filter(ACL.allow_source == False)
821     elif mode == 'list-source':
822         q = q.join(Keyring.acl).filter(ACL.allow_source == True)
823     else:
824         die("E: keyring command unknown")
825
826     for k in q.all():
827         print k.keyring_name
828
829 def keyring_add_buildd(command):
830     name = command[2]
831     arch_names = command[3:]
832
833     session = DBConn().session()
834     arches = session.query(Architecture).filter(Architecture.arch_string.in_(arch_names))
835
836     acl = ACL()
837     acl.name = 'buildd-{0}'.format('+'.join(arch_names))
838     acl.architectures.update(arches)
839     acl.allow_new = True
840     acl.allow_binary = True
841     acl.allow_binary_only = True
842     acl.allow_hijack = True
843     session.add(acl)
844
845     k = Keyring()
846     k.keyring_name = name
847     k.acl = acl
848     k.priority = 10
849     session.add(k)
850
851     session.commit()
852
853 def keyring(command):
854     if command[1].startswith('list-'):
855         show_keyring(command)
856     elif command[1] == 'add-buildd':
857         keyring_add_buildd(command)
858     else:
859         die("E: keyring command unknown")
860
861 dispatch['keyring'] = keyring
862 dispatch['k'] = keyring
863
864 ################################################################################
865
866 def main():
867     """Perform administrative work on the dak database"""
868     global dryrun
869     Cnf = utils.get_conf()
870     arguments = [('h', "help", "Admin::Options::Help"),
871                  ('n', "dry-run", "Admin::Options::Dry-Run")]
872     for i in [ "help", "dry-run" ]:
873         if not Cnf.has_key("Admin::Options::%s" % (i)):
874             Cnf["Admin::Options::%s" % (i)] = ""
875
876     arguments = apt_pkg.parse_commandline(Cnf, arguments, sys.argv)
877
878     options = Cnf.subtree("Admin::Options")
879     if options["Help"] or len(arguments) < 1:
880         usage()
881     if options["Dry-Run"]:
882         dryrun = True
883
884     subcommand = str(arguments[0])
885
886     if subcommand in dispatch.keys():
887         dispatch[subcommand](arguments)
888     else:
889         die("E: Unknown command")
890
891 ################################################################################
892
893 if __name__ == '__main__':
894     main()