]> git.decadent.org.uk Git - dak.git/blob - dak/admin.py
Merge remote branch 'mario/master' into merge
[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 from daklib import utils
27 from daklib.dbconn import *
28
29 ################################################################################
30
31 dispatch = {}
32 dryrun = False
33
34 ################################################################################
35 def warn(msg):
36     print >> sys.stderr, msg
37
38 def die(msg, exit_code=1):
39     print >> sys.stderr, msg
40     sys.exit(exit_code)
41
42 def die_arglen(args, args_needed, msg):
43     if len(args) < args_needed:
44         die(msg)
45
46 def usage(exit_code=0):
47     """Perform administrative work on the dak database."""
48
49     print """Usage: dak admin COMMAND
50 Perform administrative work on the dak database.
51
52   -h, --help          show this help and exit.
53   -n, --dry-run       don't do anything, just show what would have been done
54                       (only applies to add or rm operations).
55
56   Commands can use a long or abbreviated form:
57
58   architecture / a:
59      a list                 show a list of architectures
60      a rm ARCH              remove an architecture (will only work if
61                             no longer linked to any suites)
62      a add ARCH DESCRIPTION [SUITELIST]
63                             add architecture ARCH with DESCRIPTION.
64                             If SUITELIST is given, add to each of the
65                             suites at the same time
66
67   suite / s:
68      s list                 show a list of suites
69      s show SUITE           show config details for a suite
70      s add SUITE VERSION [ label=LABEL ] [ description=DESCRIPTION ]
71                          [ origin=ORIGIN ] [ codename=CODENAME ]
72                             add suite SUITE, version VERSION. label,
73                             description, origin and codename are optional.
74
75   suite-architecture / s-a:
76      s-a list-suite ARCH    show the suites an ARCH is in
77      s-a list-arch SUITE    show the architectures in a SUITE
78      s-a add SUITE ARCH     add ARCH to suite
79      s-a rm SUITE ARCH      remove ARCH from suite (will only work if
80                             no packages remain for the arch in the suite)
81 """
82     sys.exit(exit_code)
83
84 ################################################################################
85
86 def __architecture_list(d, args):
87     q = d.session().query(Architecture).order_by('arch_string')
88     for j in q.all():
89         # HACK: We should get rid of source from the arch table
90         if j.arch_string == 'source': continue
91         print j.arch_string
92     sys.exit(0)
93
94 def __architecture_add(d, args):
95     die_arglen(args, 3, "E: adding an architecture requires a name and a description")
96     print "Adding architecture %s" % args[2]
97     suites = [str(x) for x in args[4:]]
98     print suites
99     if not dryrun:
100         try:
101             s = d.session()
102             a = Architecture()
103             a.arch_string = str(args[2]).lower()
104             a.description = str(args[3])
105             s.add(a)
106             for sn in suites:
107                 su = get_suite(sn ,s)
108                 if su is not None:
109                     archsu = SuiteArchitecture()
110                     archsu.arch_id = a.arch_id
111                     archsu.suite_id = su.suite_id
112                     s.add(archsu)
113                 else:
114                     warn("W: Cannot find suite %s" % su)
115             s.commit()
116         except IntegrityError, e:
117             die("E: Integrity error adding architecture %s (it probably already exists)" % args[2])
118         except SQLAlchemyError, e:
119             die("E: Error adding architecture %s (%s)" % (args[2], e))
120     print "Architecture %s added" % (args[2])
121
122 def __architecture_rm(d, args):
123     die_arglen(args, 3, "E: removing an architecture requires at least a name")
124     print "Removing architecture %s" % args[2]
125     if not dryrun:
126         try:
127             s = d.session()
128             a = get_architecture(args[2].lower(), s)
129             if a is None:
130                 die("E: Cannot find architecture %s" % args[2])
131             s.delete(a)
132             s.commit()
133         except IntegrityError, e:
134             die("E: Integrity error removing architecture %s (suite-arch entries probably still exist)" % args[2])
135         except SQLAlchemyError, e:
136             die("E: Error removing architecture %s (%s)" % (args[2], e))
137     print "Architecture %s removed" % args[2]
138
139 def architecture(command):
140     args = [str(x) for x in command]
141     Cnf = utils.get_conf()
142     d = DBConn()
143
144     die_arglen(args, 2, "E: architecture needs at least a command")
145
146     mode = args[1].lower()
147     if mode == 'list':
148         __architecture_list(d, args)
149     elif mode == 'add':
150         __architecture_add(d, args)
151     elif mode == 'rm':
152         __architecture_rm(d, args)
153     else:
154         die("E: architecture command unknown")
155
156 dispatch['architecture'] = architecture
157 dispatch['a'] = architecture
158
159 ################################################################################
160
161 def __suite_list(d, args):
162     s = d.session()
163     for j in s.query(Suite).order_by('suite_name').all():
164         print j.suite_name
165
166 def __suite_show(d, args):
167     if len(args) < 2:
168         die("E: showing an suite entry requires a suite")
169
170     s = d.session()
171     su = get_suite(args[2].lower())
172     if su is None:
173         die("E: can't find suite entry for %s" % (args[2].lower()))
174
175     print su.details()
176
177 def __suite_add(d, args):
178     die_arglen(args, 4, "E: adding a suite requires at least a name and a version")
179     suite_name = args[2].lower()
180     version = args[3]
181     rest = args[3:]
182
183     def get_field(field):
184         for varval in args:
185             if varval.startswith(field + '='):
186                 return varval.split('=')[1]
187         return None
188
189     print "Adding suite %s" % suite_name
190     if not dryrun:
191         try:
192             s = d.session()
193             suite = Suite()
194             suite.suite_name = suite_name
195             suite.version = version
196             suite.label = get_field('label')
197             suite.description = get_field('description')
198             suite.origin = get_field('origin')
199             suite.codename = get_field('codename')
200             s.add(suite)
201             s.commit()
202         except IntegrityError, e:
203             die("E: Integrity error adding suite %s (it probably already exists)" % suite_name)
204         except SQLAlchemyError, e:
205             die("E: Error adding suite %s (%s)" % (suite_name, e))
206     print "Suite %s added" % (suite_name)
207
208 def suite(command):
209     args = [str(x) for x in command]
210     Cnf = utils.get_conf()
211     d = DBConn()
212
213     die_arglen(args, 2, "E: suite needs at least a command")
214
215     mode = args[1].lower()
216
217     if mode == 'list':
218         __suite_list(d, args)
219     elif mode == 'show':
220         __suite_show(d, args)
221     elif mode == 'add':
222         __suite_add(d, args)
223     else:
224         die("E: suite command unknown")
225
226 dispatch['suite'] = suite
227 dispatch['s'] = suite
228
229 ################################################################################
230
231 def __suite_architecture_list(d, args):
232     s = d.session()
233     for j in s.query(Suite).order_by('suite_name').all():
234         print j.suite_name + ' ' + \
235               ','.join([a.architecture.arch_string for a in j.suitearchitectures])
236
237 def __suite_architecture_listarch(d, args):
238     die_arglen(args, 3, "E: suite-architecture list-arch requires a suite")
239     a = get_suite_architectures(args[2].lower())
240     for j in a:
241         # HACK: We should get rid of source from the arch table
242         if j.arch_string != 'source':
243             print j.arch_string
244
245
246 def __suite_architecture_listsuite(d, args):
247     die_arglen(args, 3, "E: suite-architecture list-suite requires an arch")
248     for j in get_architecture_suites(args[2].lower()):
249         print j.suite_name
250
251
252 def __suite_architecture_add(d, args):
253     if len(args) < 3:
254         die("E: adding a suite-architecture entry requires a suite and arch")
255
256     s = d.session()
257
258     suite = get_suite(args[2].lower(), s)
259     if suite is None: die("E: Can't find suite %s" % args[2].lower())
260
261     arch = get_architecture(args[3].lower(), s)
262     if arch is None: die("E: Can't find architecture %s" % args[3].lower())
263
264     if not dryrun:
265         try:
266             sa = SuiteArchitecture()
267             sa.arch_id = arch.arch_id
268             sa.suite_id = suite.suite_id
269             s.add(sa)
270             s.commit()
271         except IntegrityError, e:
272             die("E: Can't add suite-architecture entry (%s, %s) - probably already exists" % (args[2].lower(), args[3].lower()))
273         except SQLAlchemyError, e:
274             die("E: Can't add suite-architecture entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
275
276     print "Added suite-architecture entry for %s, %s" % (args[2].lower(), args[3].lower())
277
278
279 def __suite_architecture_rm(d, args):
280     if len(args) < 3:
281         die("E: removing an suite-architecture entry requires a suite and arch")
282
283     s = d.session()
284     if not dryrun:
285         try:
286             sa = get_suite_architecture(args[2].lower(), args[3].lower(), s)
287             if sa is None:
288                 die("E: can't find suite-architecture entry for %s, %s" % (args[2].lower(), args[3].lower()))
289             s.delete(sa)
290             s.commit()
291         except IntegrityError, e:
292             die("E: Can't remove suite-architecture entry (%s, %s) - it's probably referenced" % (args[2].lower(), args[3].lower()))
293         except SQLAlchemyError, e:
294             die("E: Can't remove suite-architecture entry (%s, %s) - %s" % (args[2].lower(), args[3].lower(), e))
295
296     print "Removed suite-architecture entry for %s, %s" % (args[2].lower(), args[3].lower())
297
298
299 def suite_architecture(command):
300     args = [str(x) for x in command]
301     Cnf = utils.get_conf()
302     d = DBConn()
303
304     die_arglen(args, 2, "E: suite-architecture needs at least a command")
305
306     mode = args[1].lower()
307
308     if mode == 'list':
309         __suite_architecture_list(d, args)
310     elif mode == 'list-arch':
311         __suite_architecture_listarch(d, args)
312     elif mode == 'list-suite':
313         __suite_architecture_listsuite(d, args)
314     elif mode == 'add':
315         __suite_architecture_add(d, args)
316     elif mode == 'rm':
317         __suite_architecture_rm(d, args)
318     else:
319         die("E: suite-architecture command unknown")
320
321 dispatch['suite-architecture'] = suite_architecture
322 dispatch['s-a'] = suite_architecture
323
324 ################################################################################
325
326 def main():
327     """Perform administrative work on the dak database"""
328     global dryrun
329     Cnf = utils.get_conf()
330     arguments = [('h', "help", "Admin::Options::Help"),
331                  ('n', "dry-run", "Admin::Options::Dry-Run")]
332     for i in [ "help", "dry-run" ]:
333         if not Cnf.has_key("Admin::Options::%s" % (i)):
334             Cnf["Admin::Options::%s" % (i)] = ""
335
336     arguments = apt_pkg.ParseCommandLine(Cnf, arguments, sys.argv)
337
338     options = Cnf.SubTree("Admin::Options")
339     if options["Help"] or len(arguments) < 1:
340         usage()
341     if options["Dry-Run"]:
342         dryrun = True
343
344     subcommand = str(arguments[0])
345
346     if subcommand in dispatch.keys():
347         dispatch[subcommand](arguments)
348     else:
349         die("E: Unknown command")
350
351 ################################################################################
352
353 if __name__ == '__main__':
354     main()