sb: Complete support for INI file reporting.

The INI file format provides a parsable configuration file format.
This commit is contained in:
Chris Johns
2014-08-12 12:22:30 +10:00
parent 91462f6d5e
commit 8db5212665
3 changed files with 210 additions and 88 deletions

1
rtems/.gitignore vendored
View File

@@ -5,6 +5,7 @@ tar
build
*.txt
*.html
*.ini
#*#
.*
log_*

View File

@@ -27,6 +27,9 @@ import datetime
import os
import sys
import pprint
pp = pprint.PrettyPrinter(indent = 2)
try:
import build
import check
@@ -46,6 +49,17 @@ except:
print 'error: unknown application load error'
sys.exit(1)
def _tree_name(path_):
return path.splitext(path.basename(path_))[0]
def _merge(_dict, new):
new = copy.deepcopy(new)
for i in new:
if i not in _dict:
_dict[i] = new[i]
else:
_dict[i] += new[i]
class report:
"""Report the build details about a package given a config file."""
@@ -67,9 +81,8 @@ class report:
self.cini = ';'
else:
self.cini = ''
self.tree = {}
self.files = { 'buildsets':[], 'configs':[] }
self.sources = {}
self.patches = {}
def _sbpath(self, *args):
p = self.macros.expand('%{_sbdir}')
@@ -177,6 +190,7 @@ class report:
def introduction(self, name, intro_text = None):
now = datetime.datetime.now().ctime()
title = 'RTEMS Tools Project <users@rtems.org>'
if self.is_asciidoc():
h = 'RTEMS Source Builder Report'
self.output(h)
@@ -188,7 +202,7 @@ class report:
self.output(':numbered:')
self.output(':data-uri:')
self.output('')
self.output('RTEMS Tools Project <rtems-users@rtems.org>')
self.output(title)
self.output(datetime.datetime.now().ctime())
self.output('')
image = self._sbpath(options.basepath, 'images', 'rtemswhitebg.jpg')
@@ -198,14 +212,14 @@ class report:
self.output('%s' % ('\n'.join(intro_text)))
elif self.is_ini():
self.output(';')
self.output('; RTEMS Tools Project <rtems-users@rtems.org> %s' % now)
self.output('; %s %s' % (title, now))
if intro_text:
self.output(';')
self.output('; %s' % ('\n; '.join(intro_text)))
self.output(';')
else:
self.output('=' * self.line_len)
self.output('RTEMS Tools Project <rtems-users@rtems.org> %s' % now)
self.output('%s %s' % (title, now))
if intro_text:
self.output('')
self.output('%s' % ('\n'.join(intro_text)))
@@ -245,9 +259,15 @@ class report:
def source(self, macros):
def err(msg):
raise error.general('%s' % (msg))
_srcs = {}
for p in sources.get_source_names(macros, err):
if 'setup' in sources.get_source_keys(p, macros, err):
_srcs[p] = \
[s for s in sources.get_sources(p, macros, err) if not s.startswith('%setup')]
_srcs[p] = [macros.expand(s) for s in _srcs[p]]
srcs = {}
for n in sources.get_source_names(macros, err):
srcs[n] = sources.get_sources(n, macros, err)
for p in _srcs:
srcs[p] = [(s, sources.get_hash(path.basename(s).lower(), macros)) for s in _srcs[p]]
return srcs
def patch(self, macros):
@@ -255,18 +275,15 @@ class report:
raise error.general('%s' % (msg))
_patches = {}
for n in sources.get_patch_names(macros, err):
_patches[n] = sources.get_patches(n, macros, err)
if 'setup' in sources.get_patch_keys(n, macros, err):
_patches[n] = \
[p for p in sources.get_patches(n, macros, err) if not p.startswith('%setup')]
_patches[n] = [macros.expand(p.split()[-1]) for p in _patches[n]]
patches = {}
for n in _patches:
pl = []
for p in _patches[n]:
pl += [p.split()[-1]]
patches[n] = pl
patches[n] = [(p, sources.get_hash(path.basename(p).lower(), macros)) for p in _patches[n]]
return patches
def hash(self, name, macros):
return sources.get_hash(name, macros)
def output_info(self, name, info, separated = False):
if info is not None:
end = ''
@@ -301,25 +318,41 @@ class report:
if self.is_asciidoc():
self.output('--------------------------------------------')
def get_sources_patches(self, macros):
def _merge(src, dst):
for name in src:
if name not in dst:
dst[name] = []
for s in src[name]:
dst[name] += [s]
dst[name] = dst[name]
sources = self.source(macros)
_merge(sources, self.sources)
patches = self.patch(macros)
_merge(patches, self.patches)
return sources, patches
def tree_sources(self, name, tree, sources = []):
if 'cfg' in tree:
packages = {}
if 'sources' in tree['cfg']:
_merge(packages, tree['cfg']['sources'])
if 'patches' in tree['cfg']:
_merge(packages, tree['cfg']['patches'])
for package in packages:
for source in packages[package]:
if not source[0].startswith('git') and not source[0].startswith('cvs'):
sources += [(path.basename(source[0]), source[0], source[1])]
if 'bset' in tree:
for node in sorted(tree['bset'].keys()):
self.tree_sources(_tree_name(node), tree['bset'][node], sources)
return sources
def config(self, _config, opts, macros):
def config(self, _config, tree, opts, macros):
packages = _config.packages()
package = packages['main']
name = package.name()
sources, patches = self.get_sources_patches(macros)
if len(name) == 0:
return
tree['file'] += [_config.file_name()]
sources = self.source(macros)
patches = self.patch(macros)
if len(sources):
if 'sources' in tree:
tree['sources'] = dict(tree['sources'].items() + sources.items())
else:
tree['sources'] = sources
if len(patches):
if 'patches' in tree:
tree['patches'] = dict(tree['patches'].items() + patches.items())
else:
tree['patches'] = patches
self.config_start(name, _config)
if self.is_ini():
return
@@ -349,17 +382,16 @@ class report:
for s in sources[name]:
c += 1
if self.is_asciidoc():
self.output('. %s' % (s))
self.output('. %s' % (s[0]))
else:
self.output(' %2d: %s' % (c, s))
hash = self.hash(path.basename(s).lower(), macros)
if hash is None:
self.output(' %2d: %s' % (c, s[0]))
if s[1] is None:
h = 'No checksum'
else:
hash = hash.split()
hash = s[1].split()
h = '%s: %s' % (hash[0], hash[1])
if self.is_asciidoc():
self.output(' %s' % (h))
self.output('+\n%s\n' % (h))
else:
self.output(' %s' % (h))
if self.is_asciidoc():
@@ -370,20 +402,21 @@ class report:
else:
self.output(' Patches: %s' % (len(patches)))
c = 0
for p in patches:
c += 1
if self.is_asciidoc():
self.output('. %s' % (patches[p][0]))
else:
self.output(' %2d: %s' % (c, patches[p][0]))
hash = self.hash(path.basename(s).lower(), macros)
for name in patches:
for p in patches[name]:
c += 1
if self.is_asciidoc():
self.output('. %s' % (p[0]))
else:
self.output(' %2d: %s' % (c, p[0]))
hash = p[1]
if hash is None:
h = 'No checksum'
else:
hash = hash.split()
h = '%s: %s' % (hash[0], hash[1])
if self.is_asciidoc():
self.output(' %s' % (h))
self.output('+\n(%s)\n' % (h))
else:
self.output(' %s' % (h))
self.output_directive('Preparation', package.prep())
@@ -392,30 +425,94 @@ class report:
self.output_directive('Clean', package.clean())
self.config_end(name, _config)
def generate_ini(self, sysname):
self.output(';')
self.output('; Buildset File(s):')
for bf in sorted(self.files['buildsets']):
self.output('; %s' % (bf))
self.output(';')
self.output('; Configuration File(s):')
for cf in sorted(self.files['configs']):
self.output('; %s' % (cf))
names = sorted(set(self.sources.keys() + self.patches.keys()))
self.output(';')
self.output('')
self.output('[%s]' % (sysname))
for name in names:
self.output('%s = rtems-%s' % (name, name))
for name in names:
self.output('')
self.output('[%s-%s]' % (sysname, name))
if name in self.sources:
self.output('sources = %s' % (', '.join(set(self.sources[name]))))
if name in self.patches:
self.output('patches = %s' % (', '.join(set(self.patches[name]))))
def generate_ini_tree(self, name, tree, prefix_char, prefix = ''):
if prefix_char == '|':
c = '|'
else:
c = '+'
self.output('; %s %s- %s' % (prefix, c, name))
prefix += ' %s ' % (prefix_char)
if 'cfg' in tree:
files = sorted(tree['cfg']['file'])
if len(files):
for f in range(0, len(files) - 1):
self.output('; %s |- %s' % (prefix, files[f]))
if 'bset' in tree and len(tree['bset'].keys()):
c = '|'
else:
c = '+'
self.output('; %s %s- %s' % (prefix, c, files[f + 1]))
if 'bset' in tree:
nodes = sorted(tree['bset'].keys())
for node in range(0, len(nodes)):
if node == len(nodes) - 1:
prefix_char = ' '
else:
prefix_char = '|'
self.generate_ini_tree(nodes[node],
tree['bset'][nodes[node]],
prefix_char,
prefix)
def write(self, sysname, name):
def generate_ini_node(self, name, tree, sections = []):
if name not in sections:
sections += [name]
self.output('')
self.output('[%s]' % (name))
if 'bset' in tree and len(tree['bset']):
self.output(' packages = %s' % \
(', '.join([_tree_name(n) for n in sorted(tree['bset'])])))
if 'cfg' in tree:
packages = {}
if 'sources' in tree['cfg']:
_merge(packages, tree['cfg']['sources'])
if 'patches' in tree['cfg']:
_merge(packages, tree['cfg']['patches'])
for package in packages:
self.output(' %s = %s' % (package, ', '.join([s[0] for s in packages[package]])))
if 'bset' in tree:
for node in sorted(tree['bset'].keys()):
self.generate_ini_node(_tree_name(node), tree['bset'][node], sections)
def generate_ini_source(self, sources):
self.output('')
self.output('[source]')
for source in sources:
self.output(' %s = %s' % (source[0], source[1]))
def generate_ini_hash(self, sources):
self.output('')
self.output('[hash]')
for source in sources:
if source[2] is None:
hash = ''
else:
hash = source[2].split()
hash = '%s:%s' % (hash[0], hash[1])
self.output(' %s = %s' % (source[0], hash))
def generate_ini(self):
#self.output(pp.pformat(self.tree))
nodes = sorted([node for node in self.tree.keys() if node != 'bset'])
self.output(';')
self.output('; Configuration Tree:')
for node in range(0, len(nodes)):
if node == len(nodes) - 1:
prefix_char = ' '
else:
prefix_char = '|'
self.generate_ini_tree(nodes[node], self.tree[nodes[node]], prefix_char)
self.output(';')
sources = []
for node in nodes:
sources += self.tree_sources(_tree_name(node), self.tree[node])
sources = sorted(set(sources))
self.generate_ini_source(sources)
self.generate_ini_hash(sources)
for node in nodes:
self.generate_ini_node(_tree_name(node), self.tree[node])
def write(self, name):
if self.is_html():
if self.asciidoc is None:
raise error.general('asciidoc not initialised')
@@ -427,7 +524,7 @@ class report:
infile.close()
outfile.close()
elif self.is_ini():
self.generate_ini(sysname)
self.generate_ini()
if name is not None:
try:
o = open(path.host(name), "w")
@@ -437,34 +534,37 @@ class report:
except IOError, err:
raise error.general('writing output file: %s: %s' % (name, err))
def generate(self, name, opts = None, macros = None):
def generate(self, name, tree = None, opts = None, defaults = None):
self.bset_nesting += 1
self.buildset_start(name)
if tree is None:
tree = self.tree
if opts is None:
opts = self.opts
if macros is None:
macros = self.macros
bset = setbuilder.buildset(name, self.configs, opts, macros)
bset = setbuilder.buildset(name, self.configs, opts, defaults)
if name in tree:
raise error.general('duplicate build set in tree: %s' % (name))
tree[name] = { 'bset': { }, 'cfg': { 'file': [] } }
for c in bset.load():
macros = copy.copy(bset.macros)
if c.endswith('.bset'):
self.generate(c, bset.opts, bset.macros)
self.generate(c, tree[name]['bset'], bset.opts, macros)
elif c.endswith('.cfg'):
self.config(config.file(c, bset.opts, bset.macros),
bset.opts, bset.macros)
self.config(config.file(c, bset.opts, macros),
tree[name]['cfg'], bset.opts, macros)
else:
raise error.general('invalid config type: %s' % (c))
self.buildset_end(name)
self.bset_nesting -= 1
def create(self, sysname, inname, outname = None, intro_text = None):
def create(self, inname, outname = None, intro_text = None):
self.setup()
self.introduction(inname, intro_text)
self.generate(inname)
self.write(sysname, outname)
self.write(outname)
def run(args):
try:
sysname = 'rtems'
optargs = { '--list-bsets': 'List available build sets',
'--list-configs': 'List available configurations',
'--format': 'Output format (text, html, asciidoc, ini)',
@@ -510,7 +610,7 @@ def run(args):
config = build.find_config(_config, configs)
if config is None:
raise error.general('config file not found: %s' % (inname))
r.create(sysname, config, outname)
r.create(config, outname)
del r
else:
raise error.general('invalid config type: %s' % (config))

View File

@@ -32,9 +32,14 @@ def add(label, args, macros, error):
error('%%%s requires at least 2 arguments' % (label))
_map = '%s-%s' % (label, args[0])
macros.create_map(_map)
index = 0
while True:
key = '%s%d' % (label, index)
if key not in macros.map_keys(_map):
break
index += 1
macros.set_write_map(_map)
index = macros.map_num_keys(_map)
macros.define('%s%d' % (label, index), ' '.join(args[1:]))
macros.define(key, ' '.join(args[1:]))
macros.unset_write_map()
return None
@@ -55,8 +60,14 @@ def setup(label, args, macros, error):
args = _args(args)
if len(args) < 2:
error('%%%s requires at least 2 arguments: %s' % (label, ' '.join(args)))
ss = '%%setup %s %s' % (label, ' '.join(args))
_map = '%s-%s' % (label, args[0])
return ['%%setup %s %s' % (label, ' '.join(args))]
if 'setup' in macros.map_keys(_map):
error('%%%s already setup source: %s' % (label, ' '.join(args)))
macros.set_write_map(_map)
macros.define('setup', ss)
macros.unset_write_map()
return [ss]
def process(label, args, macros, error):
if label != 'source' and label != 'patch':
@@ -87,11 +98,11 @@ def hash(args, macros, error):
macros.unset_write_map()
return None
def get(type_, name, macros, error):
_map = '%s-%s' % (type_, name)
def get(label, name, macros, error):
_map = '%s-%s' % (label, name)
keys = macros.map_keys(_map)
if len(keys) == 0:
error('no %s set: %s (%s)' % (type_, name, _map))
error('no %s set: %s (%s)' % (label, name, _map))
srcs = []
for s in keys:
sm = macros.get(s, globals = False, maps = _map)
@@ -106,11 +117,21 @@ def get_sources(name, macros, error):
def get_patches(name, macros, error):
return get('patch', name, macros, error)
def get_names(type_, macros, error):
def get_keys(label, name, macros, error):
_map = '%s-%s' % (label, name)
return macros.map_keys(_map)
def get_source_keys(name, macros, error):
return get_keys('source', name, macros, error)
def get_patch_keys(name, macros, error):
return get_keys('patch', name, macros, error)
def get_names(label, macros, error):
names = []
for m in macros.maps():
if m.startswith('%s-' % (type_)):
names += [m[len('%s-' % (type_)):]]
if m.startswith('%s-' % (label)):
names += [m[len('%s-' % (label)):]]
return names
def get_source_names(macros, error):