Commits

Ronald Oussoren  committed 7911183

Remove most of the 'build-support' directory because the code is no longer used.

  • Participants
  • Parent commits 4ebfdb8

Comments (0)

Files changed (9)

 dist
 .DS_Store
 __pycache__
-build-support/checkouts
-build-support/virtualenvs
-build-support/cache
 autom4te.cache
 sdists
 

File build-support/Makefile

-default:
-	@echo "Usage:"
-	@echo " - build: Create test frameworks"
-	@echo " - test:  Build PyObjC and run tests"
-	@echo
-	@echo "WARNING: 'test' doesn't automaticly 'build'"
-	@echo
-
-build:
-	python3	build_frameworks.py
-
-test:
-	python3 run_tests.py
-
-.PHONY: default build test clean

File build-support/ReadMe.txt

-This directory contains a number of scripts
-that help in testing PyObjC on a number 
-of platforms.
-
-All scripts are python3 scripts.
-
-WARNING: The scripts are a work-in-progress and don't 
-work right now.
-
-* build_frameworks.py:
-  This script creates a couple of framework
-  builds of Python for various Python
-  releases:
-
-  - 32-bit (i386, ppc) and intel (i386, x86)
-  - 2.6, 2.7, 3.1 and 3.2
-
-  All builds are with '--with-pydebug' and
-  are installed using an alternate framework
-  name to avoid messing with an already existing
-  install.
-
-  TODO: also install distribute and virtualenv
-
-* run_tests.py
-
-  Uses the frameworks installed by build_frameworks.py
-  to run all PyObjC tests with all supported Python
-  variants.
-
-  TODO:
-  - create virtual env and install PyObjC dependencies
-  - install pyobjc-core, pyobjc-framework-Cocoa and
-    pyobjc-framework-Quartz
-  - run tests for pyobjc-core and all framework wrappers
-  - collect the results and create an HTML page with
-    the summary and details.
-  - send e-mail with the result to an e-mail address
-
-* TODO: run_distributed_tests.py
-
-  This script will do something simular to run_tests,
-  but builds on a 10.6 machine and runs the tests on
-  a number of different machines (10.4, 10.5)

File build-support/build_frameworks.py

