#!/usr/bin/python
-# Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+# Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-#
-# Configuration
-#
-
-# Directory to build things in within chroots
-DIR_IN_CHROOT = '/home/carl'
-# Prefix of chroots in the filesystem
-CHROOT_PREFIX = '/home/carl/Environments'
-# Prefix of windows environments
-WINDOWS_ENVIRONMENT_PREFIX = '/home/carl/Environments/windows'
-# Git prefix
-GIT_DIR = 'ssh://houllier/home/carl/git'
-OSX_BUILD_HOST = 'carl@192.168.1.202'
-DIR_ON_HOST = '/Users/carl/cdist'
-OSX_ENVIRONMENT_PREFIX = '/Users/carl/Environments/osx/10.8'
-
-
import os
import sys
import shutil
import datetime
import subprocess
import re
+import copy
+import inspect
+
+TEMPORARY_DIRECTORY = '/tmp'
+
+class Error(Exception):
+ def __init__(self, value):
+ self.value = value
+ def __str__(self):
+ return '\x1b[31m%s\x1b[0m' % repr(self.value)
+ def __repr__(self):
+ return str(self)
+
+#
+# Configuration
+#
+
+class Option(object):
+ def __init__(self, key):
+ self.key = key
+ self.value = None
+
+ def offer(self, key, value):
+ if key == self.key:
+ self.value = value
+
+class BoolOption(object):
+ def __init__(self, key):
+ self.key = key
+ self.value = False
+
+ def offer(self, key, value):
+ if key == self.key:
+ self.value = (value == 'yes' or value == '1' or value == 'true')
+
+class Config:
+ def __init__(self):
+ self.options = [ Option('linux_chroot_prefix'),
+ Option('windows_environment_prefix'),
+ Option('mingw_prefix'),
+ Option('git_prefix'),
+ Option('osx_build_host'),
+ Option('osx_environment_prefix'),
+ Option('osx_sdk_prefix'),
+ Option('osx_sdk') ]
+
+ try:
+ f = open('%s/.config/cdist' % os.path.expanduser('~'), 'r')
+ while 1:
+ l = f.readline()
+ if l == '':
+ break
+
+ if len(l) > 0 and l[0] == '#':
+ continue
+
+ s = l.strip().split()
+ if len(s) == 2:
+ for k in self.options:
+ k.offer(s[0], s[1])
+ except:
+ raise
+
+ def get(self, k):
+ for o in self.options:
+ if o.key == k:
+ return o.value
+
+ raise Error('Required setting %s not found' % k)
+
+config = Config()
#
# Utility bits
if not args.quiet:
print '\x1b[33m* %s\x1b[0m' % m
-def error(e):
- print '\x1b[31mError: %s\x1b[0m' % e
- sys.exit(1)
-
def copytree(a, b):
log('copy %s -> %s' % (a, b))
shutil.copytree(a, b)
log(c)
r = os.system(c)
if (r >> 8) and not can_fail:
- error('command %s failed' % c)
+ raise Error('command %s failed' % c)
def command_and_read(c):
log(c)
f = os.fdopen(os.dup(p.stdout.fileno()))
return f
+def read_wscript_variable(directory, variable):
+ f = open('%s/wscript' % directory, 'r')
+ while 1:
+ l = f.readline()
+ if l == '':
+ break
+
+ s = l.split()
+ if len(s) == 3 and s[0] == variable:
+ f.close()
+ return s[2][1:-1]
+
+ f.close()
+ return None
#
# Version
class Version:
def __init__(self, s):
- self.pre = False
- self.beta = None
+ self.devel = False
if s.startswith("'"):
s = s[1:]
if s.endswith("'"):
s = s[0:-1]
+ if s.endswith('devel'):
+ s = s[0:-5]
+ self.devel = True
+
if s.endswith('pre'):
s = s[0:-3]
- self.pre = True
-
- b = s.find("beta")
- if b != -1:
- self.beta = int(s[b+4:])
- s = s[0:b]
p = s.split('.')
self.major = int(p[0])
self.minor = int(p[1])
+ if len(p) == 3:
+ self.micro = int(p[2])
+ else:
+ self.micro = 0
- def bump(self):
+ def bump_minor(self):
self.minor += 1
- self.pre = False
- self.beta = None
+ self.micro = 0
- def to_pre(self):
- self.pre = True
- self.beta = None
+ def bump_micro(self):
+ self.micro += 1
- def bump_and_to_pre(self):
- self.bump()
- self.pre = True
- self.beta = None
+ def to_devel(self):
+ self.devel = True
def to_release(self):
- self.pre = False
- self.beta = None
-
- def bump_beta(self):
- if self.pre:
- self.pre = False
- self.beta = 1
- elif self.beta is not None:
- self.beta += 1
- elif self.beta is None:
- self.beta = 1
+ self.devel = False
def __str__(self):
- s = '%d.%02d' % (self.major, self.minor)
- if self.beta is not None:
- s += 'beta%d' % self.beta
- elif self.pre:
- s += 'pre'
+ s = '%d.%d.%d' % (self.major, self.minor, self.micro)
+ if self.devel:
+ s += 'devel'
return s
-
#
-# Environment
+# Targets
#
-class Environment(object):
- def __init__(self):
+class Target(object):
+ # @param directory directory to work in; if None we will use a temporary directory
+ # Temporary directories will be removed after use; specified directories will not
+ def __init__(self, platform, parallel, directory=None):
+ self.platform = platform
+ self.parallel = parallel
+
+ if directory is None:
+ self.directory = tempfile.mkdtemp('', 'tmp', TEMPORARY_DIRECTORY)
+ self.rmdir = True
+ else:
+ self.directory = directory
+ self.rmdir = False
+
+ print 'Working in %s' % self.directory
+
+ # Environment variables that we will use when we call cscripts
self.variables = {}
+ self.debug = False
+
+ def build_dependencies(self, project):
+ cwd = os.getcwd()
+ if 'dependencies' in project.cscript:
+ for d in project.cscript['dependencies'](self):
+ log('Building dependency %s %s of %s' % (d[0], d[1], project.name))
+ dep = Project(d[0], '.', d[1])
+ dep.checkout(self)
+ self.build_dependencies(dep)
+
+ # Make the options to pass in from the option_defaults of the thing
+ # we are building and any options specified by the parent.
+ options = {}
+ if 'option_defaults' in dep.cscript:
+ options = dep.cscript['option_defaults']()
+ if len(d) > 2:
+ for k, v in d[2].iteritems():
+ options[k] = v
+
+ self.build(dep, options)
+
+ os.chdir(cwd)
+
+ def build(self, project, options=None):
+ variables = copy.copy(self.variables)
+ if len(inspect.getargspec(project.cscript['build']).args) == 2:
+ project.cscript['build'](self, options)
+ else:
+ project.cscript['build'](self)
+ self.variables = variables
+
+ def package(self, project):
+ project.checkout(self)
+ self.build_dependencies(project)
+ self.build(project)
+ return project.cscript['package'](self, project.version)
+
+ def test(self, project):
+ project.checkout(self)
+ self.build_dependencies(project)
+ self.build(project)
+ project.cscript['test'](self)
def set(self, a, b):
self.variables[a] = b
+ def unset(self, a):
+ del(self.variables[a])
+
def get(self, a):
return self.variables[a]
+ def append_with_space(self, k, v):
+ if not k in self.variables:
+ self.variables[k] = v
+ else:
+ self.variables[k] = '%s %s' % (self.variables[k], v)
+
def variables_string(self, escaped_quotes=False):
e = ''
for k, v in self.variables.iteritems():
e += '%s=%s ' % (k, v)
return e
- def work_dir_cdist(self, sub):
- assert(false)
-
- def work_dir_cscript(self):
- assert(false)
-
- def build_dependencies(self, target, project):
- cwd = os.getcwd()
- if 'dependencies' in project.cscript:
- for d in project.cscript['dependencies'](target):
- dep = Project(d[0], '.', d[1])
- dep.checkout(self)
- self.build(target, dep)
- os.chdir(cwd)
+ def cleanup(self):
+ if self.rmdir:
+ rmtree(self.directory)
- def build(self, target, project):
- project.cscript['build'](self, target)
+#
+# Windows
+#
- def package(self, target, project):
- project.checkout(self)
- if target.platform != 'source':
- self.build_dependencies(target, project)
- if target.platform == 'source':
- command('./waf dist')
- if project.directory != '.':
- return os.path.abspath('%s-%s.tar.bz2' % (project.directory, project.version))
- return os.path.abspath('%s-%s.tar.bz2' % (project.name, project.version))
+class WindowsTarget(Target):
+ def __init__(self, bits, directory=None):
+ super(WindowsTarget, self).__init__('windows', 2, directory)
+ self.bits = bits
+
+ self.windows_prefix = '%s/%d' % (config.get('windows_environment_prefix'), self.bits)
+ if not os.path.exists(self.windows_prefix):
+ raise Error('windows prefix %s does not exist' % self.windows_prefix)
+
+ if self.bits == 32:
+ self.mingw_name = 'i686'
else:
- project.cscript['build'](self, target)
- return project.cscript['package'](self, target, project.version)
+ self.mingw_name = 'x86_64'
+
+ mingw_path = '%s/%d/bin' % (config.get('mingw_prefix'), self.bits)
+ self.mingw_prefixes = ['/%s/%d' % (config.get('mingw_prefix'), self.bits), '%s/%d/%s-w64-mingw32' % (config.get('mingw_prefix'), bits, self.mingw_name)]
+
+ self.set('PKG_CONFIG_LIBDIR', '%s/lib/pkgconfig' % self.windows_prefix)
+ self.set('PKG_CONFIG_PATH', '%s/lib/pkgconfig:%s/bin/pkgconfig' % (self.directory, self.directory))
+ self.set('PATH', '%s/bin:%s:%s' % (self.windows_prefix, mingw_path, os.environ['PATH']))
+ self.set('CC', '%s-w64-mingw32-gcc' % self.mingw_name)
+ self.set('CXX', '%s-w64-mingw32-g++' % self.mingw_name)
+ self.set('LD', '%s-w64-mingw32-ld' % self.mingw_name)
+ self.set('RANLIB', '%s-w64-mingw32-ranlib' % self.mingw_name)
+ self.set('WINRC', '%s-w64-mingw32-windres' % self.mingw_name)
+ cxx = '-I%s/include -I%s/include' % (self.windows_prefix, self.directory)
+ link = '-L%s/lib -L%s/lib' % (self.windows_prefix, self.directory)
+ for p in self.mingw_prefixes:
+ cxx += ' -I%s/include' % p
+ link += ' -L%s/lib' % p
+ self.set('CXXFLAGS', '"%s"' % cxx)
+ self.set('LINKFLAGS', '"%s"' % link)
- def cleanup(self):
- pass
+ def command(self, c):
+ log('host -> %s' % c)
+ command('%s %s' % (self.variables_string(), c))
#
-# ChrootEnvironment
+# Linux
#
-class ChrootEnvironment(Environment):
- def __init__(self, chroot):
- super(ChrootEnvironment, self).__init__()
- self.chroot = chroot
- self.dir_in_chroot = DIR_IN_CHROOT
- self.chroot_dir = CHROOT_PREFIX
-
- # ChrootEnvironments work in dir_in_chroot, and clear
- # it out before use
- for g in glob.glob('%s/*' % self.work_dir_cdist()):
- rmtree(g)
-
- # Environment variables
- self.set('CXXFLAGS', '-I%s/include' % self.work_dir_cscript())
- self.set('LINKFLAGS', '-L%s/lib' % self.work_dir_cscript())
- self.set('PKG_CONFIG_PATH', '%s/lib/pkgconfig' % self.work_dir_cscript())
-
- def work_dir_cdist(self):
- return '%s/%s%s' % (self.chroot_dir, self.chroot, self.dir_in_chroot)
-
- def work_dir_cscript(self):
- return self.dir_in_chroot
+class LinuxTarget(Target):
+ def __init__(self, distro, version, bits, directory=None):
+ super(LinuxTarget, self).__init__('linux', 2, directory)
+ self.distro = distro
+ self.version = version
+ self.bits = bits
+ # e.g. ubuntu-14.04-64
+ self.chroot = '%s-%s-%d' % (self.distro, self.version, self.bits)
+ # e.g. /home/carl/Environments/ubuntu-14.04-64
+ self.chroot_prefix = '%s/%s' % (config.get('linux_chroot_prefix'), self.chroot)
+
+ self.set('CXXFLAGS', '-I%s/include' % self.directory)
+ self.set('LINKFLAGS', '-L%s/lib' % self.directory)
+ self.set('PKG_CONFIG_PATH', '%s/lib/pkgconfig:/usr/local/lib/pkgconfig' % self.directory)
+ self.set('PATH', '%s:/usr/local/bin' % (os.environ['PATH']))
def command(self, c):
- # Work out the cwd for the chrooted command
- cwd = os.getcwd()
- prefix = '%s/%s' % (self.chroot_dir, self.chroot)
- assert(cwd.startswith(prefix))
- cwd = cwd[len(prefix):]
-
- log('schroot [%s] -> %s' % (cwd, c))
- command('%s schroot -c %s -d %s -p -- %s' % (self.variables_string(), self.chroot, cwd, c))
-
+ command('%s schroot -c %s -p -- %s' % (self.variables_string(), self.chroot, c))
#
-# RemoteEnvironment
+# OS X
#
-class RemoteEnvironment(Environment):
- def __init__(self, host):
- super(RemoteEnvironment, self).__init__()
- self.host = host
- self.dir_on_host = DIR_ON_HOST
- self.host_mount_dir = tempfile.mkdtemp()
+class OSXTarget(Target):
+ def __init__(self, directory=None):
+ super(OSXTarget, self).__init__('osx', 4, directory)
- # Mount the remote host on host_mount_dir
- command('sshfs %s:%s %s' % (self.host, self.dir_on_host, self.host_mount_dir))
- for g in glob.glob('%s/*' % self.host_mount_dir):
- rmtree(g)
+ def command(self, c):
+ command('%s %s' % (self.variables_string(False), c))
- # Environment variables
- self.set('CXXFLAGS', '"-I%s/include -I%s/include"' % (self.dir_on_host, OSX_ENVIRONMENT_PREFIX))
- self.set('LINKFLAGS', '"-L%s/lib -L%s/lib"' % (self.dir_on_host, OSX_ENVIRONMENT_PREFIX))
- self.set('PKG_CONFIG_PATH', '%s/lib/pkgconfig:%s/lib/pkgconfig' % (self.dir_on_host, OSX_ENVIRONMENT_PREFIX))
- self.set('PATH', '$PATH:/usr/local/bin:%s/bin' % OSX_ENVIRONMENT_PREFIX)
- def work_dir_cdist(self):
- return self.host_mount_dir
+class OSXSingleTarget(OSXTarget):
+ def __init__(self, bits, directory=None):
+ super(OSXSingleTarget, self).__init__(directory)
+ self.bits = bits
- def work_dir_cscript(self):
- return self.dir_on_host
+ if bits == 32:
+ arch = 'i386'
+ else:
+ arch = 'x86_64'
- def command(self, c):
- # Work out the cwd for the chrooted command
- cwd = os.getcwd()
- assert(cwd.startswith(self.host_mount_dir))
- cwd = cwd[len(self.host_mount_dir):]
+ flags = '-isysroot %s/MacOSX%s.sdk -arch %s' % (config.get('osx_sdk_prefix'), config.get('osx_sdk'), arch)
+ enviro = '%s/%d' % (config.get('osx_environment_prefix'), bits)
- log('ssh [%s] -> %s' % (cwd, c))
- command('ssh %s -- "PATH=/usr/bin:/sbin cd %s%s; %s %s"' % (self.host, self.dir_on_host, cwd, self.variables_string(True), c))
+ # Environment variables
+ self.set('CFLAGS', '"-I%s/include -I%s/include %s"' % (self.directory, enviro, flags))
+ self.set('CXXFLAGS', '"-I%s/include -I%s/include %s"' % (self.directory, enviro, flags))
+ self.set('LDFLAGS', '"-L%s/lib -L%s/lib %s"' % (self.directory, enviro, flags))
+ self.set('LINKFLAGS', '"-L%s/lib -L%s/lib %s"' % (self.directory, enviro, flags))
+ self.set('PKG_CONFIG_PATH', '%s/lib/pkgconfig:%s/lib/pkgconfig:/usr/lib/pkgconfig' % (self.directory, enviro))
+ self.set('PATH', '$PATH:/usr/bin:/sbin:/usr/local/bin:%s/bin' % enviro)
+ self.set('MACOSX_DEPLOYMENT_TARGET', config.get('osx_sdk'))
- def cleanup(self):
- os.chdir('/')
- command('fusermount -u %s' % self.host_mount_dir)
- rmdir(self.host_mount_dir)
+ def package(self, project):
+ raise Error('cannot package non-universal OS X versions')
-#
-# HostEnvironment
-#
-class HostEnvironment(Environment):
+class OSXUniversalTarget(OSXTarget):
def __init__(self, directory=None):
- super(HostEnvironment, self).__init__()
- if directory is None:
- self.directory = tempfile.mkdtemp()
- self.rmdir = True
- else:
- self.directory = directory
- self.rmdir = False
+ super(OSXUniversalTarget, self).__init__(directory)
+ self.parts = []
+ self.parts.append(OSXSingleTarget(32, os.path.join(self.directory, '32')))
+ self.parts.append(OSXSingleTarget(64, os.path.join(self.directory, '64')))
+
+ def package(self, project):
+ for p in self.parts:
+ project.checkout(p)
+ p.build_dependencies(project)
+ p.build(project)
+
+ return project.cscript['package'](self, project.version)
+
- def work_dir_cdist(self):
- return self.directory
+#
+# Source
+#
- def work_dir_cscript(self):
- return self.directory
+class SourceTarget(Target):
+ def __init__(self):
+ super(SourceTarget, self).__init__('source', 2)
def command(self, c):
log('host -> %s' % c)
command('%s %s' % (self.variables_string(), c))
def cleanup(self):
- if self.rmdir:
- rmtree(self.directory)
-
+ rmtree(self.directory)
-def prepare_for_windows(env, bits):
- env.windows_prefix = '%s/%d' % (WINDOWS_ENVIRONMENT_PREFIX, bits)
- if not os.path.exists(env.windows_prefix):
- error('windows prefix %s does not exist' % env.windows_prefix)
-
- if bits == 32:
- mingw_name = 'i686'
- else:
- mingw_name = 'x86_64'
-
- mingw_path = '/mingw/%d/bin' % bits
- mingw_prefixes = ['/mingw/%d' % bits, '/mingw/%d/%s-w64-mingw32' % (bits, mingw_name)]
-
- env.set('PKG_CONFIG_LIBDIR', '%s/lib/pkgconfig' % env.windows_prefix)
- env.set('PKG_CONFIG_PATH', '%s/lib/pkgconfig' % env.work_dir_cscript())
- env.set('PATH', '%s/bin:%s:%s' % (env.windows_prefix, mingw_path, os.environ['PATH']))
- env.set('CC', '%s-w64-mingw32-gcc' % mingw_name)
- env.set('CXX', '%s-w64-mingw32-g++' % mingw_name)
- env.set('LD', '%s-w64-mingw32-ld' % mingw_name)
- env.set('RANLIB', '%s-w64-mingw32-ranlib' % mingw_name)
- env.set('WINRC', '%s-w64-mingw32-windres' % mingw_name)
- cxx = '-I%s/include -I%s/include' % (env.windows_prefix, env.work_dir_cscript())
- link = '-L%s/lib -L%s/lib' % (env.windows_prefix, env.work_dir_cscript())
- for p in mingw_prefixes:
- cxx += ' -I%s/include' % p
- link += ' -L%s/lib' % p
- env.set('CXXFLAGS', '"%s"' % cxx)
- env.set('LINKFLAGS', '"%s"' % link)
+ def package(self, project):
+ project.checkout(self)
+ name = read_wscript_variable(os.getcwd(), 'APPNAME')
+ command('./waf dist')
+ return os.path.abspath('%s-%s.tar.bz2' % (name, project.version))
+
+
+# @param s Target string:
+# windows-{32,64}
+# or ubuntu-version-{32,64}
+# or debian-version-{32,64}
+# or centos-version-{32,64}
+# or osx-{32,64}
+# or source
+# @param debug True to build with debugging symbols (where possible)
+def target_factory(s, debug, work):
+ target = None
+ if s.startswith('windows-'):
+ target = WindowsTarget(int(s.split('-')[1]), work)
+ elif s.startswith('ubuntu-') or s.startswith('debian-') or s.startswith('centos-'):
+ p = s.split('-')
+ if len(p) != 3:
+ print >>sys.stderr,"Bad Linux target name `%s'; must be something like ubuntu-12.04-32 (i.e. distro-version-bits)" % s
+ sys.exit(1)
+ target = LinuxTarget(p[0], p[1], int(p[2]), work)
+ elif s.startswith('osx-'):
+ target = OSXSingleTarget(int(s.split('-')[1]), work)
+ elif s == 'osx':
+ if args.command == 'build':
+ target = OSXSingleTarget(64, work)
+ else:
+ target = OSXUniversalTarget(work)
+ elif s == 'source':
+ target = SourceTarget()
+ if target is not None:
+ target.debug = debug
-#
-# Target
-#
+ return target
-class Target:
- def __init__(self, name):
- self.name = name
- if name.startswith('ubuntu-') or name.startswith('debian-'):
- self.platform = 'linux'
- self.version = name.split('-')[1]
- self.bits = int(name.split('-')[2])
- elif name.startswith('windows-'):
- self.platform = 'windows'
- self.bits = int(name.split('-')[1])
- elif name == 'osx':
- self.platform = 'osx'
- elif name == 'source':
- self.platform = 'source'
-
-def environment_for_target(target, directory):
- if target.platform == 'linux':
- return ChrootEnvironment(target.name)
- elif target.platform == 'windows':
- env = HostEnvironment(directory)
- prepare_for_windows(env, target.bits)
- return env
- elif target.platform == 'osx':
- env = RemoteEnvironment(OSX_BUILD_HOST)
- return env
- elif target.platform == 'source':
- return HostEnvironment()
-
- return None
#
# Project
def __init__(self, name, directory, specifier=None):
self.name = name
self.directory = directory
- self.git_dir = GIT_DIR
self.version = None
self.specifier = specifier
+ self.git_commit = None
if self.specifier is None:
self.specifier = 'master'
- def checkout(self, env):
+ def checkout(self, target):
flags = ''
redirect = ''
if args.quiet:
flags = '-q'
redirect = '>/dev/null'
- command('git clone --depth 0 %s %s/%s.git %s/src/%s' % (flags, self.git_dir, self.name, env.work_dir_cdist(), self.name))
- os.chdir('%s/src/%s' % (env.work_dir_cdist(), self.name))
+ command('git clone %s %s/%s.git %s/src/%s' % (flags, config.get('git_prefix'), self.name, target.directory, self.name))
+ os.chdir('%s/src/%s' % (target.directory, self.name))
command('git checkout %s %s %s' % (flags, self.specifier, redirect))
- command('git submodule init')
- command('git submodule update')
+ self.git_commit = command_and_read('git rev-parse --short=7 HEAD').readline().strip()
+ command('git submodule init --quiet')
+ command('git submodule update --quiet')
os.chdir(self.directory)
- proj = '%s/src/%s/%s' % (env.work_dir_cdist(), self.name, self.directory)
+ proj = '%s/src/%s/%s' % (target.directory, self.name, self.directory)
self.read_cscript('%s/cscript' % proj)
if os.path.exists('%s/wscript' % proj):
- f = open('%s/wscript' % proj, 'r')
- version = None
- while 1:
- l = f.readline()
- if l == '':
- break
-
- s = l.split()
- if len(s) == 3 and s[0] == "VERSION":
- self.version = Version(s[2])
-
- f.close()
+ v = read_wscript_variable(proj, "VERSION");
+ if v is not None:
+ self.version = Version(v)
def read_cscript(self, s):
self.cscript = {}
command('dch -b -v %s-1 "New upstream release."' % version)
+def devel_to_git(project, filename):
+ if project.git_commit is not None:
+ filename = filename.replace('devel', '-%s' % project.git_commit)
+ return filename
+
#
# Command-line parser
#
parser = argparse.ArgumentParser()
parser.add_argument('command')
-parser.add_argument('-p', '--project', help='project name', required=True)
+parser.add_argument('-p', '--project', help='project name')
parser.add_argument('-d', '--directory', help='directory within project repo', default='.')
-parser.add_argument('--beta', help='beta release', action='store_true')
-parser.add_argument('--full', help='full release', action='store_true')
+parser.add_argument('--minor', help='minor version number bump', action='store_true')
+parser.add_argument('--micro', help='micro version number bump', action='store_true')
parser.add_argument('-c', '--checkout', help='string to pass to git for checkout')
parser.add_argument('-o', '--output', help='output directory', default='.')
parser.add_argument('-q', '--quiet', help='be quiet', action='store_true')
parser.add_argument('-t', '--target', help='target')
parser.add_argument('-k', '--keep', help='keep working tree', action='store_true')
+parser.add_argument('--debug', help='build with debugging symbols where possible', action='store_true')
+parser.add_argument('-w', '--work', help='override default work directory')
args = parser.parse_args()
args.output = os.path.abspath(args.output)
+if args.work is not None:
+ args.work = os.path.abspath(args.work)
-if args.project is None:
- error('you must specify -p or --project')
+if args.project is None and args.command != 'shell':
+ raise Error('you must specify -p or --project')
project = Project(args.project, args.directory, args.checkout)
if args.command == 'build':
if args.target is None:
- error('you must specify -t or --target')
+ raise Error('you must specify -t or --target')
- target = Target(args.target)
- env = environment_for_target(target, None)
- project.checkout(env)
- env.build_dependencies(target, project)
- env.build(target, project)
-
- env.cleanup()
+ target = target_factory(args.target, args.debug, args.work)
+ project.checkout(target)
+ target.build_dependencies(project)
+ target.build(project)
+ if not args.keep:
+ target.cleanup()
elif args.command == 'package':
if args.target is None:
- error('you must specify -t or --target')
+ raise Error('you must specify -t or --target')
- target = Target(args.target)
- env = environment_for_target(target, None)
+ target = target_factory(args.target, args.debug, args.work)
- packages = env.package(target, project)
+ packages = target.package(project)
if hasattr(packages, 'strip') or (not hasattr(packages, '__getitem__') and not hasattr(packages, '__iter__')):
packages = [packages]
if target.platform == 'linux':
- out = '%s/%s-%d' % (args.output, target.version, target.bits)
+ out = '%s/%s-%s-%d' % (args.output, target.distro, target.version, target.bits)
try:
os.makedirs(out)
except:
pass
for p in packages:
- copyfile(p, '%s/%s' % (out, os.path.basename(p)))
+ copyfile(p, '%s/%s' % (out, os.path.basename(devel_to_git(project, p))))
else:
for p in packages:
- copyfile(p, '%s/%s' % (args.output, os.path.basename(p)))
+ copyfile(p, '%s/%s' % (args.output, os.path.basename(devel_to_git(project, p))))
- env.cleanup()
+ if not args.keep:
+ target.cleanup()
elif args.command == 'release':
- if args.full is False and args.beta is False:
- error('you must specify --full or --beta')
+ if args.minor is False and args.micro is False:
+ raise Error('you must specify --minor or --micro')
- env = HostEnvironment()
- project.checkout(env)
+ target = SourceTarget()
+ project.checkout(target)
version = project.version
- if args.full:
- version.to_release()
+ version.to_release()
+ if args.minor:
+ version.bump_minor()
else:
- version.bump_beta()
+ version.bump_micro()
set_version_in_wscript(version)
append_version_to_changelog(version)
command('git commit -a -m "Bump version"')
command('git tag -m "v%s" v%s' % (version, version))
- if args.full:
- version.bump_and_to_pre()
- set_version_in_wscript(version)
- command('git commit -a -m "Bump version"')
-
+ version.to_devel()
+ set_version_in_wscript(version)
+ command('git commit -a -m "Bump version"')
command('git push')
command('git push --tags')
- env.cleanup()
+ target.cleanup()
elif args.command == 'pot':
- env = HostEnvironment()
- project.checkout(env)
+ target = SourceTarget()
+ project.checkout(target)
- pots = project.cscript['make_pot'](env)
+ pots = project.cscript['make_pot'](target)
for p in pots:
copyfile(p, '%s/%s' % (args.output, os.path.basename(p)))
- env.cleanup()
+ target.cleanup()
elif args.command == 'changelog':
- env = HostEnvironment()
- project.checkout(env)
+ target = SourceTarget()
+ project.checkout(target)
text = open('ChangeLog', 'r')
html = open('%s/changelog.html' % args.output, 'w')
if len(l) > 0 and l[0] == "\t":
s = l.split()
if len(s) == 4 and s[1] == "Version" and s[3] == "released.":
- if not "beta" in s[2]:
+ v = Version(s[2])
+ if v.micro == 0:
if last is not None and len(changes) > 0:
print >>html,"<h2>Changes between version %s and %s</h2>" % (s[2], last)
print >>html,"<ul>"
else:
changes[-1] += " " + c
- env.cleanup()
+ target.cleanup()
elif args.command == 'manual':
- env = HostEnvironment()
- project.checkout(env)
+ target = SourceTarget()
+ project.checkout(target)
- dirs = project.cscript['make_manual'](env)
- for d in dirs:
- copytree(d, '%s/%s' % (args.output, os.path.basename(d)))
+ outs = project.cscript['make_manual'](target)
+ for o in outs:
+ if os.path.isfile(o):
+ copyfile(o, '%s/%s' % (args.output, os.path.basename(o)))
+ else:
+ copytree(o, '%s/%s' % (args.output, os.path.basename(o)))
- env.cleanup()
+ target.cleanup()
elif args.command == 'doxygen':
- env = HostEnvironment()
- project.checkout(env)
+ target = SourceTarget()
+ project.checkout(target)
- dirs = project.cscript['make_doxygen'](env)
+ dirs = project.cscript['make_doxygen'](target)
if hasattr(dirs, 'strip') or (not hasattr(dirs, '__getitem__') and not hasattr(dirs, '__iter__')):
dirs = [dirs]
for d in dirs:
copytree(d, '%s/%s' % (args.output, 'doc'))
- env.cleanup()
+ target.cleanup()
elif args.command == 'latest':
- env = HostEnvironment()
- project.checkout(env)
+ target = SourceTarget()
+ project.checkout(target)
f = command_and_read('git log --tags --simplify-by-decoration --pretty="%d"')
t = f.readline()
if m:
tags = m.group(1).split(', ')
for t in tags:
+ s = t.split()
+ if len(s) > 1:
+ t = s[1]
if len(t) > 0 and t[0] == 'v':
latest = t[1:]
print latest
- env.cleanup()
+ target.cleanup()
elif args.command == 'test':
if args.target is None:
- error('you must specify -t or --target')
+ raise Error('you must specify -t or --target')
+
+ target = None
+ try:
+ target = target_factory(args.target, args.debug, args.work)
+ target.test(project)
+ except Error as e:
+ if target is not None:
+ target.cleanup()
+ raise
+
+ if target is not None:
+ target.cleanup()
+
+elif args.command == 'shell':
+ if args.target is None:
+ raise Error('you must specify -t or --target')
- target = Target(args.target)
- env = environment_for_target(target, '.')
- project.read_cscript('cscript')
- env.build(target, project)
+ target = target_factory(args.target, args.debug, args.work)
+ target.command('bash')
else:
- error('invalid command %s' % args.command)
+ raise Error('invalid command %s' % args.command)