source: rtems-source-builder/source-builder/sb/reports.py @ 6733a85

4.104.114.95
Last change on this file since 6733a85 was 6733a85, checked in by Sebastian Huber <sebastian.huber@…>, on 12/08/14 at 06:19:07

sb: Move content to formatter classes

  • Property mode set to 100644
File size: 26.2 KB
Line 
1#
2# RTEMS Tools Project (http://www.rtems.org/)
3# Copyright 2010-2013 Chris Johns (chrisj@rtems.org)
4# All rights reserved.
5#
6# This file is part of the RTEMS Tools package in 'rtems-tools'.
7#
8# Permission to use, copy, modify, and/or distribute this software for any
9# purpose with or without fee is hereby granted, provided that the above
10# copyright notice and this permission notice appear in all copies.
11#
12# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20#
21# This code builds a package given a config file. It only builds to be
22# installed not to be package unless you run a packager around this.
23#
24
25import copy
26import datetime
27import os
28import sys
29
30import pprint
31pp = pprint.PrettyPrinter(indent = 2)
32
33try:
34    import build
35    import check
36    import config
37    import error
38    import git
39    import log
40    import options
41    import path
42    import setbuilder
43    import sources
44    import version
45except KeyboardInterrupt:
46    print 'user terminated'
47    sys.exit(1)
48except:
49    print 'error: unknown application load error'
50    sys.exit(1)
51
52_line_len = 78
53
54_title = 'RTEMS Tools Project <users@rtems.org>'
55
56_git_status_text = 'RTEMS Source Builder Repository Status'
57
58def _make_path(p, *args):
59    for arg in args:
60        p = path.join(p, arg)
61    return os.path.abspath(path.host(p))
62
63class formatter(object):
64    def __init__(self):
65        self.content = ''
66
67    def line(self, text):
68        self.content += text + '\n'
69
70    def add(self, text):
71        self.content += text
72
73    def set_sbpath(self, sbpath):
74        self.sbpath = sbpath
75
76    def format(self):
77        raise error.general('internal error: formatter.format() not implemented')
78
79    def ext(self):
80        raise error.general('internal error: formatter.ext() not implemented')
81
82    def introduction(self, name, now, intro_text):
83        self.line('=' * _line_len)
84        self.line('%s %s' % (_title, now))
85        if intro_text:
86            self.line('')
87            self.line('%s' % ('\n'.join(intro_text)))
88        self.line('=' * _line_len)
89        self.line('Report: %s' % (name))
90
91    def epilogue(self, name):
92        return
93
94    def config_start(self, nest_level, name):
95        return
96
97    def config(self, nest_level, name, _config):
98        self.line('-' * _line_len)
99        self.line('Package: %s' % (name))
100        self.line(' Config: %s' % (_config.file_name()))
101
102    def config_end(self, nest_level, name):
103        return
104
105    def buildset_start(self, nest_level, name):
106        self.line('=-' * (_line_len / 2))
107        self.line('Build Set: %s' % (name))
108
109    def buildset_end(self, nest_level, name):
110        return
111
112    def info(self, nest_level, name, info, separated):
113        self.line(' ' + name + ':')
114        for l in info:
115            self.line('  ' + l)
116
117    def directive(self, nest_level, name, data):
118        self.line(' %s:' % (name))
119        for l in data:
120            self.line('  ' + l)
121
122    def files(self, nest_level, sigular, plural, _files):
123        self.line('  ' + plural + ': %d' % (len(_files)))
124        i = 0
125        for name in _files:
126            for s in _files[name]:
127                i += 1
128                self.line('   %2d: %s' % (i, s[0]))
129                if s[1] is None:
130                    h = 'No checksum'
131                else:
132                    hash = s[1].split()
133                    h = '%s: %s' % (hash[0], hash[1])
134                self.line('       %s' % (h))
135
136    def post_process(self):
137        return self.content
138
139class asciidoc_formatter(formatter):
140    def __init__(self):
141        super(asciidoc_formatter, self).__init__()
142
143    def format(self):
144        return 'asciidoc'
145
146    def ext(self):
147        return '.txt'
148
149    def introduction(self, name, now, intro_text):
150        h = 'RTEMS Source Builder Report'
151        self.line(h)
152        self.line('=' * len(h))
153        self.line(':doctype: book')
154        self.line(':toc2:')
155        self.line(':toclevels: 5')
156        self.line(':icons:')
157        self.line(':numbered:')
158        self.line(':data-uri:')
159        self.line('')
160        self.line(_title)
161        self.line(now)
162        self.line('')
163        image = _make_path(self.sbpath, options.basepath, 'images', 'rtemswhitebg.jpg')
164        self.line('image:%s["RTEMS",width="20%%"]' % (image))
165        self.line('')
166        if intro_text:
167            self.line('%s' % ('\n'.join(intro_text)))
168
169    def git_status(self, valid, dirty, head, remotes):
170        self.line('')
171        self.line("'''")
172        self.line('')
173        self.line('.%s' % (_git_status_text))
174        if valid:
175            self.line('*Remotes*:;;')
176            for r in remotes:
177                if 'url' in remotes[r]:
178                    text = remotes[r]['url']
179                else:
180                    text = 'no URL found'
181                text = '%s: %s' % (r, text)
182                self.line('. %s' % (text))
183            self.line('*Status*:;;')
184            if dirty:
185                self.line('_Repository is dirty_')
186            else:
187                self.line('Clean')
188            self.line('*Head*:;;')
189            self.line('Commit: %s' % (head))
190        else:
191            self.line('_Not a valid GIT repository_')
192        self.line('')
193        self.line("'''")
194        self.line('')
195
196    def config(self, nest_level, name, _config):
197        self.line('*Package*: _%s_ +' % (name))
198        self.line('*Config*: %s' % (_config.file_name()))
199        self.line('')
200
201    def config_end(self, nest_level, name):
202        self.line('')
203        self.line("'''")
204        self.line('')
205
206    def buildset_start(self, nest_level, name):
207        h = '%s' % (name)
208        self.line('=%s %s' % ('=' * nest_level, h))
209
210    def info(self, nest_level, name, info, separated):
211        end = ''
212        if separated:
213            self.line('*%s:*::' % (name))
214            self.line('')
215        else:
216            self.line('*%s:* ' % (name))
217            end = ' +'
218        spaces = ''
219        for l in info:
220            self.line('%s%s%s' % (spaces, l, end))
221        if separated:
222            self.line('')
223
224    def directive(self, nest_level, name, data):
225        self.line('')
226        self.line('*%s*:' % (name))
227        self.line('--------------------------------------------')
228        for l in data:
229            self.line(l)
230        self.line('--------------------------------------------')
231
232    def files(self, nest_level, singular, plural, _files):
233        self.line('')
234        self.line('*' + plural + ':*::')
235        if len(_files) == 0:
236            self.line('No ' + plural.lower())
237        for name in _files:
238            for s in _files[name]:
239                self.line('. %s' % (s[0]))
240                if s[1] is None:
241                    h = 'No checksum'
242                else:
243                    hash = s[1].split()
244                    h = '%s: %s' % (hash[0], hash[1])
245                self.line('+\n%s\n' % (h))
246
247class html_formatter(asciidoc_formatter):
248    def __init__(self):
249        super(html_formatter, self).__init__()
250        try:
251            import asciidocapi
252        except:
253            raise error.general('installation error: no asciidocapi found')
254        asciidoc_py = _make_path(self.sbpath, options.basepath, 'asciidoc', 'asciidoc.py')
255        try:
256            self.asciidoc = asciidocapi.AsciiDocAPI(asciidoc_py)
257        except:
258            raise error.general('application error: asciidocapi failed')
259
260    def format(self):
261        return 'html'
262
263    def ext(self):
264        return '.html'
265
266    def post_process(self):
267        import StringIO
268        infile = StringIO.StringIO(self.content)
269        outfile = StringIO.StringIO()
270        self.asciidoc.execute(infile, outfile)
271        out = outfile.getvalue()
272        infile.close()
273        outfile.close()
274        return out
275
276class text_formatter(formatter):
277    def __init__(self):
278        super(text_formatter, self).__init__()
279        self.cini = ''
280
281    def format(self):
282        return 'text'
283
284    def ext(self):
285        return '.txt'
286
287    def introduction(self, name, now, intro_text):
288        self.line('=' * _line_len)
289        self.line('%s %s' % (_title, now))
290        if intro_text:
291            self.line('')
292            self.line('%s' % ('\n'.join(intro_text)))
293        self.line('=' * _line_len)
294        self.line('Report: %s' % (name))
295
296    def git_status_header(self):
297        self.line('-' * _line_len)
298        self.line('%s' % (_git_status_text))
299
300    def git_status(self, valid, dirty, head, remotes):
301        self.git_status_header()
302        if valid:
303            self.line('%s Remotes:' % (self.cini))
304            rc = 0
305            for r in remotes:
306                rc += 1
307                if 'url' in remotes[r]:
308                    text = remotes[r]['url']
309                else:
310                    text = 'no URL found'
311                text = '%s: %s' % (r, text)
312                self.line('%s  %2d: %s' % (self.cini, rc, text))
313            self.line('%s Status:' % (self.cini))
314            if dirty:
315                self.line('%s  Repository is dirty' % (self.cini))
316            else:
317                self.line('%s  Clean' % (self.cini))
318            self.line('%s Head:' % (self.cini))
319            self.line('%s  Commit: %s' % (self.cini, head))
320        else:
321            self.line('%s Not a valid GIT repository' % (self.cini))
322
323class ini_formatter(text_formatter):
324    def __init__(self):
325        super(ini_formatter, self).__init__()
326        self.cini = ';'
327
328    def format(self):
329        return 'ini'
330
331    def ext(self):
332        return '.ini'
333
334    def introduction(self, name, now, intro_text):
335        self.line(';')
336        self.line('; %s %s' % (_title, now))
337        if intro_text:
338            self.line(';')
339            self.line('; %s' % ('\n; '.join(intro_text)))
340            self.line(';')
341
342    def git_status_header(self):
343        self.line(';')
344        self.line('; %s' % (_git_status_text))
345        self.line(';')
346
347    def config(self, nest_level, name, _config):
348        return
349
350    def buildset_start(self, nest_level, name):
351        return
352
353    def info(self, nest_level, name, info, separated):
354        return
355
356    def directive(self, nest_level, name, data):
357        return
358
359    def files(self, nest_level, singular, plural, _files):
360        return
361
362class xml_formatter(formatter):
363    def __init__(self):
364        super(xml_formatter, self).__init__()
365
366    def format(self):
367        return 'xml'
368
369    def ext(self):
370        return '.xml'
371
372    def introduction(self, name, now, intro_text):
373        self.line('<RTEMSSourceBuilderReport>')
374        if intro_text:
375            self.line('\t<Introduction>%s</Introduction>' % (intro_text))
376
377    def epilogue(self, name):
378        self.line('</RTEMSSourceBuilderReport>')
379
380    def git_status(self, valid, dirty, head, remotes):
381        self.line('\t<Git>')
382        if valid:
383            if dirty:
384                self.line('\t\t<Status>dirty</Status>')
385            else:
386                self.line('\t\t<Status>clean</Status>')
387            self.line('\t\t<Commit>' + head + '</Commit>')
388        else:
389            self.line('\t\t<Status>invalid</Status>')
390        self.line('\t</Git>')
391
392    def config_start(self, nest_level, name):
393        self.line('\t' * nest_level + '<Package name="' + name + '">')
394
395    def config(self, nest_level, name, _config):
396        self.line('\t' * nest_level + '<Config>' + _config.file_name() + '</Config>')
397
398    def config_end(self, nest_level, name):
399        self.line('\t' * nest_level + '</Package>')
400
401    def buildset_start(self, nest_level, name):
402        self.line('\t' * nest_level + '<BuildSet name="' + name + '">')
403
404    def buildset_end(self, nest_level, name):
405        self.line('\t' * nest_level + '</BuildSet>')
406
407    def info(self, nest_level, name, info, separated):
408        self.add('\t' * nest_level + '<' + name.replace(' ', '') + '>')
409        for l in info:
410            self.add(l)
411        self.line('</' + name + '>')
412
413    def directive(self, nest_level, name, data):
414        self.line('\t' * nest_level + '<' + name + '><![CDATA[')
415        for l in data:
416            self.line(l.replace(']]>', ']]]><![CDATA[]>'))
417        self.line(']]></' + name + '>')
418
419    def files(self, nest_level, sigular, plural, _files):
420        for name in _files:
421            for s in _files[name]:
422                self.add('\t' * nest_level + '<' + sigular)
423                if not (s[1] is None):
424                    hash = s[1].split()
425                    self.add(' ' + hash[0] + '="' + hash[1] + '"')
426                self.line('>' + s[0] + '</' + sigular + '>')
427
428def _tree_name(path_):
429    return path.splitext(path.basename(path_))[0]
430
431def _merge(_dict, new):
432    new = copy.deepcopy(new)
433    for i in new:
434        if i not in _dict:
435            _dict[i] = new[i]
436        else:
437            _dict[i] += new[i]
438
439class report:
440    """Report the build details about a package given a config file."""
441
442    def __init__(self, formatter, _configs, opts, macros = None):
443        self.formatter = formatter
444        self.configs = _configs
445        self.opts = opts
446        if macros is None:
447            self.macros = opts.defaults
448        else:
449            self.macros = macros
450        self.sbpath = self.macros.expand('%{_sbdir}')
451        self.formatter.set_sbpath(self.sbpath)
452        self.bset_nesting = 0
453        self.out = ''
454        self.tree = {}
455        self.files = { 'buildsets':[], 'configs':[] }
456
457    def output(self, text):
458        self.out += text + '\n'
459
460    def is_ini(self):
461        return self.formatter.format() == 'ini'
462
463    def header(self):
464        pass
465
466    def footer(self):
467        pass
468
469    def git_status(self):
470        r = git.repo('.', self.opts, self.macros)
471        self.formatter.git_status(r.valid(), r.dirty(), r.head(), r.remotes())
472
473    def introduction(self, name, intro_text = None):
474        now = datetime.datetime.now().ctime()
475        self.formatter.introduction(name, now, intro_text)
476        self.git_status()
477
478    def epilogue(self, name):
479        self.formatter.epilogue(name)
480
481    def config_start(self, name, _config):
482        self.files['configs'] += [name]
483        for cf in _config.includes():
484            cfbn = path.basename(cf)
485            if cfbn not in self.files['configs']:
486                self.files['configs'] += [cfbn]
487        self.formatter.config_start(self.bset_nesting + 1, name)
488
489    def config_end(self, name, _config):
490        self.formatter.config_end(self.bset_nesting + 1, name)
491
492    def buildset_start(self, name):
493        self.files['buildsets'] += [name]
494        self.formatter.buildset_start(self.bset_nesting, name)
495
496    def buildset_end(self, name):
497        self.formatter.buildset_end(self.bset_nesting, name)
498
499    def source(self, macros):
500        def err(msg):
501            raise error.general('%s' % (msg))
502        _srcs = {}
503        for p in sources.get_source_names(macros, err):
504            if 'setup' in sources.get_source_keys(p, macros, err):
505                _srcs[p] = \
506                    [s for s in sources.get_sources(p, macros, err) if not s.startswith('%setup')]
507                _srcs[p] = [macros.expand(s) for s in _srcs[p]]
508        srcs = {}
509        for p in _srcs:
510            srcs[p] = [(s, sources.get_hash(path.basename(s).lower(), macros)) for s in _srcs[p]]
511        return srcs
512
513    def patch(self, macros):
514        def err(msg):
515            raise error.general('%s' % (msg))
516        _patches = {}
517        for n in sources.get_patch_names(macros, err):
518            if 'setup' in sources.get_patch_keys(n, macros, err):
519                _patches[n] = \
520                    [p for p in sources.get_patches(n, macros, err) if not p.startswith('%setup')]
521                _patches[n] = [macros.expand(p.split()[-1]) for p in _patches[n]]
522        patches = {}
523        for n in _patches:
524            patches[n] = [(p, sources.get_hash(path.basename(p).lower(), macros)) for p in _patches[n]]
525        return patches
526
527    def output_info(self, name, info, separated = False):
528        if info is not None:
529            self.formatter.info(self.bset_nesting + 2, name, info, separated)
530
531    def output_directive(self, name, directive):
532        if directive is not None:
533            self.formatter.directive(self.bset_nesting + 2, name, directive)
534
535    def tree_sources(self, name, tree, sources = []):
536        if 'cfg' in tree:
537            packages = {}
538            if 'sources' in tree['cfg']:
539                _merge(packages, tree['cfg']['sources'])
540            if 'patches' in tree['cfg']:
541                _merge(packages, tree['cfg']['patches'])
542            for package in packages:
543                for source in packages[package]:
544                    if not source[0].startswith('git') and not source[0].startswith('cvs'):
545                        sources += [(path.basename(source[0]), source[0], source[1])]
546        if 'bset' in tree:
547            for node in sorted(tree['bset'].keys()):
548                self.tree_sources(_tree_name(node), tree['bset'][node], sources)
549        return sources
550
551    def config(self, _config, tree, opts, macros):
552        packages = _config.packages()
553        package = packages['main']
554        name = package.name()
555        if len(name) == 0:
556            return
557        tree['file'] += [_config.file_name()]
558        sources = self.source(macros)
559        patches = self.patch(macros)
560        if len(sources):
561            if 'sources' in tree:
562                tree['sources'] = dict(tree['sources'].items() + sources.items())
563            else:
564                tree['sources'] = sources
565        if len(patches):
566            if 'patches' in tree:
567                tree['patches'] = dict(tree['patches'].items() + patches.items())
568            else:
569                tree['patches'] = patches
570        self.config_start(name, _config)
571        self.formatter.config(self.bset_nesting + 2, name, _config)
572        self.output_info('Summary', package.get_info('summary'), True)
573        self.output_info('URL', package.get_info('url'))
574        self.output_info('Version', package.get_info('version'))
575        self.output_info('Release', package.get_info('release'))
576        self.output_info('Build Arch', package.get_info('buildarch'))
577        self.formatter.files(self.bset_nesting + 2, "Source", "Sources", sources)
578        self.formatter.files(self.bset_nesting + 2, "Patch", "Patches", patches)
579        self.output_directive('Preparation', package.prep())
580        self.output_directive('Build', package.build())
581        self.output_directive('Install', package.install())
582        self.output_directive('Clean', package.clean())
583        self.config_end(name, _config)
584
585    def generate_ini_tree(self, name, tree, prefix_char, prefix = ''):
586        if prefix_char == '|':
587            c = '|'
588        else:
589            c = '+'
590        self.output('; %s  %s- %s' % (prefix, c, name))
591        prefix += '  %s ' % (prefix_char)
592        if 'cfg' in tree:
593            files = sorted(tree['cfg']['file'])
594            if len(files):
595                for f in range(0, len(files) - 1):
596                    self.output('; %s  |- %s' % (prefix, files[f]))
597                if 'bset' in tree and len(tree['bset'].keys()):
598                    c = '|'
599                else:
600                    c = '+'
601                self.output('; %s  %s- %s' % (prefix, c, files[f + 1]))
602        if 'bset' in tree:
603            nodes = sorted(tree['bset'].keys())
604            for node in range(0, len(nodes)):
605                if node == len(nodes) - 1:
606                    prefix_char = ' '
607                else:
608                    prefix_char = '|'
609                self.generate_ini_tree(nodes[node],
610                                       tree['bset'][nodes[node]],
611                                       prefix_char,
612                                       prefix)
613
614    def generate_ini_node(self, name, tree, sections = []):
615        if name not in sections:
616            sections += [name]
617            self.output('')
618            self.output('[%s]' % (name))
619            if 'bset' in tree and len(tree['bset']):
620                self.output(' packages = %s' % \
621                                (', '.join([_tree_name(n) for n in sorted(tree['bset'])])))
622            if 'cfg' in tree:
623                packages = {}
624                if 'sources' in tree['cfg']:
625                    _merge(packages, tree['cfg']['sources'])
626                if 'patches' in tree['cfg']:
627                    _merge(packages, tree['cfg']['patches'])
628                for package in packages:
629                    self.output(' %s = %s' % (package, ', '.join([s[0] for s in packages[package]])))
630            if 'bset' in tree:
631                for node in sorted(tree['bset'].keys()):
632                    self.generate_ini_node(_tree_name(node), tree['bset'][node], sections)
633
634    def generate_ini_source(self, sources):
635        self.output('')
636        self.output('[source]')
637        for source in sources:
638            self.output(' %s = %s' % (source[0], source[1]))
639
640    def generate_ini_hash(self, sources):
641        self.output('')
642        self.output('[hash]')
643        for source in sources:
644            if source[2] is None:
645                hash = ''
646            else:
647                hash = source[2].split()
648                hash = '%s:%s' % (hash[0], hash[1])
649            self.output(' %s = %s' % (source[0], hash))
650
651    def generate_ini(self):
652        #self.output(pp.pformat(self.tree))
653        nodes = sorted([node for node in self.tree.keys() if node != 'bset'])
654        self.output(';')
655        self.output('; Configuration Tree:')
656        for node in range(0, len(nodes)):
657            if node == len(nodes) - 1:
658                prefix_char = ' '
659            else:
660                prefix_char = '|'
661            self.generate_ini_tree(nodes[node], self.tree[nodes[node]], prefix_char)
662        self.output(';')
663        sources = []
664        for node in nodes:
665            sources += self.tree_sources(_tree_name(node), self.tree[node])
666        sources = sorted(set(sources))
667        self.generate_ini_source(sources)
668        self.generate_ini_hash(sources)
669        for node in nodes:
670            self.generate_ini_node(_tree_name(node), self.tree[node])
671
672    def write(self, name):
673        self.out = self.formatter.post_process()
674        if self.is_ini():
675            self.generate_ini()
676        if name is not None:
677            try:
678                o = open(path.host(name), "w")
679                o.write(self.out)
680                o.close()
681                del o
682            except IOError, err:
683                raise error.general('writing output file: %s: %s' % (name, err))
684
685    def generate(self, name, tree = None, opts = None, defaults = None):
686        self.bset_nesting += 1
687        self.buildset_start(name)
688        if tree is None:
689            tree = self.tree
690        if opts is None:
691            opts = self.opts
692        bset = setbuilder.buildset(name, self.configs, opts, defaults)
693        if name in tree:
694            raise error.general('duplicate build set in tree: %s' % (name))
695        tree[name] = { 'bset': { }, 'cfg': { 'file': []  } }
696        for c in bset.load():
697            macros = copy.copy(bset.macros)
698            if c.endswith('.bset'):
699                self.generate(c, tree[name]['bset'], bset.opts, macros)
700            elif c.endswith('.cfg'):
701                self.config(config.file(c, bset.opts, macros),
702                            tree[name]['cfg'], bset.opts, macros)
703            else:
704                raise error.general('invalid config type: %s' % (c))
705        self.buildset_end(name)
706        self.bset_nesting -= 1
707
708    def create(self, inname, outname = None, intro_text = None):
709        self.introduction(inname, intro_text)
710        self.generate(inname)
711        self.epilogue(inname)
712        self.write(outname)
713
714def run(args):
715    try:
716        optargs = { '--list-bsets':   'List available build sets',
717                    '--list-configs': 'List available configurations',
718                    '--format':       'Output format (text, html, asciidoc, ini, xml)',
719                    '--output':       'File name to output the report' }
720        opts = options.load(args, optargs)
721        if opts.get_arg('--output') and len(opts.params()) > 1:
722            raise error.general('--output can only be used with a single config')
723        print 'RTEMS Source Builder, Reporter v%s' % (version.str())
724        opts.log_info()
725        if not check.host_setup(opts):
726            log.warning('forcing build with known host setup problems')
727        configs = build.get_configs(opts)
728        if not setbuilder.list_bset_cfg_files(opts, configs):
729            output = opts.get_arg('--output')
730            if output is not None:
731                output = output[1]
732            formatter = text_formatter()
733            format_opt = opts.get_arg('--format')
734            if format_opt:
735                if len(format_opt) != 2:
736                    raise error.general('invalid format option: %s' % ('='.join(format_opt)))
737                if format_opt[1] == 'text':
738                    pass
739                elif format_opt[1] == 'asciidoc':
740                    formatter = asciidoc_formatter()
741                elif format_opt[1] == 'html':
742                    formatter = html_formatter()
743                elif format_opt[1] == 'ini':
744                    formatter = ini_formatter()
745                elif format_opt[1] == 'xml':
746                    formatter = xml_formatter()
747                else:
748                    raise error.general('invalid format: %s' % (format_opt[1]))
749            r = report(formatter, configs, opts)
750            for _config in opts.params():
751                if output is None:
752                    outname = path.splitext(_config)[0] + formatter.ext()
753                    outname = outname.replace('/', '-')
754                else:
755                    outname = output
756                config = build.find_config(_config, configs)
757                if config is None:
758                    raise error.general('config file not found: %s' % (inname))
759                r.create(config, outname)
760            del r
761        else:
762            raise error.general('invalid config type: %s' % (config))
763    except error.general, gerr:
764        print gerr
765        sys.exit(1)
766    except error.internal, ierr:
767        print ierr
768        sys.exit(1)
769    except error.exit, eerr:
770        pass
771    except KeyboardInterrupt:
772        log.notice('abort: user terminated')
773        sys.exit(1)
774    sys.exit(0)
775
776if __name__ == "__main__":
777    run(sys.argv)
Note: See TracBrowser for help on using the repository browser.