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