mirror of
https://git.rtems.org/rtems-tools/
synced 2025-06-11 22:52:49 +08:00
2010-08-09 Chris Johns <chrisj@rtems.org>
* specbuilder, specbuilder/sb-build, specbuilder/sb-crossgcc, specbuilder/sb-setup, specbuilder/sb-specdump, specbuilder/sb-status, specbuilder/specbuilder/.cvsignore, specbuilder/specbuilder/build.py, specbuilder/specbuilder/config.sub, specbuilder/specbuilder/crossgcc.py, specbuilder/specbuilder/darwin.py, specbuilder/specbuilder/defaults.py, specbuilder/specbuilder/error.py, specbuilder/specbuilder/execute.py, specbuilder/specbuilder/log.py, specbuilder/specbuilder/setup.py, specbuilder/specbuilder/spec.py, specbuilder/specbuilder/status.py: New.
This commit is contained in:
parent
2dc8560ba8
commit
7231f495e0
15
ChangeLog
Normal file
15
ChangeLog
Normal file
@ -0,0 +1,15 @@
|
||||
2010-08-09 Chris Johns <chrisj@rtems.org>
|
||||
|
||||
* specbuilder, specbuilder/sb-build, specbuilder/sb-crossgcc,
|
||||
specbuilder/sb-setup, specbuilder/sb-specdump,
|
||||
specbuilder/sb-status, specbuilder/specbuilder/.cvsignore,
|
||||
specbuilder/specbuilder/build.py,
|
||||
specbuilder/specbuilder/config.sub,
|
||||
specbuilder/specbuilder/crossgcc.py,
|
||||
specbuilder/specbuilder/darwin.py,
|
||||
specbuilder/specbuilder/defaults.py,
|
||||
specbuilder/specbuilder/error.py,
|
||||
specbuilder/specbuilder/execute.py,
|
||||
specbuilder/specbuilder/log.py, specbuilder/specbuilder/setup.py,
|
||||
specbuilder/specbuilder/spec.py,
|
||||
specbuilder/specbuilder/status.py: New.
|
33
specbuilder/sb-build
Executable file
33
specbuilder/sb-build
Executable file
@ -0,0 +1,33 @@
|
||||
#! /usr/bin/env python
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# RTEMS Tools Project (http://www.rtems.org/)
|
||||
# Copyright 2010 Chris Johns (chrisj@rtems.org)
|
||||
# All rights reserved.
|
||||
#
|
||||
# This file is part of the RTEMS Tools package in 'rtems-tools'.
|
||||
#
|
||||
# RTEMS Tools is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# RTEMS Tools is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with RTEMS Tools. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
import sys, os
|
||||
base = os.path.dirname(sys.argv[0])
|
||||
sys.path.insert(0, base + '/specbuilder')
|
||||
try:
|
||||
import build
|
||||
build.run(sys.argv)
|
||||
except ImportError:
|
||||
print >> sys.stderr, "Incorrect SpecBulder installation"
|
||||
sys.exit(1)
|
33
specbuilder/sb-crossgcc
Executable file
33
specbuilder/sb-crossgcc
Executable file
@ -0,0 +1,33 @@
|
||||
#! /usr/bin/env python
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# RTEMS Tools Project (http://www.rtems.org/)
|
||||
# Copyright 2010 Chris Johns (chrisj@rtems.org)
|
||||
# All rights reserved.
|
||||
#
|
||||
# This file is part of the RTEMS Tools package in 'rtems-tools'.
|
||||
#
|
||||
# RTEMS Tools is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# RTEMS Tools is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with RTEMS Tools. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
import sys, os
|
||||
base = os.path.dirname(sys.argv[0])
|
||||
sys.path.insert(0, base + '/specbuilder')
|
||||
try:
|
||||
import crossgcc
|
||||
crossgcc.run()
|
||||
except ImportError:
|
||||
print >> sys.stderr, "Incorrect SpecBulder installation"
|
||||
sys.exit(1)
|
33
specbuilder/sb-setup
Executable file
33
specbuilder/sb-setup
Executable file
@ -0,0 +1,33 @@
|
||||
#! /usr/bin/env python
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# RTEMS Tools Project (http://www.rtems.org/)
|
||||
# Copyright 2010 Chris Johns (chrisj@rtems.org)
|
||||
# All rights reserved.
|
||||
#
|
||||
# This file is part of the RTEMS Tools package in 'rtems-tools'.
|
||||
#
|
||||
# RTEMS Tools is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# RTEMS Tools is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with RTEMS Tools. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
import sys, os
|
||||
base = os.path.dirname(sys.argv[0])
|
||||
sys.path.insert(0, base + '/specbuilder')
|
||||
try:
|
||||
import setup
|
||||
setup.run()
|
||||
except ImportError:
|
||||
print >> sys.stderr, "Incorrect SpecBulder installation"
|
||||
sys.exit(1)
|
33
specbuilder/sb-specdump
Executable file
33
specbuilder/sb-specdump
Executable file
@ -0,0 +1,33 @@
|
||||
#! /usr/bin/env python
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# RTEMS Tools Project (http://www.rtems.org/)
|
||||
# Copyright 2010 Chris Johns (chrisj@rtems.org)
|
||||
# All rights reserved.
|
||||
#
|
||||
# This file is part of the RTEMS Tools package in 'rtems-tools'.
|
||||
#
|
||||
# RTEMS Tools is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# RTEMS Tools is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with RTEMS Tools. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
import sys, os
|
||||
base = os.path.dirname(sys.argv[0])
|
||||
sys.path.insert(0, base + '/specbuilder')
|
||||
try:
|
||||
import spec
|
||||
spec.run()
|
||||
except ImportError:
|
||||
print >> sys.stderr, "Incorrect SpecBulder installation"
|
||||
sys.exit(1)
|
33
specbuilder/sb-status
Executable file
33
specbuilder/sb-status
Executable file
@ -0,0 +1,33 @@
|
||||
#! /usr/bin/env python
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# RTEMS Tools Project (http://www.rtems.org/)
|
||||
# Copyright 2010 Chris Johns (chrisj@rtems.org)
|
||||
# All rights reserved.
|
||||
#
|
||||
# This file is part of the RTEMS Tools package in 'rtems-tools'.
|
||||
#
|
||||
# RTEMS Tools is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# RTEMS Tools is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with RTEMS Tools. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
import sys, os
|
||||
base = os.path.dirname(sys.argv[0])
|
||||
sys.path.insert(0, base + '/specbuilder')
|
||||
try:
|
||||
import status
|
||||
status.run()
|
||||
except ImportError:
|
||||
print >> sys.stderr, "Incorrect SpecBulder installation"
|
||||
sys.exit(1)
|
1
specbuilder/specbuilder/.cvsignore
Normal file
1
specbuilder/specbuilder/.cvsignore
Normal file
@ -0,0 +1 @@
|
||||
*.pyc
|
411
specbuilder/specbuilder/build.py
Normal file
411
specbuilder/specbuilder/build.py
Normal file
@ -0,0 +1,411 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# RTEMS Tools Project (http://www.rtems.org/)
|
||||
# Copyright 2010 Chris Johns (chrisj@rtems.org)
|
||||
# All rights reserved.
|
||||
#
|
||||
# This file is part of the RTEMS Tools package in 'rtems-tools'.
|
||||
#
|
||||
# RTEMS Tools is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# RTEMS Tools is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with RTEMS Tools. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
#
|
||||
# This code builds a package given a spec file. It only builds to be installed
|
||||
# not to be package unless you run a packager around this.
|
||||
#
|
||||
|
||||
import getopt
|
||||
import os
|
||||
import shutil
|
||||
import stat
|
||||
import sys
|
||||
import urllib2
|
||||
import urlparse
|
||||
|
||||
import defaults
|
||||
import error
|
||||
import execute
|
||||
import log
|
||||
import spec
|
||||
|
||||
#
|
||||
# Version of Spec Builder.
|
||||
#
|
||||
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 script:
|
||||
"""Create and manage a shell script."""
|
||||
|
||||
def __init__(self, quiet = True):
|
||||
self.quiet = quiet
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
self.body = []
|
||||
self.lc = 0
|
||||
|
||||
def append(self, text):
|
||||
if type(text) is str:
|
||||
text = text.splitlines()
|
||||
if not self.quiet:
|
||||
i = 0
|
||||
for l in text:
|
||||
i += 1
|
||||
log.output('script:%3d: ' % (self.lc + i) + l)
|
||||
self.lc += len(text)
|
||||
self.body.extend(text)
|
||||
|
||||
def write(self, name, check_for_errors = False):
|
||||
s = None
|
||||
try:
|
||||
s = open(name, 'w')
|
||||
s.write('\n'.join(self.body))
|
||||
s.close()
|
||||
os.chmod(name, stat.S_IRWXU | \
|
||||
stat.S_IRGRP | stat.S_IXGRP | \
|
||||
stat.S_IROTH | stat.S_IXOTH)
|
||||
except IOError, err:
|
||||
raise error.general('creating script: ' + name)
|
||||
finally:
|
||||
if s is not None:
|
||||
s.close()
|
||||
|
||||
class build:
|
||||
"""Build a package given a spec file."""
|
||||
|
||||
def __init__(self, name, _defaults, opts):
|
||||
self.opts = opts
|
||||
_notice(opts, 'building: ' + name)
|
||||
self.spec = spec.file(name, _defaults = _defaults, opts = opts)
|
||||
self.script = script(quiet = opts.quiet())
|
||||
|
||||
def _output(self, text):
|
||||
if not self.opts.quiet():
|
||||
log.output(text)
|
||||
|
||||
def rmdir(self, path):
|
||||
if not self.opts.dry_run():
|
||||
self._output('removing: ' + path)
|
||||
if os.path.exists(path):
|
||||
try:
|
||||
shutil.rmtree(path)
|
||||
except IOError, err:
|
||||
raise error.error('error removing: ' + path)
|
||||
|
||||
def mkdir(self, path):
|
||||
if not self.opts.dry_run():
|
||||
self._output('making dir: ' + path)
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except IOError, err:
|
||||
raise error.general('error creating path: ' + path)
|
||||
|
||||
def get_file(self, url, local):
|
||||
if not os.path.isdir(os.path.dirname(local)):
|
||||
raise error.general('source path not found: ' + os.path.dirname(local))
|
||||
if not os.path.exists(local):
|
||||
#
|
||||
# Not localy found so we need to download it. Check if a URL
|
||||
# has been provided on the command line.
|
||||
#
|
||||
url_bases = self.opts.urls()
|
||||
urls = []
|
||||
if url_bases is not None:
|
||||
for base in url_bases:
|
||||
if base[-1:] != '/':
|
||||
base += '/'
|
||||
url_path = urlparse.urlsplit(url).path
|
||||
slash = url_path.rfind('/')
|
||||
if slash < 0:
|
||||
url_file = url_path
|
||||
else:
|
||||
url_file = url_path[slash + 1:]
|
||||
urls.append(urlparse.urljoin(base, url_file))
|
||||
urls.append(url)
|
||||
for url in urls:
|
||||
_notice(self.opts, 'download: ' + url + ' -> ' + local)
|
||||
if not self.opts.dry_run():
|
||||
failed = False
|
||||
_in = None
|
||||
_out = None
|
||||
try:
|
||||
_in = urllib2.urlopen(url)
|
||||
_out = open(local, 'wb')
|
||||
_out.write(_in.read())
|
||||
except IOError, err:
|
||||
_notice(self.opts, 'download: ' + url + ': failed: ' + str(err))
|
||||
if os.path.exists(local):
|
||||
os.remove(local)
|
||||
failed = True
|
||||
finally:
|
||||
if _out is not None:
|
||||
_out.close()
|
||||
if _in is not None:
|
||||
del _in
|
||||
if not failed:
|
||||
if not os.path.isfile(local):
|
||||
raise error.general('source is not a file: ' + local)
|
||||
return
|
||||
raise error.general('downloading ' + url + ': all paths have failed, giving up')
|
||||
|
||||
def parse_url(self, url):
|
||||
#
|
||||
# Split the source up into the parts we need.
|
||||
#
|
||||
source = {}
|
||||
source['url'] = url
|
||||
source['path'] = os.path.dirname(url)
|
||||
source['file'] = os.path.basename(url)
|
||||
source['name'], source['ext'] = os.path.splitext(source['file'])
|
||||
#
|
||||
# Get the file. Checks the local source directory first.
|
||||
#
|
||||
source['local'] = os.path.join(self.spec.abspath('_sourcedir'),
|
||||
source['file'])
|
||||
#
|
||||
# Is the file compressed ?
|
||||
#
|
||||
esl = source['ext'].split('.')
|
||||
if esl[-1:][0] == 'gz':
|
||||
source['compressed'] = '%{__gzip} -dc'
|
||||
elif esl[-1:][0] == 'bz2':
|
||||
source['compressed'] = '%{__bzip2} -dc'
|
||||
elif esl[-1:][0] == 'bz2':
|
||||
source['compressed'] = '%{__zip} -u'
|
||||
source['script'] = ''
|
||||
return source
|
||||
|
||||
def source(self, package, source_tag):
|
||||
#
|
||||
# Scan the sources found in the spec file for the one we are
|
||||
# after. Infos or tags are lists.
|
||||
#
|
||||
sources = package.sources()
|
||||
url = None
|
||||
for s in sources:
|
||||
tag = s[len('source'):]
|
||||
if tag.isdigit():
|
||||
if int(tag) == source_tag:
|
||||
url = sources[s][0]
|
||||
break
|
||||
if url is None:
|
||||
raise error.general('source tag not found: source' + str(source_tag))
|
||||
source = self.parse_url(url)
|
||||
self.get_file(source['url'], source['local'])
|
||||
if 'compressed' in source:
|
||||
source['script'] = source['compressed'] + ' ' + \
|
||||
source['local'] + ' | %{__tar_extract} -'
|
||||
else:
|
||||
source['script'] = '%{__tar_extract} ' + source['local']
|
||||
return source
|
||||
|
||||
def patch(self, package, args):
|
||||
#
|
||||
# Scan the patches found in the spec file for the one we are
|
||||
# after. Infos or tags are lists.
|
||||
#
|
||||
patches = package.patches()
|
||||
url = None
|
||||
for p in patches:
|
||||
if args[0][1:].lower() == p:
|
||||
url = patches[p][0]
|
||||
break
|
||||
if url is None:
|
||||
raise error.general('patch tag not found: ' + args[0])
|
||||
patch = self.parse_url(url)
|
||||
self.get_file(patch['url'], patch['local'])
|
||||
if 'compressed' in patch:
|
||||
patch['script'] = patch['compressed'] + ' ' + patch['local']
|
||||
else:
|
||||
patch['script'] = '%{__cat} ' + patch['local']
|
||||
patch['script'] += ' | %{__patch} ' + ' '.join(args[1:])
|
||||
self.script.append(self.spec.expand(patch['script']))
|
||||
|
||||
def setup(self, package, args):
|
||||
self._output('prep: ' + package.name() + ': ' + ' '.join(args))
|
||||
opts, args = getopt.getopt(args[1:], 'qDcTn:b:a:')
|
||||
source_tag = 0
|
||||
quiet = False
|
||||
unpack_default_source = True
|
||||
delete_before_unpack = True
|
||||
create_dir = False
|
||||
name = None
|
||||
unpack_before_chdir = True
|
||||
for o in opts:
|
||||
if o[0] == '-q':
|
||||
quiet = True
|
||||
elif o[0] == '-D':
|
||||
delete_before_unpack = False
|
||||
elif o[0] == '-c':
|
||||
create_dir = True
|
||||
elif o[0] == '-T':
|
||||
unpack_default_source = False
|
||||
elif o[0] == '-n':
|
||||
name = o[1]
|
||||
elif o[0] == '-b':
|
||||
unpack_before_chdir = True
|
||||
if not o[1].isdigit():
|
||||
raise error.general('setup source tag no a number: ' + o[1])
|
||||
source_tag = int(o[1])
|
||||
elif o[0] == '-a':
|
||||
unpack_before_chdir = False
|
||||
source_tag = int(o[1])
|
||||
source0 = None
|
||||
source = self.source(package, source_tag)
|
||||
if name is None:
|
||||
if source:
|
||||
name = source['name']
|
||||
else:
|
||||
name = source0['name']
|
||||
self.script.append(self.spec.expand('cd %{_builddir}'))
|
||||
if delete_before_unpack:
|
||||
self.script.append(self.spec.expand('%{__rm} -rf ' + name))
|
||||
if create_dir:
|
||||
self.script.append(self.spec.expand('%{__mkdir_p} ' + name))
|
||||
#
|
||||
# If -a? then change directory before unpacking.
|
||||
#
|
||||
if not unpack_before_chdir:
|
||||
self.script.append(self.spec.expand('cd ' + name))
|
||||
#
|
||||
# Unpacking the source. Note, treated the same as -a0.
|
||||
#
|
||||
if unpack_default_source and source_tag != 0:
|
||||
source0 = self.source(package, 0)
|
||||
if source0 is None:
|
||||
raise error.general('no setup source0 tag found')
|
||||
self.script.append(self.spec.expand(source0['script']))
|
||||
self.script.append(self.spec.expand(source['script']))
|
||||
if unpack_before_chdir:
|
||||
self.script.append(self.spec.expand('cd ' + name))
|
||||
self.script.append(self.spec.expand('%{__setup_post}'))
|
||||
if create_dir:
|
||||
self.script.append(self.spec.expand('cd ..'))
|
||||
|
||||
def run(self, command, shell_opts = '', cwd = None):
|
||||
e = execute.capture_execution(log = log.default, dump = self.opts.quiet())
|
||||
cmd = self.spec.expand('%{___build_shell} -ex ' + shell_opts + ' ' + command)
|
||||
self._output('run: ' + cmd)
|
||||
exit_code, proc, output = e.shell(cmd, cwd = cwd)
|
||||
if exit_code != 0:
|
||||
raise error.general('shell cmd failed: ' + cmd)
|
||||
|
||||
def builddir(self):
|
||||
builddir = self.spec.abspath('_builddir')
|
||||
self.rmdir(builddir)
|
||||
if not self.opts.dry_run():
|
||||
self.mkdir(builddir)
|
||||
|
||||
def prep(self, package):
|
||||
self.script.append('echo "==> %prep:"')
|
||||
_prep = package.prep()
|
||||
for l in _prep:
|
||||
args = l.split()
|
||||
if args[0] == '%setup':
|
||||
self.setup(package, args)
|
||||
elif args[0].startswith('%patch'):
|
||||
self.patch(package, args)
|
||||
else:
|
||||
self.script.append(' '.join(args))
|
||||
|
||||
def build(self, package):
|
||||
self.script.append('echo "==> %build:"')
|
||||
_build = package.build()
|
||||
for l in _build:
|
||||
args = l.split()
|
||||
self.script.append(' '.join(args))
|
||||
|
||||
def install(self, package):
|
||||
self.script.append('echo "==> %install:"')
|
||||
_install = package.install()
|
||||
for l in _install:
|
||||
args = l.split()
|
||||
self.script.append(' '.join(args))
|
||||
|
||||
def files(self, package):
|
||||
self.script.append('echo "==> %files:"')
|
||||
prefixbase = self.opts.prefixbase()
|
||||
if prefixbase is None:
|
||||
prefixbase = ''
|
||||
inpath = os.path.join('%{buildroot}', prefixbase)
|
||||
self.script.append(self.spec.expand('cd ' + inpath))
|
||||
tar = os.path.join('%{_rpmdir}', package.long_name() + '.tar.bz2')
|
||||
cmd = self.spec.expand('%{__tar} -cf - . ' + '| %{__bzip2} > ' + tar)
|
||||
self.script.append(cmd)
|
||||
self.script.append(self.spec.expand('cd %{_builddir}'))
|
||||
|
||||
def clean(self, package):
|
||||
self.script.append('echo "==> %clean:"')
|
||||
_clean = package.clean()
|
||||
for l in _clean:
|
||||
args = l.split()
|
||||
self.script.append(' '.join(args))
|
||||
|
||||
def cleanup(self):
|
||||
buildroot = self.spec.abspath('buildroot')
|
||||
builddir = self.spec.abspath('_builddir')
|
||||
self.rmdir(buildroot)
|
||||
self.rmdir(builddir)
|
||||
|
||||
def make(self):
|
||||
packages = self.spec.packages()
|
||||
package = packages['main']
|
||||
_notice(self.opts, 'package: ' + package.name() + '-' + package.version())
|
||||
self.script.reset()
|
||||
self.script.append(self.spec.expand('%{___build_template}'))
|
||||
self.script.append('echo "=> ' + package.name() + '-' + package.version() + ':"')
|
||||
self.prep(package)
|
||||
self.build(package)
|
||||
self.install(package)
|
||||
self.files(package)
|
||||
if not self.opts.no_clean():
|
||||
self.clean(package)
|
||||
if not self.opts.dry_run():
|
||||
self.builddir()
|
||||
sn = self.spec.expand(os.path.join('%{_builddir}', 'doit'))
|
||||
self._output('write script: ' + sn)
|
||||
self.script.write(sn)
|
||||
self.run(sn)
|
||||
if not self.opts.no_clean():
|
||||
self.cleanup()
|
||||
|
||||
def run(args):
|
||||
try:
|
||||
opts, _defaults = defaults.load(args)
|
||||
log.default = log.log(opts.logfiles())
|
||||
_notice(opts, 'RTEMS Tools, Spec Builder, v%s' % (version))
|
||||
for spec_file in opts.spec_files():
|
||||
b = build(spec_file, _defaults = _defaults, opts = opts)
|
||||
b.make()
|
||||
del b
|
||||
except error.general, gerr:
|
||||
print gerr
|
||||
sys.exit(1)
|
||||
except error.internal, ierr:
|
||||
print ierr
|
||||
sys.exit(1)
|
||||
except KeyboardInterrupt:
|
||||
_notice(opts, 'user terminated')
|
||||
sys.exit(1)
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
run(sys.argv)
|
1705
specbuilder/specbuilder/config.sub
vendored
Executable file
1705
specbuilder/specbuilder/config.sub
vendored
Executable file
File diff suppressed because it is too large
Load Diff
157
specbuilder/specbuilder/crossgcc.py
Normal file
157
specbuilder/specbuilder/crossgcc.py
Normal file
@ -0,0 +1,157 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# RTEMS Tools Project (http://www.rtems.org/)
|
||||
# Copyright 2010 Chris Johns (chrisj@rtems.org)
|
||||
# All rights reserved.
|
||||
#
|
||||
# This file is part of the RTEMS Tools package in 'rtems-tools'.
|
||||
#
|
||||
# RTEMS Tools is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# RTEMS Tools is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with RTEMS Tools. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
#
|
||||
# This code builds a cross-gcc compiler suite of tools given an architecture.
|
||||
#
|
||||
|
||||
import distutils.dir_util
|
||||
import operator
|
||||
import os
|
||||
|
||||
import build
|
||||
import defaults
|
||||
import error
|
||||
import log
|
||||
|
||||
#
|
||||
# Version of Spec CrossGCC Builder.
|
||||
#
|
||||
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 crossgcc:
|
||||
"""Build a Cross GCC Compiler tool suite."""
|
||||
|
||||
_order = { 'binutils': 0,
|
||||
'gcc' : 1,
|
||||
'gdb' : 2 }
|
||||
|
||||
def __init__(self, arch, _defaults, opts):
|
||||
self.arch = arch
|
||||
self.opts = opts
|
||||
self.defaults = _defaults
|
||||
|
||||
def _output(self, text):
|
||||
if not self.opts.quiet():
|
||||
log.output(text)
|
||||
|
||||
def copy(self, src, dst):
|
||||
what = src + ' -> ' + dst
|
||||
_notice(self.opts, 'coping: ' + what)
|
||||
try:
|
||||
files = distutils.dir_util.copy_tree(src, dst)
|
||||
for f in files:
|
||||
self._output(f)
|
||||
except IOError, err:
|
||||
raise error.general('coping tree: ' + what + ': ' + str(err))
|
||||
|
||||
def first_package(self, _build):
|
||||
path = os.path.join(_build.spec.abspath('%{_tmppath}'),
|
||||
_build.spec.expand('crossgcc-%(%{__id_u} -n)'))
|
||||
_build.rmdir(path)
|
||||
_build.mkdir(path)
|
||||
prefix = os.path.join(_build.spec.expand('%{_prefix}'), 'bin')
|
||||
if prefix[0] == os.sep:
|
||||
prefix = prefix[1:]
|
||||
binpath = os.path.join(path, prefix)
|
||||
os.environ['PATH'] = binpath + os.pathsep + os.environ['PATH']
|
||||
self._output('path: ' + os.environ['PATH'])
|
||||
return path
|
||||
|
||||
def every_package(self, _build, path):
|
||||
self.copy(_build.spec.abspath('%{buildroot}'), path)
|
||||
_build.cleanup()
|
||||
|
||||
def last_package(self, _build, path):
|
||||
tar = os.path.join('%{_rpmdir}', self.arch + '-tools.tar.bz2')
|
||||
cmd = _build.spec.expand("'cd " + path + \
|
||||
" && %{__tar} -cf - . | %{__bzip2} > " + tar + "'")
|
||||
_build.run(cmd, shell_opts = '-c', cwd = path)
|
||||
if not self.opts.no_clean():
|
||||
_build.rmdir(path)
|
||||
|
||||
def make(self):
|
||||
|
||||
def _sort(specs):
|
||||
_specs = {}
|
||||
for spec in specs:
|
||||
for order in crossgcc._order:
|
||||
if spec.lower().find(order) >= 0:
|
||||
_specs[spec] = crossgcc._order[order]
|
||||
sorted_specs = sorted(_specs.iteritems(), key = operator.itemgetter(1))
|
||||
specs = []
|
||||
for s in range(0, len(sorted_specs)):
|
||||
specs.append(sorted_specs[s][0])
|
||||
return specs
|
||||
|
||||
_notice(self.opts, 'arch: ' + self.arch)
|
||||
specs = self.opts.get_spec_files('*' + self.arch + '*')
|
||||
arch_specs = []
|
||||
for spec in specs:
|
||||
if spec.lower().find(self.arch.lower()) >= 0:
|
||||
arch_specs.append(spec)
|
||||
arch_specs = _sort(arch_specs)
|
||||
self.opts.opts['no-clean'] = '1'
|
||||
current_path = os.environ['PATH']
|
||||
try:
|
||||
for s in range(0, len(arch_specs)):
|
||||
b = build.build(arch_specs[s], _defaults = self.defaults, opts = self.opts)
|
||||
if s == 0:
|
||||
path = self.first_package(b)
|
||||
b.make()
|
||||
self.every_package(b, path)
|
||||
if s == len(arch_specs) - 1:
|
||||
self.last_package(b, path)
|
||||
del b
|
||||
finally:
|
||||
os.environ['PATH'] = current_path
|
||||
|
||||
def run():
|
||||
import sys
|
||||
try:
|
||||
opts, _defaults = defaults.load(sys.argv)
|
||||
log.default = log.log(opts.logfiles())
|
||||
_notice(opts, 'RTEMS Tools, CrossGCC Spec Builder, v%s' % (version))
|
||||
for arch in opts.params():
|
||||
c = crossgcc(arch, _defaults = _defaults, opts = opts)
|
||||
c.make()
|
||||
del c
|
||||
except error.general, gerr:
|
||||
print gerr
|
||||
sys.exit(1)
|
||||
except error.internal, ierr:
|
||||
print ierr
|
||||
sys.exit(1)
|
||||
except KeyboardInterrupt:
|
||||
_notice(opts, 'user terminated')
|
||||
sys.exit(1)
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
run()
|
52
specbuilder/specbuilder/darwin.py
Normal file
52
specbuilder/specbuilder/darwin.py
Normal file
@ -0,0 +1,52 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# RTEMS Tools Project (http://www.rtems.org/)
|
||||
# Copyright 2010 Chris Johns (chrisj@rtems.org)
|
||||
# All rights reserved.
|
||||
#
|
||||
# This file is part of the RTEMS Tools package in 'rtems-tools'.
|
||||
#
|
||||
# RTEMS Tools is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# RTEMS Tools is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with RTEMS Tools. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
#
|
||||
# This code is based on what ever doco about spec files I could find and
|
||||
# RTEMS project's spec files.
|
||||
#
|
||||
|
||||
import pprint
|
||||
import os
|
||||
|
||||
def load():
|
||||
uname = os.uname()
|
||||
defines = {
|
||||
'_os': 'darwin',
|
||||
'_host': uname[4] + '-apple-darwin' + uname[2],
|
||||
'_host_vendor': 'apple',
|
||||
'_host_os': 'darwin',
|
||||
'_host_cpu': uname[4],
|
||||
'_host_alias': '%{nil}',
|
||||
'_host_arch': uname[4],
|
||||
'_usr': '/opt/local',
|
||||
'_var': '/opt/local/var',
|
||||
'optflags': '-O2 -fasynchronous-unwind-tables',
|
||||
'_smp_mflags': '-j4',
|
||||
# Build readline with gdb.
|
||||
'without_system_readline': 'without_system_readline'
|
||||
}
|
||||
return defines
|
||||
|
||||
if __name__ == '__main__':
|
||||
pprint.pprint(load())
|
407
specbuilder/specbuilder/defaults.py
Normal file
407
specbuilder/specbuilder/defaults.py
Normal file
@ -0,0 +1,407 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# RTEMS Tools Project (http://www.rtems.org/)
|
||||
# Copyright 2010 Chris Johns (chrisj@rtems.org)
|
||||
# All rights reserved.
|
||||
#
|
||||
# This file is part of the RTEMS Tools package in 'rtems-tools'.
|
||||
#
|
||||
# RTEMS Tools is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# RTEMS Tools is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with RTEMS Tools. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
#
|
||||
# Determine the defaults and load the specific file.
|
||||
#
|
||||
|
||||
import glob
|
||||
import pprint
|
||||
import re
|
||||
import os
|
||||
|
||||
import error
|
||||
import execute
|
||||
|
||||
defaults = {
|
||||
# Hack. Suspect a hidden platform or comand line thing
|
||||
'_with_noarch_subpackages': '1',
|
||||
|
||||
# Paths
|
||||
'_host_platform': '%{_host_cpu}-%{_host_vendor}-%{_host_os}%{?_gnu}',
|
||||
'_build': '%{_host}',
|
||||
'_arch': '%{_host_arch}',
|
||||
'_topdir': os.getcwd(),
|
||||
'_srcrpmdir': '%{_topdir}/SRPMS',
|
||||
'_sourcedir': '%{_topdir}/SOURCES',
|
||||
'_specdir': '%{_topdir}/SPECS',
|
||||
'_rpmdir': '%{_topdir}/TARS',
|
||||
'_builddir': '%{_topdir}/BUILD/%{name}-%{version}-%{release}',
|
||||
'_docdir': '%{_defaultdocdir}',
|
||||
'_usrlibrpm': '%{_topdir}/RPMLIB',
|
||||
'_tmppath': '%{_topdir}/TMP',
|
||||
'buildroot:': '%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)',
|
||||
|
||||
# Not sure.
|
||||
'_gnu': '-gnu',
|
||||
|
||||
# Cloned stuff from an RPM insall
|
||||
'___build_args': '-e',
|
||||
'___build_cmd': '%{?_sudo:%{_sudo} }%{?_remsh:%{_remsh} %{_remhost} }%{?_remsudo:%{_remsudo} }%{?_remchroot:%{_remchroot} %{_remroot} }%{___build_shell} %{___build_args}',
|
||||
'___build_post': 'exit 0',
|
||||
'___build_pre': '''# ___build_pre in defaults.py
|
||||
RPM_SOURCE_DIR="%{_sourcedir}"
|
||||
RPM_BUILD_DIR="%{_builddir}"
|
||||
RPM_OPT_FLAGS="%{optflags}"
|
||||
RPM_ARCH="%{_arch}"
|
||||
RPM_OS="%{_os}"
|
||||
export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_ARCH RPM_OS
|
||||
RPM_DOC_DIR="%{_docdir}"
|
||||
export RPM_DOC_DIR
|
||||
RPM_PACKAGE_NAME="%{name}"
|
||||
RPM_PACKAGE_VERSION="%{version}"
|
||||
RPM_PACKAGE_RELEASE="%{release}"
|
||||
export RPM_PACKAGE_NAME RPM_PACKAGE_VERSION RPM_PACKAGE_RELEASE
|
||||
%{?buildroot:RPM_BUILD_ROOT="%{buildroot}"}
|
||||
export RPM_BUILD_ROOT
|
||||
%{?_javaclasspath:CLASSPATH="%{_javaclasspath}"; export CLASSPATH}
|
||||
LANG=C
|
||||
export LANG
|
||||
unset DISPLAY || :
|
||||
umask 022
|
||||
cd "%{_builddir}"''',
|
||||
'___build_shell': '%{?_buildshell:%{_buildshell}}%{!?_buildshell:/bin/sh}',
|
||||
'___build_template': '''#!%{___build_shell}
|
||||
%{___build_pre}
|
||||
%{nil}''',
|
||||
'__aclocal': 'aclocal',
|
||||
'__ar': 'ar',
|
||||
'__arch_install_post': '%{nil}',
|
||||
'__as': 'as',
|
||||
'__autoconf': 'autoconf',
|
||||
'__autoheader': 'autoheader',
|
||||
'__automake': 'automake',
|
||||
'__awk': 'awk',
|
||||
'__bash': '/bin/bash',
|
||||
'__bzip2': '/usr/bin/bzip2',
|
||||
'__cat': '/bin/cat',
|
||||
'__cc': '/usr/bin/gcc',
|
||||
'__check_files': '%{_usrlibrpm}/check-files %{buildroot}',
|
||||
'__chgrp': '/usr/bin/chgrp',
|
||||
'__chmod': '/bin/chmod',
|
||||
'__chown': '/usr/sbin/chown',
|
||||
'__cp': '/bin/cp',
|
||||
'__cpio': '/usr/bin/cpio',
|
||||
'__cpp': '/usr/bin/gcc -E',
|
||||
'__cxx': '/usr/bin/g++',
|
||||
'__grep': '/usr/bin/grep',
|
||||
'__gzip': '/usr/bin/gzip',
|
||||
'__id': '/usr/bin/id',
|
||||
'__id_u': '%{__id} -u',
|
||||
'__install': '/usr/bin/install',
|
||||
'__install_info': '/usr/bin/install-info',
|
||||
'__ld': '/usr/bin/ld',
|
||||
'__ldconfig': '/sbin/ldconfig',
|
||||
'__ln_s': 'ln -s',
|
||||
'__make': '/usr/bin/make',
|
||||
'__mkdir': '/bin/mkdir',
|
||||
'__mkdir_p': '/bin/mkdir -p',
|
||||
'__mv': '/bin/mv',
|
||||
'__nm': '/usr/bin/nm',
|
||||
'__objcopy': '%{_bindir}/objcopy',
|
||||
'__objdump': '%{_bindir}/objdump',
|
||||
'__patch': '/usr/bin/patch',
|
||||
'__perl': 'perl',
|
||||
'__perl_provides': '%{_usrlibrpm}/perl.prov',
|
||||
'__perl_requires': '%{_usrlibrpm}/perl.req',
|
||||
'__ranlib': 'ranlib',
|
||||
'__remsh': '%{__rsh}',
|
||||
'__rm': '/bin/rm',
|
||||
'__rsh': '/usr/bin/rsh',
|
||||
'__sed': '/usr/bin/sed',
|
||||
'__setup_post': '%{__chmod} -R a+rX,g-w,o-w .',
|
||||
'__sh': '/bin/sh',
|
||||
'__tar': '/usr/bin/tar',
|
||||
'__tar_extract': '%{__tar} -xvvf',
|
||||
'__unzip': '/usr/bin/unzip',
|
||||
'_datadir': '%{_prefix}/share',
|
||||
'_defaultdocdir': '%{_prefix}/share/doc',
|
||||
'_exeext': '',
|
||||
'_exec_prefix': '%{_prefix}',
|
||||
'_lib': 'lib',
|
||||
'_libdir': '%{_exec_prefix}/%{_lib}',
|
||||
'_libexecdir': '%{_exec_prefix}/libexec',
|
||||
'_localedir': '%{_datadir}/locale',
|
||||
'_localstatedir': '%{_prefix}/var',
|
||||
'_usr': '/usr/local',
|
||||
'_usrsrc': '%{_usr}/src',
|
||||
'_var': '/usr/local/var',
|
||||
'_varrun': '%{_var}/run',
|
||||
'nil': ''
|
||||
}
|
||||
|
||||
class command_line:
|
||||
"""Process the command line in a common way across all speculater commands."""
|
||||
|
||||
_defaults = { 'params' : [],
|
||||
'warn-all' : '0',
|
||||
'quiet' : '0',
|
||||
'trace' : '0',
|
||||
'dry-run' : '0',
|
||||
'no-clean' : '0' }
|
||||
|
||||
_long_opts = { '--prefix' : '_prefix',
|
||||
'--prefixbase' : '_prefixbase',
|
||||
'--topdir' : '_topdir',
|
||||
'--specdir' : '_specdir',
|
||||
'--builddir' : '_builddir',
|
||||
'--sourcedir' : '_sourcedir',
|
||||
'--usrlibrpm' : '_usrlibrpm',
|
||||
'--tmppath' : '_tmppath',
|
||||
'--log' : '_logfile',
|
||||
'--url' : '_url_base' }
|
||||
|
||||
_long_true_opts = { '--trace' : '_trace',
|
||||
'--warn-all' : '_warn_all',
|
||||
'--no-clean' : '_no_clean' }
|
||||
|
||||
_target_triplets = { '--host' : '_host',
|
||||
'--build' : '_build',
|
||||
'--target' : '_target' }
|
||||
|
||||
def __init__(self, argv):
|
||||
self.command_path = os.path.dirname(argv[0])
|
||||
if len(self.command_path) == 0:
|
||||
self.command_path = '.'
|
||||
self.command_name = os.path.basename(argv[0])
|
||||
self.args = argv[1:]
|
||||
self.defaults = {}
|
||||
for to in command_line._long_true_opts:
|
||||
self.defaults[command_line._long_true_opts[to]] = '0'
|
||||
self._process()
|
||||
|
||||
def __str__(self):
|
||||
def _dict(dd):
|
||||
s = ''
|
||||
ddl = dd.keys()
|
||||
ddl.sort()
|
||||
for d in ddl:
|
||||
s += ' ' + d + ': ' + str(dd[d]) + '\n'
|
||||
return s
|
||||
|
||||
s = 'command: ' + self.command() + \
|
||||
'\nargs: ' + str(self.args) + \
|
||||
'\nopts:\n' + _dict(self.opts)
|
||||
|
||||
return s
|
||||
|
||||
def _expand(self, s, _defaults):
|
||||
"""Simple basic expander of spec file macros."""
|
||||
mf = re.compile(r'%{[^}]+}')
|
||||
expanded = True
|
||||
while expanded:
|
||||
expanded = False
|
||||
for m in mf.findall(s):
|
||||
name = m[2:-1]
|
||||
if name in _defaults:
|
||||
s = s.replace(m, _defaults[name])
|
||||
expanded = True
|
||||
else:
|
||||
raise error.general('cannot process default macro: ' + m)
|
||||
return s
|
||||
|
||||
def _process(self):
|
||||
|
||||
def _process_lopt(opt, arg, long_opts, args, values = False):
|
||||
for lo in long_opts:
|
||||
if values and opt.startswith(lo):
|
||||
equals = opt.find('=')
|
||||
if equals < 0:
|
||||
if arg == len(args) - 1:
|
||||
raise error.general('missing option value: ' + lo)
|
||||
arg += 1
|
||||
value = args[arg]
|
||||
else:
|
||||
value = opt[equals + 1:]
|
||||
return lo, long_opts[lo], value, arg
|
||||
elif opt == lo:
|
||||
return lo, long_opts[lo], True, arg
|
||||
return None, None, None, arg
|
||||
|
||||
self.opts = command_line._defaults
|
||||
i = 0
|
||||
while i < len(self.args):
|
||||
a = self.args[i]
|
||||
if a.startswith('-'):
|
||||
if a.startswith('--'):
|
||||
if a.startswith('--warn-all'):
|
||||
self.opts['warn-all'] = True
|
||||
else:
|
||||
lo, macro, value, i = _process_lopt(a, i,
|
||||
command_line._long_true_opts,
|
||||
self.args)
|
||||
if lo:
|
||||
self.defaults[macro] = '1'
|
||||
self.opts[lo[2:]] = '1'
|
||||
else:
|
||||
lo, macro, value, i = _process_lopt(a, i,
|
||||
command_line._long_opts,
|
||||
self.args, True)
|
||||
if lo:
|
||||
self.defaults[macro] = value
|
||||
self.opts[lo[2:]] = value
|
||||
else:
|
||||
#
|
||||
# The target triplet is 'cpu-vendor-os'.
|
||||
#
|
||||
lo, macro, value, i = _process_lopt(a, i,
|
||||
command_line._target_triplets,
|
||||
self.args, True)
|
||||
if lo:
|
||||
#
|
||||
# This is a target triplet. Run it past config.sub to make
|
||||
# make sure it is ok.
|
||||
#
|
||||
e = execute.capture_execution()
|
||||
config_sub = os.path.join(self.command_path, 'config.sub')
|
||||
exit_code, proc, output = e.shell(config_sub + ' ' + value)
|
||||
if exit_code == 0:
|
||||
value = output
|
||||
self.defaults[macro] = value
|
||||
self.opts[lo[2:]] = value
|
||||
_arch = macro + '_cpu'
|
||||
_vendor = macro + '_vendor'
|
||||
_os = macro + '_os'
|
||||
_arch_value = ''
|
||||
_vendor_value = ''
|
||||
_os_value = ''
|
||||
dash = value.find('-')
|
||||
if dash >= 0:
|
||||
_arch_value = value[:dash]
|
||||
value = value[dash + 1:]
|
||||
dash = value.find('-')
|
||||
if dash >= 0:
|
||||
_vendor_value = value[:dash]
|
||||
value = value[dash + 1:]
|
||||
if len(value):
|
||||
_os_value = value
|
||||
self.defaults[_arch] = _arch_value
|
||||
self.defaults[_vendor] = _vendor_value
|
||||
self.defaults[_os] = _os_value
|
||||
if not lo:
|
||||
raise error.general('invalid argument: ' + a)
|
||||
else:
|
||||
if a == '-n':
|
||||
self.opts['dry-run'] = '1'
|
||||
elif a == '-q':
|
||||
self.opts['quiet'] = '1'
|
||||
else:
|
||||
self.opts['params'].append(a)
|
||||
i += 1
|
||||
|
||||
def _post_process(self, _defaults):
|
||||
pass
|
||||
|
||||
def command(self):
|
||||
return os.path.join(self.command_path, self.command_name)
|
||||
|
||||
def dry_run(self):
|
||||
return self.opts['dry-run'] != '0'
|
||||
|
||||
def quiet(self):
|
||||
return self.opts['quiet'] != '0'
|
||||
|
||||
def trace(self):
|
||||
return self.opts['trace'] != '0'
|
||||
|
||||
def warn_all(self):
|
||||
return self.opts['warn-all'] != '0'
|
||||
|
||||
def no_clean(self):
|
||||
return self.opts['no-clean'] != '0'
|
||||
|
||||
def params(self):
|
||||
return self.opts['params']
|
||||
|
||||
def get_spec_files(self, spec):
|
||||
if spec.find('*') >= 0 or spec.find('?'):
|
||||
specdir = os.path.dirname(spec)
|
||||
specbase = os.path.basename(spec)
|
||||
if len(specbase) == 0:
|
||||
specbase = '*'
|
||||
if len(specdir) == 0:
|
||||
specdir = self._expand(defaults['_specdir'], defaults)
|
||||
if not os.path.isdir(specdir):
|
||||
raise error.general('specdir is not a directory or does not exist: ' + specdir)
|
||||
files = glob.glob(os.path.join(specdir, specbase))
|
||||
specs = files
|
||||
else:
|
||||
specs = [spec]
|
||||
return specs
|
||||
|
||||
def spec_files(self):
|
||||
specs = []
|
||||
for spec in self.opts['params']:
|
||||
specs.extend(self.get_spec_files(spec))
|
||||
return specs
|
||||
|
||||
def logfiles(self):
|
||||
if 'log' in self.opts:
|
||||
return self.opts['log'].split(',')
|
||||
return ['stdout']
|
||||
|
||||
def urls(self):
|
||||
if 'url' in self.opts:
|
||||
return self.opts['url'].split(',')
|
||||
return None
|
||||
|
||||
def prefixbase(self):
|
||||
if 'prefixbase' in self.opts:
|
||||
return self.opts['prefixbase']
|
||||
return None
|
||||
|
||||
def load(args):
|
||||
"""
|
||||
Copy the defaults, get the host specific values and merge
|
||||
them overriding any matching defaults, then create an options
|
||||
object to handle the command line merging in any command line
|
||||
overrides. Finally post process the command line.
|
||||
"""
|
||||
d = defaults
|
||||
overrides = None
|
||||
uname = os.uname()
|
||||
if uname[0] == 'Darwin':
|
||||
import darwin
|
||||
overrides = darwin.load()
|
||||
for k in overrides:
|
||||
d[k] = overrides[k]
|
||||
o = command_line(args)
|
||||
for k in o.defaults:
|
||||
d[k] = o.defaults[k]
|
||||
o._post_process(d)
|
||||
return o, d
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
try:
|
||||
_opts, _defaults = load(args = sys.argv)
|
||||
print _opts
|
||||
pprint.pprint(_defaults)
|
||||
except error.general, gerr:
|
||||
print gerr
|
||||
sys.exit(1)
|
||||
except error.internal, ierr:
|
||||
print ierr
|
||||
sys.exit(1)
|
||||
sys.exit(0)
|
||||
|
53
specbuilder/specbuilder/error.py
Normal file
53
specbuilder/specbuilder/error.py
Normal file
@ -0,0 +1,53 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# RTEMS Tools Project (http://www.rtems.org/)
|
||||
# Copyright 2010 Chris Johns (chrisj@rtems.org)
|
||||
# All rights reserved.
|
||||
#
|
||||
# This file is part of the RTEMS Tools package in 'rtems-tools'.
|
||||
#
|
||||
# RTEMS Tools is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# RTEMS Tools is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with RTEMS Tools. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
#
|
||||
# Various errors we can raise.
|
||||
#
|
||||
|
||||
class error(Exception):
|
||||
"""Base class for Builder exceptions."""
|
||||
def set_output(self, msg):
|
||||
self.msg = msg
|
||||
def __str__(self):
|
||||
return self.msg
|
||||
|
||||
class general(error):
|
||||
"""Raise for a general error."""
|
||||
def __init__(self, what):
|
||||
self.set_output('error: ' + what)
|
||||
|
||||
class internal(error):
|
||||
"""Raise for an internal error."""
|
||||
def __init__(self, what):
|
||||
self.set_output('internal error: ' + what)
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
raise general('a general error')
|
||||
except general, gerr:
|
||||
print 'caught:', gerr
|
||||
try:
|
||||
raise internal('an internal error')
|
||||
except internal, ierr:
|
||||
print 'caught:', ierr
|
367
specbuilder/specbuilder/execute.py
Executable file
367
specbuilder/specbuilder/execute.py
Executable file
@ -0,0 +1,367 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# RTEMS Tools Project (http://www.rtems.org/)
|
||||
# Copyright 2010 Chris Johns (chrisj@rtems.org)
|
||||
# All rights reserved.
|
||||
#
|
||||
# This file is part of the RTEMS Tools package in 'rtems-tools'.
|
||||
#
|
||||
# RTEMS Tools is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# RTEMS Tools is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with RTEMS Tools. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
#
|
||||
# Execute commands or scripts.
|
||||
#
|
||||
# Note, the subprocess module is only in Python 2.4 or higher.
|
||||
#
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import subprocess
|
||||
import threading
|
||||
|
||||
import error
|
||||
import log
|
||||
|
||||
# Redefine the PIPE from subprocess
|
||||
PIPE = subprocess.PIPE
|
||||
|
||||
# Regular expression to find quotes.
|
||||
qstr = re.compile('[rR]?\'([^\\n\'\\\\]|\\\\.)*\'|[rR]?"([^\\n"\\\\]|\\\\.)*"')
|
||||
|
||||
def check_type(command):
|
||||
"""Checks the type of command we have. The types are spawn and
|
||||
shell."""
|
||||
if command in ['spawn', 'shell']:
|
||||
return True
|
||||
return False
|
||||
|
||||
def arg_list(args):
|
||||
"""Turn a string of arguments into a list suitable for
|
||||
spawning a command. If the args are already a list return
|
||||
it."""
|
||||
if type(args) is list:
|
||||
return args
|
||||
argstr = args
|
||||
args = []
|
||||
while len(argstr):
|
||||
qs = qstr.search(argstr)
|
||||
if not qs:
|
||||
args.extend(argstr.split())
|
||||
argstr= ''
|
||||
else:
|
||||
# We have a quoted string. Get the string before
|
||||
# the quoted string and spltt on white space then
|
||||
# add the quoted string as an option then remove
|
||||
# the first + quoted string and try again
|
||||
front = argstr[:qs.start()]
|
||||
args.extend(front.split())
|
||||
args.append(argstr[qs.start() + 1:qs.end() - 1])
|
||||
argstr = argstr[qs.end():]
|
||||
return args
|
||||
|
||||
def arg_subst(command, substs):
|
||||
"""Substitute the %[0-9] in the command with the subst values."""
|
||||
args = arg_list(command)
|
||||
if substs:
|
||||
for a in range(0, len(args)):
|
||||
for r in range(0, len(substs)):
|
||||
args[a] = re.compile(('%%%d' % (r))).sub(substs[r], args[a])
|
||||
return args
|
||||
|
||||
def arg_subst_str(command, subst):
|
||||
cmd = arg_subst(command, subst)
|
||||
def add(x, y): return x + ' ' + str(y)
|
||||
return reduce(add, cmd, '')
|
||||
|
||||
class execute:
|
||||
"""Execute commands or scripts. The 'output' is a funtion
|
||||
that handles the output from the process."""
|
||||
def __init__(self, output = None, error_prefix = '', verbose = False):
|
||||
self.output = output
|
||||
self.error_prefix = error_prefix
|
||||
self.verbose = verbose
|
||||
self.shell_exe = None
|
||||
self.shell_commands = False
|
||||
self.path = None
|
||||
self.environment = None
|
||||
|
||||
def capture(self, proc, timeout = None):
|
||||
"""Create 2 threads to read stdout and stderr and send to the
|
||||
output handler. Based on the 'communicate' code in the subprocess
|
||||
module."""
|
||||
def _readthread(fh, out, prefix = ''):
|
||||
"""Read from a file handle and write to the output handler
|
||||
until the file closes."""
|
||||
while True:
|
||||
line = fh.readline()
|
||||
if len(line) == 0:
|
||||
break
|
||||
if out:
|
||||
out(prefix + line)
|
||||
else:
|
||||
log.output(prefix + line)
|
||||
def _timerthread(proc, timer):
|
||||
"""Timer thread calls the timer handler if one
|
||||
is present once a second. The user provides a handler
|
||||
and returns False to kill the process or True continue."""
|
||||
while True:
|
||||
time.sleep(1)
|
||||
if not timer(proc):
|
||||
proc.stdout.close()
|
||||
proc.stderr.close()
|
||||
|
||||
if proc.stdout:
|
||||
stdout_thread = threading.Thread(target = _readthread,
|
||||
args = (proc.stdout,
|
||||
self.output,
|
||||
''))
|
||||
stdout_thread.setDaemon(True)
|
||||
stdout_thread.start()
|
||||
if proc.stderr:
|
||||
stderr_thread = threading.Thread(target = _readthread,
|
||||
args = (proc.stderr,
|
||||
self.output,
|
||||
self.error_prefix))
|
||||
stderr_thread.setDaemon(True)
|
||||
stderr_thread.start()
|
||||
if proc.stdout:
|
||||
stdout_thread.join()
|
||||
if proc.stderr:
|
||||
stderr_thread.join()
|
||||
return proc.wait()
|
||||
|
||||
def open(self, command, capture = True, shell = False,
|
||||
cwd = None, env = None,
|
||||
stdin = None, stdout = None, stderr = None):
|
||||
"""Open a command with arguments. Provide the arguments as a list or
|
||||
a string."""
|
||||
if self.verbose:
|
||||
s = command
|
||||
if type(command) is list:
|
||||
def add(x, y): return x + ' ' + str(y)
|
||||
s = reduce(add, command, '')[1:]
|
||||
what = 'spawn'
|
||||
if shell:
|
||||
what = 'shell'
|
||||
log.output(what + ': ' + s)
|
||||
if shell and self.shell_exe:
|
||||
command = arg_list(command)
|
||||
command[:0] = self.shell_exe
|
||||
if not stdout:
|
||||
stdout = subprocess.PIPE
|
||||
if not stderr:
|
||||
stderr = subprocess.PIPE
|
||||
proc = None
|
||||
if cwd is None:
|
||||
cwd = self.path
|
||||
if env is None:
|
||||
env = self.environment
|
||||
try:
|
||||
# Work around a problem on Windows with commands that
|
||||
# have a '.' and no extension. Windows needs the full
|
||||
# command name.
|
||||
if sys.platform == "win32" and type(command) is list:
|
||||
if command[0].find('.') >= 0:
|
||||
r, e = os.path.splitext(command[0])
|
||||
if e not in ['.exe', '.com', '.bat']:
|
||||
command[0] = command[0] + '.exe'
|
||||
proc = subprocess.Popen(command, shell = shell,
|
||||
cwd = cwd, env = env,
|
||||
stdin = stdin, stdout = stdout,
|
||||
stderr = stderr)
|
||||
if not capture:
|
||||
return (0, proc)
|
||||
exit_code = self.capture(proc)
|
||||
if self.verbose:
|
||||
log.output('exit: ' + str(exit_code))
|
||||
except OSError, ose:
|
||||
exit_code = ose.errno
|
||||
if self.verbose:
|
||||
log.output('exit: ' + str(ose))
|
||||
return (exit_code, proc)
|
||||
|
||||
def spawn(self, command, capture = True, cwd = None, env = None,
|
||||
stdin = None, stdout = None, stderr = None):
|
||||
"""Spawn a command with arguments. Provide the arguments as a list or
|
||||
a string."""
|
||||
return self.open(command, capture, False, cwd, env,
|
||||
stdin, stdout, stderr)
|
||||
|
||||
def shell(self, command, capture = True, cwd = None, env = None,
|
||||
stdin = None, stdout = None, stderr = None):
|
||||
"""Execute a command within a shell context. The command can contain
|
||||
argumments. The shell is specific to the operating system. For example
|
||||
it is cmd.exe on Windows XP."""
|
||||
return self.open(command, capture, True, cwd, env,
|
||||
stdin, stdout, stderr)
|
||||
|
||||
def command(self, command, args = None, capture = True, shell = False,
|
||||
cwd = None, env = None,
|
||||
stdin = None, stdout = None, stderr = None):
|
||||
"""Run the command with the args. The args can be a list
|
||||
or a string."""
|
||||
if args and not type(args) is list:
|
||||
args = arg_list(args)
|
||||
cmd = [command]
|
||||
if args:
|
||||
cmd.extend(args)
|
||||
return self.open(cmd, capture = capture, shell = shell,
|
||||
cwd = cwd, env = env,
|
||||
stdin = stdin, stdout = stdout, stderr = stderr)
|
||||
|
||||
def command_subst(self, command, substs, capture = True, shell = False,
|
||||
cwd = None, env = None,
|
||||
stdin = None, stdout = None, stderr = None):
|
||||
"""Run the command from the config data with the
|
||||
option format string subsituted with the subst variables."""
|
||||
args = arg_subst(command, substs)
|
||||
return self.command(args[0], args[1:], capture = capture,
|
||||
shell = shell or self.shell_commands,
|
||||
cwd = cwd, env = env,
|
||||
stdin = stdin, stdout = stdout, stderr = stderr)
|
||||
|
||||
def set_shell(self, execute):
|
||||
"""Set the shell to execute when issuing a shell command."""
|
||||
args = arg_list(execute)
|
||||
if len(args) == 0 or not os.path.isfile(args[0]):
|
||||
raise error.general('could find shell: ' + execute)
|
||||
self.shell_exe = args
|
||||
|
||||
def command_use_shell(self):
|
||||
"""Force all commands to use a shell. This can be used with set_shell
|
||||
to allow Unix commands be executed on Windows with a Unix shell such
|
||||
as Cygwin or MSYS. This may cause piping to fail."""
|
||||
self.shell_commands = True
|
||||
|
||||
def set_output(self, output):
|
||||
"""Set the output handler. The stdout of the last process in a pipe
|
||||
line is passed to this handler."""
|
||||
old_output = self.output
|
||||
self.output = output
|
||||
return old_output
|
||||
|
||||
def set_path(self, path):
|
||||
"""Set the path changed to before the child process is created."""
|
||||
old_path = self.path
|
||||
self.path = path
|
||||
return old_path
|
||||
|
||||
def set_environ(self, environment):
|
||||
"""Set the environment passed to the child process when created."""
|
||||
old_environment = self.environment
|
||||
self.environment = environment
|
||||
return old_environment
|
||||
|
||||
class capture_execution(execute):
|
||||
"""Capture all output as a string and return it."""
|
||||
|
||||
class _output_snapper:
|
||||
def __init__(self, log = None, dump = False):
|
||||
self.output = ''
|
||||
self.log = log
|
||||
self.dump = dump
|
||||
|
||||
def handler(self, text):
|
||||
if not self.dump:
|
||||
if self.log is not None:
|
||||
self.log.output(text)
|
||||
else:
|
||||
self.output += text
|
||||
|
||||
def get_and_clear(self):
|
||||
text = self.output
|
||||
self.output = ''
|
||||
return text.strip()
|
||||
|
||||
def __init__(self, log = None, dump = False, error_prefix = '', verbose = False):
|
||||
self.snapper = capture_execution._output_snapper(log = log, dump = dump)
|
||||
execute.__init__(self, output = self.snapper.handler,
|
||||
error_prefix = error_prefix,
|
||||
verbose = verbose)
|
||||
|
||||
def open(self, command, capture = True, shell = False, cwd = None, env = None,
|
||||
stdin = None, stdout = None, stderr = None):
|
||||
if not capture:
|
||||
raise error.general('output capture must be true; leave as default')
|
||||
#self.snapper.get_and_clear()
|
||||
exit_code, proc = execute.open(self, command, capture = True, shell = shell,
|
||||
cwd = cwd, env = env,
|
||||
stdin = stdin, stdout = stdout, stderr = stderr)
|
||||
return (exit_code, proc, self.snapper.get_and_clear())
|
||||
|
||||
def set_output(self, output):
|
||||
raise error.general('output capture cannot be overrided')
|
||||
|
||||
if __name__ == "__main__":
|
||||
def run_tests(e, commands, use_shell):
|
||||
for c in commands['shell']:
|
||||
e.shell(c)
|
||||
for c in commands['spawn']:
|
||||
e.spawn(c)
|
||||
for c in commands['cmd']:
|
||||
if type(c) is str:
|
||||
e.command(c, shell = use_shell)
|
||||
else:
|
||||
e.command(c[0], c[1], shell = use_shell)
|
||||
for c in commands['csubsts']:
|
||||
e.command_subst(c[0], c[1], shell = use_shell)
|
||||
ec, proc = e.command(commands['pipe'][0], commands['pipe'][1],
|
||||
capture = False, stdin = subprocess.PIPE)
|
||||
if ec == 0:
|
||||
print 'piping input into ' + commands['pipe'][0] + ': ' + \
|
||||
commands['pipe'][2]
|
||||
proc.stdin.write(commands['pipe'][2])
|
||||
proc.stdin.close()
|
||||
e.capture(proc)
|
||||
del proc
|
||||
|
||||
cmd_shell_test = 'if "%OS%" == "Windows_NT" (echo It is WinNT) else echo Is is not WinNT'
|
||||
sh_shell_test = 'x="me"; if [ $x = "me" ]; then echo "It was me"; else "It was him"; fi'
|
||||
|
||||
commands = {}
|
||||
commands['windows'] = {}
|
||||
commands['unix'] = {}
|
||||
commands['windows']['shell'] = ['cd', 'dir /w', '.\\xyz', cmd_shell_test]
|
||||
commands['windows']['spawn'] = ['hostname', 'hostnameZZ', ['netstat', '/e']]
|
||||
commands['windows']['cmd'] = [('ipconfig'), ('nslookup', 'www.python.org')]
|
||||
commands['windows']['csubsts'] = [('netstat %0', ['-a']),
|
||||
('netstat %0 %1', ['-a', '-n'])]
|
||||
commands['windows']['pipe'] = ('ftp', None, 'help\nquit')
|
||||
commands['unix']['shell'] = ['pwd', 'ls -las', './xyz', sh_shell_test]
|
||||
commands['unix']['spawn'] = ['ls', 'execute.pyc', ['ls', '-i']]
|
||||
commands['unix']['cmd'] = [('date'), ('date', '-R'), ('date', ['-u', '+%d %D']),
|
||||
('date', '-u "+%d %D %S"')]
|
||||
commands['unix']['csubsts'] = [('date %0 "+%d %D %S"', ['-u']),
|
||||
('date %0 %1', ['-u', '+%d %D %S'])]
|
||||
commands['unix']['pipe'] = ('grep', 'hello', 'hello world')
|
||||
|
||||
print arg_list('cmd a1 a2 "a3 is a string" a4')
|
||||
print arg_list('cmd b1 b2 "b3 is a string a4')
|
||||
print arg_subst(['nothing', 'xx-%0-yyy', '%1', '%2-something'],
|
||||
['subst0', 'subst1', 'subst2'])
|
||||
|
||||
e = execute(error_prefix = 'ERR: ', verbose = True)
|
||||
if sys.platform == "win32":
|
||||
run_tests(e, commands['windows'], False)
|
||||
if os.path.exists('c:\\msys\\1.0\\bin\\sh.exe'):
|
||||
e.set_shell('c:\\msys\\1.0\\bin\\sh.exe --login -c')
|
||||
commands['unix']['pipe'] = ('c:\\msys\\1.0\\bin\\grep',
|
||||
'hello', 'hello world')
|
||||
run_tests(e, commands['unix'], True)
|
||||
else:
|
||||
run_tests(e, commands['unix'], False)
|
||||
del e
|
115
specbuilder/specbuilder/log.py
Executable file
115
specbuilder/specbuilder/log.py
Executable file
@ -0,0 +1,115 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# RTEMS Tools Project (http://www.rtems.org/)
|
||||
# Copyright 2010 Chris Johns (chrisj@rtems.org)
|
||||
# All rights reserved.
|
||||
#
|
||||
# This file is part of the RTEMS Tools package in 'rtems-testing'.
|
||||
#
|
||||
# RTEMS Tools is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# RTEMS Tools is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with RTEMS Tools. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
#
|
||||
# Log output to stdout and/or a file.
|
||||
#
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import error
|
||||
|
||||
#
|
||||
# A global log.
|
||||
#
|
||||
default = None
|
||||
|
||||
def set_default_once(log):
|
||||
if default is None:
|
||||
default = log
|
||||
|
||||
def output(text = os.linesep, log = None):
|
||||
"""Output the text to a log if provided else send it to stdout."""
|
||||
if text is None:
|
||||
text = os.linesep
|
||||
if type(text) is list:
|
||||
_text = ''
|
||||
for l in text:
|
||||
_text += l + os.linesep
|
||||
text = _text
|
||||
if log:
|
||||
log.output(text)
|
||||
elif default is not None:
|
||||
default.output(text)
|
||||
else:
|
||||
for l in text.replace(chr(13), '').splitlines():
|
||||
print l
|
||||
|
||||
def flush(log = None):
|
||||
if log:
|
||||
log.flush()
|
||||
elif default is not None:
|
||||
default.flush()
|
||||
|
||||
class log:
|
||||
"""Log output to stdout or a file."""
|
||||
def __init__(self, streams = None):
|
||||
self.fhs = [None, None]
|
||||
if streams:
|
||||
for s in streams:
|
||||
if s == 'stdout':
|
||||
self.fhs[0] = sys.stdout
|
||||
elif s == 'stderr':
|
||||
self.fhs[1] = sys.stderr
|
||||
else:
|
||||
try:
|
||||
self.fhs.append(file(s, 'w'))
|
||||
except IOError, ioe:
|
||||
raise error.general("creating log file '" + s + \
|
||||
"': " + str(ioe))
|
||||
|
||||
def __del__(self):
|
||||
for f in range(2, len(self.fhs)):
|
||||
self.fhs[f].close()
|
||||
|
||||
def has_stdout(self):
|
||||
return self.fhs[0] is not None
|
||||
|
||||
def has_stderr(self):
|
||||
return self.fhs[1] is not None
|
||||
|
||||
def output(self, text):
|
||||
"""Output the text message to all the logs."""
|
||||
# Reformat the text to have local line types.
|
||||
out = ''
|
||||
for l in text.replace(chr(13), '').splitlines():
|
||||
out += l + os.linesep
|
||||
for f in range(0, len(self.fhs)):
|
||||
if self.fhs[f] is not None:
|
||||
self.fhs[f].write(out)
|
||||
|
||||
def flush(self):
|
||||
"""Flush the output."""
|
||||
for f in range(0, len(self.fhs)):
|
||||
if self.fhs[f] is not None:
|
||||
self.fhs[f].flush()
|
||||
|
||||
if __name__ == "__main__":
|
||||
l = log(['stdout', 'log.txt'])
|
||||
for i in range(0, 10):
|
||||
l.output('hello world: %d\n' % (i))
|
||||
l.output('hello world CRLF\r\n')
|
||||
l.output('hello world NONE')
|
||||
l.flush()
|
||||
del l
|
101
specbuilder/specbuilder/setup.py
Normal file
101
specbuilder/specbuilder/setup.py
Normal file
@ -0,0 +1,101 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# RTEMS Tools Project (http://www.rtems.org/)
|
||||
# Copyright 2010 Chris Johns (chrisj@rtems.org)
|
||||
# All rights reserved.
|
||||
#
|
||||
# This file is part of the RTEMS Tools package in 'rtems-tools'.
|
||||
#
|
||||
# RTEMS Tools is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# RTEMS Tools is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with RTEMS Tools. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
#
|
||||
# Setup a series of directories ready for building with the Spec Builder.
|
||||
#
|
||||
|
||||
import os
|
||||
import shutil
|
||||
|
||||
import build
|
||||
import defaults
|
||||
import error
|
||||
import log
|
||||
|
||||
#
|
||||
# Version of Spec CrossGCC Builder.
|
||||
#
|
||||
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 setup:
|
||||
"""Set up the various directories in a specified path"""
|
||||
|
||||
_dirs = [ 'TARS',
|
||||
'TARS',
|
||||
'SPECS',
|
||||
'SOURCE',
|
||||
'RPMLIB',
|
||||
'BUILD',
|
||||
'TMP' ]
|
||||
|
||||
def __init__(self, path, _defaults, opts):
|
||||
self.path = path
|
||||
self.opts = opts
|
||||
self.defaults = _defaults
|
||||
|
||||
def _output(self, text):
|
||||
if not self.opts.quiet():
|
||||
log.output(text)
|
||||
|
||||
def mkdir(self, path):
|
||||
if not self.opts.dry_run():
|
||||
self._output('making dir: ' + path)
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except IOError, err:
|
||||
raise error.general('error creating path: ' + path)
|
||||
|
||||
def make(self, path):
|
||||
for d in setup._dirs:
|
||||
self.mkdir(os.path.join(path, d))
|
||||
|
||||
def run():
|
||||
import sys
|
||||
try:
|
||||
opts, _defaults = defaults.load(sys.argv)
|
||||
log.default = log.log(opts.logfiles())
|
||||
_notice(opts, 'RTEMS Tools, Setup Spec Builder, v%s' % (version))
|
||||
for path in opts.params():
|
||||
s = setup(path, _defaults = _defaults, opts = opts)
|
||||
s.make()
|
||||
del s
|
||||
except error.general, gerr:
|
||||
print gerr
|
||||
sys.exit(1)
|
||||
except error.internal, ierr:
|
||||
print ierr
|
||||
sys.exit(1)
|
||||
except KeyboardInterrupt:
|
||||
print 'user terminated'
|
||||
sys.exit(1)
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
run()
|
760
specbuilder/specbuilder/spec.py
Normal file
760
specbuilder/specbuilder/spec.py
Normal file
@ -0,0 +1,760 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# RTEMS Tools Project (http://www.rtems.org/)
|
||||
# Copyright 2010 Chris Johns (chrisj@rtems.org)
|
||||
# All rights reserved.
|
||||
#
|
||||
# This file is part of the RTEMS Tools package in 'rtems-tools'.
|
||||
#
|
||||
# RTEMS Tools is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# RTEMS Tools is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with RTEMS Tools. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
#
|
||||
# This code is based on what ever doco about spec files I could find and
|
||||
# RTEMS project's spec files. It parses a spec file into Python data types
|
||||
# that can be used by other software modules.
|
||||
#
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
import defaults
|
||||
import error
|
||||
import execute
|
||||
import log
|
||||
|
||||
debug = False
|
||||
|
||||
class package:
|
||||
|
||||
def __init__(self, name, arch):
|
||||
self._name = name
|
||||
self._arch = arch
|
||||
self.directives = {}
|
||||
self.infos = {}
|
||||
|
||||
def __str__(self):
|
||||
|
||||
def _dictlist(dl):
|
||||
s = ''
|
||||
dll = dl.keys()
|
||||
dll.sort()
|
||||
for d in dll:
|
||||
s += ' ' + d + ':\n'
|
||||
for l in dl[d]:
|
||||
s += ' ' + l + '\n'
|
||||
return s
|
||||
|
||||
s = '\npackage: ' + self._name + \
|
||||
'\n directives:\n' + _dictlist(self.directives) + \
|
||||
'\n infos:\n' + _dictlist(self.infos)
|
||||
|
||||
return s
|
||||
|
||||
def get_info(self, info):
|
||||
if not info in self.infos:
|
||||
raise error.general('no ' + info + ' in package "' + self.name + '"')
|
||||
return self.info
|
||||
|
||||
def version(self):
|
||||
return self.get_info('Version')
|
||||
|
||||
def extract_info(self, label):
|
||||
infos = {}
|
||||
for i in self.infos:
|
||||
il = i.lower()
|
||||
if il.startswith(label) and il[len(label):].isdigit():
|
||||
infos[il] = self.infos[i]
|
||||
return infos
|
||||
|
||||
def find_info(self, label):
|
||||
for i in self.infos:
|
||||
if i.lower() == label:
|
||||
return self.infos[i]
|
||||
return None
|
||||
|
||||
def find_directive(self, label):
|
||||
for d in self.directives:
|
||||
if d.lower() == label:
|
||||
return self.directives[d]
|
||||
return None
|
||||
|
||||
def name(self):
|
||||
info = self.find_info('name')
|
||||
if info:
|
||||
return info[0]
|
||||
return self._name
|
||||
|
||||
def version(self):
|
||||
info = self.find_info('version')
|
||||
if not info:
|
||||
return None
|
||||
return info[0]
|
||||
|
||||
def release(self):
|
||||
info = self.find_info('release')
|
||||
if not info:
|
||||
return None
|
||||
return info[0]
|
||||
|
||||
def buildarch(self):
|
||||
info = self.find_info('buildarch')
|
||||
if not info:
|
||||
return self._arch
|
||||
return info[0]
|
||||
|
||||
def sources(self):
|
||||
return self.extract_info('source');
|
||||
|
||||
def patches(self):
|
||||
return self.extract_info('patch')
|
||||
|
||||
def prep(self):
|
||||
return self.find_directive('%prep')
|
||||
|
||||
def build(self):
|
||||
return self.find_directive('%build')
|
||||
|
||||
def install(self):
|
||||
return self.find_directive('%install')
|
||||
|
||||
def clean(self):
|
||||
return self.find_directive('%clean')
|
||||
|
||||
def post(self):
|
||||
return self.find_directive('%post')
|
||||
|
||||
def long_name(self):
|
||||
buildarch = self.buildarch()
|
||||
return '-'.join([self.name(), self.version(), self.release()]) + \
|
||||
'.' + buildarch
|
||||
|
||||
class file:
|
||||
"""Parse a spec file."""
|
||||
|
||||
_directive = [ '%description',
|
||||
'%prep',
|
||||
'%build',
|
||||
'%install',
|
||||
'%clean',
|
||||
'%post',
|
||||
'%preun',
|
||||
'%files' ]
|
||||
|
||||
_ignore = [ re.compile('%setup'),
|
||||
re.compile('%doc'),
|
||||
re.compile('%dir'),
|
||||
re.compile('%ghost'),
|
||||
re.compile('%exclude'),
|
||||
re.compile('%source[0-9]*'),
|
||||
re.compile('%patch[0-9]*'),
|
||||
re.compile('%__os_install_post') ]
|
||||
|
||||
def __init__(self, name, _defaults, opts):
|
||||
self.opts = opts
|
||||
self.specpath = 'not set'
|
||||
self.wss = re.compile(r'\s+')
|
||||
self.tags = re.compile(r':+')
|
||||
self.sf = re.compile(r'%\([^\)]+\)')
|
||||
self.default_defines = {}
|
||||
for d in _defaults:
|
||||
self.default_defines[self._label(d)] = _defaults[d]
|
||||
for arg in self.opts.args:
|
||||
if arg.startswith('--with-') or arg.startswith('--without-'):
|
||||
label = arg[2:].lower().replace('-', '_')
|
||||
self.default_defines[self._label(label)] = label
|
||||
self.load(name)
|
||||
|
||||
def __str__(self):
|
||||
|
||||
def _dict(dd):
|
||||
s = ''
|
||||
ddl = dd.keys()
|
||||
ddl.sort()
|
||||
for d in ddl:
|
||||
s += ' ' + d + ': ' + dd[d] + '\n'
|
||||
return s
|
||||
|
||||
s = 'spec: %s' % (self.specpath) + \
|
||||
'\n' + str(self.opts) + \
|
||||
'\nlines parsed: %d' % (self.lc) + \
|
||||
'\nname: ' + self.name + \
|
||||
'\ndefines:\n' + _dict(self.defines)
|
||||
for _package in self._packages:
|
||||
s += str(self._packages[_package])
|
||||
return s
|
||||
|
||||
def _output(self, text):
|
||||
if not self.opts.quiet():
|
||||
log.output(text)
|
||||
|
||||
def _warning(self, msg):
|
||||
self._output('warning: ' + self.name + ':' + str(self.lc) + ': ' + msg)
|
||||
|
||||
def _error(self, msg):
|
||||
print >> sys.stderr, \
|
||||
'error: ' + self.name + ':' + str(self.lc) + ': ' + msg
|
||||
self.in_error = True
|
||||
|
||||
def _label(self, name):
|
||||
return '%{' + name.lower() + '}'
|
||||
|
||||
def _macro_split(self, s):
|
||||
'''Split the string (s) up by macros. Only split on the
|
||||
outter level. Nested levels will need to split with futher calls.'''
|
||||
trace_me = False
|
||||
macros = []
|
||||
nesting = []
|
||||
has_braces = False
|
||||
c = 0
|
||||
while c < len(s):
|
||||
if trace_me:
|
||||
print 'ms:', c, '"' + s[c:] + '"', has_braces, len(nesting), nesting
|
||||
#
|
||||
# We need to watch for shell type variables or the form '${var}' because
|
||||
# they can upset the brace matching.
|
||||
#
|
||||
if s[c] == '%' or s[c] == '$':
|
||||
start = s[c]
|
||||
c += 1
|
||||
if c == len(s):
|
||||
continue
|
||||
#
|
||||
# Do we have '%%' or '%(' or '$%' or '$(' or not '${' ?
|
||||
#
|
||||
if s[c] == '%' or s[c] == '(' or (start == '$' and s[c] != '{'):
|
||||
continue
|
||||
elif not s[c].isspace():
|
||||
#
|
||||
# If this is a shell macro and we are at the outter
|
||||
# level or is '$var' forget it and move on.
|
||||
#
|
||||
if start == '$' and (s[c] != '{' or len(nesting) == 0):
|
||||
continue
|
||||
if s[c] == '{':
|
||||
this_has_braces = True
|
||||
else:
|
||||
this_has_braces = False
|
||||
nesting.append((c - 1, has_braces))
|
||||
has_braces = this_has_braces
|
||||
elif len(nesting) > 0:
|
||||
if s[c] == '}' or (s[c].isspace() and not has_braces):
|
||||
#
|
||||
# Can have '%{?test: something %more}' where the
|
||||
# nested %more ends with the '}' which also ends
|
||||
# the outter macro.
|
||||
#
|
||||
if not has_braces:
|
||||
if s[c] == '}':
|
||||
macro_start, has_braces = nesting[len(nesting) - 1]
|
||||
nesting = nesting[:-1]
|
||||
if len(nesting) == 0:
|
||||
macros.append(s[macro_start:c].strip())
|
||||
if len(nesting) > 0:
|
||||
macro_start, has_braces = nesting[len(nesting) - 1]
|
||||
nesting = nesting[:-1]
|
||||
if len(nesting) == 0:
|
||||
macros.append(s[macro_start:c + 1].strip())
|
||||
c += 1
|
||||
if trace_me:
|
||||
print 'ms:', macros
|
||||
return macros
|
||||
|
||||
def _shell(self, line):
|
||||
sl = self.sf.findall(line)
|
||||
if len(sl):
|
||||
e = execute.capture_execution()
|
||||
for s in sl:
|
||||
exit_code, proc, output = e.shell(s[2:-1])
|
||||
if exit_code == 0:
|
||||
line = line.replace(s, output)
|
||||
else:
|
||||
raise error.general('shell macro failed: ' + s + ': ' + output)
|
||||
return line
|
||||
|
||||
def _expand(self, s):
|
||||
expanded = True
|
||||
while expanded:
|
||||
expanded = False
|
||||
ms = self._macro_split(s)
|
||||
for m in ms:
|
||||
mn = m
|
||||
#
|
||||
# A macro can be '%{macro}' or '%macro'. Turn the later into
|
||||
# the former.
|
||||
#
|
||||
show_warning = True
|
||||
if mn[1] != '{':
|
||||
for r in self._ignore:
|
||||
if r.match(mn) is not None:
|
||||
mn = None
|
||||
break
|
||||
else:
|
||||
mn = self._label(mn[1:])
|
||||
show_warning = False
|
||||
elif m.startswith('%{expand'):
|
||||
colon = m.find(':')
|
||||
if colon < 8:
|
||||
self._warning('malformed expand macro, no colon found')
|
||||
else:
|
||||
e = self._expand(m[colon + 1:-1].strip())
|
||||
s = s.replace(m, e)
|
||||
expanded = True
|
||||
mn = None
|
||||
elif m.startswith('%{with '):
|
||||
#
|
||||
# Change the ' ' to '_' because the macros have no spaces.
|
||||
#
|
||||
n = self._label('with_' + m[7:-1].strip())
|
||||
if n in self.defines:
|
||||
s = s.replace(m, '1')
|
||||
else:
|
||||
s = s.replace(m, '0')
|
||||
expanded = True
|
||||
mn = None
|
||||
elif m.startswith('%{echo'):
|
||||
mn = None
|
||||
elif m.startswith('%{defined'):
|
||||
n = self._label(m[9:-1].strip())
|
||||
if n in self.defines:
|
||||
s = s.replace(m, '1')
|
||||
else:
|
||||
s = s.replace(m, '0')
|
||||
expanded = True
|
||||
mn = None
|
||||
elif m.startswith('%{?') or m.startswith('%{!?'):
|
||||
if m[2] == '!':
|
||||
start = 4
|
||||
else:
|
||||
start = 3
|
||||
colon = m[start:].find(':')
|
||||
if colon < 0:
|
||||
if not m.endswith('}'):
|
||||
self._warning("malform conditional macro'" + m)
|
||||
mn = None
|
||||
else:
|
||||
mn = self._label(m[start:-1])
|
||||
else:
|
||||
mn = self._label(m[start:start + colon])
|
||||
if mn:
|
||||
if m.startswith('%{?'):
|
||||
if mn in self.defines:
|
||||
if colon >= 0:
|
||||
s = s.replace(m, m[start + colon + 1:-1])
|
||||
expanded = True
|
||||
mn = None
|
||||
else:
|
||||
mn = '%{nil}'
|
||||
else:
|
||||
if mn not in self.defines:
|
||||
if colon >= 0:
|
||||
s = s.replace(m, m[start + colon + 1:-1])
|
||||
expanded = True
|
||||
mn = None
|
||||
else:
|
||||
mn = '%{nil}'
|
||||
if mn:
|
||||
if mn.lower() in self.defines:
|
||||
s = s.replace(m, self.defines[mn.lower()])
|
||||
expanded = True
|
||||
elif show_warning:
|
||||
self._error("macro '" + mn + "' not found")
|
||||
return self._shell(s)
|
||||
|
||||
def _define(self, spec, ls):
|
||||
if len(ls) <= 1:
|
||||
self._warning('invalid macro definition')
|
||||
else:
|
||||
d = self._label(ls[1])
|
||||
if d not in self.defines:
|
||||
if len(ls) == 2:
|
||||
self.defines[d] = '1'
|
||||
else:
|
||||
self.defines[d] = ls[2].strip()
|
||||
else:
|
||||
if self.opts.warn_all():
|
||||
self._warning("macro '" + d + "' already defined")
|
||||
|
||||
def _undefine(self, spec, ls):
|
||||
if len(ls) <= 1:
|
||||
self._warning('invalid macro definition')
|
||||
else:
|
||||
mn = self._label(ls[1])
|
||||
if mn in self.defines:
|
||||
self._error("macro '" + mn + "' not defined")
|
||||
del self.defines[mn]
|
||||
|
||||
def _ifs(self, spec, ls, label, iftrue, isvalid):
|
||||
text = []
|
||||
in_iftrue = True
|
||||
while True:
|
||||
if isvalid and \
|
||||
((iftrue and in_iftrue) or (not iftrue and not in_iftrue)):
|
||||
this_isvalid = True
|
||||
else:
|
||||
this_isvalid = False
|
||||
r = self._parse(spec, roc = True, isvalid = this_isvalid)
|
||||
if r[0] == 'control':
|
||||
if r[1] == '%end':
|
||||
self._error(label + ' without %endif')
|
||||
if r[1] == '%endif':
|
||||
return text
|
||||
if r[1] == '%else':
|
||||
in_iftrue = False
|
||||
elif r[0] == 'data':
|
||||
if this_isvalid:
|
||||
text.extend(r[1])
|
||||
|
||||
def _if(self, spec, ls, isvalid):
|
||||
|
||||
global debug
|
||||
|
||||
def add(x, y):
|
||||
return x + ' ' + str(y)
|
||||
|
||||
def check_bool(value):
|
||||
if value.isdigit():
|
||||
if int(value) == 0:
|
||||
istrue = False
|
||||
else:
|
||||
istrue = True
|
||||
else:
|
||||
istrue = None
|
||||
return istrue
|
||||
|
||||
istrue = False
|
||||
if isvalid:
|
||||
if len(ls) == 2:
|
||||
s = ls[1]
|
||||
else:
|
||||
s = (ls[1] + ' ' + ls[2])
|
||||
ifls = s.split()
|
||||
if len(ifls) == 1:
|
||||
istrue = check_bool(ifls[0])
|
||||
if istrue == None:
|
||||
self._error('invalid if bool value: ' + reduce(add, ls, ''))
|
||||
istrue = False
|
||||
elif len(ifls) == 2:
|
||||
if ifls[0] == '!':
|
||||
istrue = check_bool(ifls[1])
|
||||
if istrue == None:
|
||||
self._error('invalid if bool value: ' + reduce(add, ls, ''))
|
||||
istrue = False
|
||||
else:
|
||||
istrue = not istrue
|
||||
else:
|
||||
self._error('invalid if bool operator: ' + reduce(add, ls, ''))
|
||||
elif len(ifls) == 3:
|
||||
if ifls[1] == '==':
|
||||
if ifls[0] == ifls[2]:
|
||||
istrue = True
|
||||
else:
|
||||
istrue = False
|
||||
elif ifls[1] == '!=' or ifls[1] == '=!':
|
||||
if ifls[0] != ifls[2]:
|
||||
istrue = True
|
||||
else:
|
||||
istrue = False
|
||||
elif ifls[1] == '>':
|
||||
if ifls[0] > ifls[2]:
|
||||
istrue = True
|
||||
else:
|
||||
istrue = False
|
||||
elif ifls[1] == '>=' or ifls[1] == '=>':
|
||||
if ifls[0] >= ifls[2]:
|
||||
istrue = True
|
||||
else:
|
||||
istrue = False
|
||||
elif ifls[1] == '<=' or ifls[1] == '=<':
|
||||
if ifls[0] <= ifls[2]:
|
||||
istrue = True
|
||||
else:
|
||||
istrue = False
|
||||
elif ifls[1] == '<':
|
||||
if ifls[0] < ifls[2]:
|
||||
istrue = True
|
||||
else:
|
||||
istrue = False
|
||||
else:
|
||||
self._error('invalid %if operator: ' + reduce(add, ls, ''))
|
||||
else:
|
||||
self._error('malformed if: ' + reduce(add, ls, ''))
|
||||
if debug:
|
||||
print '_if: ', ifls, istrue
|
||||
return self._ifs(spec, ls, '%if', istrue, isvalid)
|
||||
|
||||
def _ifos(self, spec, ls, isvalid):
|
||||
isos = False
|
||||
if isvalid:
|
||||
os = self.define('_os')
|
||||
if ls[0].find(os) >= 0 or ls[1].find(os) >= 0:
|
||||
isos = True
|
||||
else:
|
||||
isos = False
|
||||
return self._ifs(spec, ls, '%ifos', isos, isvalid)
|
||||
|
||||
def _ifarch(self, spec, positive, ls, isvalid):
|
||||
isarch = False
|
||||
if isvalid:
|
||||
arch = self.define('_arch')
|
||||
if ls[0].find(arch) >= 0 or ls[1].find(arch) >= 0:
|
||||
isarch = True
|
||||
else:
|
||||
isarch = False
|
||||
if not positive:
|
||||
isarch = not isarch
|
||||
return self._ifs(spec, ls, '%ifarch', isarch, isvalid)
|
||||
|
||||
def _parse(self, spec, roc = False, isvalid = True):
|
||||
# roc = return on control
|
||||
|
||||
global debug
|
||||
|
||||
def _clean(line):
|
||||
line = line[0:-1]
|
||||
b = line.find('#')
|
||||
if b >= 0:
|
||||
line = line[1:b]
|
||||
return line.strip()
|
||||
|
||||
#
|
||||
# Need to add code to count matching '{' and '}' and if they
|
||||
# do not match get the next line and add to the string until
|
||||
# they match. This closes an opening '{' that is on another
|
||||
# line.
|
||||
#
|
||||
|
||||
for l in spec:
|
||||
self.lc += 1
|
||||
l = _clean(l)
|
||||
if len(l) == 0:
|
||||
continue
|
||||
if debug:
|
||||
print '%03d: %d %s' % (self.lc, isvalid, l)
|
||||
if isvalid:
|
||||
l = self._expand(l)
|
||||
if len(l) == 0:
|
||||
continue
|
||||
if l[0] == '%':
|
||||
ls = self.wss.split(l, 2)
|
||||
if ls[0] == '%package':
|
||||
if isvalid:
|
||||
if ls[1] == '-n':
|
||||
name = ls[2]
|
||||
else:
|
||||
name = self.name + '-' + ls[1]
|
||||
return ('package', name)
|
||||
elif ls[0] == '%define' or ls[0] == '%global':
|
||||
if isvalid:
|
||||
self._define(spec, ls)
|
||||
elif ls[0] == '%undefine':
|
||||
if isvalid:
|
||||
self._undefine(spec, ls)
|
||||
elif ls[0] == '%if':
|
||||
d = self._if(spec, ls, isvalid)
|
||||
if len(d):
|
||||
return ('data', d)
|
||||
elif ls[0] == '%ifos':
|
||||
d = self._ifos(spec, ls, isvalid)
|
||||
if len(d):
|
||||
return ('data', d)
|
||||
elif ls[0] == '%ifarch':
|
||||
d = self._ifarch(spec, True, ls, isvalid)
|
||||
if len(d):
|
||||
return ('data', d)
|
||||
elif ls[0] == '%ifnarch':
|
||||
d = self._ifarch(spec, False, ls, isvalid)
|
||||
if len(d):
|
||||
return ('data', d)
|
||||
elif ls[0] == '%endif':
|
||||
if roc:
|
||||
return ('control', '%endif')
|
||||
self._warning("unexpected '" + ls[0] + "'")
|
||||
elif ls[0] == '%else':
|
||||
if roc:
|
||||
return ('control', '%else')
|
||||
self._warning("unexpected '" + ls[0] + "'")
|
||||
elif ls[0].startswith('%defattr'):
|
||||
return ('data', [l])
|
||||
elif ls[0] == '%bcond_with':
|
||||
if isvalid:
|
||||
#
|
||||
# Check is already defined. Would be by the command line or
|
||||
# even a host specific default.
|
||||
#
|
||||
if self._label('with_' + ls[1]) not in self.defines:
|
||||
self._define(spec, (ls[0], 'without_' + ls[1]))
|
||||
elif ls[0] == '%bcond_without':
|
||||
if isvalid:
|
||||
if self._label('without_' + ls[1]) not in self.defines:
|
||||
self._define(spec, (ls[0], 'with_' + ls[1]))
|
||||
else:
|
||||
for r in self._ignore:
|
||||
if r.match(ls[0]) is not None:
|
||||
return ('data', [l])
|
||||
if isvalid:
|
||||
for d in self._directive:
|
||||
if ls[0].strip() == d:
|
||||
if len(ls) == 1:
|
||||
package = 'main'
|
||||
elif len(ls) == 2:
|
||||
package = ls[1].strip()
|
||||
else:
|
||||
if ls[1].strip() != '-n':
|
||||
self._warning("unknown directive option: '" + ls[1] + "'")
|
||||
package = ls[2].strip()
|
||||
return ('directive', ls[0].strip(), package)
|
||||
self._warning("unknown directive: '" + ls[0] + "'")
|
||||
return ('data', [l])
|
||||
else:
|
||||
return ('data', [l])
|
||||
return ('control', '%end')
|
||||
|
||||
def _set_package(self, _package):
|
||||
if self.package == 'main' and \
|
||||
self._packages[self.package].name() != None:
|
||||
if self._packages[self.package].name() == _package:
|
||||
return
|
||||
if _package not in self._packages:
|
||||
self._packages[_package] = package(_package,
|
||||
self.define('%{_arch}'))
|
||||
self.package = _package
|
||||
|
||||
def _directive_extend(self, dir, data):
|
||||
if dir not in self._packages[self.package].directives:
|
||||
self._packages[self.package].directives[dir] = []
|
||||
for i in range(0, len(data)):
|
||||
data[i] = data[i].strip()
|
||||
self._packages[self.package].directives[dir].extend(data)
|
||||
|
||||
def _info_append(self, info, data):
|
||||
if info not in self._packages[self.package].infos:
|
||||
self._packages[self.package].infos[info] = []
|
||||
self._packages[self.package].infos[info].append(data)
|
||||
|
||||
def load(self, name):
|
||||
|
||||
global debug
|
||||
|
||||
self.in_error = False
|
||||
self.name = name
|
||||
self.lc = 0
|
||||
self.defines = self.default_defines
|
||||
self.conditionals = {}
|
||||
self._packages = {}
|
||||
self.package = 'main'
|
||||
self._packages[self.package] = package(self.package,
|
||||
self.define('%{_arch}'))
|
||||
self.specpath = os.path.join(self.abspath('_specdir'), name)
|
||||
if not os.path.exists(self.specpath):
|
||||
raise error.general('no spec file found: ' + self.specpath)
|
||||
try:
|
||||
spec = open(self.specpath, 'r')
|
||||
except IOError, err:
|
||||
raise error.general('error opening spec file: ' + self.specpath)
|
||||
try:
|
||||
dir = None
|
||||
data = []
|
||||
while True:
|
||||
r = self._parse(spec)
|
||||
if r[0] == 'package':
|
||||
self._set_package(r[1])
|
||||
dir = None
|
||||
elif r[0] == 'control':
|
||||
if r[1] == '%end':
|
||||
break
|
||||
self._warning("unexpected '" + r[1] + "'")
|
||||
elif r[0] == 'directive':
|
||||
self._set_package(r[2])
|
||||
if dir and dir != r[1]:
|
||||
self._directive_extend(dir, data)
|
||||
dir = r[1]
|
||||
data = []
|
||||
elif r[0] == 'data':
|
||||
for l in r[1]:
|
||||
l = self._expand(l)
|
||||
if not dir:
|
||||
ls = self.tags.split(l, 1)
|
||||
if debug:
|
||||
print '_tag: ', l, ls
|
||||
if len(ls) > 1:
|
||||
i = ls[0]
|
||||
self._info_append(i, ls[1].strip())
|
||||
# It seems like the info's also appear as
|
||||
# defines or can be accessed via macros.
|
||||
if ls[0][len(ls[0]) - 1] == ':':
|
||||
ls[0] = ls[0][:-1]
|
||||
ls[0] = ls[0].lower()
|
||||
self._define(None, ('', ls[0], ls[1]))
|
||||
else:
|
||||
self._warning("invalid format: '" + l[:-1] + "'")
|
||||
else:
|
||||
data.append(l)
|
||||
else:
|
||||
self._error("invalid parse state: '" + r[0] + "'")
|
||||
self._directive_extend(dir, data)
|
||||
finally:
|
||||
spec.close()
|
||||
|
||||
def define(self, name):
|
||||
if name.lower() in self.defines:
|
||||
d = self.defines[name.lower()]
|
||||
else:
|
||||
n = self._label(name)
|
||||
if n in self.defines:
|
||||
d = self.defines[n]
|
||||
else:
|
||||
raise error.general('macro "' + name + '" not found')
|
||||
return self._expand(d)
|
||||
|
||||
def expand(self, line):
|
||||
return self._expand(line)
|
||||
|
||||
def directive(self, _package, name):
|
||||
if _package not in self._packages:
|
||||
raise error.general('package "' + _package + '" not found')
|
||||
if name not in self._packages[_package].directives:
|
||||
raise error.general('directive "' + name + \
|
||||
'" not found in package "' + _package + '"')
|
||||
return self._packages[_package].directives[name]
|
||||
|
||||
def abspath(self, path):
|
||||
return os.path.abspath(self.define(path))
|
||||
|
||||
def packages(self):
|
||||
return self._packages
|
||||
|
||||
def run():
|
||||
import sys
|
||||
try:
|
||||
opts, _defaults = defaults.load(sys.argv)
|
||||
for spec_file in opts.spec_files():
|
||||
s = file(spec_file, _defaults = _defaults, opts = opts)
|
||||
print s
|
||||
del s
|
||||
except error.general, gerr:
|
||||
print gerr
|
||||
sys.exit(1)
|
||||
except error.internal, ierr:
|
||||
print ierr
|
||||
sys.exit(1)
|
||||
except KeyboardInterrupt:
|
||||
print 'user terminated'
|
||||
sys.exit(1)
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
run()
|
95
specbuilder/specbuilder/status.py
Normal file
95
specbuilder/specbuilder/status.py
Normal file
@ -0,0 +1,95 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# RTEMS Tools Project (http://www.rtems.org/)
|
||||
# Copyright 2010 Chris Johns (chrisj@rtems.org)
|
||||
# All rights reserved.
|
||||
#
|
||||
# This file is part of the RTEMS Tools package in 'rtems-tools'.
|
||||
#
|
||||
# RTEMS Tools is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# RTEMS Tools is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with RTEMS Tools. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
#
|
||||
# Extract the status of the spec files found in the SPECS directory.
|
||||
# The status is the name, source and patches.
|
||||
#
|
||||
|
||||
import os
|
||||
|
||||
import defaults
|
||||
import error
|
||||
import spec
|
||||
|
||||
class status:
|
||||
"""Return the status of a package given a spec file."""
|
||||
|
||||
def __init__(self, name, _defaults, opts):
|
||||
self.opts = opts
|
||||
self.spec = spec.file(name, _defaults = _defaults, opts = opts)
|
||||
|
||||
def __str__(self):
|
||||
|
||||
def str_package(package):
|
||||
sources = package.sources()
|
||||
patches = package.patches()
|
||||
version = package.version()
|
||||
release = package.release()
|
||||
buildarch = package.buildarch()
|
||||
s = '\n name: ' + package.name()
|
||||
if buildarch:
|
||||
s += '\n arch: ' + buildarch
|
||||
if version:
|
||||
s += '\n version: ' + version
|
||||
if release:
|
||||
s += '\n release: ' + release
|
||||
if len(sources):
|
||||
s += '\n sources: %d' % (len(sources))
|
||||
c = 1
|
||||
for i in sources:
|
||||
s += '\n %d: ' % (c) + sources[i][0]
|
||||
c += 1
|
||||
s += '\n patches: %d' % (len(patches))
|
||||
c = 1
|
||||
for i in patches:
|
||||
s += '\n %d: ' % (c) + patches[i][0]
|
||||
c += 1
|
||||
return s
|
||||
|
||||
packages = self.spec.packages()
|
||||
s = 'spec: ' + os.path.basename(self.spec.name) + \
|
||||
str_package(packages['main'])
|
||||
for p in packages:
|
||||
if p != 'main':
|
||||
s += str_package(packages[p])
|
||||
return s
|
||||
|
||||
def run():
|
||||
import sys
|
||||
try:
|
||||
opts, _defaults = defaults.load(sys.argv)
|
||||
for spec_file in opts.spec_files():
|
||||
s = status(spec_file, _defaults = _defaults, opts = opts)
|
||||
print s
|
||||
del s
|
||||
except error.general, gerr:
|
||||
print gerr
|
||||
sys.exit(1)
|
||||
except error.internal, ierr:
|
||||
print ierr
|
||||
sys.exit(1)
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
run()
|
Loading…
x
Reference in New Issue
Block a user