]> git.decadent.org.uk Git - dak.git/blob - dak/admin.py
Adjust to deal with the new Debian supplementaryGid
[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     s.archive = build_queue_archive
424     s.architectures.extend(suite.architectures)
425     s.components.extend(suite.components)
426     s.srcformats.extend(suite.srcformats)
427
428     session.add(s)
429     session.flush()
430
431     bq = BuildQueue()
432     bq.queue_name = build_queue_codename
433     bq.suite = s
434
435     session.add(bq)
436     session.flush()
437
438     suite.copy_queues.append(bq)
439
440     session.commit()
441
442 def suite(command):
443     args = [str(x) for x in command]
444     Cnf = utils.get_conf()
445     d = DBConn()
446
447     die_arglen(args, 2, "E: suite needs at least a command")
448
449     mode = args[1].lower()
450
451     if mode == 'list':
452         __suite_list(d, args)
453     elif mode == 'show':
454         __suite_show(d, args)
455     elif mode == 'rm':
456         __suite_rm(d, args)
457     elif mode == 'add':
458         __suite_add(d, args, False)
459     elif mode == 'add-all-arches':
460         __suite_add(d, args, True)
461     elif mode == 'add-build-queue':
462         __suite_add_build_queue(d, args)
463     else:
464         die("E: suite command unknown")
465
466 dispatch['suite'] = suite
467 dispatch['s'] = suite
468
469 ################################################################################
470
471 def __suite_architecture_list(d, args):
472     s = d.session()
473     for j in s.query(Suite).order_by(Suite.suite_name):
474         architectures = j.get_architectures(skipsrc = True, skipall = True)
475         print j.suite_name + ': ' + \
476               ', '.join([a.arch_string for a in architectures])
477
478 def __suite_architecture_listarch(d, args):
479     die_arglen(args, 3, "E: suite-architecture list-arch requires a suite")
480     suite = get_suite(args[2].lower(), d.session())
481     if suite is None:
482         die('E: suite %s is invalid' % args[2].lower())
483     a = suite.get_architectures(skipsrc = True, skipall = True)
484     for j in a:
485         print j.arch_string
486
487
488 def __suite_architecture_listsuite(d, args):
489     die_arglen(args, 3, "E: suite-architecture list-suite requires an arch")
490     architecture = get_architecture(args[2].lower(), d.session())
491     if architecture is None:
492         die("E: architecture %s is invalid" % args[2].lower())
493     for j in architecture.suites:
494         print j.suite_name
495
496
497 def __suite_architecture_add(d, args):
498     if len(args) < 3:
499         die("E: adding a suite-architecture entry requires a suite and arch")
500
501     s = d.session()
502
503     suite = get_suite(args[2].lower(), s)
504     if suite is None: die("E: Can't find suite %s" % args[2].lower())
505
506     for arch_name in args[3:]:
507         arch = get_architecture(arch_name.lower(), s)
508         if arch is None: die("E: Can't find architecture %s" % args[3].lower())
509
510         try:
511             suite.architectures.append(arch)
512             s.flush()
513         except IntegrityError as e:
514             die("E: Can't add suite-architecture entry (%s, %s) - probably already exists" % (args[2].lower(), arch_name))
515         except SQLAlchemyError as e:
516             die("E: Can't add suite-architecture entry (%s, %s) - %s" % (args[2].lower(), arch_name, e))
517
518         print "Added suite-architecture entry for %s, %s" % (args[2].lower(), arch_name)
519
520     if not dryrun:
521         s.commit()
522
523     s.close()
524
525 def __suite_architecture_rm(d, args):
526     if len(args) < 3:
527         die("E: removing an suite-architecture entry requires a suite and arch")
528
529     s = d.session()
530     if not dryrun:
531         try:
532             suite_name = args[2].lower()
533             suite = get_suite(suite_name, s)
534             if suite is None:
535                 die('E: no such suite %s' % suite_name)
536             arch_string = args[3].lower()
537             architecture = get_architecture(arch_string, s)
538             if architecture not in suite.architectures:
539                 die("E: architecture %s not found in suite %s" % (arch_string, suite_name))
540             suite.architectures.remove(architecture)
541             s.commit()
542         except IntegrityError as e:
543             die("E: Can't remove suite-architecture entry (%s, %s) - it's probably referenced" % (args[2].lower(), args[3].lower()))
544         except SQLAlchemyError as e:
545             die("E: Can't remove suite-architecture entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
546
547     print "Removed suite-architecture entry for %s, %s" % (args[2].lower(), args[3].lower())
548
549
550 def suite_architecture(command):
551     args = [str(x) for x in command]
552     Cnf = utils.get_conf()
553     d = DBConn()
554
555     die_arglen(args, 2, "E: suite-architecture needs at least a command")
556
557     mode = args[1].lower()
558
559     if mode == 'list':
560         __suite_architecture_list(d, args)
561     elif mode == 'list-arch':
562         __suite_architecture_listarch(d, args)
563     elif mode == 'list-suite':
564         __suite_architecture_listsuite(d, args)
565     elif mode == 'add':
566         __suite_architecture_add(d, args)
567     elif mode == 'rm':
568         __suite_architecture_rm(d, args)
569     else:
570         die("E: suite-architecture command unknown")
571
572 dispatch['suite-architecture'] = suite_architecture
573 dispatch['s-a'] = suite_architecture
574
575 ################################################################################
576
577 def __suite_component_list(d, args):
578     s = d.session()
579     for j in s.query(Suite).order_by(Suite.suite_name):
580         components = j.components
581         print j.suite_name + ': ' + \
582               ', '.join([c.component_name for c in components])
583
584
585 def __suite_component_listcomponent(d, args):
586      die_arglen(args, 3, "E: suite-component list-component requires a suite")
587      suite = get_suite(args[2].lower(), d.session())
588      if suite is None:
589          die('E: suite %s is invalid' % args[2].lower())
590      for c in suite.components:
591          print c.component_name
592
593
594 def __suite_component_listsuite(d, args):
595      die_arglen(args, 3, "E: suite-component list-suite requires an component")
596      component = get_component(args[2].lower(), d.session())
597      if component is None:
598          die("E: component %s is invalid" % args[2].lower())
599      for s in component.suites:
600          print s.suite_name
601
602
603 def __suite_component_add(d, args):
604      if len(args) < 3:
605          die("E: adding a suite-component entry requires a suite and component")
606
607      s = d.session()
608
609      suite = get_suite(args[2].lower(), s)
610      if suite is None: die("E: Can't find suite %s" % args[2].lower())
611
612      for component_name in args[3:]:
613          component = get_component(component_name.lower(), s)
614          if component is None: die("E: Can't find component %s" % args[3].lower())
615
616          try:
617              suite.components.append(component)
618              s.flush()
619          except IntegrityError as e:
620              die("E: Can't add suite-component entry (%s, %s) - probably already exists" % (args[2].lower(), component_name))
621          except SQLAlchemyError as e:
622              die("E: Can't add suite-component entry (%s, %s) - %s" % (args[2].lower(), component_name, e))
623
624          print "Added suite-component entry for %s, %s" % (args[2].lower(), component_name)
625
626      if not dryrun:
627          s.commit()
628      s.close()
629
630 def __suite_component_rm(d, args):
631      if len(args) < 3:
632          die("E: removing an suite-component entry requires a suite and component")
633
634      s = d.session()
635      if not dryrun:
636          try:
637              suite_name = args[2].lower()
638              suite = get_suite(suite_name, s)
639              if suite is None:
640                  die('E: no such suite %s' % suite_name)
641              component_string = args[3].lower()
642              component = get_component(arch_string, s)
643              if component not in suite.components:
644                  die("E: component %s not found in suite %s" % (component_string, suite_name))
645              suite.components.remove(component)
646              s.commit()
647          except IntegrityError as e:
648              die("E: Can't remove suite-component entry (%s, %s) - it's probably referenced" % (args[2].lower(), args[3].lower()))
649          except SQLAlchemyError as e:
650              die("E: Can't remove suite-component entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
651
652      print "Removed suite-component entry for %s, %s" % (args[2].lower(), args[3].lower())
653
654
655 def suite_component(command):
656     args = [str(x) for x in command]
657     Cnf = utils.get_conf()
658     d = DBConn()
659
660     die_arglen(args, 2, "E: suite-component needs at least a command")
661
662     mode = args[1].lower()
663
664     if mode == 'list':
665         __suite_component_list(d, args)
666     elif mode == 'list-component':
667         __suite_component_listcomponent(d, args)
668     elif mode == 'list-suite':
669         __suite_component_listsuite(d, args)
670     elif mode == 'add':
671         __suite_component_add(d, args)
672     # elif mode == 'rm':
673     #     __suite_architecture_rm(d, args)
674     else:
675         die("E: suite-component command unknown")
676
677 dispatch['suite-component'] = suite_component
678 dispatch['s-c'] = suite_component
679
680 ################################################################################
681
682 def archive_list():
683     session = DBConn().session()
684     for archive in session.query(Archive).order_by(Archive.archive_name):
685         print "{0} path={1} description={2} tainted={3}".format(archive.archive_name, archive.path, archive.description, archive.tainted)
686
687 def archive_add(args):
688     (name, path, description) = args[0:3]
689
690     attributes = dict(
691         archive_name=name,
692         path=path,
693         description=description,
694         )
695
696     for option in args[3:]:
697         (key, value) = option.split('=')
698         attributes[key] = value
699
700     session = DBConn().session()
701
702     archive = Archive()
703     for key, value in attributes.iteritems():
704         setattr(archive, key, value)
705
706     session.add(archive)
707     session.flush()
708
709     if dryrun:
710         session.rollback()
711     else:
712         session.commit()
713
714 def archive_rm(name):
715     session = DBConn().session()
716     archive = get_archive(name, session)
717     session.delete(archive)
718     session.flush()
719
720     if dryrun:
721         session.rollback()
722     else:
723         session.commit()
724
725 def archive_rename(oldname, newname):
726     session = DBConn().session()
727     archive = get_archive(oldname, session)
728     archive.archive_name = newname
729     session.flush()
730
731     if dryrun:
732         session.rollback()
733     else:
734         session.commit()
735
736 def archive(command):
737     mode = command[1]
738     if mode == 'list':
739         archive_list()
740     elif mode == 'rename':
741         archive_rename(command[2], command[3])
742     elif mode == 'add':
743         archive_add(command[2:])
744     elif mode == 'rm':
745         archive_rm(command[2])
746     else:
747         die("E: archive command unknown")
748
749 dispatch['archive'] = archive
750
751 ################################################################################
752
753 def __version_check_list(d):
754     session = d.session()
755     for s in session.query(Suite).order_by(Suite.suite_name):
756         __version_check_list_suite(d, s.suite_name)
757
758 def __version_check_list_suite(d, suite_name):
759     vcs = get_version_checks(suite_name)
760     for vc in vcs:
761         print "%s %s %s" % (suite_name, vc.check, vc.reference.suite_name)
762
763 def __version_check_add(d, suite_name, check, reference_name):
764     suite = get_suite(suite_name)
765     if not suite:
766         die("E: Could not find suite %s." % (suite_name))
767     reference = get_suite(reference_name)
768     if not reference:
769         die("E: Could not find reference suite %s." % (reference_name))
770
771     session = d.session()
772     vc = VersionCheck()
773     vc.suite = suite
774     vc.check = check
775     vc.reference = reference
776     session.add(vc)
777     session.commit()
778
779 def __version_check_rm(d, suite_name, check, reference_name):
780     suite = get_suite(suite_name)
781     if not suite:
782         die("E: Could not find suite %s." % (suite_name))
783     reference = get_suite(reference_name)
784     if not reference:
785         die("E: Could not find reference suite %s." % (reference_name))
786
787     session = d.session()
788     try:
789       vc = session.query(VersionCheck).filter_by(suite=suite, check=check, reference=reference).one()
790       session.delete(vc)
791       session.commit()
792     except NoResultFound:
793       print "W: version-check not found."
794
795 def version_check(command):
796     args = [str(x) for x in command]
797     Cnf = utils.get_conf()
798     d = DBConn()
799
800     die_arglen(args, 2, "E: version-check needs at least a command")
801     mode = args[1].lower()
802
803     if mode == 'list':
804         __version_check_list(d)
805     elif mode == 'list-suite':
806         if len(args) != 3:
807             die("E: version-check list-suite needs a single parameter")
808         __version_check_list_suite(d, args[2])
809     elif mode == 'add':
810         if len(args) != 5:
811             die("E: version-check add needs three parameters")
812         __version_check_add(d, args[2], args[3], args[4])
813     elif mode == 'rm':
814         if len(args) != 5:
815             die("E: version-check rm needs three parameters")
816         __version_check_rm(d, args[2], args[3], args[4])
817     else:
818         die("E: version-check command unknown")
819
820 dispatch['version-check'] = version_check
821 dispatch['v-c'] = version_check
822
823 ################################################################################
824
825 def show_config(command):
826     args = [str(x) for x in command]
827     cnf = utils.get_conf()
828
829     die_arglen(args, 2, "E: config needs at least a command")
830
831     mode = args[1].lower()
832
833     if mode == 'db':
834         connstr = ""
835         if cnf.has_key("DB::Service"):
836             # Service mode
837             connstr = "postgresql://service=%s" % cnf["DB::Service"]
838         elif cnf.has_key("DB::Host"):
839             # TCP/IP
840             connstr = "postgres://%s" % cnf["DB::Host"]
841             if cnf.has_key("DB::Port") and cnf["DB::Port"] != "-1":
842                 connstr += ":%s" % cnf["DB::Port"]
843             connstr += "/%s" % cnf["DB::Name"]
844         else:
845             # Unix Socket
846             connstr = "postgres:///%s" % cnf["DB::Name"]
847             if cnf["DB::Port"] and cnf["DB::Port"] != "-1":
848                 connstr += "?port=%s" % cnf["DB::Port"]
849         print connstr
850     elif mode == 'db-shell':
851         e = []
852         if cnf.has_key("DB::Service"):
853             e.append('PGSERVICE')
854             print "PGSERVICE=%s" % cnf["DB::Service"]
855         if cnf.has_key("DB::Name"):
856             e.append('PGDATABASE')
857             print "PGDATABASE=%s" % cnf["DB::Name"]
858         if cnf.has_key("DB::Host"):
859             print "PGHOST=%s" % cnf["DB::Host"]
860             e.append('PGHOST')
861         if cnf.has_key("DB::Port") and cnf["DB::Port"] != "-1":
862             print "PGPORT=%s" % cnf["DB::Port"]
863             e.append('PGPORT')
864         print "export " + " ".join(e)
865     elif mode == 'get':
866         print cnf.get(args[2])
867     else:
868         session = DBConn().session()
869         try:
870             o = session.query(DBConfig).filter_by(name = mode).one()
871             print o.value
872         except NoResultFound:
873             print "W: option '%s' not set" % mode
874
875 dispatch['config'] = show_config
876 dispatch['c'] = show_config
877
878 ################################################################################
879
880 def show_keyring(command):
881     args = [str(x) for x in command]
882     cnf = utils.get_conf()
883
884     die_arglen(args, 2, "E: keyring needs at least a command")
885
886     mode = args[1].lower()
887
888     d = DBConn()
889
890     q = d.session().query(Keyring).filter(Keyring.active == True)
891
892     if mode == 'list-all':
893         pass
894     elif mode == 'list-binary':
895         q = q.join(Keyring.acl).filter(ACL.allow_source == False)
896     elif mode == 'list-source':
897         q = q.join(Keyring.acl).filter(ACL.allow_source == True)
898     else:
899         die("E: keyring command unknown")
900
901     for k in q.all():
902         print k.keyring_name
903
904 def keyring_add_buildd(command):
905     name = command[2]
906     arch_names = command[3:]
907
908     session = DBConn().session()
909     arches = session.query(Architecture).filter(Architecture.arch_string.in_(arch_names))
910
911     acl = ACL()
912     acl.name = 'buildd-{0}'.format('+'.join(arch_names))
913     acl.architectures.update(arches)
914     acl.allow_new = True
915     acl.allow_binary = True
916     acl.allow_binary_only = True
917     acl.allow_hijack = True
918     session.add(acl)
919
920     k = Keyring()
921     k.keyring_name = name
922     k.acl = acl
923     k.priority = 10
924     session.add(k)
925
926     session.commit()
927
928 def keyring(command):
929     if command[1].startswith('list-'):
930         show_keyring(command)
931     elif command[1] == 'add-buildd':
932         keyring_add_buildd(command)
933     else:
934         die("E: keyring command unknown")
935
936 dispatch['keyring'] = keyring
937 dispatch['k'] = keyring
938
939 ################################################################################
940
941 def change_component_source(transaction, suite, component, source_names):
942     session = transaction.session
943
944     overrides = session.query(Override).filter(Override.package.in_(source_names)).filter_by(suite=suite).join(OverrideType).filter_by(overridetype='dsc')
945     for override in overrides:
946         print "Changing override for {0}".format(override.package)
947         override.component = component
948     session.flush()
949
950     sources = session.query(DBSource).filter(DBSource.source.in_(source_names)).filter(DBSource.suites.contains(suite))
951     for source in sources:
952         print "Copying {0}={1}".format(source.source, source.version)
953         transaction.copy_source(source, suite, component)
954
955 def change_component_binary(transaction, suite, component, binary_names):
956     session = transaction.session
957
958     overrides = session.query(Override).filter(Override.package.in_(binary_names)).filter_by(suite=suite).join(OverrideType).filter(OverrideType.overridetype.in_(['deb', 'udeb']))
959     for override in overrides:
960         print "Changing override for {0}".format(override.package)
961         override.component = component
962     session.flush()
963
964     binaries = session.query(DBBinary).filter(DBBinary.package.in_(binary_names)).filter(DBBinary.suites.contains(suite))
965     for binary in binaries:
966         print "Copying {0}={1} [{2}]".format(binary.package, binary.version, binary.architecture.arch_string)
967         transaction.copy_binary(binary, suite, component)
968     pass
969
970 def change_component(args):
971     with daklib.archive.ArchiveTransaction() as transaction:
972         session = transaction.session
973
974         suite = session.query(Suite).filter_by(suite_name=args[1]).one()
975         component = session.query(Component).filter_by(component_name=args[2]).one()
976
977         if args[3] == 'source':
978             change_component_source(transaction, suite, component, args[4:])
979         elif args[3] == 'binary':
980             change_component_binary(transaction, suite, component, args[4:])
981         else:
982             raise Exception("Can only move source or binary, not {0}".format(args[3]))
983
984         transaction.commit()
985
986 dispatch['change-component'] = change_component
987
988 ################################################################################
989
990 def forget_signature(args):
991     filename = args[1]
992     with open(filename, 'r') as fh:
993         data = fh.read()
994
995     session = DBConn().session()
996     keyrings = [ k.keyring_name for k in session.query(Keyring).filter_by(active=True).order_by(Keyring.priority) ]
997     signed_file = daklib.gpg.SignedFile(data, keyrings)
998     history = SignatureHistory.from_signed_file(signed_file).query(session)
999     if history is not None:
1000         session.delete(history)
1001         session.commit()
1002     else:
1003         print "Signature was not known to dak."
1004     session.rollback()
1005
1006 dispatch['forget-signature'] = forget_signature
1007
1008 ################################################################################
1009
1010 def main():
1011     """Perform administrative work on the dak database"""
1012     global dryrun
1013     Cnf = utils.get_conf()
1014     arguments = [('h', "help", "Admin::Options::Help"),
1015                  ('n', "dry-run", "Admin::Options::Dry-Run")]
1016     for i in [ "help", "dry-run" ]:
1017         if not Cnf.has_key("Admin::Options::%s" % (i)):
1018             Cnf["Admin::Options::%s" % (i)] = ""
1019
1020     arguments = apt_pkg.parse_commandline(Cnf, arguments, sys.argv)
1021
1022     options = Cnf.subtree("Admin::Options")
1023     if options["Help"] or len(arguments) < 1:
1024         usage()
1025     if options["Dry-Run"]:
1026         dryrun = True
1027
1028     subcommand = str(arguments[0])
1029
1030     if subcommand in dispatch.keys():
1031         dispatch[subcommand](arguments)
1032     else:
1033         die("E: Unknown command")
1034
1035 ################################################################################
1036
1037 if __name__ == '__main__':
1038     main()