#!/cygdrive/C/Python25/python """A script to help automate the build process.""" # When preparing a new release, make sure to set all of these to the latest # values. VERSIONS = { 'bzr': '1.17', 'qbzr': '0.12', 'bzrtools': '1.17.0', 'bzr-svn': '0.6.3', 'bzr-rewrite': '0.5.2', 'subvertpy': '0.6.8', } # This will be passed to 'make' to ensure we build with the right python PYTHON='/cygdrive/c/Python25/python' # Create the final build in this directory TARGET_ROOT='release' DEBUG_SUBPROCESS = True import os import shutil import subprocess import sys BZR_EXE = None def bzr(): global BZR_EXE if BZR_EXE is not None: return BZR_EXE try: subprocess.call(['bzr', '--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) BZR_EXE = 'bzr' except OSError: try: subprocess.call(['bzr.bat', '--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) BZR_EXE = 'bzr.bat' except OSError: raise RuntimeError('Could not find bzr or bzr.bat on your path.') return BZR_EXE def call_or_fail(*args, **kwargs): """Call a subprocess, and fail if the return code is not 0.""" if DEBUG_SUBPROCESS: print ' calling: "%s"' % (' '.join(args[0]),) p = subprocess.Popen(*args, **kwargs) (out, err) = p.communicate() if p.returncode != 0: raise RuntimeError('Failed to run: %s, %s' % (args, kwargs)) return out TARGET = None def get_target(): global TARGET if TARGET is not None: return TARGET out = call_or_fail([sys.executable, get_bzr_dir() + '/bzr', 'version', '--short'], stdout=subprocess.PIPE) version = out.strip() TARGET = os.path.abspath(TARGET_ROOT + '-' + version) return TARGET def clean_target(): """Nuke the target directory so we know we are starting from scratch.""" target = get_target() if os.path.isdir(target): print "Deleting: %s" % (target,) shutil.rmtree(target) def get_bzr_dir(): return 'bzr.' + VERSIONS['bzr'] def update_bzr(): """Make sure we have the latest bzr in play.""" bzr_dir = get_bzr_dir() if not os.path.isdir(bzr_dir): bzr_version = VERSIONS['bzr'] # bzr_url = 'http://bazaar-vcs.org/bzr/bzr.' + bzr_version bzr_url = 'lp:bzr/' + bzr_version print "Getting bzr release %s from %s" % (bzr_version, bzr_url) call_or_fail([bzr(), 'co', bzr_url, bzr_dir]) else: print "Ensuring %s is up-to-date" % (bzr_dir,) call_or_fail([bzr(), 'update', bzr_dir]) def create_target(): target = get_target() print "Creating target dir: %s" % (target,) call_or_fail([bzr(), 'co', get_bzr_dir(), target]) def get_plugin_trunk_dir(plugin_name): return '%s/trunk' % (plugin_name,) def get_plugin_release_dir(plugin_name): return '%s/%s' % (plugin_name, VERSIONS[plugin_name]) def get_plugin_trunk_branch(plugin_name): return 'lp:%s' % (plugin_name,) def update_plugin_trunk(plugin_name): trunk_dir = get_plugin_trunk_dir(plugin_name) if not os.path.isdir(trunk_dir): plugin_trunk = get_plugin_trunk_branch(plugin_name) print "Getting latest %s trunk" % (plugin_name,) call_or_fail([bzr(), 'co', plugin_trunk, trunk_dir]) else: print "Ensuring %s is up-to-date" % (trunk_dir,) call_or_fail([bzr(), 'update', trunk_dir]) return trunk_dir def _plugin_tag_name(plugin_name): if plugin_name in ('bzr-svn', 'bzr-rewrite', 'subvertpy'): return '%s-%s' % (plugin_name, VERSIONS[plugin_name]) # bzrtools and qbzr use 'release-X.Y.Z' return 'release-' + VERSIONS[plugin_name] def update_plugin(plugin_name): release_dir = get_plugin_release_dir(plugin_name) if not os.path.isdir(plugin_name): if plugin_name in ('bzr-svn', 'bzr-rewrite'): # bzr-svn uses a different repo format call_or_fail([bzr(), 'init-repo', '--rich-root-pack', plugin_name]) else: os.mkdir(plugin_name) if os.path.isdir(release_dir): print "Removing existing dir: %s" % (release_dir,) shutil.rmtree(release_dir) # First update trunk trunk_dir = update_plugin_trunk(plugin_name) # Now create the tagged directory tag_name = _plugin_tag_name(plugin_name) print "Creating the branch %s" % (release_dir,) call_or_fail([bzr(), 'co', '-rtag:%s' % (tag_name,), trunk_dir, release_dir]) return release_dir def install_plugin(plugin_name): release_dir = update_plugin(plugin_name) # at least bzrtools doesn't like you to call 'setup.py' unless you are in # that directory specifically, so we cd, rather than calling it from # outside print "Installing %s" % (release_dir,) call_or_fail([sys.executable, 'setup.py', 'install', '-O1', '--install-lib=%s' % (get_target(),)], cwd=release_dir) def update_tbzr(): tbzr_loc = os.environ.get('TBZR', None) if tbzr_loc is None: raise ValueError('You must set TBZR to the location of tortoisebzr.') print 'Updating %s' % (tbzr_loc,) call_or_fail([bzr(), 'update', tbzr_loc]) def build_installer(): target = get_target() print print print '*' * 60 print 'Building standalone installer' call_or_fail(['make', 'PYTHON=%s' % (PYTHON,), 'installer'], cwd=target) def main(args): import optparse p = optparse.OptionParser(usage='%prog [OPTIONS]') opts, args = p.parse_args(args) update_bzr() update_tbzr() clean_target() create_target() install_plugin('subvertpy') install_plugin('bzrtools') install_plugin('qbzr') install_plugin('bzr-svn') install_plugin('bzr-rewrite') build_installer() if __name__ == '__main__': main(sys.argv[1:]) # vim: ts=4 sw=4 sts=4 et ai