-#!/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] \\
-   [--refresh-clone|--no-refresh-clone]
-
-- 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", "intel")
-
-
-# Name of the Python framework and any additional arguments
-# passed to the configure command.
-gFlavours = [
-        dict(
-            name="debug",
-            template="DbgPython-{archs}",
-            flags=[
-                "--with-pydebug",
-            ],
-        ),
-#        dict(
-#            name="release",
-#            template="ReleasePython-{archs}",
-#            flags=[
-#            ],
-#        ),
-]
-
-gHgURL='http://hg.python.org/cpython'
-gBranchMap={
-    '2.6': '2.6',
-    '2.7': '2.7',
-    '3.1': '3.1',
-    '3.2': '3.2',
-    '3.3': 'default',
-}
-
-# Name of the OSX SDK used to build the framework, keyed of the architecture
-# variant.
-gSdkMap={
-    '32-bit': '/Developer/SDKs/MacOSX10.4u.sdk',
-    '3-way': '/',
-    'intel': '/',
-}
-
-# Name of the OSX Deployment Target used to build the framework, keyed of 
-# the architecture variant.
-gDeploymentTargetMap={
-    '32-bit': '10.3',
-    #'32-bit': '10.5',
-    '3-way':  '10.5',
-    'intel':  '10.5',
-}
-
-class ShellError (Exception):
-    """ An error occurred while running a shell command """
-    pass
-
-def refresh_local_clone():
-    lg = logging.getLogger("refresh_local_clone")
-    lg.info("Refreshing local clone")
-
-    checkoutdir = os.path.join(gBaseDir, "checkout")
-    if not os.path.exists(checkoutdir):
-        lg.debug("Create directory %r", checkoutdir)
-        os.makedirs(checkoutdir)
-
-    if not os.path.exists(os.path.join(checkoutdir, '.hg')):
-        lg.debug("Initial clone")
-        p = subprocess.Popen([
-            'hg', 'clone', gHgURL, checkoutdir
-        ])
-
-    else:
-        lg.debug("Update clone")
-        p = subprocess.Popen([
-            'hg', 'pull', '-u'],
-            cwd=checkoutdir,
-        )
-
-    xit = p.wait()
-    if xit == 0:
-        lg.info("Local clone is now up-to-date")
-    else:
-        lg.warn("Pull for local clone failed")
-        raise ShellError(xit)
-
-
-def switch_branch(version):
-    """
-    Create or update the checkout of the given version
-    of Python.
-    """
-    lg = logging.getLogger("switch_branch")
-    lg.info("Switch to branch %s", version)
-
-    checkoutdir = os.path.join(gBaseDir, "checkout")
-    if not os.path.exists(checkoutdir):
-        lg.error("No local clone available")
-        raise ShellError(1)
-
-    p = subprocess.Popen([
-        'hg', 'up', '-C', version],
-        cwd=checkoutdir)
-
-    xit = p.wait()
-    if xit == 0:
-        lg.info("Branch for %s is now up-to-date", version)
-    else:
-        lg.warn("Branch for %s failed", version)
-        raise ShellError(xit)
-
-    p = subprocess.Popen([
-        'hg', 'branch'],
-        cwd=checkoutdir,
-        stdout=subprocess.PIPE)
-    data = p.communicate()[0]
-    data = data.decode('utf-8').strip()
-    xit = p.wait()
-    if data != version:
-        lg.warn("Switching branch failed")
-        raise ShellExit(1)
-
-
-def build_framework(flavour, 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 %s framework version=%r archs=%r", flavour["name"], version, archs)
-
-    builddir = os.path.join(gBaseDir, "checkout", "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(flavour["template"].format(version=version, archs=archs)),
-            "--enable-universalsdk={0}".format(gSdkMap[archs]),
-            "--with-universal-archs={0}".format(archs),
-            ] + flavour["flags"] + [
-            "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('Removing unwanted installation bits from Makefile')
-    fp = open(os.path.join(builddir, 'Makefile'))
-    contents = fp.read()
-    fp.close()
-    
-    # Ensure that nothing gets installed in /Applications
-    contents = contents.replace('frameworkinstallapps4way', '')
-    contents = contents.replace('frameworkinstallapps', '')
-
-    # Ensure that nothting gets installed in /usr/local
-    contents = contents.replace(' frameworkinstallunixtools4way', ' ')
-    contents = contents.replace(' frameworkinstallunixtools', ' ')
-    
-    fp = open(os.path.join(builddir, 'Makefile'), 'w')
-    fp.write(contents)
-    fp.close()
-
-
-
-
-    fp = open(os.path.join(builddir, 'Mac', 'Makefile'))
-    contents = fp.read()
-    fp.close()
-
-    contents = contents.replace('"$(PYTHONAPPSDIR)"', '')
-    fp = open(os.path.join(builddir, 'Mac', 'Makefile'), 'w')
-    fp.write(contents)
-    fp.close()
-
-
-
-    
-    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)
-
-    install_tree = "/Library/Frameworks/{0}.framework/Versions/{1}".format(
-            flavour["template"].format(version=version, archs=archs), version)
-    if os.path.exists(install_tree):
-        lg.debug("Removing existing tree (%s)", install_tree)
-        #shutil.rmtree(install_tree)
-
-    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(flavour, version, archs):
-    lg = logging.getLogger("install_distribute")
-    lg.debug("Installing distribute")
-
-    distribute='distribute-0.6.16'
-
-    # Temporarily use a checkout, the latest release at this time is broken with
-    # recent python3 checkouts.
-    distribute='tarek-distribute-7f58b783778a'
-
-    if not os.path.exists(os.path.join(gBaseDir, 'cache')):
-        os.mkdir(os.path.join(gBaseDir, 'cache'))
-
-    archivefn = os.path.join(gBaseDir, 'cache', distribute + '.tar.bz2')
-    if not os.path.exists(archivefn):
-        archivefn = os.path.exists(os.path.join(gBaseDir, 'cache', distribute + '.tar.gz'))
-        if not os.path.exists(archivefn):
-            lg.warning("Downloading %s from PyPI"%(distribute,))
-            url = 'http://pypi.python.org/packages/source/d/distribute/' + distribute + '.tar.gz'
-            fp = urlopen(url)
-            data = fp.read()
-            fp.close()
-
-            fp = open(archivefn, 'wb')
-            fp.write(data)
-            fp.close()
-
-    if not os.path.exists(os.path.join(gBaseDir, 'cache', distribute)):
-        lg.warning("Unpacking %s archive"%(distribute,))
-        shutil.unpack_archive(
-            archivefn,
-            os.path.join(gBaseDir, 'cache'))
-
-    distribute_dir = os.path.join(gBaseDir, "cache", distribute)
-    builddir = os.path.join(distribute_dir, "build")
-    if os.path.exists(builddir):
-        lg.debug("Remove existing 'build' subdir")
-        shutil.rmtree(builddir)
-
-    frameworkName=flavour["template"].format(archs=archs, version=version)
-
-    python = "/Library/Frameworks/{0}.framework/Versions/{1}/bin/python".format(
-            frameworkName, version)
-    if version[0] == '3':
-        python += '3'
-
-    lg.debug("Run setup script with '%s'", python)
-    p = subprocess.Popen([
-        python, "setup.py", "install"],
-        cwd=distribute_dir)
-    xit = p.wait()
-    if xit != 0:
-        lg.warning("Installing 'distribute' failed")
-        raise ShellError(xit)
-
-def install_virtualenv(flavour, version, archs):
-    lg = logging.getLogger("install_distribute")
-    lg.debug("Installing virtualenv")
-
-    virtualenv='virtualenv-1.6'
-
-    if not os.path.exists(os.path.join(gBaseDir, 'cache')):
-        os.mkdir(os.path.join(gBaseDir, 'cache'))
-
-    if not os.path.exists(os.path.join(gBaseDir, 'cache', virtualenv + '.tar.gz')):
-        lg.warning("Downloading %s from PyPI"%(virtualenv,))
-        url = 'http://pypi.python.org/packages/source/v/virtualenv/' + virtualenv + '.tar.gz'
-        fp = urlopen(url)
-        data = fp.read()
-        fp.close()
-
-        fp = open(os.path.join(gBaseDir, 'cache', virtualenv + '.tar.gz'), 'wb')
-        fp.write(data)
-        fp.close()
-
-    if not os.path.exists(os.path.join(gBaseDir, 'cache', virtualenv)):
-        lg.warning("Unpacking %s archive"%(virtualenv,))
-        shutil.unpack_archive(
-            os.path.join(gBaseDir, 'cache', virtualenv + '.tar.gz'),
-            os.path.join(gBaseDir, 'cache'))
-
-    virtualenv_dir = os.path.join(gBaseDir, "cache", virtualenv)
-    virtualenv_dir = os.path.join(gBaseDir, virtualenv)
-    builddir = os.path.join(virtualenv_dir, "build")
-    if os.path.exists(builddir):
-        lg.debug("Remove existing 'build' subdir")
-        shutil.rmtree(builddir)
-
-    frameworkName=flavour["template"].format(archs=archs, version=version)
-
-    python = "/Library/Frameworks/{0}.framework/Versions/{1}/bin/python".format(
-            frameworkName, version)
-    if version[0] == '3':
-        python += '3'
-
-    lg.debug("Run setup script with '%s'", python)
-    p = subprocess.Popen([
-        python, "setup.py", "install"],
-        cwd=virtualenv_dir)
-    xit = p.wait()
-    if xit != 0:
-        lg.warning("Installing 'virtualenv' failed")
-        raise ShellError(xit)
-
-
-
-def main():
-    logging.basicConfig(level=logging.DEBUG)
-    import sysconfig
-
-    import os
-    os.environ['PATH'] = '/Developer/usr/bin:' + os.environ['PATH']
-
-    if 'MACOSX_DEPLOYMENT_TARGET' in os.environ:
-        del os.environ['MACOSX_DEPLOYMENT_TARGET']
-    os.unsetenv('MACOSX_DEPLOYMENT_TARGET')
-
-    try:
-        opts, args = getopt.getopt(sys.argv[1:], 'v:a:h?', ['help', 'versions=', 'archs=', 
-            'refresh-clone', 'no-refresh-clone'])
-    except getopt.error as msg:
-        print(msg, file=sys.stderr)
-        print(gUsage, file=sys.stderr)
-        sys.exit(1)
-
-    versions = sorted(gBranchMap.keys())
-    archs = gArchs
-    refresh_clone = True
-
-    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 == '--refresh-clone':
-            refresh_clone=True
-
-        elif k == '--no-refresh-clone':
-            refresh_clone=False
-
-        elif k in ('-v', '--versions'):
-            versions = v.split(',')
-
-            for v in versions:
-                if v not in gBranchMap:
-                    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)
-    if refresh_clone:
-        refresh_local_clone()
-    try:
-        for version in sorted(versions):
-            switch_branch(gBranchMap[version])
-
-            for flavour in gFlavours:
-                for arch in sorted(archs):
-                    try:
-                        lg.info('Building %s framework for python %s (%s)', flavour["name"], version, arch)
-                        build_framework(flavour, version, arch)
-                        lg.info('Installing distribute for python %s (%s)', version, arch)
-                        install_distribute(flavour, version, arch)
-                        lg.info('Installing virtualenv for python %s (%s)', version, arch)
-                        install_virtualenv(flavour, version, arch)
-                        lg.info('Done %s python %s (%s)', flavour["name"], version, arch)
-
-                    except ShellError:
-                        raise
-                    except Exception as exc:
-                        lg.warning("building %s for pyton %s (%s) failed: %s",
-                                flavour["name"], version, arch, exc)
-                        import traceback
-                        traceback.print_exc()
-    
-    except ShellError:
-        sys.exit(1)
-
-if __name__ == "__main__":
-    main()

File build-support/distribute_setup.py

