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