source: rtems-source-builder/source-builder/sb/reports.py @ e794d0a

4.104.114.95
Last change on this file since e794d0a was e794d0a, checked in by Sebastian Huber <sebastian.huber@…>, on 12/08/14 at 05:44:56

sb: Add HTML generation to formatter class

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