mirror of
https://git.rtems.org/rtems-source-builder
synced 2024-10-09 07:15:10 +08:00
Add support for GIT.
The git module allows basic access to git. Hosts are now required to provide git support. The defaults module now returns options as a list split on '='.
This commit is contained in:
parent
45ca8cf134
commit
d7e4900fe7
@ -119,6 +119,7 @@ defaults = {
|
||||
'__cpp': ('exe', 'none', '%{__cc} -E'),
|
||||
'__cxx': ('exe', 'required', '/usr/bin/g++'),
|
||||
'__flex': ('exe', 'required', '/usr/bin/flex'),
|
||||
'__git': ('exe', 'required', '/usr/bin/git'),
|
||||
'__grep': ('exe', 'required', '/usr/bin/grep'),
|
||||
'__gzip': ('exe', 'required', '/usr/bin/gzip'),
|
||||
'__id': ('exe', 'required', '/usr/bin/id'),
|
||||
@ -401,8 +402,10 @@ class command_line:
|
||||
self.defaults[_arch] = ('none', 'none', _arch_value)
|
||||
self.defaults[_vendor] = ('none', 'none', _vendor_value)
|
||||
self.defaults[_os] = ('none', 'none', _os_value)
|
||||
if not lo and a not in self.optargs:
|
||||
raise error.general('invalid argument (try --help): %s' % (a))
|
||||
if not lo:
|
||||
sa = a.split('=')
|
||||
if sa[0] not in self.optargs:
|
||||
raise error.general('invalid argument (try --help): %s' % (a))
|
||||
else:
|
||||
if a == '-f':
|
||||
self.opts['force'] = '1'
|
||||
@ -477,8 +480,9 @@ class command_line:
|
||||
if not arg in self.optargs:
|
||||
raise error.internal('bad arg: %s' % (arg))
|
||||
for a in self.args:
|
||||
if a.startswith(arg):
|
||||
return a
|
||||
sa = a.split('=')
|
||||
if sa[0].startswith(arg):
|
||||
return sa
|
||||
return None
|
||||
|
||||
def get_config_files(self, config):
|
||||
|
@ -59,6 +59,7 @@ def load():
|
||||
'_smp_mflags': ('none', 'none', smp_mflags),
|
||||
'__bash': ('exe', 'optional', '/usr/local/bin/bash'),
|
||||
'__bison': ('exe', 'required', '/usr/local/bin/bison'),
|
||||
'__git': ('exe', 'required', '/usr/local/bin/git'),
|
||||
'__xz': ('exe', 'optional', '/usr/bin/xz'),
|
||||
'__make': ('exe', 'required', 'gmake')
|
||||
}
|
||||
|
130
source-builder/sb/git.py
Normal file
130
source-builder/sb/git.py
Normal file
@ -0,0 +1,130 @@
|
||||
#
|
||||
# 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.
|
||||
|
||||
#
|
||||
# Provide some basic access to the git command.
|
||||
#
|
||||
|
||||
import os
|
||||
|
||||
import defaults
|
||||
import error
|
||||
import execute
|
||||
import path
|
||||
|
||||
class repo:
|
||||
"""An object to manage a git repo."""
|
||||
|
||||
def _git_exit_code(self, ec):
|
||||
if ec:
|
||||
raise error.general('git command failed (%s): %d' % (self.git, ec))
|
||||
|
||||
def _run(self, args, check = False):
|
||||
e = execute.capture_execution()
|
||||
exit_code, proc, output = e.spawn([self.git] + args)
|
||||
if check:
|
||||
self._git_exit_code(exit_code)
|
||||
return exit_code, output
|
||||
|
||||
def __init__(self, _path, _opts, _defaults):
|
||||
self.path = _path
|
||||
self.opts = _opts
|
||||
self.default = _defaults
|
||||
self.git = _opts.expand('%{__git}', _defaults)
|
||||
|
||||
def git_version(self):
|
||||
ec, output = self._run(['--version'], True)
|
||||
gvs = output.split()
|
||||
if len(gvs) < 3:
|
||||
raise error.general('invalid version string from git: %s' % (output))
|
||||
vs = gvs[2].split('.')
|
||||
if len(vs) != 4:
|
||||
raise error.general('invalid version number from git: %s' % (gvs[2]))
|
||||
return (int(vs[0]), int(vs[1]), int(vs[2]), int(vs[3]))
|
||||
|
||||
def status(self):
|
||||
_status = {}
|
||||
ec, output = self._run(['status'])
|
||||
if ec == 0:
|
||||
state = 'none'
|
||||
for l in output.split('\n'):
|
||||
if l.startswith('# On branch '):
|
||||
_status['branch'] = l[len('# On branch '):]
|
||||
elif l.startswith('# Changes to be committed:'):
|
||||
state = 'staged'
|
||||
elif l.startswith('# Changes not staged for commit:'):
|
||||
state = 'unstaged'
|
||||
elif l.startswith('# Untracked files:'):
|
||||
state = 'untracked'
|
||||
elif state != 'none' and l[0] == '#':
|
||||
if l.strip() != '#' and not l.startswith('# ('):
|
||||
if state not in _status:
|
||||
_status[state] = []
|
||||
l = l[1:]
|
||||
if ':' in l:
|
||||
l = l.split(':')[1]
|
||||
_status[state] += [l.strip()]
|
||||
return _status
|
||||
|
||||
def clean(self):
|
||||
_status = self.status()
|
||||
return len(_status) == 1 and 'branch' in _status
|
||||
|
||||
def valid(self):
|
||||
ec, output = self._run(['status'])
|
||||
return ec == 0
|
||||
|
||||
def remotes(self):
|
||||
_remotes = {}
|
||||
ec, output = self._run(['config', '--list'])
|
||||
if ec == 0:
|
||||
for l in output.split('\n'):
|
||||
if l.startswith('remote'):
|
||||
ls = l.split('=')
|
||||
if len(ls) >= 2:
|
||||
rs = ls[0].split('.')
|
||||
if len(rs) == 3:
|
||||
r_name = rs[1]
|
||||
r_type = rs[2]
|
||||
if r_name not in _remotes:
|
||||
_remotes[r_name] = {}
|
||||
if r_type not in _remotes[r_name]:
|
||||
_remotes[r_name][r_type] = []
|
||||
_remotes[r_name][r_type] = '='.join(ls[1:])
|
||||
return _remotes
|
||||
|
||||
def head(self):
|
||||
hash = ''
|
||||
ec, output = self._run(['log', '-n', '1'])
|
||||
if ec == 0:
|
||||
l1 = output.split('\n')[0]
|
||||
if l1.startswith('commit '):
|
||||
hash = l1[len('commit '):]
|
||||
return hash
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
_opts, _defaults = defaults.load(sys.argv)
|
||||
g = repo('.', _opts, _defaults)
|
||||
print g.git_version()
|
||||
print g.valid()
|
||||
print g.status()
|
||||
print g.clean()
|
||||
print g.remotes()
|
||||
print g.head()
|
@ -22,16 +22,26 @@
|
||||
# installed not to be package unless you run a packager around this.
|
||||
#
|
||||
|
||||
import datetime
|
||||
import os
|
||||
import sys
|
||||
|
||||
import build
|
||||
import check
|
||||
import config
|
||||
import defaults
|
||||
import error
|
||||
import log
|
||||
import setbuilder
|
||||
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 'unknown application load error'
|
||||
sys.exit(1)
|
||||
|
||||
#
|
||||
# Version of Sourcer Builder Build.
|
||||
@ -49,18 +59,18 @@ class report:
|
||||
|
||||
line_len = 78
|
||||
|
||||
def __init__(self, name, format, _configs, _defaults, opts):
|
||||
def __init__(self, format, _configs, _defaults, opts):
|
||||
self.format = format
|
||||
self.name = name
|
||||
self.configs = _configs
|
||||
self.defaults = _defaults
|
||||
self.opts = opts
|
||||
self.bset_nesting = 0
|
||||
self.configs_active = False
|
||||
self.out = ''
|
||||
self.asciidoc = None
|
||||
|
||||
def _output(self, text):
|
||||
if not self.opts.quiet():
|
||||
log.output(text)
|
||||
def output(self, text):
|
||||
self.out += '%s\n' % (text)
|
||||
|
||||
def is_text(self):
|
||||
return self.format == 'text'
|
||||
@ -70,7 +80,14 @@ class report:
|
||||
|
||||
def setup(self):
|
||||
if self.is_asciidoc():
|
||||
pass
|
||||
try:
|
||||
import asciidocapi
|
||||
except:
|
||||
raise error.general('installation error: no asciidocapi found')
|
||||
try:
|
||||
self.asciidoc = asciidocapi.AsciiDocAPI()
|
||||
except:
|
||||
raise error.general('application error: asciidocapi failed')
|
||||
|
||||
def header(self):
|
||||
pass
|
||||
@ -78,46 +95,118 @@ class report:
|
||||
def footer(self):
|
||||
pass
|
||||
|
||||
def introduction(self, name):
|
||||
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'
|
||||
log.output(h)
|
||||
log.output('=' * len(h))
|
||||
log.output(':doctype: book')
|
||||
log.output(':toc2:')
|
||||
log.output(':toclevels: 5')
|
||||
log.output(':icons:')
|
||||
log.output(':numbered:')
|
||||
log.output(' ')
|
||||
log.output('RTEMS Project <rtems-user@rtems.org>')
|
||||
log.output('28th Feb 2013')
|
||||
log.output(' ')
|
||||
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 = os.path.abspath(path.host(path.join(self.opts.expand('%{_sbdir}', self.defaults),
|
||||
'sb', 'images', 'rtemswhitebg.jpg')))
|
||||
self.output('image:%s["RTEMS",width="20%%"]' % (image))
|
||||
self.output('')
|
||||
if intro_text:
|
||||
self.output('%s' % ('\n'.join(intro_text)))
|
||||
else:
|
||||
log.output('report: %s' % (name))
|
||||
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
|
||||
if self.is_asciidoc():
|
||||
log.output('.Config: %s' % name)
|
||||
log.output('')
|
||||
self.output('.Config: %s' % name)
|
||||
self.output('')
|
||||
else:
|
||||
log.output('-' * self.line_len)
|
||||
log.output('config: %s' % (name))
|
||||
self.output('-' * self.line_len)
|
||||
self.output('Config: %s' % (name))
|
||||
|
||||
def config_end(self, name):
|
||||
if self.is_asciidoc():
|
||||
log.output(' ')
|
||||
log.output("'''")
|
||||
log.output(' ')
|
||||
self.output('')
|
||||
self.output("'''")
|
||||
self.output('')
|
||||
|
||||
def buildset_start(self, name):
|
||||
if self.is_asciidoc():
|
||||
h = '%s' % (name)
|
||||
log.output('=%s %s' % ('=' * self.bset_nesting, h))
|
||||
self.output('=%s %s' % ('=' * self.bset_nesting, h))
|
||||
else:
|
||||
log.output('=' * self.line_len)
|
||||
log.output('build set: %s' % (name))
|
||||
self.output('=-' * (self.line_len / 2))
|
||||
self.output('Build Set: %s' % (name))
|
||||
|
||||
def buildset_end(self, name):
|
||||
self.configs_active = False
|
||||
@ -135,39 +224,39 @@ class report:
|
||||
package = packages['main']
|
||||
name = package.name()
|
||||
if self.is_asciidoc():
|
||||
log.output('*Package*: _%s_' % name)
|
||||
log.output(' ')
|
||||
self.output('*Package*: _%s_' % name)
|
||||
self.output('')
|
||||
else:
|
||||
log.output(' package: %s' % (name))
|
||||
self.output(' Package: %s' % (name))
|
||||
sources = package.sources()
|
||||
if self.is_asciidoc():
|
||||
log.output('*Sources*;;')
|
||||
self.output('*Sources*:;;')
|
||||
if len(sources) == 0:
|
||||
log.output('No sources')
|
||||
self.output('No sources')
|
||||
else:
|
||||
log.output(' sources: %d' % (len(sources)))
|
||||
self.output(' Sources: %d' % (len(sources)))
|
||||
c = 0
|
||||
for s in sources:
|
||||
c += 1
|
||||
if self.is_asciidoc():
|
||||
log.output('. %s' % (sources[s][0]))
|
||||
self.output('. %s' % (sources[s][0]))
|
||||
else:
|
||||
log.output(' %2d: %s' % (c, sources[s][0]))
|
||||
self.output(' %2d: %s' % (c, sources[s][0]))
|
||||
patches = package.patches()
|
||||
if self.is_asciidoc():
|
||||
log.output(' ')
|
||||
log.output('*Patches*:;;')
|
||||
self.output('')
|
||||
self.output('*Patches*:;;')
|
||||
if len(patches) == 0:
|
||||
log.output('No patches')
|
||||
self.output('No patches')
|
||||
else:
|
||||
log.output(' patches: %s' % (len(patches)))
|
||||
self.output(' Patches: %s' % (len(patches)))
|
||||
c = 0
|
||||
for p in patches:
|
||||
c += 1
|
||||
if self.is_asciidoc():
|
||||
log.output('. %s' % (patches[p][0]))
|
||||
self.output('. %s' % (patches[p][0]))
|
||||
else:
|
||||
log.output(' %2d: %s' % (c, patches[p][0]))
|
||||
self.output(' %2d: %s' % (c, patches[p][0]))
|
||||
self.config_end(name)
|
||||
|
||||
def buildset(self, name):
|
||||
@ -196,33 +285,73 @@ class report:
|
||||
if try_config:
|
||||
self.config(name)
|
||||
|
||||
def generate(self):
|
||||
self.introduction(self.name)
|
||||
self.buildset(self.name)
|
||||
def generate(self, name):
|
||||
if self.is_asciidoc():
|
||||
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)
|
||||
self.buildset(inname)
|
||||
self.generate(outname)
|
||||
|
||||
def run(args):
|
||||
try:
|
||||
optargs = { '--list-bsets': 'List available build sets',
|
||||
'--list-configs': 'List available configurations',
|
||||
'--asciidoc': 'Output report as asciidoc' }
|
||||
'--format': 'Output format (text, 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'
|
||||
if opts.get_arg('--asciidoc'):
|
||||
format = 'asciidoc'
|
||||
for _file in opts.params():
|
||||
r = report(_file,
|
||||
format = format,
|
||||
_configs = configs,
|
||||
_defaults = _defaults,
|
||||
opts = opts)
|
||||
r.generate()
|
||||
del r
|
||||
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 = '.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)
|
||||
|
@ -63,6 +63,7 @@ def load():
|
||||
'__cp': ('exe', 'required', 'cp'),
|
||||
'__cxx': ('exe', 'required', 'g++'),
|
||||
'__flex': ('exe', 'required', 'flex'),
|
||||
'__git': ('exe', 'required', 'git'),
|
||||
'__grep': ('exe', 'required', 'grep'),
|
||||
'__gzip': ('exe', 'required', 'gzip'),
|
||||
'__id': ('exe', 'required', 'id'),
|
||||
|
Loading…
x
Reference in New Issue
Block a user