-#!python
-"""Bootstrap distribute installation
-
-If you want to use setuptools in your package's setup.py, just include this
-file in the same directory with it, and add this to the top of your setup.py::
-
-    from distribute_setup import use_setuptools
-    use_setuptools()
-
-If you want to require a specific version of setuptools, set a download
-mirror, or use an alternate download directory, you can do so by supplying
-the appropriate options to ``use_setuptools()``.
-
-This file can also be run as a script to install or upgrade setuptools.
-"""
-import os
-import sys
-import time
-import fnmatch
-import tempfile
-import tarfile
-from distutils import log
-
-try:
-    from site import USER_SITE
-except ImportError:
-    USER_SITE = None
-
-try:
-    import subprocess
-
-    def _python_cmd(*args):
-        args = (sys.executable,) + args
-        return subprocess.call(args) == 0
-
-except ImportError:
-    # will be used for python 2.3
-    def _python_cmd(*args):
-        args = (sys.executable,) + args
-        # quoting arguments if windows
-        if sys.platform == 'win32':
-            def quote(arg):
-                if ' ' in arg:
-                    return '"%s"' % arg
-                return arg
-            args = [quote(arg) for arg in args]
-        return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
-
-DEFAULT_VERSION = "0.6.15"
-DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
-SETUPTOOLS_PKG_INFO = """\
-Metadata-Version: 1.0
-Name: setuptools
-Version: 0.6c9
-Summary: xxxx
-Home-page: xxx
-Author: xxx
-Author-email: xxx
-License: xxx
-Description: xxx
-"""
-
-
-def _install(tarball):
-    # extracting the tarball
-    tmpdir = tempfile.mkdtemp()
-    log.warn('Extracting in %s', tmpdir)
-    old_wd = os.getcwd()
-    try:
-        os.chdir(tmpdir)
-        tar = tarfile.open(tarball)
-        _extractall(tar)
-        tar.close()
-
-        # going in the directory
-        subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
-        os.chdir(subdir)
-        log.warn('Now working in %s', subdir)
-
-        # installing
-        log.warn('Installing Distribute')
-        assert _python_cmd('setup.py', 'install')
-    finally:
-        os.chdir(old_wd)
-
-
-def _build_egg(egg, tarball, to_dir):
-    # extracting the tarball
-    tmpdir = tempfile.mkdtemp()
-    log.warn('Extracting in %s', tmpdir)
-    old_wd = os.getcwd()
-    try:
-        os.chdir(tmpdir)
-        tar = tarfile.open(tarball)
-        _extractall(tar)
-        tar.close()
-
-        # going in the directory
-        subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
-        os.chdir(subdir)
-        log.warn('Now working in %s', subdir)
-
-        # building an egg
-        log.warn('Building a Distribute egg in %s', to_dir)
-        _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
-
-    finally:
-        os.chdir(old_wd)
-    # returning the result
-    log.warn(egg)
-    if not os.path.exists(egg):
-        raise IOError('Could not build the egg.')
-
-
-def _do_download(version, download_base, to_dir, download_delay):
-    egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg'
-                       % (version, sys.version_info[0], sys.version_info[1]))
-    if not os.path.exists(egg):
-        tarball = download_setuptools(version, download_base,
-                                      to_dir, download_delay)
-        _build_egg(egg, tarball, to_dir)
-    sys.path.insert(0, egg)
-    import setuptools
-    setuptools.bootstrap_install_from = egg
-
-
-def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
-                   to_dir=os.curdir, download_delay=15, no_fake=True):
-    # making sure we use the absolute path
-    to_dir = os.path.abspath(to_dir)
-    was_imported = 'pkg_resources' in sys.modules or \
-        'setuptools' in sys.modules
-    try:
-        try:
-            import pkg_resources
-            if not hasattr(pkg_resources, '_distribute'):
-                if not no_fake:
-                    _fake_setuptools()
-                raise ImportError
-        except ImportError:
-            return _do_download(version, download_base, to_dir, download_delay)
-        try:
-            pkg_resources.require("distribute>="+version)
-            return
-        except pkg_resources.VersionConflict:
-            e = sys.exc_info()[1]
-            if was_imported:
-                sys.stderr.write(
-                "The required version of distribute (>=%s) is not available,\n"
-                "and can't be installed while this script is running. Please\n"
-                "install a more recent version first, using\n"
-                "'easy_install -U distribute'."
-                "\n\n(Currently using %r)\n" % (version, e.args[0]))
-                sys.exit(2)
-            else:
-                del pkg_resources, sys.modules['pkg_resources']    # reload ok
-                return _do_download(version, download_base, to_dir,
-                                    download_delay)
-        except pkg_resources.DistributionNotFound:
-            return _do_download(version, download_base, to_dir,
-                                download_delay)
-    finally:
-        if not no_fake:
-            _create_fake_setuptools_pkg_info(to_dir)
-
-def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
-                        to_dir=os.curdir, delay=15):
-    """Download distribute from a specified location and return its filename
-
-    `version` should be a valid distribute version number that is available
-    as an egg for download under the `download_base` URL (which should end
-    with a '/'). `to_dir` is the directory where the egg will be downloaded.
-    `delay` is the number of seconds to pause before an actual download
-    attempt.
-    """
-    # making sure we use the absolute path
-    to_dir = os.path.abspath(to_dir)
-    try:
-        from urllib.request import urlopen
-    except ImportError:
-        from urllib2 import urlopen
-    tgz_name = "distribute-%s.tar.gz" % version
-    url = download_base + tgz_name
-    saveto = os.path.join(to_dir, tgz_name)
-    src = dst = None
-    if not os.path.exists(saveto):  # Avoid repeated downloads
-        try:
-            log.warn("Downloading %s", url)
-            src = urlopen(url)
-            # Read/write all in one block, so we don't create a corrupt file
-            # if the download is interrupted.
-            data = src.read()
-            dst = open(saveto, "wb")
-            dst.write(data)
-        finally:
-            if src:
-                src.close()
-            if dst:
-                dst.close()
-    return os.path.realpath(saveto)
-
-
-def _patch_file(path, content):
-    """Will backup the file then patch it"""
-    existing_content = open(path).read()
-    if existing_content == content:
-        # already patched
-        log.warn('Already patched.')
-        return False
-    log.warn('Patching...')
-    _rename_path(path)
-    f = open(path, 'w')
-    try:
-        f.write(content)
-    finally:
-        f.close()
-    return True
-
-
-def _same_content(path, content):
-    return open(path).read() == content
-
-
-def _rename_path(path):
-    new_name = path + '.OLD.%s' % time.time()
-    log.warn('Renaming %s into %s', path, new_name)
-    try:
-        from setuptools.sandbox import DirectorySandbox
-        def _violation(*args):
-            pass
-        DirectorySandbox._violation = _violation
-    except ImportError:
-        pass
-
-    os.rename(path, new_name)
-    return new_name
-
-
-def _remove_flat_installation(placeholder):
-    if not os.path.isdir(placeholder):
-        log.warn('Unkown installation at %s', placeholder)
-        return False
-    found = False
-    for file in os.listdir(placeholder):
-        if fnmatch.fnmatch(file, 'setuptools*.egg-info'):
-            found = True
-            break
-    if not found:
-        log.warn('Could not locate setuptools*.egg-info')
-        return
-
-    log.warn('Removing elements out of the way...')
-    pkg_info = os.path.join(placeholder, file)
-    if os.path.isdir(pkg_info):
-        patched = _patch_egg_dir(pkg_info)
-    else:
-        patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO)
-
-    if not patched:
-        log.warn('%s already patched.', pkg_info)
-        return False
-    # now let's move the files out of the way
-    for element in ('setuptools', 'pkg_resources.py', 'site.py'):
-        element = os.path.join(placeholder, element)
-        if os.path.exists(element):
-            _rename_path(element)
-        else:
-            log.warn('Could not find the %s element of the '
-                     'Setuptools distribution', element)
-    return True
-
-
-def _after_install(dist):
-    log.warn('After install bootstrap.')
-    placeholder = dist.get_command_obj('install').install_purelib
-    _create_fake_setuptools_pkg_info(placeholder)
-
-def _create_fake_setuptools_pkg_info(placeholder):
-    if not placeholder or not os.path.exists(placeholder):
-        log.warn('Could not find the install location')
-        return
-    pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1])
-    setuptools_file = 'setuptools-0.6c9-py%s.egg-info' % pyver
-    pkg_info = os.path.join(placeholder, setuptools_file)
-    if os.path.exists(pkg_info):
-        log.warn('%s already exists', pkg_info)
-        return
-    log.warn('Creating %s', pkg_info)
-    f = open(pkg_info, 'w')
-    try:
-        f.write(SETUPTOOLS_PKG_INFO)
-    finally:
-        f.close()
-    pth_file = os.path.join(placeholder, 'setuptools.pth')
-    log.warn('Creating %s', pth_file)
-    f = open(pth_file, 'w')
-    try:
-        f.write(os.path.join(os.curdir, setuptools_file))
-    finally:
-        f.close()
-
-
-def _patch_egg_dir(path):
-    # let's check if it's already patched
-    pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
-    if os.path.exists(pkg_info):
-        if _same_content(pkg_info, SETUPTOOLS_PKG_INFO):
-            log.warn('%s already patched.', pkg_info)
-            return False
-    _rename_path(path)
-    os.mkdir(path)
-    os.mkdir(os.path.join(path, 'EGG-INFO'))
-    pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
-    f = open(pkg_info, 'w')
-    try:
-        f.write(SETUPTOOLS_PKG_INFO)
-    finally:
-        f.close()
-    return True
-
-
-def _before_install():
-    log.warn('Before install bootstrap.')
-    _fake_setuptools()
-
-
-def _under_prefix(location):
-    if 'install' not in sys.argv:
-        return True
-    args = sys.argv[sys.argv.index('install')+1:]
-    for index, arg in enumerate(args):
-        for option in ('--root', '--prefix'):
-            if arg.startswith('%s=' % option):
-                top_dir = arg.split('root=')[-1]
-                return location.startswith(top_dir)
-            elif arg == option:
-                if len(args) > index:
-                    top_dir = args[index+1]
-                    return location.startswith(top_dir)
-            elif option == '--user' and USER_SITE is not None:
-                return location.startswith(USER_SITE)
-    return True
-
-
-def _fake_setuptools():
-    log.warn('Scanning installed packages')
-    try:
-        import pkg_resources
-    except ImportError:
-        # we're cool
-        log.warn('Setuptools or Distribute does not seem to be installed.')
-        return
-    ws = pkg_resources.working_set
-    try:
-        setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools',
-                                  replacement=False))
-    except TypeError:
-        # old distribute API
-        setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools'))
-
-    if setuptools_dist is None:
-        log.warn('No setuptools distribution found')
-        return
-    # detecting if it was already faked
-    setuptools_location = setuptools_dist.location
-    log.warn('Setuptools installation detected at %s', setuptools_location)
-
-    # if --root or --preix was provided, and if
-    # setuptools is not located in them, we don't patch it
-    if not _under_prefix(setuptools_location):
-        log.warn('Not patching, --root or --prefix is installing Distribute'
-                 ' in another location')
-        return
-
-    # let's see if its an egg
-    if not setuptools_location.endswith('.egg'):
-        log.warn('Non-egg installation')
-        res = _remove_flat_installation(setuptools_location)
-        if not res:
-            return
-    else:
-        log.warn('Egg installation')
-        pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO')
-        if (os.path.exists(pkg_info) and
-            _same_content(pkg_info, SETUPTOOLS_PKG_INFO)):
-            log.warn('Already patched.')
-            return
-        log.warn('Patching...')
-        # let's create a fake egg replacing setuptools one
-        res = _patch_egg_dir(setuptools_location)
-        if not res:
-            return
-    log.warn('Patched done.')
-    _relaunch()
-
-
-def _relaunch():
-    log.warn('Relaunching...')
-    # we have to relaunch the process
-    args = [sys.executable] + sys.argv
-    sys.exit(subprocess.call(args))
-
-
-def _extractall(self, path=".", members=None):
-    """Extract all members from the archive to the current working
-       directory and set owner, modification time and permissions on
-       directories afterwards. `path' specifies a different directory
-       to extract to. `members' is optional and must be a subset of the
-       list returned by getmembers().
-    """
-    import copy
-    import operator
-    from tarfile import ExtractError
-    directories = []
-
-    if members is None:
-        members = self
-
-    for tarinfo in members:
-        if tarinfo.isdir():
-            # Extract directories with a safe mode.
-            directories.append(tarinfo)
-            tarinfo = copy.copy(tarinfo)
-            tarinfo.mode = 448 # decimal for oct 0700
-        self.extract(tarinfo, path)
-
-    # Reverse sort directories.
-    if sys.version_info < (2, 4):
-        def sorter(dir1, dir2):
-            return cmp(dir1.name, dir2.name)
-        directories.sort(sorter)
-        directories.reverse()
-    else:
-        directories.sort(key=operator.attrgetter('name'), reverse=True)
-
-    # Set correct owner, mtime and filemode on directories.
-    for tarinfo in directories:
-        dirpath = os.path.join(path, tarinfo.name)
-        try:
-            self.chown(tarinfo, dirpath)
-            self.utime(tarinfo, dirpath)
-            self.chmod(tarinfo, dirpath)
-        except ExtractError:
-            e = sys.exc_info()[1]
-            if self.errorlevel > 1:
-                raise
-            else:
-                self._dbg(1, "tarfile: %s" % e)
-
-
-def main(argv, version=DEFAULT_VERSION):
-    """Install or upgrade setuptools and EasyInstall"""
-    tarball = download_setuptools()
-    _install(tarball)
-
-
-if __name__ == '__main__':
-    main(sys.argv[1:])

