3 """Configure dak parameters in the database"""
4 # Copyright (C) 2009 Mark Hymers <mhy@debian.org>
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.
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.
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
20 ################################################################################
26 from daklib import utils
27 from daklib.dbconn import *
28 from sqlalchemy.orm.exc import NoResultFound
30 ################################################################################
35 ################################################################################
37 print >> sys.stderr, msg
39 def die(msg, exit_code=1):
40 print >> sys.stderr, msg
43 def die_arglen(args, args_needed, msg):
44 if len(args) < args_needed:
47 def usage(exit_code=0):
48 """Perform administrative work on the dak database."""
50 print """Usage: dak admin COMMAND
51 Perform administrative work on the dak database.
53 -h, --help show this help and exit.
54 -n, --dry-run don't do anything, just show what would have been done
55 (only applies to add or rm operations).
57 Commands can use a long or abbreviated form:
61 c db-shell show db config in a usable form for psql
62 c NAME show option NAME as set in configuration table
65 k list-all list all keyrings
66 k list-binary list all keyrings with a NULL source acl
67 k list-source list all keyrings with a non NULL source acl
70 a list show a list of architectures
71 a rm ARCH remove an architecture (will only work if
72 no longer linked to any suites)
73 a add ARCH DESCRIPTION [SUITELIST]
74 add architecture ARCH with DESCRIPTION.
75 If SUITELIST is given, add to each of the
76 suites at the same time
79 s list show a list of suites
80 s show SUITE show config details for a suite
81 s add SUITE VERSION [ label=LABEL ] [ description=DESCRIPTION ]
82 [ origin=ORIGIN ] [ codename=CODENAME ]
83 [ signingkey=SIGNINGKEY ]
84 add suite SUITE, version VERSION.
85 label, description, origin, codename
86 and signingkey are optional.
88 s add-all-arches SUITE VERSION... as "s add" but adds suite-architecture
89 relationships for all architectures
91 suite-architecture / s-a:
92 s-a list show the architectures for all suites
93 s-a list-suite ARCH show the suites an ARCH is in
94 s-a list-arch SUITE show the architectures in a SUITE
95 s-a add SUITE ARCH add ARCH to suite
96 s-a rm SUITE ARCH remove ARCH from suite (will only work if
97 no packages remain for the arch in the suite)
100 archive list list all archives
101 archive add NAME ROOT DESCRIPTION [primary-mirror=MIRROR] [tainted=1]
102 add archive NAME with path ROOT,
103 primary mirror MIRROR.
104 archive rm NAME remove archive NAME (will only work if there are
105 no files and no suites in the archive)
106 archive rename OLD NEW rename archive OLD to NEW
109 v-c list show version checks for all suites
110 v-c list-suite SUITE show version checks for suite SUITE
111 v-c add SUITE CHECK REFERENCE add a version check for suite SUITE
112 v-c rm SUITE CHECK REFERENCE remove a version check
114 CHECK is one of Enhances, MustBeNewerThan, MustBeOlderThan
115 REFERENCE is another suite name
119 ################################################################################
121 def __architecture_list(d, args):
122 q = d.session().query(Architecture).order_by(Architecture.arch_string)
124 # HACK: We should get rid of source from the arch table
125 if j.arch_string == 'source': continue
129 def __architecture_add(d, args):
130 die_arglen(args, 4, "E: adding an architecture requires a name and a description")
131 print "Adding architecture %s" % args[2]
132 suites = [str(x) for x in args[4:]]
134 print "Adding to suites %s" % ", ".join(suites)
139 a.arch_string = str(args[2]).lower()
140 a.description = str(args[3])
143 su = get_suite(sn, s)
147 warn("W: Cannot find suite %s" % su)
149 except IntegrityError as e:
150 die("E: Integrity error adding architecture %s (it probably already exists)" % args[2])
151 except SQLAlchemyError as e:
152 die("E: Error adding architecture %s (%s)" % (args[2], e))
153 print "Architecture %s added" % (args[2])
155 def __architecture_rm(d, args):
156 die_arglen(args, 3, "E: removing an architecture requires at least a name")
157 print "Removing architecture %s" % args[2]
161 a = get_architecture(args[2].lower(), s)
163 die("E: Cannot find architecture %s" % args[2])
166 except IntegrityError as e:
167 die("E: Integrity error removing architecture %s (suite-arch entries probably still exist)" % args[2])
168 except SQLAlchemyError as e:
169 die("E: Error removing architecture %s (%s)" % (args[2], e))
170 print "Architecture %s removed" % args[2]
172 def architecture(command):
173 args = [str(x) for x in command]
174 Cnf = utils.get_conf()
177 die_arglen(args, 2, "E: architecture needs at least a command")
179 mode = args[1].lower()
181 __architecture_list(d, args)
183 __architecture_add(d, args)
185 __architecture_rm(d, args)
187 die("E: architecture command unknown")
189 dispatch['architecture'] = architecture
190 dispatch['a'] = architecture
192 ################################################################################
194 def __suite_list(d, args):
196 for j in s.query(Suite).order_by(Suite.suite_name).all():
199 def __suite_show(d, args):
201 die("E: showing an suite entry requires a suite")
204 su = get_suite(args[2].lower())
206 die("E: can't find suite entry for %s" % (args[2].lower()))
210 def __suite_add(d, args, addallarches=False):
211 die_arglen(args, 4, "E: adding a suite requires at least a name and a version")
212 suite_name = args[2].lower()
216 def get_field(field):
218 if varval.startswith(field + '='):
219 return varval.split('=')[1]
222 print "Adding suite %s" % suite_name
227 suite.suite_name = suite_name
228 suite.overridecodename = suite_name
229 suite.version = version
230 suite.label = get_field('label')
231 suite.description = get_field('description')
232 suite.origin = get_field('origin')
233 suite.codename = get_field('codename')
234 signingkey = get_field('signingkey')
235 if signingkey is not None:
236 suite.signingkeys = [signingkey.upper()]
237 archive_name = get_field('archive')
238 if archive_name is not None:
239 suite.archive = get_archive(archive_name, s)
241 suite.archive = s.query(Archive).filter(~Archive.archive_name.in_(['build-queues', 'new', 'policy'])).one()
242 suite.srcformats = s.query(SrcFormat).all()
245 except IntegrityError as e:
246 die("E: Integrity error adding suite %s (it probably already exists)" % suite_name)
247 except SQLAlchemyError as e:
248 die("E: Error adding suite %s (%s)" % (suite_name, e))
249 print "Suite %s added" % (suite_name)
253 q = s.query(Architecture).order_by(Architecture.arch_string)
255 suite.architectures.append(arch)
256 arches.append(arch.arch_string)
258 print "Architectures %s added to %s" % (','.join(arches), suite_name)
264 args = [str(x) for x in command]
265 Cnf = utils.get_conf()
268 die_arglen(args, 2, "E: suite needs at least a command")
270 mode = args[1].lower()
273 __suite_list(d, args)
275 __suite_show(d, args)
277 __suite_add(d, args, False)
278 elif mode == 'add-all-arches':
279 __suite_add(d, args, True)
281 die("E: suite command unknown")
283 dispatch['suite'] = suite
284 dispatch['s'] = suite
286 ################################################################################
288 def __suite_architecture_list(d, args):
290 for j in s.query(Suite).order_by(Suite.suite_name):
291 architectures = j.get_architectures(skipsrc = True, skipall = True)
292 print j.suite_name + ': ' + \
293 ', '.join([a.arch_string for a in architectures])
295 def __suite_architecture_listarch(d, args):
296 die_arglen(args, 3, "E: suite-architecture list-arch requires a suite")
297 suite = get_suite(args[2].lower(), d.session())
299 die('E: suite %s is invalid' % args[2].lower())
300 a = suite.get_architectures(skipsrc = True, skipall = True)
305 def __suite_architecture_listsuite(d, args):
306 die_arglen(args, 3, "E: suite-architecture list-suite requires an arch")
307 architecture = get_architecture(args[2].lower(), d.session())
308 if architecture is None:
309 die("E: architecture %s is invalid" % args[2].lower())
310 for j in architecture.suites:
314 def __suite_architecture_add(d, args):
316 die("E: adding a suite-architecture entry requires a suite and arch")
320 suite = get_suite(args[2].lower(), s)
321 if suite is None: die("E: Can't find suite %s" % args[2].lower())
323 arch = get_architecture(args[3].lower(), s)
324 if arch is None: die("E: Can't find architecture %s" % args[3].lower())
328 suite.architectures.append(arch)
330 except IntegrityError as e:
331 die("E: Can't add suite-architecture entry (%s, %s) - probably already exists" % (args[2].lower(), args[3].lower()))
332 except SQLAlchemyError as e:
333 die("E: Can't add suite-architecture entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
335 print "Added suite-architecture entry for %s, %s" % (args[2].lower(), args[3].lower())
338 def __suite_architecture_rm(d, args):
340 die("E: removing an suite-architecture entry requires a suite and arch")
345 suite_name = args[2].lower()
346 suite = get_suite(suite_name, s)
348 die('E: no such suite %s' % suite_name)
349 arch_string = args[3].lower()
350 architecture = get_architecture(arch_string, s)
351 if architecture not in suite.architectures:
352 die("E: architecture %s not found in suite %s" % (arch_string, suite_name))
353 suite.architectures.remove(architecture)
355 except IntegrityError as e:
356 die("E: Can't remove suite-architecture entry (%s, %s) - it's probably referenced" % (args[2].lower(), args[3].lower()))
357 except SQLAlchemyError as e:
358 die("E: Can't remove suite-architecture entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
360 print "Removed suite-architecture entry for %s, %s" % (args[2].lower(), args[3].lower())
363 def suite_architecture(command):
364 args = [str(x) for x in command]
365 Cnf = utils.get_conf()
368 die_arglen(args, 2, "E: suite-architecture needs at least a command")
370 mode = args[1].lower()
373 __suite_architecture_list(d, args)
374 elif mode == 'list-arch':
375 __suite_architecture_listarch(d, args)
376 elif mode == 'list-suite':
377 __suite_architecture_listsuite(d, args)
379 __suite_architecture_add(d, args)
381 __suite_architecture_rm(d, args)
383 die("E: suite-architecture command unknown")
385 dispatch['suite-architecture'] = suite_architecture
386 dispatch['s-a'] = suite_architecture
388 ################################################################################
391 session = DBConn().session()
392 for archive in session.query(Archive).order_by(Archive.archive_name):
393 print "{0} path={1} description={2} tainted={3}".format(archive.archive_name, archive.path, archive.description, archive.tainted)
395 def archive_add(args):
396 (name, path, description) = args[0:3]
401 description=description,
404 for option in args[3:]:
405 (key, value) = option.split('=')
406 attributes[key] = value
408 session = DBConn().session()
411 for key, value in attributes.iteritems():
412 setattr(archive, key, value)
422 def archive_rm(name):
423 session = DBConn().session()
424 archive = session.query(Archive).filter_by(archive_name=name).one()
425 session.delete(archive)
433 def archive_rename(oldname, newname):
434 session = DBConn().session()
435 archive = get_archive(oldname, session)
436 archive.archive_name = newname
444 def archive(command):
448 elif mode == 'rename':
449 archive_rename(command[2], command[3])
451 archive_add(command[2:])
453 archive_rm(command[2])
455 die("E: archive command unknown")
457 dispatch['archive'] = archive
459 ################################################################################
461 def __version_check_list(d):
462 session = d.session()
463 for s in session.query(Suite).order_by(Suite.suite_name):
464 __version_check_list_suite(d, s.suite_name)
466 def __version_check_list_suite(d, suite_name):
467 vcs = get_version_checks(suite_name)
469 print "%s %s %s" % (suite_name, vc.check, vc.reference.suite_name)
471 def __version_check_add(d, suite_name, check, reference_name):
472 suite = get_suite(suite_name)
474 die("E: Could not find suite %s." % (suite_name))
475 reference = get_suite(reference_name)
477 die("E: Could not find reference suite %s." % (reference_name))
479 session = d.session()
483 vc.reference = reference
487 def __version_check_rm(d, suite_name, check, reference_name):
488 suite = get_suite(suite_name)
490 die("E: Could not find suite %s." % (suite_name))
491 reference = get_suite(reference_name)
493 die("E: Could not find reference suite %s." % (reference_name))
495 session = d.session()
497 vc = session.query(VersionCheck).filter_by(suite=suite, check=check, reference=reference).one()
500 except NoResultFound:
501 print "W: version-check not found."
503 def version_check(command):
504 args = [str(x) for x in command]
505 Cnf = utils.get_conf()
508 die_arglen(args, 2, "E: version-check needs at least a command")
509 mode = args[1].lower()
512 __version_check_list(d)
513 elif mode == 'list-suite':
515 die("E: version-check list-suite needs a single parameter")
516 __version_check_list_suite(d, args[2])
519 die("E: version-check add needs three parameters")
520 __version_check_add(d, args[2], args[3], args[4])
523 die("E: version-check rm needs three parameters")
524 __version_check_rm(d, args[2], args[3], args[4])
526 die("E: version-check command unknown")
528 dispatch['version-check'] = version_check
529 dispatch['v-c'] = version_check
531 ################################################################################
533 def show_config(command):
534 args = [str(x) for x in command]
535 cnf = utils.get_conf()
537 die_arglen(args, 2, "E: config needs at least a command")
539 mode = args[1].lower()
543 if cnf.has_key("DB::Service"):
545 connstr = "postgresql://service=%s" % cnf["DB::Service"]
546 elif cnf.has_key("DB::Host"):
548 connstr = "postgres://%s" % cnf["DB::Host"]
549 if cnf.has_key("DB::Port") and cnf["DB::Port"] != "-1":
550 connstr += ":%s" % cnf["DB::Port"]
551 connstr += "/%s" % cnf["DB::Name"]
554 connstr = "postgres:///%s" % cnf["DB::Name"]
555 if cnf["DB::Port"] and cnf["DB::Port"] != "-1":
556 connstr += "?port=%s" % cnf["DB::Port"]
558 elif mode == 'db-shell':
560 if cnf.has_key("DB::Service"):
561 e.append('PGSERVICE')
562 print "PGSERVICE=%s" % cnf["DB::Service"]
563 if cnf.has_key("DB::Name"):
564 e.append('PGDATABASE')
565 print "PGDATABASE=%s" % cnf["DB::Name"]
566 if cnf.has_key("DB::Host"):
567 print "PGHOST=%s" % cnf["DB::Host"]
569 if cnf.has_key("DB::Port") and cnf["DB::Port"] != "-1":
570 print "PGPORT=%s" % cnf["DB::Port"]
572 print "export " + " ".join(e)
574 print cnf.get(args[2])
576 session = DBConn().session()
578 o = session.query(DBConfig).filter_by(name = mode).one()
580 except NoResultFound:
581 print "W: option '%s' not set" % mode
583 dispatch['config'] = show_config
584 dispatch['c'] = show_config
586 ################################################################################
588 def show_keyring(command):
589 args = [str(x) for x in command]
590 cnf = utils.get_conf()
592 die_arglen(args, 2, "E: keyring needs at least a command")
594 mode = args[1].lower()
598 q = d.session().query(Keyring).filter(Keyring.active == True)
600 if mode == 'list-all':
602 elif mode == 'list-binary':
603 q = q.join(Keyring.acl).filter(ACL.allow_source == False)
604 elif mode == 'list-source':
605 q = q.join(Keyring.acl).filter(ACL.allow_source == True)
607 die("E: keyring command unknown")
612 dispatch['keyring'] = show_keyring
613 dispatch['k'] = show_keyring
615 ################################################################################
618 """Perform administrative work on the dak database"""
620 Cnf = utils.get_conf()
621 arguments = [('h', "help", "Admin::Options::Help"),
622 ('n', "dry-run", "Admin::Options::Dry-Run")]
623 for i in [ "help", "dry-run" ]:
624 if not Cnf.has_key("Admin::Options::%s" % (i)):
625 Cnf["Admin::Options::%s" % (i)] = ""
627 arguments = apt_pkg.parse_commandline(Cnf, arguments, sys.argv)
629 options = Cnf.subtree("Admin::Options")
630 if options["Help"] or len(arguments) < 1:
632 if options["Dry-Run"]:
635 subcommand = str(arguments[0])
637 if subcommand in dispatch.keys():
638 dispatch[subcommand](arguments)
640 die("E: Unknown command")
642 ################################################################################
644 if __name__ == '__main__':