source: rtems-source-builder/source-builder/sb/reports.py @ 69e5938

4.104.114.95
Last change on this file since 69e5938 was 4266597, checked in by Chris Johns <chrisj@…>, on 03/13/13 at 04:08:22

Fix the second config call to pass defaults and opts.

  • Property mode set to 100644
File size: 14.6 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
30try:
31    import build
32    import check
33    import config
34    import defaults
35    import error
36    import git
37    import log
38    import path
39    import setbuilder
40except KeyboardInterrupt:
41    print 'user terminated'
42    sys.exit(1)
43except:
44    print 'error: unknown application load error'
45    sys.exit(1)
46
47#
48# Version of Sourcer Builder Build.
49#
50version = '0.1'
51
52def _notice(opts, text):
53    if not opts.quiet() and not log.default.has_stdout():
54        print text
55    log.output(text)
56    log.flush()
57
58class report:
59    """Report the build details about a package given a config file."""
60
61    line_len = 78
62
63    def __init__(self, format, _configs, _defaults, opts):
64        self.format = format
65        self.configs = _configs
66        self.defaults = _defaults
67        self.opts = opts
68        self.bset_nesting = 0
69        self.configs_active = False
70        self.out = ''
71        self.asciidoc = None
72
73    def _sbpath(self, *args):
74        p = self.opts.expand('%{_sbdir}', self.defaults)
75        for arg in args:
76            p = path.join(p, arg)
77        return os.path.abspath(path.host(p))
78
79    def output(self, text):
80        self.out += '%s\n' % (text)
81
82    def is_text(self):
83        return self.format == 'text'
84
85    def is_asciidoc(self):
86        return self.format == 'asciidoc' or self.format == 'html'
87
88    def setup(self):
89        if self.format == 'html':
90            try:
91                import asciidocapi
92            except:
93                raise error.general('installation error: no asciidocapi found')
94            asciidoc_py = self._sbpath(defaults.basepath, 'asciidoc', 'asciidoc.py')
95            try:
96                self.asciidoc = asciidocapi.AsciiDocAPI(asciidoc_py)
97            except:
98                raise error.general('application error: asciidocapi failed')
99
100    def header(self):
101        pass
102
103    def footer(self):
104        pass
105
106    def git_status(self):
107        text = 'RTEMS Source Builder Repository Status'
108        if self.is_asciidoc():
109            self.output('')
110            self.output("'''")
111            self.output('')
112            self.output('.%s' % (text))
113        else:
114            self.output('-' * self.line_len)
115            self.output('%s' % (text))
116        repo = git.repo('.', self.opts, self.defaults)
117        repo_valid = repo.valid()
118        if repo_valid:
119            if self.is_asciidoc():
120                self.output('*Remotes*:;;')
121            else:
122                self.output(' Remotes:')
123            repo_remotes = repo.remotes()
124            rc = 0
125            for r in repo_remotes:
126                rc += 1
127                if 'url' in repo_remotes[r]:
128                    text = repo_remotes[r]['url']
129                else:
130                    text = 'no URL found'
131                text = '%s: %s' % (r, text)
132                if self.is_asciidoc():
133                    self.output('. %s' % (text))
134                else:
135                    self.output('  %2d: %s' % (rc, text))
136            if self.is_asciidoc():
137                self.output('*Status*:;;')
138            else:
139                self.output(' Status:')
140            if repo.clean():
141                if self.is_asciidoc():
142                    self.output('Clean')
143                else:
144                    self.output('  Clean')
145            else:
146                if self.is_asciidoc():
147                    self.output('_Repository is dirty_')
148                else:
149                    self.output('  Repository is dirty')
150            repo_head = repo.head()
151            if self.is_asciidoc():
152                self.output('*Head*:;;')
153                self.output('Commit: %s' % (repo_head))
154            else:
155                self.output(' Head:')
156                self.output('  Commit: %s' % (repo_head))
157        else:
158            self.output('_Not a valid GIT repository_')
159        if self.is_asciidoc():
160            self.output('')
161            self.output("'''")
162            self.output('')
163
164    def introduction(self, name, intro_text):
165        if self.is_asciidoc():
166            h = 'RTEMS Source Builder Report'
167            self.output(h)
168            self.output('=' * len(h))
169            self.output(':doctype: book')
170            self.output(':toc2:')
171            self.output(':toclevels: 5')
172            self.output(':icons:')
173            self.output(':numbered:')
174            self.output(':data-uri:')
175            self.output('')
176            self.output('RTEMS Tools Project <rtems-users@rtems.org>')
177            self.output(datetime.datetime.now().ctime())
178            self.output('')
179            image = self._sbpath(defaults.basepath, 'images', 'rtemswhitebg.jpg')
180            self.output('image:%s["RTEMS",width="20%%"]' % (image))
181            self.output('')
182            if intro_text:
183                self.output('%s' % ('\n'.join(intro_text)))
184        else:
185            self.output('=' * self.line_len)
186            self.output('RTEMS Tools Project <rtems-users@rtems.org> %s' % datetime.datetime.now().ctime())
187            if intro_text:
188                self.output('')
189                self.output('%s' % ('\n'.join(intro_text)))
190            self.output('=' * self.line_len)
191            self.output('Report: %s' % (name))
192        self.git_status()
193
194    def config_start(self, name):
195        first = not self.configs_active
196        self.configs_active = True
197
198    def config_end(self, name):
199        if self.is_asciidoc():
200            self.output('')
201            self.output("'''")
202            self.output('')
203
204    def buildset_start(self, name):
205        if self.is_asciidoc():
206            h = '%s' % (name)
207            self.output('=%s %s' % ('=' * self.bset_nesting, h))
208        else:
209            self.output('=-' * (self.line_len / 2))
210            self.output('Build Set: %s' % (name))
211
212    def buildset_end(self, name):
213        self.configs_active = False
214
215    def source(self, package, source_tag):
216        return package.sources()
217
218    def patch(self, package, args):
219        return package.patches()
220
221    def output_info(self, name, info, separated = False):
222        if info is not None:
223            end = ''
224            if self.is_asciidoc():
225                if separated:
226                    self.output('*%s:*::' % (name))
227                    self.output('')
228                else:
229                    self.output('*%s:* ' % (name))
230                    end = ' +'
231                spaces = ''
232            else:
233                self.output(' %s:' % (name))
234                spaces = '  '
235            for l in info:
236                self.output('%s%s%s' % (spaces, l, end))
237            if self.is_asciidoc() and separated:
238                self.output('')
239
240    def output_directive(self, name, directive):
241        if directive is not None:
242            if self.is_asciidoc():
243                self.output('')
244                self.output('*%s*:' % (name))
245                self.output('--------------------------------------------')
246                spaces = ''
247            else:
248                self.output(' %s:' % (name))
249                spaces = '  '
250            for l in directive:
251                self.output('%s%s' % (spaces, l))
252            if self.is_asciidoc():
253                self.output('--------------------------------------------')
254
255    def config(self, configname, _defaults, _opts):
256
257        _config = config.file(configname, _defaults = _defaults, opts = _opts)
258        packages = _config.packages()
259        package = packages['main']
260        name = package.name()
261        self.config_start(name)
262        if self.is_asciidoc():
263            self.output('*Package*: _%s_ +' % (name))
264            self.output('*Config*: %s' % (configname))
265            self.output('')
266        else:
267            self.output('-' * self.line_len)
268            self.output('Package: %s' % (name))
269            self.output(' Config: %s' % (configname))
270        self.output_info('Summary', package.get_info('summary'), True)
271        self.output_info('URL', package.get_info('url'))
272        self.output_info('Version', package.get_info('version'))
273        self.output_info('Release', package.get_info('release'))
274        self.output_info('Build Arch', package.get_info('buildarch'))
275        if self.is_asciidoc():
276            self.output('')
277        sources = package.sources()
278        if self.is_asciidoc():
279            self.output('*Sources:*::')
280            if len(sources) == 0:
281                self.output('No sources')
282        else:
283            self.output('  Sources: %d' % (len(sources)))
284        c = 0
285        for s in sources:
286            c += 1
287            if self.is_asciidoc():
288                self.output('. %s' % (sources[s][0]))
289            else:
290                self.output('   %2d: %s' % (c, sources[s][0]))
291        patches = package.patches()
292        if self.is_asciidoc():
293            self.output('')
294            self.output('*Patches:*::')
295            if len(patches) == 0:
296                self.output('No patches')
297        else:
298            self.output('  Patches: %s' % (len(patches)))
299        c = 0
300        for p in patches:
301            c += 1
302            if self.is_asciidoc():
303                self.output('. %s' % (patches[p][0]))
304            else:
305                self.output('   %2d: %s' % (c, patches[p][0]))
306        self.output_directive('Preparation', package.prep())
307        self.output_directive('Build', package.build())
308        self.output_directive('Install', package.install())
309        self.output_directive('Clean', package.clean())
310        self.config_end(name)
311
312    def buildset(self, name):
313        self.bset_nesting += 1
314        self.buildset_start(name)
315        _opts = copy.deepcopy(self.opts)
316        _defaults = copy.deepcopy(self.defaults)
317        bset = setbuilder.buildset(name,
318                                   _configs = self.configs,
319                                   _defaults = _defaults,
320                                   opts = _opts)
321        for c in bset.load():
322            if c.endswith('.bset'):
323                self.buildset(c)
324            elif c.endswith('.cfg'):
325                self.config(c, _defaults, _opts)
326            else:
327                raise error.general('invalid config type: %s' % (c))
328        self.buildset_end(name)
329        self.bset_nesting -= 1
330
331    def generate(self, name):
332        if self.format == 'html':
333            if self.asciidoc is None:
334                raise error.general('asciidoc not initialised')
335            import StringIO
336            infile = StringIO.StringIO(self.out)
337            outfile = StringIO.StringIO()
338            self.asciidoc.execute(infile, outfile)
339            self.out = outfile.getvalue()
340            infile.close()
341            outfile.close()
342        try:
343            o = open(name, "w")
344            o.write(self.out)
345            o.close()
346            del o
347        except IOError, err:
348            raise error.general('writing output file: %s: %s' % (name, err))
349
350    def make(self, inname, outname, intro_text = None):
351        self.setup()
352        self.introduction(inname, intro_text)
353        config = build.find_config(inname, self.configs)
354        if config is None:
355            raise error.general('config file not found: %s' % (inname))
356        if config.endswith('.bset'):
357            self.buildset(config)
358        elif config.endswith('.cfg'):
359            self.config(config, self.defaults, self.opts)
360        else:
361            raise error.general('invalid config type: %s' % (config))
362        self.generate(outname)
363
364def run(args):
365    try:
366        optargs = { '--list-bsets':   'List available build sets',
367                    '--list-configs': 'List available configurations',
368                    '--format':       'Output format (text, html, asciidoc)',
369                    '--output':       'File name to output the report' }
370        opts, _defaults = defaults.load(args, optargs)
371        log.default = log.log(opts.logfiles())
372        if opts.get_arg('--output') and len(opts.params()) > 1:
373            raise error.general('--output can only be used with a single config')
374        print 'RTEMS Source Builder, Reporter v%s' % (version)
375        if not check.host_setup(opts, _defaults):
376            _notice(opts, 'warning: forcing build with known host setup problems')
377        configs = build.get_configs(opts, _defaults)
378        if not setbuilder.list_bset_cfg_files(opts, configs):
379            output = opts.get_arg('--output')
380            if output is not None:
381                output = output[1]
382            format = 'text'
383            ext = '.txt'
384            format_opt = opts.get_arg('--format')
385            if format_opt:
386                if len(format_opt) != 2:
387                    raise error.general('invalid format option: %s' % ('='.join(format_opt)))
388                if format_opt[1] == 'text':
389                    pass
390                elif format_opt[1] == 'asciidoc':
391                    format = 'asciidoc'
392                    ext = '.txt'
393                elif format_opt[1] == 'html':
394                    format = 'html'
395                    ext = '.html'
396                else:
397                    raise error.general('invalid format: %s' % (format_opt[1]))
398            r = report(format = format,
399                       _configs = configs,
400                       _defaults = _defaults,
401                       opts = opts)
402            for _config in opts.params():
403                if output is None:
404                    outname = path.splitext(_config)[0] + ext
405                else:
406                    outname = output
407                r.make(_config, outname)
408            del r
409    except error.general, gerr:
410        print gerr
411        sys.exit(1)
412    except error.internal, ierr:
413        print ierr
414        sys.exit(1)
415    except error.exit, eerr:
416        pass
417    except KeyboardInterrupt:
418        _notice(opts, 'abort: user terminated')
419        sys.exit(1)
420    sys.exit(0)
421
422if __name__ == "__main__":
423    run(sys.argv)
Note: See TracBrowser for help on using the repository browser.