File build-support/release.py

-#!/usr/bin/env python3
-# TODO: 
-# - create and upload eggs for 'intel' builds of 2.7 and 3.2
-# - create and upload documentation (to packages.python.org)
-# - sign release files using gpg (distutils has support, need to find a way
-#   to avoid typing password dozens of times)
-import getopt
-import subprocess
-import shutil
-import os
-import sys
-from topsort import topological_sort
-
-
-gUsage="""\
-    release.py --all
-or
-    release.py package...
-"""
-
-gTopDir = os.path.dirname(
-        os.path.dirname(
-            os.path.abspath(__file__)))
-
-def main():
-    try:
-        opts, args = getopt.getopt(sys.argv[1:], 'h?',
-                ['all', 'help', 'identity='])
-    except getopt.error as msg:
-        print(msg, file=sys.stderr)
-        print(gUsage, file=sys.stderr)
-        sys.exit(1)
-
-    all=False
-    packages = args
-    identity = 'ronaldoussoren@mac.com'
-    upload = ['upload',]
-
-    for k, v in opts:
-        if k in ('-h', '-?', '--help'):
-            print(gUsage)
-            sys.exit(0)
-
-        elif k in ('--all',):
-            all=True
-
-        elif k in ('--identity',):
-            identity = v
-
-        elif k in ('--no-upload',):
-            upload = []
-
-        elif k in ('--upload',):
-            upload = ['upload',]
-
-        else:
-            raise ValueError("Unhandled option: %s"%(k,))
-
-    if all and packages:
-        print("Specify either --all or a list of packages", file=sys.stderr)
-        sys.exit(1)
-
-    if not all and not packages:
-        print("Specify either --all or a list of packages", file=sys.stderr)
-        sys.exit(1)
-
-    if all:
-        packages = [ 'pyobjc-core' ] 
-        packages += detect_frameworks()
-        packages += ['pyobjc']
-
-    for pkg in packages:
-        print("== ", pkg)
-        srcdir = os.path.join(gTopDir, pkg)
-        if not os.path.exists(srcdir):
-            print("No such package:", srcdir, file=sys.stderr)
-            continue
-
-        if os.path.exists(os.path.join(srcdir, 'build')):
-            shutil.rmtree(os.path.join(srcdir, 'build'))
-
-        if os.path.exists(os.path.join(srcdir, 'dist')):
-            shutil.rmtree(os.path.join(srcdir, 'dist'))
-
-        print(" - sdist")
-        p = subprocess.Popen(
-            ['python2.7', 'setup.py', 'sdist', ] + upload,
-                # 'upload', '--sign', '--identity',  identity ],
-            cwd=srcdir, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-        lines, _ = p.communicate()
-        exit = p.wait()
-
-        if exit != 0:
-            print(lines.decode('utf-8'))
-            print("Creating or uploading sdist failed")
-            sys.exit(1)
-
-        for python in ('python2.6', 'python2.7', 'python3.1', 'python3.2'):
-            print(" -", python)
-
-            # Force removal of 'build', I ran into 2to3 issues for some python
-            # versions.
-            if os.path.exists(os.path.join(srcdir, 'build')):
-                shutil.rmtree(os.path.join(srcdir, 'build'))
-
-            p = subprocess.Popen(
-                [python, 'setup.py', 'bdist_egg', ] + upload,
-                    # 'upload', '--sign', '--identity',  identity ],
-                cwd=srcdir, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-            lines, _ = p.communicate()
-            exit = p.wait()
-            if exit != 0:
-                print(lines.decode('utf-8'))
-                print("Creating or uploading bdist_egg for", python, "failed")
-                sys.exit(1)
-
-            p = subprocess.Popen(
-                [python, 'setup.py', 'install'], 
-                cwd=srcdir, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-            lines, _ = p.communicate()
-            exit = p.wait()
-            if exit != 0:
-                print(lines.decode('utf-8'))
-                print("Installing for", python, "failed")
-                sys.exit(1)
-
-
-        # TODO: create and upload eggs for 'intel' builds of 2.7 and 3.2
-        # TODO: create and upload documentation (to packages.python.org)
-
-        print()
-
-
-def detect_frameworks():
-    """
-    Returns a list of framework wrappers in the order they should
-    be build in.
-    """
-    topdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-
-    frameworks = []
-    partial_order = []
-
-    for subdir in os.listdir(topdir):
-        if not subdir.startswith('pyobjc-framework-'): continue
-
-        setup = os.path.join(topdir, subdir, 'setup.py')
-
-        requires = None
-        with open(setup) as fp:
-            for ln in fp:
-                if requires is None:
-                    if ln.strip().startswith('install_requires'):
-                        requires = []
-                else:
-                    if ln.strip().startswith(']'):
-                        break
-
-                    dep = ln.strip()[1:-1]
-                    if dep.startswith('pyobjc-framework'):
-                        dep = dep.split('>')[0]
-                        requires.append(dep)
-
-        frameworks.append(subdir)
-        for dep in requires:
-            partial_order.append((dep, subdir))
-
-    frameworks = topological_sort(frameworks, partial_order)
-    return frameworks
-
-if __name__ == "__main__":
-    main()

File build-support/run_tests.py

-#!/usr/bin/env python3
-"""
-A script that builds and tests the entire pyobjc tree
-in a number of virtual environments:
-
-- python 2.6
-- python 2.7
-- python 3.1
-- python 3.2
-
-- all in 32-bit, 3-way
-
-- with command-line arguments to select specific 
-  combinations
-
-Assumptions:
-- there are python frameworks for the various architectures: DbgPython-VARIANT.framework
-- those frameworks contain distribute and virtualenv
-
-"""
-import sys
-sys.dont_write_bytecode = True
-
-import distribute_setup
-distribute_setup.use_setuptools()
-
-import pkg_resources
-# Use Jinja2 for templating because that's the
-# only one that supports Python3 at this time.
-pkg_resources.require('Jinja2')
-
-import getopt, os, shutil, logging, subprocess, time
-from topsort import topological_sort
-
-from jinja2 import Template
-
-gBaseDir = '.'
-gIndexTemplate = os.path.join(gBaseDir, 'templates', 'index.html')
-gTestResults = os.path.join(gBaseDir, "testresults")
-
-gArchMap={
-    '3-way': ['ppc', 'i386', 'x86_64'],
-    '32-bit': ['ppc', 'i386'],
-    'intel': ['i386', 'x86_64'],
-}
-
-gVersionArchs = {
-    '2.6': {'32-bit'},
-    '2.7': {'32-bit', 'intel', '3-way'},
-    '3.1': {'32-bit'},
-    '3.2': {'32-bit', 'intel', '3-way'},
-    '3.3': {'32-bit', 'intel', '3-way'},
-}
-gVersions=list(sorted(gVersionArchs))
-gArchs=list(sorted(gArchMap))
-
-
-gUsage = """\
-run_tests.py [-a archs] [--archs=archs] [-v versions] [--versions=versions] [-s|--setup-only] [-i index.html|--index=index.html] [--skip-quartz]
-
-archs:    %s (values separated by commas)
-versions: %s (values seperated by commas)
-"""%(",".join(gArchs), ",".join(gVersions))
-
-gBaseDir = os.path.dirname(os.path.abspath(__file__))
-gRootDir = os.path.dirname(gBaseDir)
-gTestResults = os.path.join(gBaseDir, "testresults")
-
-gFrameworkNameTemplate="DbgPython-{archs}"
-
-
-
-def supports_arch_command(version):
-
-    # In virtualenvs both 2.6 and 2.7 support
-    # the 'arch' command because virtualenv
-    # copies the real interpreter into the 
-    # virtualenv.
-    return True
-
-    # This code is true for the python 
-    # interpreter outside of virtual environments:
-    """
-    major, minor = map(int, version.split('.'))
-    if major == 2:
-        return minor >= 7
-    else:
-        return minor >= 2
-    """
-
-def main():
-    logging.basicConfig(level=logging.DEBUG)
-
-    import sysconfig
-    import os
-    os.environ['PATH'] = '/Developer/usr/bin:' + os.environ['PATH']
-
-    if 'MACOSX_DEPLOYMENT_TARGET' in os.environ:
-        del os.environ['MACOSX_DEPLOYMENT_TARGET']
-    os.unsetenv('MACOSX_DEPLOYMENT_TARGET')
-
-    try:
-        opts, args = getopt.getopt(sys.argv[1:], 'a:v:h?si', ["help", "archs=", "versions=", "setup-only", "index=", "skip-quartz"])
-    except getopt.error as msg:
-        print(msg, file=sys.stderr)
-        print(gUsage, file=sys.stderr)
-        sys.exit(1)
-
-    if args:
-        print("Additional arguments", file=sys.stderr)
-        print(gUsage, file=sys.stderr)
-        sys.exit(1)
-
-    versions = gVersions
-    archs = gArchs
-    setup_only = False
-    index_html = 'index.html'
-    skip_quartz = False
-
-    for k, v in opts:
-        if k in ('-?', '-h', '--help'):
-            print(gUsage)
-            sys.exit(0)
-        elif k in ['-a', '--archs']:
-            archs=v.split(',')
-
-            for v in archs:
-                if v not in gArchs:
-                    print("Unsupported architecture: {0}".format(v),
-                            file=sys.stderr)
-                    sys.exit(1)
-
-        elif k in ['-v', '--versions']:
-            versions=v.split(',')
-
-            for v in versions:
-                if v not in gVersions:
-                    print("Unsupported Python version: {0}".format(v),
-                            file=sys.stderr)
-                    sys.exit(1)
-
-        elif k in ['-s', '--setup-only']:
-            setup_only = True
-
-        elif k in ['-i', '--index']:
-            index_html = v
-
-        elif k in ['--skip-quartz']:
-            skip_quartz = True
-
-        else:
-            print("ERROR: Unhandled script option: {0}".format(k),
-                    file=sys.stderr)
-            sys.exit(2)
-
-    if 'MACOSX_DEPLOYMENT_TARGET' in os.environ:
-        del os.environ['MACOSX_DEPLOYMENT_TARGET']
-
-    for ver in versions:
-        for arch in archs:
-            if arch not in gVersionArchs[ver]:
-                continue
-            run_tests(ver, arch, setup_only, skip_quartz)
-
-    if setup_only:
-        return
-
-    gen_summary(index_html, versions, archs)
-
-def detect_frameworks():
-    """
-    Returns a list of framework wrappers in the order they should
-    be build in.
-    """
-    topdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-
-    frameworks = []
-    partial_order = []
-
-    for subdir in os.listdir(topdir):
-        if not subdir.startswith('pyobjc-framework-'): continue
-
-        setup = os.path.join(topdir, subdir, 'setup.py')
-
-        requires = None
-        with open(setup) as fp:
-            for ln in fp:
-                if requires is None:
-                    if ln.strip().startswith('install_requires'):
-                        requires = []
-                else:
-                    if ln.strip().startswith(']'):
-                        break
-
-                    dep = ln.strip()[1:-1]
-                    if dep.startswith('pyobjc-framework'):
-                        dep = dep.split('>')[0]
-                        requires.append(dep)
-
-        frameworks.append(subdir)
-        for dep in requires:
-            partial_order.append((dep, subdir))
-
-    frameworks = topological_sort(frameworks, partial_order)
-    return frameworks
-
-
-
-def run_tests(version, archs, setup_only, skip_quartz):
-
-    lg = logging.getLogger("run_tests")
-
-    lg.info("Running tests python %s with archs %s setup_only=%s skip_quartz=%s",
-            version, archs, setup_only, skip_quartz)
-
-    p = subprocess.Popen(["xcode-select", "-print-path" ],
-        stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
-        env=os.environ)
-
-    stdout, _ = p.communicate()
-    path = stdout.strip()
-    path = os.path.join(path.decode('UTF-8'), "Library", "PrivateFrameworks")
-    ib_env = {
-        'DYLD_FRAMEWORK_PATH': path,
-    }
-    del path
-    
-
-    lg.info("Run tests for Python %s with archs %s", version, archs)
-
-    subdir = os.path.join(gBaseDir, "virtualenvs", "{0}--{1}".format(version, archs))
-    if os.path.exists(subdir):
-        lg.debug("Remove existing virtualenv")
-        shutil.rmtree(subdir)
-
-    if not os.path.exists(os.path.dirname(subdir)):
-        os.mkdir(os.path.dirname(subdir))
-
-    resultdir = os.path.join(gTestResults, "{0}--{1}".format(version, archs))
-    if os.path.exists(resultdir):
-        lg.debug("Remove existing results directory")
-        shutil.rmtree(resultdir)
-
-    if not os.path.exists(os.path.dirname(resultdir)):
-        os.mkdir(os.path.dirname(resultdir))
-
-    base_python = "/Library/Frameworks/{0}.framework/Versions/{1}/bin/python".format(
-            gFrameworkNameTemplate.format(archs=archs, version=version), version)
-    if version[0] == '3':
-        base_python += '3'
-
-    if os.path.exists(base_python + "-all"):
-        base_python = base_python + "-all"
-
-    lg.debug("Interpreter: %s", base_python)
-
-    if not os.path.exists(base_python):
-        lg.warning("No python installation for Python %r %r", version, archs)
-        raise RuntimeError(base_python)
-
-
-    lg.debug("Create virtualenv in %s", subdir)
-    if version[0] == '2':
-        p = subprocess.Popen([
-            base_python,
-            "-mvirtualenv",
-            subdir], env=os.environ)
-    else:
-        p = subprocess.Popen([
-            base_python,
-            "-mvirtualenv3",
-            subdir], env=os.environ)
-
-    xit = p.wait()
-    if xit != 0:
-        lg.warning("Cannot create virtualenv in %s", subdir)
-        raise RuntimeError(subdir)
-
-    lg.debug("Install dependencies")
-    pass # Nothing to do here
-
-
-    lg.debug("Install base packages")
-    if version[0] == '3':
-        python = os.path.join(subdir, "bin", "python3")
-    else:
-        python = os.path.join(subdir, "bin", "python")
-    # There are circular dependencies w.r.t. testing the Cocoa and Quartz wrappers,
-    # install pyobjc-core, pyobjc-framework-Cocoa and pyobjc-framework-Quartz
-    # to ensure we avoid those problems.
-    for pkg in ["pyobjc-core", "pyobjc-framework-Cocoa", "pyobjc-framework-Quartz"]:
-        if not os.path.exists(os.path.join(resultdir, pkg)):
-            os.makedirs(os.path.join(resultdir, pkg))
-
-        pkgroot = os.path.join(gRootDir, pkg)
-        pkgbuild = os.path.join(pkgroot, "build")
-        if os.path.exists(pkgbuild):
-            lg.debug("Remove build directory for %s", pkg)
-            shutil.rmtree(pkgbuild)
-        
-        lg.info("Install %s into %s", pkg, os.path.basename(subdir))
-        p = subprocess.Popen([
-            python, "setup.py", "install"],
-            cwd=pkgroot, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
-            env=os.environ)
-
-        stdout, _ = p.communicate()
-
-        with open(os.path.join(resultdir, pkg, "pre-build-stdout.txt"), "wb") as fd:
-            fd.write(stdout)
-
-        xit = p.wait()
-        if xit != 0:
-            lg.warning("Install %s failed", pkg)
-            raise RuntimeError(pkg)
-
-    if setup_only:
-        lg.info("Don't actually run the tests")
-        return
-
-    lg.debug("Start testing cycle")
-    for pkg in ["pyobjc-core"] + detect_frameworks():
-        if not os.path.exists(os.path.join(resultdir, pkg)):
-            os.makedirs(os.path.join(resultdir, pkg))
-
-        pkgroot = os.path.join(gRootDir, pkg)
-
-        if pkg == "pyobjc-framework-InterfaceBuilderKit":
-            env = os.environ.copy()
-            env.update(ib_env)
-            
-        else:
-            env = os.environ
-
-        pkgbuild = os.path.join(pkgroot, "build")
-        if os.path.exists(pkgbuild):
-            lg.debug("Remove build directory for %s", pkg)
-            shutil.rmtree(pkgbuild)
-
-        lg.debug("Build %s for %s", pkg, os.path.basename(subdir))
-        p = subprocess.Popen([
-            python, "setup.py", "install"],
-            cwd=pkgroot, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, 
-            env=os.environ)
-
-        stdout, _ = p.communicate()
-        with open(os.path.join(resultdir, pkg, "build-stdout.txt"), "wb") as fd:
-            fd.write(stdout)
-
-        xit = p.wait()
-        if xit != 0:
-            print(stdout)
-            lg.warning("Build %s failed", pkg)
-            #raise RuntimeError(pkg)
-            continue
-
-        lg.debug("Install %s into %s", pkg, os.path.basename(subdir))
-        p = subprocess.Popen([
-            python, "setup.py", "install"],
-            cwd=pkgroot, env=os.environ)
-
-        xit = p.wait()
-        if xit != 0:
-            lg.warning("Install %s failed", pkg)
-            raise RuntimeError(pkg)
-
-        if pkg == 'pyobjc-framework-Quartz':
-            if skip_quartz:
-                continue
-
-        # TODO: 
-        # - For python2.7/3.2: use `arch` to run tests with all architectures
-        # - For python2.6/3.1: run tests using 'python-32' and 'python-64' 
-        #   when those are available
-
-        if supports_arch_command(version):
-            for a in gArchMap[archs]:
-                lg.info("Test %s for %s (%s)", pkg, os.path.basename(subdir), a)
-                p = subprocess.Popen([
-                    '/usr/bin/arch', '-' + a,
-                    python, "setup.py", "test"],
-                    cwd=pkgroot, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env)
-                stdout, _ = p.communicate()
-
-                with open(os.path.join(resultdir, pkg, "test-stdout-{0}.txt".format(a)), "wb") as fd:
-                    fd.write(stdout)
-
-                status = stdout.splitlines()
-                if status[-1].startswith(b'['):
-                    status = status[-2]
-                else:
-                    status = status[-1]
-                status = status.decode('UTF-8')
-                lg.info("Test %s for %s (%s): %s", pkg, os.path.basename(subdir), a, status)
-
-                xit = p.wait()
-                if xit != 0:
-                    lg.warning("Test %s failed", pkg)
-
-                with open(os.path.join(resultdir, pkg, "test-stdout-{0}.exit".format(a)), "w") as fd:
-                    fd.write(str(xit))
-                
-        else:
-            lg.debug("Test %s for %s", pkg, os.path.basename(subdir))
-            p = subprocess.Popen([
-                python, "setup.py", "test"],
-                cwd=pkgroot, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
-                env=env)
-            stdout, _ = p.communicate()
-
-            with open(os.path.join(resultdir, pkg, "test-stdout.txt"), "wb") as fd:
-                fd.write(stdout)
-
-            status = stdout.splitlines()[-1]
-            lg.info("Test %s for %s: %s", pkg, os.path.basename(subdir), status)
-
-            xit = p.wait()
-            if xit != 0:
-                lg.warning("Test %s failed", pkg)
-                continue
-                #raise RuntimeError(pkg)
-
-        
-
-       
-
-def parse_tests(inputfile):
-    result = {
-        'test_pass':  0,
-        'test_fail':  0,
-        'test_error': 0,
-    }
-    last_line = ''
-    with open(inputfile) as stream:
-        for ln in stream:
-            if not ln.startswith('['):
-                last_line = ln
-            ln = ln.rstrip()
-            if ln.endswith('... ok'):
-                result['test_pass'] += 1
-            elif ln.endswith('... FAIL'):
-                result['test_fail'] += 1
-            elif ln.endswith('... ERROR'):
-                result['test_error'] += 1
-
-            elif 'Fatal Python error' in ln:
-                # Interpreter aborted itself, 
-                # treat this as a test error
-                result['test_error'] += 1
-
-
-    if not last_line.split()[0].isupper():
-        # The last line of the output should
-        # be the unittest status line, which
-        # starts with an uppercase word. 
-        # Not having it is an error (and tends
-        # to be caused by interpreter crashes)
-        result['test_error'] += 1
-
-    result['class_pass'] = ''
-    result['class_fail'] = ''
-    result['class_error'] = ''
-    if result['test_pass'] == 0  \
-        and result['test_fail'] == 0 \
-        and result['test_error'] == 0:
-            result['class_pass'] = 'error'
-    if result['test_fail']:
-        result['class_fail'] = 'warning'
-    if result['test_error']:
-        result['class_error'] = 'error'
-
-    if result['test_error'] + result['test_fail'] == 0:
-        result['class_pass'] = 'ok'
-                
-    return result
-
-def parse_build(inputfile):
-    result = {
-        'build_warnings': 0,
-        'build_errors':   0,
-    }
-    with open(inputfile) as stream:
-        for ln in stream:
-            if 'warning: no directories found matching' in ln:
-                # Completely harmless warning
-                continue
-
-
-            if 'error:' in ln:
-                result['build_errors'] += 1
-
-            elif ln.startswith('../../libxml2-src/') or \
-                    ln.startswith('libffi-src'):
-                # Ignore warnings in 3th-party libraries (pyobjc-core)
-                continue
-
-
-            elif 'is deprecated' in ln and 'objc/Protocol.h' in ln:
-                # Pyobjc-core uses deprecated access methods for protocols
-                # in 32-bit mode. 
-                continue
-
-            elif 'is deprecated' in ln:
-                # Ignore all deprecation errors for now, framework wrappers
-                # also trigger these when they contain manual wrappers for
-                # deprecated APIs.
-                continue
-
-            elif 'warning:' in ln:
-                result['build_warnings'] += 1
-
-    result['class_warnings'] = ''
-    result['class_errors'] = ''
-    if result['build_warnings']:
-        result['class_warnings'] = 'warning'
-    if result['build_errors']:
-        result['class_errors'] = 'error'
-
-    if result['build_warnings'] + result['build_errors'] == 0:
-        result['class_warnings'] = 'ok'
-        result['class_errors'] = 'ok'
-
-    return result
-
-def get_svnversion():
-    p = subprocess.Popen([
-        'svnversion',
-        ], cwd='..', stdout=subprocess.PIPE)
-    stdout, _ = p.communicate()
-    xit = p.wait()
-    if xit != 0:
-        raise RuntimeError(xit)
-
-    return stdout.decode('UTF-8')
-
-def get_svnurl():
-    p = subprocess.Popen([
-        'svn', 'info', '.'
-        ], cwd='..', stdout=subprocess.PIPE)
-    stdout, _ = p.communicate()
-    xit = p.wait()
-    if xit != 0:
-        raise RuntimeError(xit)
-
-    for ln in stdout.splitlines():
-        if ln.startswith(b'URL'):
-            return ln.split(None, 1)[1].decode('UTF-8')
-
-def get_osx_version():
-    p = subprocess.Popen([
-        'sw_vers',
-        ], cwd='..', stdout=subprocess.PIPE)
-    stdout, _ = p.communicate()
-    xit = p.wait()
-    if xit != 0:
-        raise RuntimeError(xit)
-
-    r = {}
-    for ln in stdout.splitlines():
-        k, v = ln.decode('UTF-8').split(':', 1)
-        r[k.strip()] = v.strip()
-
-    return "{ProductName} {ProductVersion} ({BuildVersion})".format(**r)
-
-def gen_summary(index_html, report_versions, report_archs):
-    with open(gIndexTemplate) as fp:
-        tmpl = Template(fp.read())
-
-    svn={}
-    svn['revision'] = get_svnversion()
-    svn['url'] = get_svnurl()
-
-    osx={}
-    osx['version'] = get_osx_version()
-
-    versions = {}
-
-    for subdir in os.listdir(gTestResults):
-        if '--' not in subdir: continue
-        version, style = subdir.split('--')
-
-        if version not in report_versions: continue
-        if style not in report_archs: continue
-
-        if style not in gVersionArchs[version]:
-            continue
-
-        versions[(version, style)] = modules = []
-
-        for mod in os.listdir(os.path.join(gTestResults, subdir)):
-            moddir = os.path.join(gTestResults, subdir, mod)
-            info = parse_build(os.path.join(moddir, 'build-stdout.txt'))
-            info['name'] = mod
-            modules.append(info)
-            info['archs'] = []
-            info['class'] = None
-
-            if info['build_errors']:
-                info['class'] = 'error'
-            #elif info['build_warnings']:
-                #info['class'] = 'warning'
-
-            for fn in os.listdir(moddir):
-                if not fn.startswith('test'): continue
-                if fn.endswith('exit'): continue
-
-                if fn == 'test-stdout.txt':
-                    a = 'all'
-
-                else:
-                    a = fn.split('-')[-1].split('.')[0]
-
-                info['archs'].append(a)
-                info[a] =  parse_tests(os.path.join(moddir, fn))
-
-                with open (os.path.join(moddir, fn)[:-3] + 'exit') as fd:
-                    info[a]['exit'] = fd.read().strip()
-
-
-                if info[a]['test_fail'] and (info['class'] is None):
-                    info['class'] = 'warning'
-
-                if info[a]['test_error']:
-                    info['class'] = 'error'
-
-                if info[a]['exit'] != 0:
-                    info['class'] = 'crash'
-
-
-            if info['class'] is None:
-                info['class'] = 'ok'
-
-    with open(os.path.join(gTestResults, index_html), 'w') as fp:
-        fp.write(tmpl.render(
-            svn=svn,
-            osx=osx,
-            versions=versions,
-            sorted=sorted,
-            timestamp=time.ctime(),
-            ))
-
-if __name__ == "__main__":
-    try:
-        main()
-    except RuntimeError:
-        sys.exit(1)

File build-support/templates/index.html

-<html>
-  <head>
-    <title>PyObjC Test results</title>
-    <style type="text/css">
-      table#summary {
-        border-collapse: collapse;
-      }
-      table#summary th {
-        border-left: 1px solid black;
-        border-right: 1px solid black;
-      }
-      table#summary th.bottom {
-        border-left: 1px solid black;
-        border-right: 1px solid black;
-        border-bottom: 3px solid black;
-      }
-      table#summary th.bottom-left {
-        border-left: 1px solid black;
-        border-right: none;
-        border-bottom: 3px solid black;
-      }
-      table#summary th.bottom-mid {
-        border-left: none;
-        border-right: none;
-        border-bottom: 3px solid black;
-      }
-      table#summary th.bottom-right {
-        border-right: 1px solid black;
-        border-left: none;
-        border-bottom: 3px solid black;
-      }
-      table#summary td {
-        border: 1px solid black;
-      }
-      /*
-      table#summary tr.ok td { 
-        background-color: green;
-      }
-      table#summary tr.warning td { 
-        background-color: orange;
-      }
-      table#summary tr.error td { 
-        background-color: red;
-      }
-      */
-
-      table#summary td.ok { 
-        background-color: rgb(0, 120, 0);
-      }
-      table#summary td.warning { 
-        background-color: orange;
-      }
-      table#summary td.error { 
-        background-color: red;
-      }
-      table#summary td.crash { 
-        background-color: red;
-        text-decoration: underline;
-      }
-
-    </style>
-  </head>
-  <body>
-    <h1>PyObjC Test results</h1>
-
-    <ul>
-      <li>Repository:  {{ svn['url'] }}</li>
-      <li>Checkout:    {{ svn['revision'] }}</li>
-      <li>OSX Version: {{ osx['version'] }}</li>
-      <li>Timestamp:   {{ timestamp }}</li>
-    {% for ver, style in sorted(versions) %}
-      <li><a href="#{{ver}}--{{style}}">Python {{ver}} ({{style}})</a></li>
-    {% endfor %}
-    </ul>
-
-    {% for ver, style in sorted(versions) %}
-
-    <a name="${ver}--${style}"><h2>Python {{ ver }} ({{ style }})</h2>
-
-    <table id="summary">
-      <tr>
-        <th></th>
-        <th colspan="2">Build</th>
-        {% for a in versions[(ver, style)][0]['archs'] %}
-        <th colspan="3">Test ({{ a }})</th>
-        {% endfor %}
-      </tr>
-      <tr>
-        <th class="bottom">Subproject</th>
-        <th class="bottom-left">Warnings</th>
-        <th class="bottom-right">Errors</th>
-        {% for a in versions[(ver, style)][0]['archs'] %}
-        <th class="bottom-left">Pass</th>
-        <th class="bottom-mid">Fail</th>
-        <th class="bottom-right">Error</th>
-        {% endfor %}
-      </tr>
-      {% for item in versions[(ver, style)] %}
-      <tr class="{{ item['class'] }}">
-        <td>{{ item['name'] }}</td>
-        <td class="{{ item['class_warnings'] }}">{{ item['build_warnings'] }}</td>
-        <td class="{{ item['class_errors'] }}">{{ item['build_errors'] }}</td>
-        {% for a in item['archs'] %}
-        <td class="{{ item[a]['class_pass']}}">{{ item[a]['test_pass'] }}</td>
-        <td class="{{ item[a]['class_fail']}}">{{ item[a]['test_fail'] }}</td>
-        <td class="{{ item[a]['class_error']}}">{{ item[a]['test_error'] }}</td>
-        {% endfor %}
-      </tr>
-      {% endfor %}
-    </table>
-
-    {% endfor %}
-  </body>
-</html>

