#!/usr/bin/env python3
"""
Script that builds a number of python frameworks as
used by the run_tests.py script
FIXME:
- Both variants need to be build with simular options
to the official builds: 32-bit with SDK 10.4u and deployment
target 10.3, 3-way without SDK and depl. target 10.5.
This will have to wait until my sdkroot patches get committed,
without that patch I cannot build the 32-bit variant on
SL.
- get rid of the global variables
"""
import sys
sys.dont_write_bytecode = True
import subprocess, getopt, logging, os, shutil
from urllib.request import urlopen
gUsage="""\
build_frameworks.py [-v versions] [--versions=versions] [-a archs] [--arch archs]
- versions: comma seperated list of python versiosn, defaults to "2.6,2.7,3.1,3.2"
- archs: comma seperated list of build variations, defaults to "32-bit,3-way"
"""
gBaseDir = os.path.dirname(os.path.abspath(__file__))
gArchs = ("32-bit", "3-way")
# Name of the Python framework and any additional arguments
# passed to the configure command.
gFrameworkNameTemplate="DbgPython-{archs}"
gExtraConfigureArgs=[
"--with-pydebug",
]
# Location of the SVN branches to be used
gURLMap = {
'2.6': 'http://svn.python.org/projects/python/branches/release26-maint',
'2.7': 'http://svn.python.org/projects/python/trunk',
'3.1': 'http://svn.python.org/projects/python/branches/release31-maint',
'3.2': 'http://svn.python.org/projects/python/branches/py3k',
}
# Name of the OSX SDK used to build the framework, keyed of the architecture
# variant.
gSdkMap={
'32-bit': '/',
'3-way': '/',
}
# Name of the OSX Deployment Target used to build the framework, keyed of
# the architecture variant.
gDeploymentTargetMap={
#'32-bit': '10.4',
'32-bit': '10.5',
'3-way': '10.5',
}
class ShellError (Exception):
""" An error occurred while running a shell command """
pass
def create_checkout(version):
"""
Create or update the checkout of the given version
of Python.
"""
lg = logging.getLogger("create_checkout")
lg.info("Create checkout for %s", version)
checkoutdir = os.path.join(gBaseDir, "checkouts", version)
if not os.path.exists(checkoutdir):
lg.debug("Create directory %r", checkoutdir)
os.makedirs(checkoutdir)
if os.path.exists(os.path.join(checkoutdir, '.svn')):
lg.debug("Update checkout")
p = subprocess.Popen([
'svn', 'up'],
cwd=checkoutdir)
else:
lg.debug("Initial checkout checkout")
p = subprocess.Popen([
'svn', 'co', gURLMap[version], checkoutdir])
xit = p.wait()
if xit == 0:
lg.info("Checkout for %s is now up-to-date", version)
else:
lg.warn("Checkout for %s failed", version)
raise ShellError(xit)
def build_framework(version, archs):
"""
Build the given version of Python in the given architecture
variant.
This also installs distribute and virtualenv (the latter using
a local copy of the package).
"""
lg = logging.getLogger("build_framework")
lg.info("Build framework version=%r archs=%r", version, archs)
builddir = os.path.join(gBaseDir, "checkouts", version, "build")
if os.path.exists(builddir):
lg.debug("Remove existing build tree")
shutil.rmtree(builddir)
lg.debug("Create build tree %r", builddir)
os.mkdir(builddir)
lg.debug("Running 'configure'")
p = subprocess.Popen([
"../configure",
"--enable-framework",
"--with-framework-name={0}".format(gFrameworkNameTemplate.format(version=version, archs=archs)),
"--enable-universalsdk={0}".format(gSdkMap[archs]),
"--with-universal-archs={0}".format(archs),
] + gExtraConfigureArgs + [
"MACOSX_DEPLOYMENT_TARGET={0}".format(gDeploymentTargetMap[archs]),
], cwd=builddir)
xit = p.wait()
if xit != 0:
lg.debug("Configure failed for %s", version)
raise ShellError(xit)
lg.debug("Running 'make'")
p = subprocess.Popen([
"make",
], cwd=builddir)
xit = p.wait()
if xit != 0:
lg.debug("Make failed for %s", version)
raise ShellError(xit)
lg.debug("Running 'make install'")
p = subprocess.Popen([
"make",
"install",
], cwd=builddir)
xit = p.wait()
if xit != 0:
lg.debug("Install failed for %r", version)
raise ShellError(xit)
def install_distribute(version, archs):
lg = logging.getLogger("install_distribute")
lg.debug("Installing distribute")
builddir = os.path.join(gBaseDir, "checkouts", version, "build")
lg.debug("Download distribute_setup script")
fd = urlopen("http://python-distribute.org/distribute_setup.py")
data = fd.read()
fd.close()
scriptfn = os.path.join(builddir, "distribute_setup.py")
fd = open(scriptfn, "wb")
fd.write(data)
fd.close()
frameworkName=gFrameworkNameTemplate.format(archs=archs, version=version)
python = "/Library/Frameworks/{0}.framework/Versions/{1}/bin/python".format(
frameworkName, version)
if version[0] == '3':
python += '3'
# Script is in python2 format, translate to python3 before
# trying to run it.
lg.debug("Convert install script to python3")
p = subprocess.Popen([
os.path.join(os.path.dirname(python), "2to3"),
scriptfn])
xit = p.wait()
if xit != 0:
lg.warning("Running 2to3 failed")
raise ShellError(xit)
lg.debug("Run distribute_setup script '%s' with '%s'", scriptfn, python)
p = subprocess.Popen([
python,
scriptfn],
cwd=os.path.join(gBaseDir, "checkouts"))
xit = p.wait()
if xit != 0:
lg.warning("Installing 'distribute' failed")
raise ShellError(xit)
def install_virtualenv(version, archs):
lg = logging.getLogger("install_virtualenv")
lg.info("Installing virtualenv from local source")
frameworkName=gFrameworkNameTemplate.format(archs=archs, version=version)
python = "/Library/Frameworks/{0}.framework/Versions/{1}/bin/python".format(
frameworkName, version)
if version[0] == '3':
python += '3'
# Sadly enough plain virtualenv doens't support
# python3 yet, but there is a fork that does.
# Therefore install the real virtualenv for python 2.x
# and the fork for python 3.x
if version[0] == '2':
srcdir = os.path.join(gBaseDir, 'virtualenv-src')
else:
srcdir = os.path.join(gBaseDir, 'virtualenv3-src')
p = subprocess.Popen([ python, "setup.py", "install" ],
cwd=srcdir)
xit = p.wait()
if xit != 0:
lg.warning("Installing 'virtualenv' failed")
raise ShellError(xit)
def main():
logging.basicConfig(level=logging.DEBUG)
try:
opts, args = getopt.getopt(sys.argv[1:], 'v:a:h?', ['help', 'versions=', 'archs='])
except getopt.error as msg:
print(msg, file=sys.stderr)
print(gUsage, file=sys.stderr)
sys.exit(1)
versions = sorted(gURLMap.keys())
archs = gArchs
if args:
print("Additional arguments", file=sys.stderr)
print(gUsage, file=sys.stderr)
sys.exit(1)
for k, v in opts:
if k in ('-h', '-?', '--help'):
print(gUsage)
sys.exit(0)
elif k in ('-v', '--versions'):
versions = v.split(',')
for v in versions:
if v not in gURLMap:
print("Unsupported python version: {0}".format(v),
file=sys.stderr)
sys.exit(1)
elif k in ('-a', '--archs'):
archs = v.split(',')
for v in archs:
if v not in gArchs:
print("Unsupported python architecture: {0}".format(v),
file=sys.stderr)
sys.exit(1)
else:
print("ERROR: unhandled script option: {0}".format(k),
file=sys.stderr)
sys.exit(2)
lg = logging.getLogger("build_frameworks")
lg.info("Building versions: %s", versions)
lg.info("Building architectures: %s", archs)
try:
for version in sorted(versions):
create_checkout(version)
for arch in sorted(archs):
lg.info('Building framework for python %s (%s)', version, arch)
build_framework(version, arch)
lg.info('Installing distribute for python %s (%s)', version, arch)
install_distribute(version, arch)
lg.info('Installing virtualenv for python %s (%s)', version, arch)
install_virtualenv(version, arch)
lg.info('Done python %s (%s)', version, arch)
except ShellError:
sys.exit(1)
if __name__ == "__main__":
main()
|