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)
108 v-c list show version checks for all suites
109 v-c list-suite SUITE show version checks for suite SUITE
110 v-c add SUITE CHECK REFERENCE add a version check for suite SUITE
111 v-c rm SUITE CHECK REFERENCE remove a version check
113 CHECK is one of Enhances, MustBeNewerThan, MustBeOlderThan
114 REFERENCE is another suite name
118 ################################################################################
120 def __architecture_list(d, args):
121 q = d.session().query(Architecture).order_by(Architecture.arch_string)
123 # HACK: We should get rid of source from the arch table
124 if j.arch_string == 'source': continue
128 def __architecture_add(d, args):
129 die_arglen(args, 4, "E: adding an architecture requires a name and a description")
130 print "Adding architecture %s" % args[2]
131 suites = [str(x) for x in args[4:]]
133 print "Adding to suites %s" % ", ".join(suites)
138 a.arch_string = str(args[2]).lower()
139 a.description = str(args[3])
142 su = get_suite(sn, s)
146 warn("W: Cannot find suite %s" % su)
148 except IntegrityError as e:
149 die("E: Integrity error adding architecture %s (it probably already exists)" % args[2])
150 except SQLAlchemyError as e:
151 die("E: Error adding architecture %s (%s)" % (args[2], e))
152 print "Architecture %s added" % (args[2])
154 def __architecture_rm(d, args):
155 die_arglen(args, 3, "E: removing an architecture requires at least a name")
156 print "Removing architecture %s" % args[2]
160 a = get_architecture(args[2].lower(), s)
162 die("E: Cannot find architecture %s" % args[2])
165 except IntegrityError as e:
166 die("E: Integrity error removing architecture %s (suite-arch entries probably still exist)" % args[2])
167 except SQLAlchemyError as e:
168 die("E: Error removing architecture %s (%s)" % (args[2], e))
169 print "Architecture %s removed" % args[2]
171 def architecture(command):
172 args = [str(x) for x in command]
173 Cnf = utils.get_conf()
176 die_arglen(args, 2, "E: architecture needs at least a command")
178 mode = args[1].lower()
180 __architecture_list(d, args)
182 __architecture_add(d, args)
184 __architecture_rm(d, args)
186 die("E: architecture command unknown")
188 dispatch['architecture'] = architecture
189 dispatch['a'] = architecture
191 ################################################################################
193 def __suite_list(d, args):
195 for j in s.query(Suite).order_by(Suite.suite_name).all():
198 def __suite_show(d, args):
200 die("E: showing an suite entry requires a suite")
203 su = get_suite(args[2].lower())
205 die("E: can't find suite entry for %s" % (args[2].lower()))
209 def __suite_add(d, args, addallarches=False):
210 die_arglen(args, 4, "E: adding a suite requires at least a name and a version")
211 suite_name = args[2].lower()
215 def get_field(field):
217 if varval.startswith(field + '='):
218 return varval.split('=')[1]
221 print "Adding suite %s" % suite_name
226 suite.suite_name = suite_name
227 suite.overridecodename = suite_name
228 suite.version = version
229 suite.label = get_field('label')
230 suite.description = get_field('description')
231 suite.origin = get_field('origin')
232 suite.codename = get_field('codename')
233 signingkey = get_field('signingkey')
234 if signingkey is not None:
235 suite.signingkeys = [signingkey.upper()]
236 archive_name = get_field('archive')
237 if archive_name is not None:
238 suite.archive = get_archive(archive_name, s)
240 suite.archive = s.query(Archive).filter(~Archive.archive_name.in_(['build-queues', 'new', 'policy'])).one()
241 suite.srcformats = s.query(SrcFormat).all()
244 except IntegrityError as e:
245 die("E: Integrity error adding suite %s (it probably already exists)" % suite_name)
246 except SQLAlchemyError as e:
247 die("E: Error adding suite %s (%s)" % (suite_name, e))
248 print "Suite %s added" % (suite_name)
252 q = s.query(Architecture).order_by(Architecture.arch_string)
254 suite.architectures.append(arch)
255 arches.append(arch.arch_string)
257 print "Architectures %s added to %s" % (','.join(arches), suite_name)
263 args = [str(x) for x in command]
264 Cnf = utils.get_conf()
267 die_arglen(args, 2, "E: suite needs at least a command")
269 mode = args[1].lower()
272 __suite_list(d, args)
274 __suite_show(d, args)
276 __suite_add(d, args, False)
277 elif mode == 'add-all-arches':
278 __suite_add(d, args, True)
280 die("E: suite command unknown")
282 dispatch['suite'] = suite
283 dispatch['s'] = suite
285 ################################################################################
287 def __suite_architecture_list(d, args):
289 for j in s.query(Suite).order_by(Suite.suite_name):
290 architectures = j.get_architectures(skipsrc = True, skipall = True)
291 print j.suite_name + ': ' + \
292 ', '.join([a.arch_string for a in architectures])
294 def __suite_architecture_listarch(d, args):
295 die_arglen(args, 3, "E: suite-architecture list-arch requires a suite")
296 suite = get_suite(args[2].lower(), d.session())
298 die('E: suite %s is invalid' % args[2].lower())
299 a = suite.get_architectures(skipsrc = True, skipall = True)
304 def __suite_architecture_listsuite(d, args):
305 die_arglen(args, 3, "E: suite-architecture list-suite requires an arch")
306 architecture = get_architecture(args[2].lower(), d.session())
307 if architecture is None:
308 die("E: architecture %s is invalid" % args[2].lower())
309 for j in architecture.suites:
313 def __suite_architecture_add(d, args):
315 die("E: adding a suite-architecture entry requires a suite and arch")
319 suite = get_suite(args[2].lower(), s)
320 if suite is None: die("E: Can't find suite %s" % args[2].lower())
322 arch = get_architecture(args[3].lower(), s)
323 if arch is None: die("E: Can't find architecture %s" % args[3].lower())
327 suite.architectures.append(arch)
329 except IntegrityError as e:
330 die("E: Can't add suite-architecture entry (%s, %s) - probably already exists" % (args[2].lower(), args[3].lower()))
331 except SQLAlchemyError as e:
332 die("E: Can't add suite-architecture entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
334 print "Added suite-architecture entry for %s, %s" % (args[2].lower(), args[3].lower())
337 def __suite_architecture_rm(d, args):
339 die("E: removing an suite-architecture entry requires a suite and arch")
344 suite_name = args[2].lower()
345 suite = get_suite(suite_name, s)
347 die('E: no such suite %s' % suite_name)
348 arch_string = args[3].lower()
349 architecture = get_architecture(arch_string, s)
350 if architecture not in suite.architectures:
351 die("E: architecture %s not found in suite %s" % (arch_string, suite_name))
352 suite.architectures.remove(architecture)
354 except IntegrityError as e:
355 die("E: Can't remove suite-architecture entry (%s, %s) - it's probably referenced" % (args[2].lower(), args[3].lower()))
356 except SQLAlchemyError as e:
357 die("E: Can't remove suite-architecture entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
359 print "Removed suite-architecture entry for %s, %s" % (args[2].lower(), args[3].lower())
362 def suite_architecture(command):
363 args = [str(x) for x in command]
364 Cnf = utils.get_conf()
367 die_arglen(args, 2, "E: suite-architecture needs at least a command")
369 mode = args[1].lower()
372 __suite_architecture_list(d, args)
373 elif mode == 'list-arch':
374 __suite_architecture_listarch(d, args)
375 elif mode == 'list-suite':
376 __suite_architecture_listsuite(d, args)
378 __suite_architecture_add(d, args)
380 __suite_architecture_rm(d, args)
382 die("E: suite-architecture command unknown")
384 dispatch['suite-architecture'] = suite_architecture
385 dispatch['s-a'] = suite_architecture
387 ################################################################################
390 session = DBConn().session()
391 for archive in session.query(Archive).order_by(Archive.archive_name):
392 print "{0} path={1} description={2} tainted={3}".format(archive.archive_name, archive.path, archive.description, archive.tainted)
394 def archive_add(args):
395 (name, path, description) = args[0:3]
400 description=description,
403 for option in args[3:]:
404 (key, value) = option.split('=')
405 attributes[key] = value
407 session = DBConn().session()
410 for key, value in attributes.iteritems():
411 setattr(archive, key, value)
421 def archive_rm(name):
422 session = DBConn().session()
423 archive = session.query(Archive).filter_by(archive_name=name).one()
424 session.delete(archive)
432 def archive(command):
437 archive_add(command[2:])
439 archive_rm(command[2])
441 die("E: archive command unknown")
443 dispatch['archive'] = archive
445 ################################################################################
447 def __version_check_list(d):
448 session = d.session()
449 for s in session.query(Suite).order_by(Suite.suite_name):
450 __version_check_list_suite(d, s.suite_name)
452 def __version_check_list_suite(d, suite_name):
453 vcs = get_version_checks(suite_name)
455 print "%s %s %s" % (suite_name, vc.check, vc.reference.suite_name)
457 def __version_check_add(d, suite_name, check, reference_name):
458 suite = get_suite(suite_name)
460 die("E: Could not find suite %s." % (suite_name))
461 reference = get_suite(reference_name)
463 die("E: Could not find reference suite %s." % (reference_name))
465 session = d.session()
469 vc.reference = reference
473 def __version_check_rm(d, suite_name, check, reference_name):
474 suite = get_suite(suite_name)
476 die("E: Could not find suite %s." % (suite_name))
477 reference = get_suite(reference_name)
479 die("E: Could not find reference suite %s." % (reference_name))
481 session = d.session()
483 vc = session.query(VersionCheck).filter_by(suite=suite, check=check, reference=reference).one()
486 except NoResultFound:
487 print "W: version-check not found."
489 def version_check(command):
490 args = [str(x) for x in command]
491 Cnf = utils.get_conf()
494 die_arglen(args, 2, "E: version-check needs at least a command")
495 mode = args[1].lower()
498 __version_check_list(d)
499 elif mode == 'list-suite':
501 die("E: version-check list-suite needs a single parameter")
502 __version_check_list_suite(d, args[2])
505 die("E: version-check add needs three parameters")
506 __version_check_add(d, args[2], args[3], args[4])
509 die("E: version-check rm needs three parameters")
510 __version_check_rm(d, args[2], args[3], args[4])
512 die("E: version-check command unknown")
514 dispatch['version-check'] = version_check
515 dispatch['v-c'] = version_check
517 ################################################################################
519 def show_config(command):
520 args = [str(x) for x in command]
521 cnf = utils.get_conf()
523 die_arglen(args, 2, "E: config needs at least a command")
525 mode = args[1].lower()
529 if cnf.has_key("DB::Service"):
531 connstr = "postgresql://service=%s" % cnf["DB::Service"]
532 elif cnf.has_key("DB::Host"):
534 connstr = "postgres://%s" % cnf["DB::Host"]
535 if cnf.has_key("DB::Port") and cnf["DB::Port"] != "-1":
536 connstr += ":%s" % cnf["DB::Port"]
537 connstr += "/%s" % cnf["DB::Name"]
540 connstr = "postgres:///%s" % cnf["DB::Name"]
541 if cnf["DB::Port"] and cnf["DB::Port"] != "-1":
542 connstr += "?port=%s" % cnf["DB::Port"]
544 elif mode == 'db-shell':
546 if cnf.has_key("DB::Service"):
547 e.append('PGSERVICE')
548 print "PGSERVICE=%s" % cnf["DB::Service"]
549 if cnf.has_key("DB::Name"):
550 e.append('PGDATABASE')
551 print "PGDATABASE=%s" % cnf["DB::Name"]
552 if cnf.has_key("DB::Host"):
553 print "PGHOST=%s" % cnf["DB::Host"]
555 if cnf.has_key("DB::Port") and cnf["DB::Port"] != "-1":
556 print "PGPORT=%s" % cnf["DB::Port"]
558 print "export " + " ".join(e)
560 session = DBConn().session()
562 o = session.query(DBConfig).filter_by(name = mode).one()
564 except NoResultFound:
565 print "W: option '%s' not set" % mode
567 dispatch['config'] = show_config
568 dispatch['c'] = show_config
570 ################################################################################
572 def show_keyring(command):
573 args = [str(x) for x in command]
574 cnf = utils.get_conf()
576 die_arglen(args, 2, "E: keyring needs at least a command")
578 mode = args[1].lower()
582 q = d.session().query(Keyring).filter(Keyring.active == True)
584 if mode == 'list-all':
586 elif mode == 'list-binary':
587 q = q.filter(Keyring.default_source_acl_id == None)
588 elif mode == 'list-source':
589 q = q.filter(Keyring.default_source_acl_id != None)
591 die("E: keyring command unknown")
596 dispatch['keyring'] = show_keyring
597 dispatch['k'] = show_keyring
599 ################################################################################
602 """Perform administrative work on the dak database"""
604 Cnf = utils.get_conf()
605 arguments = [('h', "help", "Admin::Options::Help"),
606 ('n', "dry-run", "Admin::Options::Dry-Run")]
607 for i in [ "help", "dry-run" ]:
608 if not Cnf.has_key("Admin::Options::%s" % (i)):
609 Cnf["Admin::Options::%s" % (i)] = ""
611 arguments = apt_pkg.parse_commandline(Cnf, arguments, sys.argv)
613 options = Cnf.subtree("Admin::Options")
614 if options["Help"] or len(arguments) < 1:
616 if options["Dry-Run"]:
619 subcommand = str(arguments[0])
621 if subcommand in dispatch.keys():
622 dispatch[subcommand](arguments)
624 die("E: Unknown command")
626 ################################################################################
628 if __name__ == '__main__':