File build-support/topsort.py

-"""
-Module defining a topological sort function, see 
-<http://www.bitformation.com/art/python_toposort.html> for more
-information.
-
-Original topological sort code written by Ofer Faigon (www.bitformation.com) and used with permission
-"""
-
-def topological_sort(items, partial_order):
-    """
-    Perform topological sort.
-    items is a list of items to be sorted.
-    partial_order is a list of pairs. If pair (a,b) is in it, it means
-    that item a should appear before item b.
-    Returns a list of the items in one of the possible orders, or None
-    if partial_order contains a loop.
-    """
-
-    def add_node(graph, node):
-        """Add a node to the graph if not already exists."""
-        if node not in graph:
-            graph[node] = [0] # 0 = number of arcs coming into this node.
-
-    def add_arc(graph, fromnode, tonode):
-        """Add an arc to a graph. Can create multiple arcs.
-           The end nodes must already exist."""
-        graph[fromnode].append(tonode)
-        # Update the count of incoming arcs in tonode.
-        graph[tonode][0] += 1
-
-    # step 1 - create a directed graph with an arc a->b for each input
-    # pair (a,b).
-    # The graph is represented by a dictionary. The dictionary contains
-    # a pair item:list for each node in the graph. /item/ is the value
-    # of the node. /list/'s 1st item is the count of incoming arcs, and
-    # the rest are the destinations of the outgoing arcs. For example:
-    #           {'a':[0,'b','c'], 'b':[1], 'c':[1]}
-    # represents the graph:   c <-- a --> b
-    # The graph may contain loops and multiple arcs.
-    # Note that our representation does not contain reference loops to
-    # cause GC problems even when the represented graph contains loops,
-    # because we keep the node names rather than references to the nodes.
-    graph = {}
-    for v in items:
-        add_node(graph, v)
-    for a,b in partial_order:
-        add_arc(graph, a, b)
-
-    # Step 2 - find all roots (nodes with zero incoming arcs).
-    roots = [node for (node,nodeinfo) in graph.items() if nodeinfo[0] == 0]
-
-    # step 3 - repeatedly emit a root and remove it from the graph. Removing
-    # a node may convert some of the node's direct children into roots.
-    # Whenever that happens, we append the new roots to the list of
-    # current roots.
-    sorted = []
-    while len(roots) != 0:
-        # If len(roots) is always 1 when we get here, it means that
-        # the input describes a complete ordering and there is only
-        # one possible output.
-        # When len(roots) > 1, we can choose any root to send to the
-        # output; this freedom represents the multiple complete orderings
-        # that satisfy the input restrictions. We arbitrarily take one of
-        # the roots using pop(). Note that for the algorithm to be efficient,
-        # this operation must be done in O(1) time.
-        root = roots.pop()
-        sorted.append(root)
-        for child in graph[root][1:]:
-            graph[child][0] = graph[child][0] - 1
-            if graph[child][0] == 0:
-                roots.append(child)
-        del graph[root]
-    if len(graph.items()) != 0:
-        # There is a loop in the input.
-        return None
-    return sorted