summaryrefslogtreecommitdiffstats
path: root/source-builder/sb/reports.py
diff options
context:
space:
mode:
Diffstat (limited to 'source-builder/sb/reports.py')
-rw-r--r--source-builder/sb/reports.py268
1 files changed, 180 insertions, 88 deletions
diff --git a/source-builder/sb/reports.py b/source-builder/sb/reports.py
index 5eb8bb8..3aa0952 100644
--- a/source-builder/sb/reports.py
+++ b/source-builder/sb/reports.py
@@ -24,6 +24,7 @@
from __future__ import print_function
+import base64
import copy
import datetime
import os
@@ -139,127 +140,212 @@ class formatter(object):
def post_process(self):
return self.content
-class asciidoc_formatter(formatter):
+class markdown_formatter(formatter):
def __init__(self):
- super(asciidoc_formatter, self).__init__()
+ super(markdown_formatter, self).__init__()
+ self.level_current = 1
+ self.level_path = '0.'
+ self.levels = { '0.': 0 }
+ self.cols = [20, 55]
+
+ def _heading(self, heading, level):
+ return '%s %s' % ('#' * level, heading)
+
+ def _strong(self, s):
+ return '__' + s + '__'
+
+ def _bold(self, s):
+ return '__' + s + '__'
+
+ def _italic(self, s):
+ return '_' + s + '_'
+
+ def _table_line(self):
+ l = '|'
+ for c in self.cols:
+ l += '-' * c + '|'
+ return l
+
+ def _table_row(self, cols):
+ if len(cols) != len(self.cols):
+ raise error.general('invalid table column count')
+ l = '|'
+ for c in range(0, len(cols)):
+ l += '%-*s|' % (self.cols[c], cols[c])
+ return l
+
+ def _btext(self, level, text):
+ return '> ' * (level - 1) + text
+
+ def _bline(self, level, text):
+ self.line(self._btext(level, text))
+
+ def _level(self, nest_level):
+ if nest_level > self.level_current:
+ self.level_path += '%d.' % (self.levels[self.level_path])
+ if nest_level < self.level_current:
+ self.level_path = self.level_path[:-2]
+ if self.level_path not in self.levels:
+ self.levels[self.level_path] = 0
+ self.level_current = nest_level
+ self.levels[self.level_path] += 1
+ return '%s%d.' % (self.level_path[2:], self.levels[self.level_path])
def format(self):
- return 'asciidoc'
+ return 'markdown'
def ext(self):
- return '.txt'
+ return '.md'
def introduction(self, name, now, intro_text):
- h = 'RTEMS Source Builder Report'
- self.line(h)
- self.line('=' * len(h))
- self.line(':doctype: book')
- self.line(':toc2:')
- self.line(':toclevels: 5')
- self.line(':icons:')
- self.line(':numbered:')
- self.line(':data-uri:')
- self.line('')
- self.line(_title)
- self.line(now)
+ self.line('- - -')
+ self.line(self._heading('RTEMS Source Builder Report', 1))
+ self.line(self._strong(_title))
self.line('')
- image = _make_path(self.sbpath, options.basepath, 'images', 'rtemswhitebg.jpg')
- self.line('image:%s["RTEMS",width="20%%"]' % (image))
+ self.line(self._bold('Generated: ' + now))
self.line('')
if intro_text:
self.line('%s' % ('\n'.join(intro_text)))
+ self.line('')
+ self.line('')
+ self.line('- - -')
+ self.line(self._heading('Table Of Contents', 2))
+ self.line('')
+ self.line('[TOC]')
+ self.line('')
def release_status(self, release_string):
self.line('')
- self.line("'''")
+ self.line(self._heading(_release_status_text, 2))
self.line('')
- self.line('.%s' % (_release_status_text))
self.line('*Version*: %s;;' % (release_string))
self.line('')
- self.line("'''")
- self.line('')
def git_status(self, valid, dirty, head, remotes):
self.line('')
- self.line("'''")
- self.line('')
- self.line('.%s' % (_git_status_text))
+ self.line('- - -')
+ self.line(self._heading(_git_status_text, 2))
if valid:
- self.line('*Remotes*:;;')
+ self.line(self._strong('Remotes:'))
+ self.line('')
+ rc = 1
for r in remotes:
if 'url' in remotes[r]:
text = remotes[r]['url']
else:
text = 'no URL found'
- text = '%s: %s' % (r, text)
- self.line('. %s' % (text))
- self.line('*Status*:;;')
+ self.line('%d. %s: %s' % (rc, r, text))
+ rc += 1
+ self.line('')
+ self.line(self._strong('Status:'))
+ self.line('')
if dirty:
- self.line('_Repository is dirty_')
+ self.line('> ' + self._italic('Repository is dirty'))
else:
- self.line('Clean')
- self.line('*Head*:;;')
- self.line('Commit: %s' % (head))
+ self.line('> Clean')
+ self.line('>')
+ self.line('> ' + self._bold('Head: ') + head)
else:
- self.line('_Not a valid GIT repository_')
- self.line('')
- self.line("'''")
+ self.line('> ' + self._italic('Not a valid GIT repository'))
self.line('')
def config(self, nest_level, name, _config):
- self.line('*Package*: _%s_ +' % (name))
- self.line('*Config*: %s' % (_config.file_name()))
- self.line('')
+ self._bline(nest_level, self._bold('Package:'))
+ self._bline(nest_level, '')
+ self._bline(nest_level + 1, self._table_row([self._bold('Item'),
+ self._bold('Description')]))
+ self._bline(nest_level + 1, self._table_line())
+ self._bline(nest_level + 1, self._table_row(['Package', name]))
+ self._bline(nest_level + 1, self._table_row(['Config',
+ _config.file_name()]))
def config_end(self, nest_level, name):
- self.line('')
- self.line("'''")
- self.line('')
+ self._bline(nest_level + 1, '')
def buildset_start(self, nest_level, name):
- h = '%s' % (name)
- self.line('=%s %s' % ('=' * int(nest_level), h))
+ if nest_level == 1:
+ self.line('- - -')
+ self._bline(nest_level,
+ self._heading('RTEMS Source Builder Packages', 2))
+ self._bline(nest_level,
+ self._heading('%s Build %s' % (self._level(nest_level), name), 3))
def info(self, nest_level, name, info, separated):
- end = ''
- if separated:
- self.line('*%s:*::' % (name))
- self.line('')
- else:
- self.line('*%s:* ' % (name))
- end = ' +'
- spaces = ''
- for l in info:
- self.line('%s%s%s' % (spaces, l, end))
- if separated:
- self.line('')
+ self._bline(nest_level + 1,
+ self._table_row([name, ' '.join(info)]))
def directive(self, nest_level, name, data):
- self.line('')
- self.line('*%s*:' % (name))
- self.line('--------------------------------------------')
+ self._bline(nest_level, '')
+ self._bline(nest_level, self._bold(name + ':'))
for l in data:
- self.line(l)
- self.line('--------------------------------------------')
+ self._bline(nest_level + 1, ' ' * 4 + l)
def files(self, nest_level, singular, plural, _files):
- self.line('')
- self.line('*' + plural + ':*::')
+ self._bline(nest_level, '')
+ self._bline(nest_level, self._bold(plural + ':'))
+ self._bline(nest_level, '')
if len(_files) == 0:
- self.line('No ' + plural.lower())
+ self._bline(nest_level + 1, 'No ' + plural.lower())
+ fc = 0
for name in _files:
for s in _files[name]:
- self.line('. %s' % (s[0]))
+ fc += 1
if s[1] is None:
- h = 'No checksum'
+ h = self._bold('No checksum')
else:
hash = s[1].split()
h = '%s: %s' % (hash[0], hash[1])
- self.line('+\n%s\n' % (h))
+ self._bline(nest_level,
+ '%d. [%s](%s "%s %s")<br/>' % (fc, s[0], s[0],
+ name, singular.lower()))
+ self._bline(nest_level,
+ ' <span class=checksum>%s</span>' % (h))
-class html_formatter(asciidoc_formatter):
+class html_formatter(markdown_formatter):
def __init__(self):
super(html_formatter, self).__init__()
+ self.html_header = '<!DOCTYPE html>' + os.linesep + \
+ '<html lang="en">' + os.linesep + \
+ '<head>' + os.linesep + \
+ '<title>RTEMS RSB - @BUILD@</title>' + os.linesep + \
+ '<meta http-equiv="content-type" content="text/html; charset=UTF-8" />' + os.linesep + \
+ '<meta name="created" content="@NOW@" />' + os.linesep + \
+ '<meta name="description" content="RTEMS RSB Report" />' + os.linesep + \
+ '<meta name="keywords" content="RTEMS RSB" />' + os.linesep + \
+ '<meta charset="utf-8">' + os.linesep + \
+ '<meta http-equiv="X-UA-Compatible" content="IE=edge">' + os.linesep + \
+ '<meta name="viewport" content="width=device-width, initial-scale=1">' + os.linesep + \
+ '<style type="text/css">' + os.linesep + \
+ 'body {' + os.linesep + \
+ ' font-family: arial, helvetica, serif;' + os.linesep + \
+ ' font-style: normal;' + os.linesep + \
+ ' font-weight: 400;' + os.linesep + \
+ '}' + os.linesep + \
+ 'h1, h2 { margin: 10px 5px 10px 5px; }' + os.linesep + \
+ 'h1 { font-size: 28px; }' + os.linesep + \
+ 'h2 { font-size: 22px;}' + os.linesep + \
+ 'h3 { font-size: 18px; }' + os.linesep + \
+ 'p, ol, blockquote, h3, table, pre { margin: 1px 20px 2px 7px; }' + os.linesep + \
+ 'table, th, td, pre { border: 1px solid gray; border-spacing: 0px; }' + os.linesep + \
+ 'table { width: 100%; }' + os.linesep + \
+ 'th, td { padding: 1px; }' + os.linesep + \
+ 'pre { padding: 4px; }' + os.linesep + \
+ '.checksum { font-size: 12px; }' + os.linesep + \
+ '</style>' + os.linesep + \
+ '</head>' + os.linesep + \
+ '<body>' + os.linesep
+ self.html_footer = '</body>' + os.linesep + \
+ '</html>' + os.linesep
+
+ def _logo(self):
+ logo = _make_path(self.sbpath, options.basepath, 'images', 'rtemswhitebg.jpg')
+ try:
+ with open(logo, "rb") as image:
+ b64 = base64.b64encode(image.read())
+ except:
+ raise error.general('installation error: no logo found')
+ logo = '<img alt="RTEMS Project" height="100" src="data:image/png;base64,' + b64 + '" />'
+ return logo
def format(self):
return 'html'
@@ -267,24 +353,30 @@ class html_formatter(asciidoc_formatter):
def ext(self):
return '.html'
+ def introduction(self, name, now, intro_text):
+ self.name = name
+ self.now = now
+ super(html_formatter, self).introduction(name, now, intro_text)
+
def post_process(self):
- import io
- infile = io.StringIO(self.content)
- outfile = io.StringIO()
try:
- import asciidocapi
+ import markdown
except:
- raise error.general('installation error: no asciidocapi found')
- asciidoc_py = _make_path(self.sbpath, options.basepath, 'asciidoc', 'asciidoc.py')
+ raise error.general('installation error: no markdown found')
try:
- asciidoc = asciidocapi.AsciiDocAPI(asciidoc_py)
+ out = markdown.markdown(self.content,
+ output_format = 'html5',
+ extensions = ['markdown.extensions.toc',
+ 'markdown.extensions.tables',
+ 'markdown.extensions.sane_lists',
+ 'markdown.extensions.smarty'])
except:
- raise error.general('application error: asciidocapi failed')
- asciidoc.execute(infile, outfile)
- out = outfile.getvalue()
- infile.close()
- outfile.close()
- return out
+ raise
+ raise error.general('application error: markdown failed')
+ header = self.html_header.replace('@BUILD@', self.name).replace('@NOW@', self.now)
+ footer = self.html_footer
+ logo = self._logo()
+ return header + logo + out + footer
class text_formatter(formatter):
def __init__(self):
@@ -503,8 +595,8 @@ class report:
if type(formatter) == str:
if formatter == 'text':
self.formatter = text_formatter()
- elif formatter == 'asciidoc':
- self.formatter = asciidoc_formatter()
+ elif formatter == 'markdown':
+ self.formatter = markdown_formatter()
elif formatter == 'html':
self.formatter = html_formatter()
elif formatter == 'ini':
@@ -784,9 +876,9 @@ def run(args):
try:
optargs = { '--list-bsets': 'List available build sets',
'--list-configs': 'List available configurations',
- '--format': 'Output format (text, html, asciidoc, ini, xml)',
+ '--format': 'Output format (text, html, markdown, ini, xml)',
'--output': 'File name to output the report' }
- opts = options.load(args, optargs)
+ opts = options.load(args, optargs, logfile = False)
if opts.get_arg('--output') and len(opts.params()) > 1:
raise error.general('--output can only be used with a single config')
print('RTEMS Source Builder, Reporter, %s' % (version.str()))
@@ -805,8 +897,8 @@ def run(args):
raise error.general('invalid format option: %s' % ('='.join(format_opt)))
if format_opt[1] == 'text':
pass
- elif format_opt[1] == 'asciidoc':
- formatter = asciidoc_formatter()
+ elif format_opt[1] == 'markdown':
+ formatter = markdown_formatter()
elif format_opt[1] == 'html':
formatter = html_formatter()
elif format_opt[1] == 'ini':
@@ -824,7 +916,7 @@ def run(args):
outname = output
config = build.find_config(_config, configs)
if config is None:
- raise error.general('config file not found: %s' % (inname))
+ raise error.general('config file not found: %s' % (_config))
r.create(config, outname)
del r
else: