-#!/usr/bin/python
+#!/usr/bin/python3
# Copyright (C) 2012-2020 Carl Hetherington <cth@carlh.net>
#
def __init__(self):
self.options = [ Option('mxe_prefix'),
Option('git_prefix'),
+ Option('git_reference'),
Option('osx_environment_prefix'),
Option('osx_sdk_prefix'),
Option('osx_sdk'),
# Utility bits
#
-def log(m):
+def log_normal(m):
if not globals.quiet:
print('\x1b[33m* %s\x1b[0m' % m)
+def log_verbose(m):
+ if globals.verbose:
+ print('\x1b[35m* %s\x1b[0m' % m)
+
def escape_spaces(s):
return s.replace(' ', '\\ ')
return '\"%s\"' % n.substr(' ', '\\ ')
def copytree(a, b):
- log('copy %s -> %s' % (scp_escape(a), scp_escape(b)))
+ log_normal('copy %s -> %s' % (scp_escape(a), scp_escape(b)))
if b.startswith('s3://'):
command('s3cmd -P -r put "%s" "%s"' % (a, b))
else:
command('scp -r %s %s' % (scp_escape(a), scp_escape(b)))
def copyfile(a, b):
- log('copy %s -> %s' % (scp_escape(a), scp_escape(b)))
+ log_normal('copy %s -> %s' % (scp_escape(a), scp_escape(b)))
if b.startswith('s3://'):
command('s3cmd -P put "%s" "%s"' % (a, b))
else:
command('ssh %s -- mkdir -p %s' % (s[0], s[1]))
def rmdir(a):
- log('remove %s' % a)
+ log_normal('remove %s' % a)
os.rmdir(a)
def rmtree(a):
- log('remove %s' % a)
+ log_normal('remove %s' % a)
shutil.rmtree(a, ignore_errors=True)
def command(c):
- log(c)
+ log_normal(c)
r = os.system(c)
if (r >> 8):
raise Error('command %s failed' % c)
def command_and_read(c):
- log(c)
+ log_normal(c)
p = subprocess.Popen(c.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(out, err) = p.communicate()
if p.returncode != 0:
raise Error('command %s failed (%s)' % (c, err))
- return out.splitlines()
+ return str(out, 'utf-8').splitlines()
def read_wscript_variable(directory, variable):
f = open('%s/wscript' % directory, 'r')
try:
f = open('ChangeLog', 'r')
except:
- log('Could not open ChangeLog')
+ log_normal('Could not open ChangeLog')
return
c = f.read()
def append_version_to_debian_changelog(version):
if not os.path.exists('debian'):
- log('Could not find debian directory')
+ log_normal('Could not find debian directory')
return
command('dch -b -v %s-1 "New upstream release."' % version)
return filename
-def get_options(args, target):
+def get_command_line_options(args):
+ """Get the options specified by --option on the command line"""
options = dict()
if args.option is not None:
for o in args.option:
options[b[0]] = True
else:
options[b[0]] = b[1]
- # Add defaults for any unspecified options
- tree = globals.trees.get(args.project, args.checkout, target)
- tree.add_defaults(options)
return options
self.set('CCACHE_BASEDIR', os.path.realpath(self.directory))
self.set('CCACHE_NOHASHDIR', '')
else:
- self.directory = directory
+ self.directory = os.path.realpath(directory)
self.rmdir = False
pass
def package(self, project, checkout, output_dir, options):
- tree = globals.trees.get(project, checkout, self)
- if self.build_dependencies:
- tree.build_dependencies(options)
- tree.build(options)
- if len(inspect.getargspec(tree.cscript['package']).args) == 3:
+ tree = self.build(project, checkout, options)
+ tree.add_defaults(options)
+ if len(inspect.getfullargspec(tree.cscript['package']).args) == 3:
packages = tree.call('package', tree.version, options)
else:
- log("Deprecated cscript package() method with no options parameter")
+ log_normal("Deprecated cscript package() method with no options parameter")
packages = tree.call('package', tree.version)
- if isinstance(packages, (str, unicode)):
- copyfile(packages, os.path.join(output_dir, os.path.basename(devel_to_git(tree.git_commit, packages))))
- else:
+ if isinstance(packages, list):
for p in packages:
copyfile(p, os.path.join(output_dir, os.path.basename(devel_to_git(tree.git_commit, p))))
+ else:
+ copyfile(packages, os.path.join(output_dir, os.path.basename(devel_to_git(tree.git_commit, packages))))
def build(self, project, checkout, options):
tree = globals.trees.get(project, checkout, self)
if self.build_dependencies:
tree.build_dependencies(options)
tree.build(options)
+ return tree
def test(self, tree, test, options):
"""test is the test case to run, or None"""
return ''
return '-u %s' % getpass.getuser()
+ def _mount_option(self, d):
+ return '-v %s:%s ' % (os.path.realpath(d), os.path.realpath(d))
+
def setup(self):
- opts = '-v %s:%s ' % (self.directory, self.directory)
+ opts = self._mount_option(self.directory)
for m in self.mounts:
- opts += '-v %s:%s ' % (m, m)
+ opts += self._mount_option(m)
+ if config.has('git_reference'):
+ opts += self._mount_option(config.get('git_reference'))
if self.privileged:
opts += '--privileged=true '
if self.ccache:
- opts += "-e CCACHE_DIR=/ccache --volumes-from ccache-%s" % self.image
+ opts += "-e CCACHE_DIR=/ccache/%s --mount source=ccache,target=/ccache" % self.image
tag = self.image
if config.has('docker_hub_repository'):
@property
def library_prefix(self):
- log('Deprecated property library_prefix: use environment_prefix')
+ log_normal('Deprecated property library_prefix: use environment_prefix')
return self.environment_prefix
@property
def windows_prefix(self):
- log('Deprecated property windows_prefix: use environment_prefix')
+ log_normal('Deprecated property windows_prefix: use environment_prefix')
return self.environment_prefix
@property
def mingw_prefixes(self):
- log('Deprecated property mingw_prefixes: use environment_prefix')
+ log_normal('Deprecated property mingw_prefixes: use environment_prefix')
return [self.environment_prefix]
@property
def mingw_path(self):
- log('Deprecated property mingw_path: use tool_path')
+ log_normal('Deprecated property mingw_path: use tool_path')
return self.tool_path
@property
def mingw_name(self):
- log('Deprecated property mingw_name: use name')
+ log_normal('Deprecated property mingw_name: use name')
return self.name
class AppImageTarget(LinuxTarget):
def __init__(self, work):
- super(AppImageTarget, self).__init__('ubuntu', '16.04', 64, work)
+ super(AppImageTarget, self).__init__('ubuntu', '18.04', 64, work)
self.detail = 'appimage'
self.privileged = True
tree = globals.trees.get(project, checkout, self)
with TreeDirectory(tree):
- if len(inspect.getargspec(tree.cscript['package']).args) == 3:
+ if len(inspect.getfullargspec(tree.cscript['package']).args) == 3:
packages = tree.call('package', tree.version, options)
else:
- log("Deprecated cscript package() method with no options parameter")
+ log_normal("Deprecated cscript package() method with no options parameter")
packages = tree.call('package', tree.version)
for p in packages:
copyfile(p, os.path.join(output_dir, os.path.basename(devel_to_git(tree.git_commit, p))))
super(SourceTarget, self).__init__('source')
def command(self, c):
- log('host -> %s' % c)
+ log_normal('host -> %s' % c)
command('%s %s' % (self.variables_string(), c))
def cleanup(self):
if globals.quiet:
flags = '-q'
redirect = '>/dev/null'
- command('git clone %s %s/%s.git %s/src/%s' % (flags, config.get('git_prefix'), self.name, target.directory, self.name))
+ if config.has('git_reference'):
+ ref = '--reference-if-able %s/%s.git' % (config.get('git_reference'), self.name)
+ else:
+ ref = ''
+ command('git clone %s %s %s/%s.git %s/src/%s' % (flags, ref, config.get('git_prefix'), self.name, target.directory, self.name))
os.chdir('%s/src/%s' % (target.directory, self.name))
spec = self.specifier
exec(open('%s/cscript' % proj).read(), self.cscript)
# cscript can include submodules = False to stop submodules being fetched
- if not 'submodules' in self.cscript or self.cscript['submodules'] == True:
- command('git submodule init --quiet')
- command('git submodule update --quiet')
+ if (not 'submodules' in self.cscript or self.cscript['submodules'] == True) and os.path.exists('.gitmodules'):
+ command('git submodule --quiet init')
+ paths = command_and_read('git config --file .gitmodules --get-regexp path')
+ urls = command_and_read('git config --file .gitmodules --get-regexp url')
+ for path, url in zip(paths, urls):
+ path = path.split(' ')[1]
+ url = url.split(' ')[1]
+ ref = ''
+ if config.has('git_reference'):
+ ref_path = os.path.join(config.get('git_reference'), os.path.basename(url))
+ if os.path.exists(ref_path):
+ ref = '--reference %s' % ref_path
+ command('git submodule --quiet update %s %s' % (ref, path))
if os.path.exists('%s/wscript' % proj):
v = read_wscript_variable(proj, "VERSION");
try:
self.version = Version(v)
except:
- tag = subprocess.Popen(shlex.split('git -C %s describe --tags' % proj), stdout=subprocess.PIPE).communicate()[0][1:]
+ tag = command_and_read('git -C %s describe --tags' % proj)[0][1:]
self.version = Version.from_git_tag(tag)
os.chdir(cwd)
return self.cscript[function](self.target, *args)
def add_defaults(self, options):
- """Add the defaults from this into a dict options"""
+ """Add the defaults from self into a dict options"""
if 'option_defaults' in self.cscript:
from_cscript = self.cscript['option_defaults']
if isinstance(from_cscript, dict):
defaults_dict = from_cscript
else:
- log("Deprecated cscript option_defaults method; replace with a dict")
+ log_normal("Deprecated cscript option_defaults method; replace with a dict")
defaults_dict = from_cscript()
for k, v in defaults_dict.items():
if not k in options:
options[k] = v
def dependencies(self, options):
+ """
+ yield details of the dependencies of this tree. Each dependency is returned
+ as a tuple of (tree, options). The 'options' parameter are the options that
+ we want to force for 'self'.
+ """
if not 'dependencies' in self.cscript:
return
- if len(inspect.getargspec(self.cscript['dependencies']).args) == 2:
- deps = self.call('dependencies', options)
+ if len(inspect.getfullargspec(self.cscript['dependencies']).args) == 2:
+ self_options = copy.copy(options)
+ self.add_defaults(self_options)
+ deps = self.call('dependencies', self_options)
else:
- log("Deprecated cscript dependencies() method with no options parameter")
+ log_normal("Deprecated cscript dependencies() method with no options parameter")
deps = self.call('dependencies')
+ # Loop over our immediate dependencies
for d in deps:
dep = globals.trees.get(d[0], d[1], self.target, self.name)
- # Start with the options passed in
- dep_options = copy.copy(options)
- # Add things specified by the parent
- if len(d) > 2:
- for k, v in d[2].items():
- if not k in dep_options:
- dep_options[k] = v
- # Then fill in the dependency's defaults
- dep.add_defaults(dep_options)
-
+ # deps only get their options from the parent's cscript
+ dep_options = d[2] if len(d) > 2 else {}
for i in dep.dependencies(dep_options):
yield i
yield (dep, dep_options)
pass
def build_dependencies(self, options):
+ """
+ Called on the 'main' project tree (-p on the command line) to build all dependencies.
+ 'options' will be the ones from the command line.
+ """
for i in self.dependencies(options):
- global args
- if args.verbose:
- print('Building a dependency of %s %s %s with %s' % (self.name, self.specifier, self.version, options))
i[0].build(i[1])
def build(self, options):
if self.built:
return
- global args
- if args.verbose:
- print("* Building %s %s %s with %s" % (self.name, self.specifier, self.version, options))
+ log_verbose("Building %s %s %s with %s" % (self.name, self.specifier, self.version, options))
variables = copy.copy(self.target.variables)
- # Start with the options passed in
options = copy.copy(options)
- # Fill in the defaults
self.add_defaults(options)
if not globals.dry_run:
- if len(inspect.getargspec(self.cscript['build']).args) == 2:
+ if len(inspect.getfullargspec(self.cscript['build']).args) == 2:
self.call('build', options)
else:
self.call('build')
raise Error('you must specify -p or --project')
globals.quiet = args.quiet
+ globals.verbose = args.verbose
globals.command = args.command
globals.dry_run = args.dry_run
raise Error('you must specify -t or --target')
target = target_factory(args)
- target.build(args.project, args.checkout, get_options(args, target))
+ target.build(args.project, args.checkout, get_command_line_options(args))
if not args.keep:
target.cleanup()
output_dir = args.output
makedirs(output_dir)
- target.package(args.project, args.checkout, output_dir, get_options(args, target))
+ target.package(args.project, args.checkout, output_dir, get_command_line_options(args))
except Error as e:
if target is not None and not args.keep:
target.cleanup()
target = target_factory(args)
tree = globals.trees.get(args.project, args.checkout, target)
with TreeDirectory(tree):
- target.test(tree, args.test, get_options(args, target))
+ target.test(tree, args.test, get_command_line_options(args))
except Error as e:
if target is not None and not args.keep:
target.cleanup()