mirror of
https://git.rtems.org/rtems-source-builder
synced 2024-10-09 07:15:10 +08:00
424 lines
14 KiB
Python
424 lines
14 KiB
Python
#
|
|
# RTEMS Tools Project (http://www.rtems.org/)
|
|
# Copyright 2010-2013 Chris Johns (chrisj@rtems.org)
|
|
# All rights reserved.
|
|
#
|
|
# This file is part of the RTEMS Tools package in 'rtems-tools'.
|
|
#
|
|
# Permission to use, copy, modify, and/or distribute this software for any
|
|
# purpose with or without fee is hereby granted, provided that the above
|
|
# copyright notice and this permission notice appear in all copies.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
#
|
|
# This code builds a package given a config file. It only builds to be
|
|
# installed not to be package unless you run a packager around this.
|
|
#
|
|
|
|
import copy
|
|
import datetime
|
|
import os
|
|
import sys
|
|
|
|
try:
|
|
import build
|
|
import check
|
|
import config
|
|
import defaults
|
|
import error
|
|
import git
|
|
import log
|
|
import path
|
|
import setbuilder
|
|
except KeyboardInterrupt:
|
|
print 'user terminated'
|
|
sys.exit(1)
|
|
except:
|
|
print 'error: unknown application load error'
|
|
sys.exit(1)
|
|
|
|
#
|
|
# Version of Sourcer Builder Build.
|
|
#
|
|
version = '0.1'
|
|
|
|
def _notice(opts, text):
|
|
if not opts.quiet() and not log.default.has_stdout():
|
|
print text
|
|
log.output(text)
|
|
log.flush()
|
|
|
|
class report:
|
|
"""Report the build details about a package given a config file."""
|
|
|
|
line_len = 78
|
|
|
|
def __init__(self, format, _configs, _defaults, opts):
|
|
self.format = format
|
|
self.configs = _configs
|
|
self.defaults = _defaults
|
|
self.opts = opts
|
|
self.bset_nesting = 0
|
|
self.configs_active = False
|
|
self.out = ''
|
|
self.asciidoc = None
|
|
|
|
def _sbpath(self, *args):
|
|
p = self.opts.expand('%{_sbdir}', self.defaults)
|
|
for arg in args:
|
|
p = path.join(p, arg)
|
|
return os.path.abspath(path.host(p))
|
|
|
|
def output(self, text):
|
|
self.out += '%s\n' % (text)
|
|
|
|
def is_text(self):
|
|
return self.format == 'text'
|
|
|
|
def is_asciidoc(self):
|
|
return self.format == 'asciidoc' or self.format == 'html'
|
|
|
|
def setup(self):
|
|
if self.format == 'html':
|
|
try:
|
|
import asciidocapi
|
|
except:
|
|
raise error.general('installation error: no asciidocapi found')
|
|
asciidoc_py = self._sbpath(defaults.basepath, 'asciidoc', 'asciidoc.py')
|
|
try:
|
|
self.asciidoc = asciidocapi.AsciiDocAPI(asciidoc_py)
|
|
except:
|
|
raise error.general('application error: asciidocapi failed')
|
|
|
|
def header(self):
|
|
pass
|
|
|
|
def footer(self):
|
|
pass
|
|
|
|
def git_status(self):
|
|
text = 'RTEMS Source Builder Repository Status'
|
|
if self.is_asciidoc():
|
|
self.output('')
|
|
self.output("'''")
|
|
self.output('')
|
|
self.output('.%s' % (text))
|
|
else:
|
|
self.output('-' * self.line_len)
|
|
self.output('%s' % (text))
|
|
repo = git.repo('.', self.opts, self.defaults)
|
|
repo_valid = repo.valid()
|
|
if repo_valid:
|
|
if self.is_asciidoc():
|
|
self.output('*Remotes*:;;')
|
|
else:
|
|
self.output(' Remotes:')
|
|
repo_remotes = repo.remotes()
|
|
rc = 0
|
|
for r in repo_remotes:
|
|
rc += 1
|
|
if 'url' in repo_remotes[r]:
|
|
text = repo_remotes[r]['url']
|
|
else:
|
|
text = 'no URL found'
|
|
text = '%s: %s' % (r, text)
|
|
if self.is_asciidoc():
|
|
self.output('. %s' % (text))
|
|
else:
|
|
self.output(' %2d: %s' % (rc, text))
|
|
if self.is_asciidoc():
|
|
self.output('*Status*:;;')
|
|
else:
|
|
self.output(' Status:')
|
|
if repo.clean():
|
|
if self.is_asciidoc():
|
|
self.output('Clean')
|
|
else:
|
|
self.output(' Clean')
|
|
else:
|
|
if self.is_asciidoc():
|
|
self.output('_Repository is dirty_')
|
|
else:
|
|
self.output(' Repository is dirty')
|
|
repo_head = repo.head()
|
|
if self.is_asciidoc():
|
|
self.output('*Head*:;;')
|
|
self.output('Commit: %s' % (repo_head))
|
|
else:
|
|
self.output(' Head:')
|
|
self.output(' Commit: %s' % (repo_head))
|
|
else:
|
|
self.output('_Not a valid GIT repository_')
|
|
if self.is_asciidoc():
|
|
self.output('')
|
|
self.output("'''")
|
|
self.output('')
|
|
|
|
def introduction(self, name, intro_text):
|
|
if self.is_asciidoc():
|
|
h = 'RTEMS Source Builder Report'
|
|
self.output(h)
|
|
self.output('=' * len(h))
|
|
self.output(':doctype: book')
|
|
self.output(':toc2:')
|
|
self.output(':toclevels: 5')
|
|
self.output(':icons:')
|
|
self.output(':numbered:')
|
|
self.output(':data-uri:')
|
|
self.output('')
|
|
self.output('RTEMS Tools Project <rtems-users@rtems.org>')
|
|
self.output(datetime.datetime.now().ctime())
|
|
self.output('')
|
|
image = self._sbpath(defaults.basepath, 'images', 'rtemswhitebg.jpg')
|
|
self.output('image:%s["RTEMS",width="20%%"]' % (image))
|
|
self.output('')
|
|
if intro_text:
|
|
self.output('%s' % ('\n'.join(intro_text)))
|
|
else:
|
|
self.output('=' * self.line_len)
|
|
self.output('RTEMS Tools Project <rtems-users@rtems.org> %s' % datetime.datetime.now().ctime())
|
|
if intro_text:
|
|
self.output('')
|
|
self.output('%s' % ('\n'.join(intro_text)))
|
|
self.output('=' * self.line_len)
|
|
self.output('Report: %s' % (name))
|
|
self.git_status()
|
|
|
|
def config_start(self, name):
|
|
first = not self.configs_active
|
|
self.configs_active = True
|
|
|
|
def config_end(self, name):
|
|
if self.is_asciidoc():
|
|
self.output('')
|
|
self.output("'''")
|
|
self.output('')
|
|
|
|
def buildset_start(self, name):
|
|
if self.is_asciidoc():
|
|
h = '%s' % (name)
|
|
self.output('=%s %s' % ('=' * self.bset_nesting, h))
|
|
else:
|
|
self.output('=-' * (self.line_len / 2))
|
|
self.output('Build Set: %s' % (name))
|
|
|
|
def buildset_end(self, name):
|
|
self.configs_active = False
|
|
|
|
def source(self, package, source_tag):
|
|
return package.sources()
|
|
|
|
def patch(self, package, args):
|
|
return package.patches()
|
|
|
|
def output_info(self, name, info, separated = False):
|
|
if info is not None:
|
|
end = ''
|
|
if self.is_asciidoc():
|
|
if separated:
|
|
self.output('*%s:*::' % (name))
|
|
self.output('')
|
|
else:
|
|
self.output('*%s:* ' % (name))
|
|
end = ' +'
|
|
spaces = ''
|
|
else:
|
|
self.output(' %s:' % (name))
|
|
spaces = ' '
|
|
for l in info:
|
|
self.output('%s%s%s' % (spaces, l, end))
|
|
if self.is_asciidoc() and separated:
|
|
self.output('')
|
|
|
|
def output_directive(self, name, directive):
|
|
if directive is not None:
|
|
if self.is_asciidoc():
|
|
self.output('')
|
|
self.output('*%s*:' % (name))
|
|
self.output('--------------------------------------------')
|
|
spaces = ''
|
|
else:
|
|
self.output(' %s:' % (name))
|
|
spaces = ' '
|
|
for l in directive:
|
|
self.output('%s%s' % (spaces, l))
|
|
if self.is_asciidoc():
|
|
self.output('--------------------------------------------')
|
|
|
|
def config(self, configname, _defaults, _opts):
|
|
|
|
_config = config.file(configname, _defaults = _defaults, opts = _opts)
|
|
packages = _config.packages()
|
|
package = packages['main']
|
|
name = package.name()
|
|
self.config_start(name)
|
|
if self.is_asciidoc():
|
|
self.output('*Package*: _%s_ +' % (name))
|
|
self.output('*Config*: %s' % (configname))
|
|
self.output('')
|
|
else:
|
|
self.output('-' * self.line_len)
|
|
self.output('Package: %s' % (name))
|
|
self.output(' Config: %s' % (configname))
|
|
self.output_info('Summary', package.get_info('summary'), True)
|
|
self.output_info('URL', package.get_info('url'))
|
|
self.output_info('Version', package.get_info('version'))
|
|
self.output_info('Release', package.get_info('release'))
|
|
self.output_info('Build Arch', package.get_info('buildarch'))
|
|
if self.is_asciidoc():
|
|
self.output('')
|
|
sources = package.sources()
|
|
if self.is_asciidoc():
|
|
self.output('*Sources:*::')
|
|
if len(sources) == 0:
|
|
self.output('No sources')
|
|
else:
|
|
self.output(' Sources: %d' % (len(sources)))
|
|
c = 0
|
|
for s in sources:
|
|
c += 1
|
|
if self.is_asciidoc():
|
|
self.output('. %s' % (sources[s][0]))
|
|
else:
|
|
self.output(' %2d: %s' % (c, sources[s][0]))
|
|
patches = package.patches()
|
|
if self.is_asciidoc():
|
|
self.output('')
|
|
self.output('*Patches:*::')
|
|
if len(patches) == 0:
|
|
self.output('No patches')
|
|
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]))
|
|
self.output_directive('Preparation', package.prep())
|
|
self.output_directive('Build', package.build())
|
|
self.output_directive('Install', package.install())
|
|
self.output_directive('Clean', package.clean())
|
|
self.config_end(name)
|
|
|
|
def buildset(self, name):
|
|
self.bset_nesting += 1
|
|
self.buildset_start(name)
|
|
_opts = copy.deepcopy(self.opts)
|
|
_defaults = copy.deepcopy(self.defaults)
|
|
bset = setbuilder.buildset(name,
|
|
_configs = self.configs,
|
|
_defaults = _defaults,
|
|
opts = _opts)
|
|
for c in bset.load():
|
|
if c.endswith('.bset'):
|
|
self.buildset(c)
|
|
elif c.endswith('.cfg'):
|
|
self.config(c, _defaults, _opts)
|
|
else:
|
|
raise error.general('invalid config type: %s' % (c))
|
|
self.buildset_end(name)
|
|
self.bset_nesting -= 1
|
|
|
|
def generate(self, name):
|
|
if self.format == 'html':
|
|
if self.asciidoc is None:
|
|
raise error.general('asciidoc not initialised')
|
|
import StringIO
|
|
infile = StringIO.StringIO(self.out)
|
|
outfile = StringIO.StringIO()
|
|
self.asciidoc.execute(infile, outfile)
|
|
self.out = outfile.getvalue()
|
|
infile.close()
|
|
outfile.close()
|
|
try:
|
|
o = open(name, "w")
|
|
o.write(self.out)
|
|
o.close()
|
|
del o
|
|
except IOError, err:
|
|
raise error.general('writing output file: %s: %s' % (name, err))
|
|
|
|
def make(self, inname, outname, intro_text = None):
|
|
self.setup()
|
|
self.introduction(inname, intro_text)
|
|
config = build.find_config(inname, self.configs)
|
|
if config is None:
|
|
raise error.general('config file not found: %s' % (inname))
|
|
if config.endswith('.bset'):
|
|
self.buildset(config)
|
|
elif config.endswith('.cfg'):
|
|
self.config(config)
|
|
else:
|
|
raise error.general('invalid config type: %s' % (config))
|
|
self.generate(outname)
|
|
|
|
def run(args):
|
|
try:
|
|
optargs = { '--list-bsets': 'List available build sets',
|
|
'--list-configs': 'List available configurations',
|
|
'--format': 'Output format (text, html, asciidoc)',
|
|
'--output': 'File name to output the report' }
|
|
opts, _defaults = defaults.load(args, optargs)
|
|
log.default = log.log(opts.logfiles())
|
|
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 v%s' % (version)
|
|
if not check.host_setup(opts, _defaults):
|
|
_notice(opts, 'warning: forcing build with known host setup problems')
|
|
configs = build.get_configs(opts, _defaults)
|
|
if not setbuilder.list_bset_cfg_files(opts, configs):
|
|
output = opts.get_arg('--output')
|
|
if output is not None:
|
|
output = output[1]
|
|
format = 'text'
|
|
ext = '.txt'
|
|
format_opt = opts.get_arg('--format')
|
|
if format_opt:
|
|
if len(format_opt) != 2:
|
|
raise error.general('invalid format option: %s' % ('='.join(format_opt)))
|
|
if format_opt[1] == 'text':
|
|
pass
|
|
elif format_opt[1] == 'asciidoc':
|
|
format = 'asciidoc'
|
|
ext = '.txt'
|
|
elif format_opt[1] == 'html':
|
|
format = 'html'
|
|
ext = '.html'
|
|
else:
|
|
raise error.general('invalid format: %s' % (format_opt[1]))
|
|
r = report(format = format,
|
|
_configs = configs,
|
|
_defaults = _defaults,
|
|
opts = opts)
|
|
for _config in opts.params():
|
|
if output is None:
|
|
outname = path.splitext(_config)[0] + ext
|
|
else:
|
|
outname = output
|
|
r.make(_config, outname)
|
|
del r
|
|
except error.general, gerr:
|
|
print gerr
|
|
sys.exit(1)
|
|
except error.internal, ierr:
|
|
print ierr
|
|
sys.exit(1)
|
|
except error.exit, eerr:
|
|
pass
|
|
except KeyboardInterrupt:
|
|
_notice(opts, 'abort: user terminated')
|
|
sys.exit(1)
|
|
sys.exit(0)
|
|
|
|
if __name__ == "__main__":
|
|
run(sys.argv)
|