From 11dc43e61bc37d274ad552c25c8d18811e56249a Mon Sep 17 00:00:00 2001 From: jim <jim@62d5b8a3-27da-0310-9561-8e5933582275> Date: Tue, 29 Aug 2006 17:45:55 +0000 Subject: [PATCH] try again git-svn-id: http://svn.zope.org/repos/main/zc.buildout/trunk@69871 62d5b8a3-27da-0310-9561-8e5933582275 --- buildout.cfg | 2 +- zc.buildoutsupport/zc/__init__.py | 5 - .../zc/buildoutsupport/__init__.py | 1 - .../zc/buildoutsupport/easy_install.py | 461 ------------------ .../zc/buildoutsupport/easy_install.txt | 440 ----------------- .../zc/buildoutsupport/testing.py | 418 ---------------- .../zc/buildoutsupport/tests.py | 115 ----- 7 files changed, 1 insertion(+), 1441 deletions(-) delete mode 100644 zc.buildoutsupport/zc/__init__.py delete mode 100644 zc.buildoutsupport/zc/buildoutsupport/__init__.py delete mode 100644 zc.buildoutsupport/zc/buildoutsupport/easy_install.py delete mode 100644 zc.buildoutsupport/zc/buildoutsupport/easy_install.txt delete mode 100644 zc.buildoutsupport/zc/buildoutsupport/testing.py delete mode 100644 zc.buildoutsupport/zc/buildoutsupport/tests.py diff --git a/buildout.cfg b/buildout.cfg index 57c7f3d..c648481 100644 --- a/buildout.cfg +++ b/buildout.cfg @@ -1,5 +1,5 @@ [buildout] -develop = zc.recipe.egg_ zc.recipe.testrunner +develop = zc.recipe.egg_ zc.recipe.testrunner zc.buildoutsupport parts = test # prevent slow access to cheeseshop: diff --git a/zc.buildoutsupport/zc/__init__.py b/zc.buildoutsupport/zc/__init__.py deleted file mode 100644 index 35cf25b..0000000 --- a/zc.buildoutsupport/zc/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -try: - __import__('pkg_resources').declare_namespace(__name__) -except: - # bootstrapping - pass diff --git a/zc.buildoutsupport/zc/buildoutsupport/__init__.py b/zc.buildoutsupport/zc/buildoutsupport/__init__.py deleted file mode 100644 index 792d600..0000000 --- a/zc.buildoutsupport/zc/buildoutsupport/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# diff --git a/zc.buildoutsupport/zc/buildoutsupport/easy_install.py b/zc.buildoutsupport/zc/buildoutsupport/easy_install.py deleted file mode 100644 index c7d83bb..0000000 --- a/zc.buildoutsupport/zc/buildoutsupport/easy_install.py +++ /dev/null @@ -1,461 +0,0 @@ -############################################################################## -# -# Copyright (c) 2005 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Python easy_install API - -This module provides a high-level Python API for installing packages. -It doesn't install scripts. It uses setuptools and requires it to be -installed. - -$Id$ -""" - -import logging, os, re, tempfile, sys -import pkg_resources, setuptools.command.setopt -import zc.buildout - -# XXX we could potentially speed this up quite a bit by keeping our -# own PackageIndex to analyse whether there are newer dists. A hitch -# is that the package index seems to go out of its way to only handle -# one Python version at a time. :( - -logger = logging.getLogger('zc.buildout.easy_install') - -# Include buildout and setuptools eggs in paths -buildout_and_setuptools_path = [ - (('.egg' in m.__file__) - and m.__file__[:m.__file__.rfind('.egg')+4] - or os.path.dirname(m.__file__) - ) - for m in (pkg_resources,) - ] -buildout_and_setuptools_path += [ - (('.egg' in m.__file__) - and m.__file__[:m.__file__.rfind('.egg')+4] - or os.path.dirname(os.path.dirname(os.path.dirname(m.__file__))) - ) - for m in (zc.buildout,) - ] - -_versions = {sys.executable: '%d.%d' % sys.version_info[:2]} -def _get_version(executable): - try: - return _versions[executable] - except KeyError: - i, o = os.popen4(executable + ' -V') - i.close() - version = o.read().strip() - o.close() - pystring, version = version.split() - assert pystring == 'Python' - version = re.match('(\d[.]\d)[.]\d$', version).group(1) - _versions[executable] = version - return version - -def _satisfied(req, env): - dists = env[req.project_name] - - best = None - for dist in dists: - if (dist.precedence == pkg_resources.DEVELOP_DIST) and (dist in req): - if best is not None and best.location != dist.location: - raise ValueError('Multiple devel eggs for', req) - best = dist - - if best is not None: - return best - - specs = [(pkg_resources.parse_version(v), op) for (op, v) in req.specs] - specs.sort() - maxv = None - greater = False - lastv = None - for v, op in specs: - if op == '==' and not greater: - maxv = v - elif op in ('>', '>=', '!='): - maxv = None - greater == True - elif op == '<': - maxv = None - greater == False - elif op == '<=': - maxv = v - greater == False - - if v == lastv: - # Repeated versions values are undefined, so - # all bets are off - maxv = None - greater = True - else: - lastv = v - - if maxv is not None: - for dist in dists: - if dist.parsed_version == maxv: - return dist - - return None - - -if sys.platform == 'win32': - # work around spawn lamosity on windows - # XXX need safe quoting (see the subproces.list2cmdline) and test - def _safe_arg(arg): - return '"%s"' % arg -else: - _safe_arg = str - -_easy_install_cmd = _safe_arg( - 'from setuptools.command.easy_install import main; main()' - ) - -def _call_easy_install(spec, dest, links=(), - index = None, - executable=sys.executable, - always_unzip=False, - ): - prefix = sys.exec_prefix + os.path.sep - path = os.pathsep.join([p for p in sys.path if not p.startswith(prefix)]) - - args = ('-c', _easy_install_cmd, '-mUNxd', _safe_arg(dest)) - if links: - args += ('-f', _safe_arg(' '.join(links))) - if index: - args += ('-i', index) - if always_unzip: - args += ('-Z', ) - level = logger.getEffectiveLevel() - if level > logging.DEBUG: - args += ('-q', ) - elif level < logging.DEBUG: - args += ('-v', ) - - args += (spec, ) - - if level <= logging.DEBUG: - logger.debug('Running easy_install:\n%s "%s"\npath=%s\n', - executable, '" "'.join(args), path) - - args += (dict(os.environ, PYTHONPATH=path), ) - sys.stdout.flush() # We want any pending output first - exit_code = os.spawnle(os.P_WAIT, executable, executable, *args) - assert exit_code == 0 - - # We may overwrite distributions, so clear importer - # cache. - sys.path_importer_cache.clear() - - - -def _get_dist(requirement, env, ws, - dest, links, index, executable, always_unzip): - # Maybe an existing dist is already the best dist that satisfies the - # requirement - dist = _satisfied(requirement, env) - - # XXX Special case setuptools because: - # 1. Almost everything depends on it and - # 2. It is expensive to checl for. - # Need to think of a cleaner way to handle this. - # If we already have a satisfactory version, use it. - if dist is None and requirement.project_name == 'setuptools': - dist = env.best_match(requirement, ws) - - if dist is None: - if dest is not None: - # May need a new one. Call easy_install - _call_easy_install(str(requirement), dest, links, index, - executable, always_unzip) - - # Because we may have added new eggs, we need to rescan - # the destination directory. A possible optimization - # is to get easy_install to recod the files installed - # and either firgure out the distribution added, or - # only rescan if any files have been added. - env.scan([dest]) - - dist = env.best_match(requirement, ws) - - if dist is None: - raise ValueError("Couldn't find", requirement) - - # XXX Need test for this - if dist.has_metadata('dependency_links.txt'): - for link in dist.get_metadata_lines('dependency_links.txt'): - link = link.strip() - if link not in links: - links.append(link) - - return dist - -def install(specs, dest, - links=(), index=None, - executable=sys.executable, always_unzip=False, - path=None): - - logger.debug('Installing %r', specs) - - path = path and path[:] or [] - if dest is not None: - path.insert(0, dest) - - path += buildout_and_setuptools_path - - links = list(links) # make copy, because we may need to mutate - - - # For each spec, see if it is already installed. We create a working - # set to keep track of what we've collected and to make sue than the - # distributions assembled are consistent. - env = pkg_resources.Environment(path, python=_get_version(executable)) - requirements = [pkg_resources.Requirement.parse(spec) for spec in specs] - - ws = pkg_resources.WorkingSet([]) - - for requirement in requirements: - ws.add(_get_dist(requirement, env, ws, - dest, links, index, executable, always_unzip) - ) - - # OK, we have the requested distributions and they're in the working - # set, but they may have unmet requirements. We'll simply keep - # trying to resolve requirements, adding missing requirements as they - # are reported. - # - # Note that we don't pass in the environment, because we - # want to look for new eggs unless what we have is the best that matches - # the requirement. - while 1: - try: - ws.resolve(requirements) - except pkg_resources.DistributionNotFound, err: - [requirement] = err - if dest: - logger.debug('Getting required %s', requirement) - ws.add(_get_dist(requirement, env, ws, - dest, links, index, executable, always_unzip) - ) - else: - break - - return ws - - -def _editable(spec, dest, links=(), index = None, executable=sys.executable): - prefix = sys.exec_prefix + os.path.sep - path = os.pathsep.join([p for p in sys.path if not p.startswith(prefix)]) - args = ('-c', _easy_install_cmd, '-eb', _safe_arg(dest)) - if links: - args += ('-f', ' '.join(links)) - if index: - args += ('-i', index) - level = logger.getEffectiveLevel() - if level > logging.DEBUG: - args += ('-q', ) - elif level < logging.DEBUG: - args += ('-v', ) - - args += (spec, ) - - if level <= logging.DEBUG: - logger.debug('Running easy_install:\n%s "%s"\npath=%s\n', - executable, '" "'.join(args), path) - - args += (dict(os.environ, PYTHONPATH=path), ) - sys.stdout.flush() # We want any pending output first - exit_code = os.spawnle(os.P_WAIT, executable, executable, *args) - assert exit_code == 0 - -def build(spec, dest, build_ext, - links=(), index=None, - executable=sys.executable, - path=None): - - # XXX we're going to download and build the egg every stinking time. - # We need to not do that. - - logger.debug('Building %r', spec) - - path = path and path[:] or [] - if dest is not None: - path.insert(0, dest) - - path += buildout_and_setuptools_path - - links = list(links) # make copy, because we may need to mutate - - # For each spec, see if it is already installed. We create a working - # set to keep track of what we've collected and to make sue than the - # distributions assembled are consistent. - env = pkg_resources.Environment(path, python=_get_version(executable)) - requirement = pkg_resources.Requirement.parse(spec) - - dist = _satisfied(requirement, env) - if dist is not None: - return dist - - # Get an editable version of the package to a temporary directory: - tmp = tempfile.mkdtemp('editable') - _editable(spec, tmp, links, index, executable) - - setup_cfg = os.path.join(tmp, requirement.key, 'setup.cfg') - if not os.path.exists(setup_cfg): - f = open(setup_cfg, 'w') - f.close() - setuptools.command.setopt.edit_config(setup_cfg, dict(build_ext=build_ext)) - - # Now run easy_install for real: - _call_easy_install( - os.path.join(tmp, requirement.key), - dest, links, index, executable, True) - -def working_set(specs, executable, path): - return install(specs, None, executable=executable, path=path) - -def scripts(reqs, working_set, executable, dest, - scripts=None, - extra_paths=(), - arguments='', - ): - reqs = [pkg_resources.Requirement.parse(r) for r in reqs] - projects = [r.project_name for r in reqs] - path = [dist.location for dist in working_set] - path.extend(extra_paths) - path = repr(path)[1:-1].replace(',', ',\n ') - generated = [] - - for dist in working_set: - if dist.project_name in projects: - for name in pkg_resources.get_entry_map(dist, 'console_scripts'): - if scripts is not None: - sname = scripts.get(name) - if sname is None: - continue - else: - sname = name - - sname = os.path.join(dest, sname) - generated.extend( - _script(dist, 'console_scripts', name, path, sname, - executable, arguments) - ) - - name = 'py-'+dist.project_name - if scripts is not None: - sname = scripts.get(name) - else: - sname = name - - if sname is not None: - sname = os.path.join(dest, sname) - generated.extend( - _pyscript(path, sname, executable) - ) - - return generated - -def _script(dist, group, name, path, dest, executable, arguments): - entry_point = dist.get_entry_info(group, name) - generated = [] - if sys.platform == 'win32': - # generate exe file and give the script a magic name: - open(dest+'.exe', 'wb').write( - pkg_resources.resource_string('setuptools', 'cli.exe') - ) - generated.append(dest+'.exe') - dest += '-script.py' - - open(dest, 'w').write(script_template % dict( - python = executable, - path = path, - project = dist.project_name, - name = name, - module_name = entry_point.module_name, - attrs = '.'.join(entry_point.attrs), - arguments = arguments, - )) - try: - os.chmod(dest, 0755) - except (AttributeError, os.error): - pass - generated.append(dest) - return generated - -script_template = '''\ -#!%(python)s - -import sys -sys.path[0:0] = [ - %(path)s - ] - -import %(module_name)s - -if __name__ == '__main__': - %(module_name)s.%(attrs)s(%(arguments)s) -''' - - -def _pyscript(path, dest, executable): - generated = [] - if sys.platform == 'win32': - # generate exe file and give the script a magic name: - open(dest+'.exe', 'wb').write( - pkg_resources.resource_string('setuptools', 'cli.exe') - ) - generated.append(dest+'.exe') - dest += '-script.py' - - open(dest, 'w').write(py_script_template % dict( - python = executable, - path = path, - )) - try: - os.chmod(dest,0755) - except (AttributeError, os.error): - pass - generated.append(dest) - return generated - -py_script_template = '''\ -#!%(python)s -import sys - -sys.path[0:0] = [ - %(path)s - ] - -_interactive = True -if len(sys.argv) > 1: - import getopt - _options, _args = getopt.getopt(sys.argv[1:], 'ic:') - _interactive = False - for (_opt, _val) in _options: - if _opt == '-i': - _interactive = True - elif _opt == '-c': - exec _val - - if _args: - sys.argv[:] = _args - execfile(sys.argv[0]) - -if _interactive: - import code - code.interact(banner="", local=globals()) -''' - - - diff --git a/zc.buildoutsupport/zc/buildoutsupport/easy_install.txt b/zc.buildoutsupport/zc/buildoutsupport/easy_install.txt deleted file mode 100644 index 5b27dc3..0000000 --- a/zc.buildoutsupport/zc/buildoutsupport/easy_install.txt +++ /dev/null @@ -1,440 +0,0 @@ -Minimal Python interface to easy_install -======================================== - -The easy_install module provides a minimal interface to the setuptools -easy_install command that provides some additional semantics: - -- By default, we look for new packages *and* the packages that - they depend on. This is somewhat like (and uses) the --upgrade - option of easy_install, except that we also upgrade required - packages. - -- If the highest-revision package satisfying a specification is - already present, then we don't try to get another one. This saves a - lot of search time in the common case that packages are pegged to - specific versions. - -- If there is a develop egg that satisfies a requirement, we don't - look for additional distributions. We always give preference to - develop eggs. - -- Distutils options for building extensions can be passed. - -The easy_install module provides a method, install, for installing one -or more packages and their dependencies. The -install function takes 2 positional arguments: - -- An iterable of setuptools requirement strings for the distributions - to be installed, and - -- A destination directory to install to and to satisfy - requirements from. - -It supports a number of optional keyword arguments: - -links - a sequence of URLs, file names, or directories to look for - links to distributions, - -index - The URL of an index server, or almost any other valid URL. :) - - If not specified, the Python Package Index, - http://cheeseshop.python.org/pypi, is used. You can specify an - alternate index with this option. If you use the links option and - if the links point to the needed distributions, then the index can - be anything and will be largely ignored. In the examples, here, - we'll just point to an empty directory on our link server. This - will make our examples run a little bit faster. - -executable - A path to a Python executable. Distributions will ne installed - using this executable and will be for the matching Python version. - -path - A list of additional directories to search for locally-installed - distributions. - -always_unzip - A flag indicating that newly-downloaded distributions should be - directories even if they could be installed as zip files. - -arguments - Source code to be used to pass arguments when calling a script entry point. - -The install method returns a working set containing the distributions -needed to meet the given requirements. - -We have a link server that has a number of eggs: - - >>> print get(link_server), - <html><body> - <a href="demo-0.1-py2.3.egg">demo-0.1-py2.3.egg</a><br> - <a href="demo-0.1-py2.4.egg">demo-0.1-py2.4.egg</a><br> - <a href="demo-0.2-py2.3.egg">demo-0.2-py2.3.egg</a><br> - <a href="demo-0.2-py2.4.egg">demo-0.2-py2.4.egg</a><br> - <a href="demo-0.3-py2.3.egg">demo-0.3-py2.3.egg</a><br> - <a href="demo-0.3-py2.4.egg">demo-0.3-py2.4.egg</a><br> - <a href="demoneeded-1.0-py2.3.egg">demoneeded-1.0-py2.3.egg</a><br> - <a href="demoneeded-1.0-py2.4.egg">demoneeded-1.0-py2.4.egg</a><br> - <a href="demoneeded-1.1-py2.3.egg">demoneeded-1.1-py2.3.egg</a><br> - <a href="demoneeded-1.1-py2.4.egg">demoneeded-1.1-py2.4.egg</a><br> - <a href="extdemo-1.4.tar.gz">extdemo-1.4.tar.gz</a><br> - <a href="index/">index/</a><br> - <a href="other-1.0-py2.3.egg">other-1.0-py2.3.egg</a><br> - <a href="other-1.0-py2.4.egg">other-1.0-py2.4.egg</a><br> - </body></html> - -Let's make a directory and install the demo egg to it, using the demo: - - >>> dest = mkdtemp('sample-install') - >>> import zc.buildout.easy_install - >>> ws = zc.buildout.easy_install.install( - ... ['demo==0.2'], dest, - ... links=[link_server], index=link_server+'index/') - -We requested version 0.2 of the demo distribution to be installed into -the destination server. We specified that we should search for links -on the link server and that we should use the (empty) link server -index directory as a package index. - -The working set contains the distributions we retrieved. - - >>> for dist in ws: - ... print dist - demo 0.2 - demoneeded 1.1 - -And the actual eggs were added to the eggs directory. - - >>> ls(dest) - - demo-0.2-py2.3.egg - - demoneeded-1.1-py2.3.egg - -If we ask for the demo distribution without a version restriction, -we'll get the newer version: - - >>> ws = zc.buildout.easy_install.install( - ... ['demo'], dest, links=[link_server], index=link_server+'index/') - >>> ls(dest) - - demo-0.2-py2.3.egg - - demo-0.3-py2.3.egg - - demoneeded-1.1-py2.3.egg - -We can supply additional distributions. We can also supply -specifications for distributions that would normally be found via -dependencies. We might do this to specify a sprcific version. - - >>> ws = zc.buildout.easy_install.install( - ... ['demo', 'other', 'demoneeded==1.0'], dest, - ... links=[link_server], index=link_server+'index/') - - >>> for dist in ws: - ... print dist - demo 0.3 - other 1.0 - demoneeded 1.0 - - >>> ls(dest) - - demo-0.2-py2.3.egg - - demo-0.3-py2.3.egg - - demoneeded-1.0-py2.3.egg - - demoneeded-1.1-py2.3.egg - - other-1.0-py2.3.egg - -We can specify an alternate Python executable, and we can specify -that, when we retrieve (or create) an egg, it should be unzipped. - - >>> dest = mkdtemp('sample-install') - >>> ws = zc.buildout.easy_install.install( - ... ['demo'], dest, links=[link_server], index=link_server+'index/', - ... always_unzip=True, executable= python2_3_executable) - - >>> ls(dest) - d demo-0.3-py2.3.egg - d demoneeded-1.1-py2.3.egg - - >>> dest = mkdtemp('sample-install') - >>> ws = zc.buildout.easy_install.install( - ... ['demo'], dest, links=[link_server], index=link_server+'index/', - ... always_unzip=True, executable=python2_4_executable) - - >>> ls(dest) - d demo-0.3-py2.4.egg - d demoneeded-1.1-py2.4.egg - -Script generation ------------------ - -The easy_install module provides support for creating scripts from -eggs. It provides a function similar to setuptools except that it -provides facilities for baking a script's path into the script. This -has two advantages: - -- The eggs to be used by a script are not chosen at run time, making - startup faster and, more importantly, deterministic. - -- The script doesn't have to import pkg_resources because the logic - that pkg_resources would execute at run time is executed at - script-creation time. - -The scripts method can be used to generate scripts. Let's create a -destination directory for it to place them in: - - >>> import tempfile - >>> bin = mkdtemp() - -Now, we'll use the scripts method to generate scripts in this directory -from the demo egg: - - >>> scripts = zc.buildout.easy_install.scripts( - ... ['demo==0.1'], ws, python2_4_executable, bin) - -the four arguments we passed were: - -1. A sequence of distribution requirements. These are of the same - form as setuptools requirements. Here we passed a single - requirement, for the version 0.1 demo distribution. - -2. A working set, - -3. The Python executable to use, and - -3. The destination directory. - -The bin directory now contains 2 generated scripts: - - >>> ls(bin) - - demo - - py-demo - -The return value is a list of the scripts generated: - - >>> import os, sys - >>> if sys.platform == 'win32': - ... scripts == [os.path.join(bin, 'demo.exe'), - ... os.path.join(bin, 'demo-script.py'), - ... os.path.join(bin, 'py-demo.exe'), - ... os.path.join(bin, 'py-demo-script.py')] - ... else: - ... scripts == [os.path.join(bin, 'demo'), - ... os.path.join(bin, 'py-demo')] - True - -The demo script run the entry point defined in the demo egg: - - >>> cat(bin, 'demo') # doctest: +NORMALIZE_WHITESPACE - #!/usr/local/bin/python2.3 - <BLANKLINE> - import sys - sys.path[0:0] = [ - '/tmp/xyzsample-install/demo-0.3-py2.3.egg', - '/tmp/xyzsample-install/demoneeded-1.1-py2.3.egg' - ] - <BLANKLINE> - import eggrecipedemo - <BLANKLINE> - if __name__ == '__main__': - eggrecipedemo.main() - -Some things to note: - -- The demo and demoneeded eggs are added to the beginning of sys.path. - -- The module for the script entry point is imported and the entry - point, in this case, 'main', is run. - -The py-demo script simply run the Python interactive interpreter with -the path set: - - >>> cat(bin, 'py-demo') # doctest: +NORMALIZE_WHITESPACE - #!/usr/local/bin/python2.4 - import sys - <BLANKLINE> - sys.path[0:0] = [ - '/tmp/tmp5zS2Afsample-install/demo-0.3-py2.4.egg', - '/tmp/tmp5zS2Afsample-install/demoneeded-1.1-py2.4.egg' - ] - <BLANKLINE> - _interactive = True - if len(sys.argv) > 1: - import getopt - _options, _args = getopt.getopt(sys.argv[1:], 'ic:') - _interactive = False - for (_opt, _val) in _options: - if _opt == '-i': - _interactive = True - elif _opt == '-c': - exec _val - <BLANKLINE> - if _args: - sys.argv[:] = _args - execfile(sys.argv[0]) - <BLANKLINE> - if _interactive: - import code - code.interact(banner="", local=globals()) - -If invoked with a script name and arguments, it will run that script, instead. - -An additional argumnet can be passed to define which scripts to install -and to provie script names. The argument is a dictionary mapping -original script names to new script names. - - >>> bin = mkdtemp() - >>> scripts = zc.buildout.easy_install.scripts( - ... ['demo==0.1'], ws, python2_4_executable, bin, dict(demo='run')) - - >>> if sys.platform == 'win32': - ... scripts == [os.path.join(bin, 'run.exe'), - ... os.path.join(bin, 'run-script.py')] - ... else: - ... scripts == [os.path.join(bin, 'run')] - True - >>> ls(bin) - - run - - >>> print system(os.path.join(bin, 'run')), - 3 1 - -Including extra paths in scripts --------------------------------- - -We can pass a keyword argument, extra paths, to caue additional paths -to be included in the a generated script: - - >>> scripts = zc.buildout.easy_install.scripts( - ... ['demo==0.1'], ws, python2_4_executable, bin, dict(demo='run'), - ... extra_paths=['/foo/bar']) - - >>> cat(bin, 'run') # doctest: +NORMALIZE_WHITESPACE - #!/usr/local/bin/python2.3 - <BLANKLINE> - import sys - sys.path[0:0] = [ - '/tmp/xyzsample-install/demo-0.3-py2.3.egg', - '/tmp/xyzsample-install/demoneeded-1.1-py2.3.egg', - '/foo/bar' - ] - <BLANKLINE> - import eggrecipedemo - <BLANKLINE> - if __name__ == '__main__': - eggrecipedemo.main() - -Providing script arguments --------------------------- - -A n "argument" keyword argument can be used to pass arguments to an -entry point. The value passed source string to be placed between the -parentheses in the call: - - >>> scripts = zc.buildout.easy_install.scripts( - ... ['demo==0.1'], ws, python2_4_executable, bin, dict(demo='run'), - ... arguments='1, 2') - - >>> cat(bin, 'run') # doctest: +NORMALIZE_WHITESPACE - #!/usr/local/bin/python2.3 - import sys - sys.path[0:0] = [ - '/tmp/xyzsample-install/demo-0.3-py2.3.egg', - '/tmp/xyzsample-install/demoneeded-1.1-py2.3.egg' - ] - <BLANKLINE> - import eggrecipedemo - <BLANKLINE> - if __name__ == '__main__': - eggrecipedemo.main(1, 2) - - - -Handling custom build options for extensions --------------------------------------------- - -Sometimes, we need to control how extension modules are built. The -build method provides this level of control. It takes a single -package specification, downloads a source distribution, and builds it -with specified custom build options. - -The build method takes 3 positional arguments: - -spec - A package specification - -dest - A destination directory - -build_ext - A dictionary of options to be passed to the distutils build_ext - command when building extensions. - -It supports a number of optional keyword arguments: - -links - a sequence of URLs, file names, or directories to look for - links to distributions, - -index - The URL of an index server, or almost any other valid URL. :) - - If not specified, the Python Package Index, - http://cheeseshop.python.org/pypi, is used. You can specify an - alternate index with this option. If you use the links option and - if the links point to the needed distributions, then the index can - be anything and will be largely ignored. In the examples, here, - we'll just point to an empty directory on our link server. This - will make our examples run a little bit faster. - -executable - A path to a Python executable. Distributions will ne installed - using this executable and will be for the matching Python version. - -path - A list of additional directories to search for locally-installed - distributions. - -always_unzip - A flag indicating that newly-downloaded distributions should be - directories even if they could be installed as zip files. - -Our link server included a source distribution that includes a simple -extension, extdemo.c:: - - #include <Python.h> - #include <extdemo.h> - - static PyMethodDef methods[] = {}; - - PyMODINIT_FUNC - initextdemo(void) - { - PyObject *d; - d = Py_InitModule3("extdemo", methods, ""); - PyDict_SetItemString(d, "val", PyInt_FromLong(EXTDEMO)); - } - -The extension depends on a system-dependnt include file, extdemo.h, -that defines a constant, EXTDEMO, that is exposed by the extension. - -We'll add an include directory to our sample buildout and add the -needed include file to it: - - >>> mkdir(sample_buildout, 'include') - >>> open(os.path.join(sample_buildout, 'include', 'extdemo.h'), 'w').write( - ... "#define EXTDEMO 42\n") - -Now, we can use the build function to create an egg from the source -distribution: - - >>> zc.buildout.easy_install.build( - ... 'extdemo', dest, - ... {'include-dirs': os.path.join(sample_buildout, 'include')}, - ... links=[link_server], index=link_server+'index/') - -Now if we look in our destination directory, we see we have an extdemo egg: - - >>> ls(dest) - d demo-0.3-py2.4.egg - d demoneeded-1.1-py2.4.egg - d extdemo-1.4-py2.3-unix-i686.egg - diff --git a/zc.buildoutsupport/zc/buildoutsupport/testing.py b/zc.buildoutsupport/zc/buildoutsupport/testing.py deleted file mode 100644 index cf2a807..0000000 --- a/zc.buildoutsupport/zc/buildoutsupport/testing.py +++ /dev/null @@ -1,418 +0,0 @@ -############################################################################## -# -# Copyright (c) 2004 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Various test-support utility functions - -$Id$ -""" - - -import BaseHTTPServer, ConfigParser, os, random, re, shutil, socket, sys -import tempfile, threading, time, urllib2, unittest - -from zope.testing import doctest, renormalizing -import pkg_resources - -import zc.buildout.buildout - -def cat(dir, *names): - path = os.path.join(dir, *names) - if (not os.path.exists(path) - and sys.platform == 'win32' - and os.path.exists(path+'-script.py') - ): - path = path+'-script.py' - print open(path).read(), - -def ls(dir, *subs): - if subs: - dir = os.path.join(dir, *subs) - names = os.listdir(dir) - names.sort() - for name in names: - if os.path.isdir(os.path.join(dir, name)): - print 'd ', - else: - print '- ', - print name - -def mkdir(dir, *subs): - if subs: - dir = os.path.join(dir, *subs) - os.mkdir(dir) - -def write(dir, *args): - open(os.path.join(dir, *(args[:-1])), 'w').write(args[-1]) - -def system(command, input=''): - i, o = os.popen4(command) - if input: - i.write(input) - i.close() - return o.read() - -def get(url): - return urllib2.urlopen(url).read() - -def buildoutSetUp(test): - # we both need to make sure that HOME isn't set and be prepared - # to restore whatever it was after the test. - test.globs['_oldhome'] = os.environ.pop('HOME', None) - - temporary_directories = [] - def mkdtemp(*args): - d = tempfile.mkdtemp(*args) - temporary_directories.append(d) - return d - - sample = mkdtemp('sample-buildout') - - # Create a basic buildout.cfg to avoid a warning from buildout: - open(os.path.join(sample, 'buildout.cfg'), 'w').write( - "[buildout]\nparts =\n" - ) - - # Use the buildout bootstrap command to create a buildout - zc.buildout.buildout.Buildout(os.path.join(sample, 'buildout.cfg'), () - ).bootstrap([]) - - test.globs.update(dict( - __here = os.getcwd(), - sample_buildout = sample, - ls = ls, - cat = cat, - mkdir = mkdir, - write = write, - system = system, - get = get, - __temporary_directories__ = temporary_directories, - __tearDown__ = [], - mkdtemp = mkdtemp, - )) - -def buildoutTearDown(test): - os.chdir(test.globs['__here']) - for d in test.globs['__temporary_directories__']: - shutil.rmtree(d) - for f in test.globs['__tearDown__']: - f() - if test.globs.get('_oldhome') is not None: - os.environ['HOME'] = test.globs['_oldhome'] - - -script_template = '''\ -#!%(python)s - -import sys -sys.path[0:0] = %(path)r - -from pkg_resources import load_entry_point -sys.exit(load_entry_point('zc.buildout', 'console_scripts', 'buildout')()) -''' - -def runsetup(d, executable): - here = os.getcwd() - try: - os.chdir(d) - os.spawnle( - os.P_WAIT, executable, executable, - 'setup.py', '-q', 'bdist_egg', - {'PYTHONPATH': os.path.dirname(pkg_resources.__file__)}, - ) - shutil.rmtree('build') - finally: - os.chdir(here) - -def create_sample_eggs(test, executable=sys.executable): - if 'sample_eggs' in test.globs: - sample = os.path.dirname(test.globs['sample_eggs']) - else: - sample = test.globs['mkdtemp']('sample-eggs') - test.globs['sample_eggs'] = os.path.join(sample, 'dist') - write(sample, 'README.txt', '') - - for i in (0, 1): - write(sample, 'eggrecipedemobeeded.py', 'y=%s\n' % i) - write( - sample, 'setup.py', - "from setuptools import setup\n" - "setup(name='demoneeded', py_modules=['eggrecipedemobeeded']," - " zip_safe=True, version='1.%s')\n" - % i - ) - runsetup(sample, executable) - - write( - sample, 'setup.py', - "from setuptools import setup\n" - "setup(name='other', zip_safe=True, version='1.0', " - "py_modules=['eggrecipedemobeeded'])\n" - ) - runsetup(sample, executable) - - os.remove(os.path.join(sample, 'eggrecipedemobeeded.py')) - - for i in (1, 2, 3): - write( - sample, 'eggrecipedemo.py', - 'import eggrecipedemobeeded\n' - 'x=%s\n' - 'def main(): print x, eggrecipedemobeeded.y\n' - % i) - write( - sample, 'setup.py', - "from setuptools import setup\n" - "setup(name='demo', py_modules=['eggrecipedemo']," - " install_requires = 'demoneeded'," - " entry_points={'console_scripts': ['demo = eggrecipedemo:main']}," - " zip_safe=True, version='0.%s')\n" % i - ) - runsetup(sample, executable) - -def find_python(version): - e = os.environ.get('PYTHON%s' % version) - if e is not None: - return e - if sys.platform == 'win32': - e = '\Python%s%s\python.exe' % tuple(version.split('.')) - if os.path.exists(e): - return e - else: - i, o = os.popen4('python%s -c "import sys; print sys.executable"' - % version) - i.close() - e = o.read().strip() - o.close() - if os.path.exists(e): - return e - i, o = os.popen4( - 'python -c "import sys; print \'%s.%s\' % sys.version_info[:2]"' - ) - i.close() - e = o.read().strip() - o.close() - if e == version: - i, o = os.popen4('python -c "import sys; print sys.executable"') - i.close() - e = o.read().strip() - o.close() - if os.path.exists(e): - return e - - raise ValueError( - "Couldn't figure out the exectable for Python %(version)s.\n" - "Set the environment variable PYTHON%(version)s to the location\n" - "of the Python %(version)s executable before running the tests." - ) - -def multi_python(test): - p23 = find_python('2.3') - p24 = find_python('2.4') - create_sample_eggs(test, executable=p23) - create_sample_eggs(test, executable=p24) - test.globs['python2_3_executable'] = p23 - test.globs['python2_4_executable'] = p24 - - - -extdemo_c = """ -#include <Python.h> -#include <extdemo.h> - -static PyMethodDef methods[] = {{NULL}}; - -PyMODINIT_FUNC -initextdemo(void) -{ - PyObject *d; - d = Py_InitModule3("extdemo", methods, ""); - PyDict_SetItemString(d, "val", PyInt_FromLong(EXTDEMO)); -} -""" - -extdemo_setup_py = """ -from distutils.core import setup, Extension - -setup(name = "extdemo", version = "1.4", url="http://www.zope.org", - author="Demo", author_email="demo@demo.com", - ext_modules = [Extension('extdemo', ['extdemo.c'])], - ) -""" - -def add_source_dist(test): - import tarfile - tmp = tempfile.mkdtemp('test-sdist') - open(os.path.join(tmp, 'extdemo.c'), 'w').write(extdemo_c); - open(os.path.join(tmp, 'setup.py'), 'w').write(extdemo_setup_py); - open(os.path.join(tmp, 'README'), 'w').write(""); - open(os.path.join(tmp, 'MANIFEST.in'), 'w').write("include *.c\n"); - here = os.getcwd() - os.chdir(tmp) - status = os.spawnl(os.P_WAIT, sys.executable, sys.executable, - os.path.join(tmp, 'setup.py'), '-q', 'sdist') - os.chdir(here) - assert status == 0 - if sys.platform == 'win32': - sname = 'extdemo-1.4.zip' - else: - sname = 'extdemo-1.4.tar.gz' - - shutil.move( - os.path.join(tmp, 'dist', sname), - os.path.join(test.globs['sample_eggs'], sname), - ) - -def make_tree(test): - sample_eggs = test.globs['sample_eggs'] - tree = dict( - [(n, open(os.path.join(sample_eggs, n), 'rb').read()) - for n in os.listdir(sample_eggs) - ]) - tree['index'] = {} - return tree - -class Server(BaseHTTPServer.HTTPServer): - - def __init__(self, tree, *args): - BaseHTTPServer.HTTPServer.__init__(self, *args) - self.tree = tree - - __run = True - def serve_forever(self): - while self.__run: - self.handle_request() - - def handle_error(self, *_): - self.__run = False - -class Handler(BaseHTTPServer.BaseHTTPRequestHandler): - - def __init__(self, request, address, server): - self.tree = server.tree - BaseHTTPServer.BaseHTTPRequestHandler.__init__( - self, request, address, server) - - def do_GET(self): - if '__stop__' in self.path: - raise SystemExit - - tree = self.tree - for name in self.path.split('/'): - if not name: - continue - tree = tree.get(name) - if tree is None: - self.send_response(404, 'Not Found') - out = '<html><body>Not Found</body></html>' - self.send_header('Content-Length', str(len(out))) - self.send_header('Content-Type', 'text/html') - self.end_headers() - self.wfile.write(out) - return - - self.send_response(200) - if isinstance(tree, dict): - out = ['<html><body>\n'] - items = tree.items() - items.sort() - for name, v in items: - if isinstance(v, dict): - name += '/' - out.append('<a href="%s">%s</a><br>\n' % (name, name)) - out.append('</body></html>\n') - out = ''.join(out) - self.send_header('Content-Length', str(len(out))) - self.send_header('Content-Type', 'text/html') - else: - out = tree - self.send_header('Content-Length', len(out)) - if name.endswith('.egg'): - self.send_header('Content-Type', 'application/zip') - elif name.endswith('.gz'): - self.send_header('Content-Type', 'application/x-gzip') - elif name.endswith('.zip'): - self.send_header('Content-Type', 'application/x-gzip') - else: - self.send_header('Content-Type', 'text/html') - self.end_headers() - - self.wfile.write(out) - - def log_request(*s): - pass - -def _run(tree, port): - server_address = ('localhost', port) - httpd = Server(tree, server_address, Handler) - httpd.serve_forever() - -def get_port(): - for i in range(10): - port = random.randrange(20000, 30000) - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - try: - try: - s.connect(('localhost', port)) - except socket.error: - return port - finally: - s.close() - raise RuntimeError, "Can't find port" - -def _start_server(tree, name=''): - port = get_port() - thread = threading.Thread(target=_run, args=(tree, port), name=name) - thread.setDaemon(True) - thread.start() - wait(port, up=True) - return port, thread - -def start_server(tree): - return _start_server(tree)[0] - -def stop_server(url, thread=None): - try: - urllib2.urlopen(url+'__stop__') - except Exception: - pass - if thread is not None: - thread.join() # wait for thread to stop - -def setUpServer(test, tree): - port, thread = _start_server(tree, name=test.name) - link_server = 'http://localhost:%s/' % port - test.globs['link_server'] = link_server - test.globs['__tearDown__'].append(lambda: stop_server(link_server, thread)) - - -def wait(port, up): - addr = 'localhost', port - for i in range(120): - time.sleep(0.25) - try: - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.connect(addr) - s.close() - if up: - break - except socket.error, e: - if e[0] not in (errno.ECONNREFUSED, errno.ECONNRESET): - raise - s.close() - if not up: - break - else: - if up: - raise - else: - raise SystemError("Couln't stop server") diff --git a/zc.buildoutsupport/zc/buildoutsupport/tests.py b/zc.buildoutsupport/zc/buildoutsupport/tests.py deleted file mode 100644 index b873952..0000000 --- a/zc.buildoutsupport/zc/buildoutsupport/tests.py +++ /dev/null @@ -1,115 +0,0 @@ -############################################################################## -# -# Copyright (c) 2004 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""XXX short summary goes here. - -$Id$ -""" - -import os, re, shutil, sys, unittest -from zope.testing import doctest, renormalizing -import zc.buildout.testing - -os_path_sep = os.path.sep -if os_path_sep == '\\': - os_path_sep *= 2 - -def easy_install_SetUp(test): - zc.buildout.testing.buildoutSetUp(test) - zc.buildout.testing.multi_python(test) - zc.buildout.testing.add_source_dist(test) - zc.buildout.testing.setUpServer(test, zc.buildout.testing.make_tree(test)) - -class PythonNormalizing(renormalizing.RENormalizing): - - def _transform(self, want, got): - if '/xyzsample-install/' in want: - got = got.replace('-py2.4.egg', '-py2.3.egg') - firstg = got.split('\n')[0] - firstw = want.split('\n')[0] - if firstg.startswith('#!') and firstw.startswith('#!'): - firstg = ' '.join(firstg.split()[1:]) - got = firstg + '\n' + '\n'.join(got.split('\n')[1:]) - firstw = ' '.join(firstw.split()[1:]) - want = firstw + '\n' + '\n'.join(want.split('\n')[1:]) - - for pattern, repl in self.patterns: - want = pattern.sub(repl, want) - got = pattern.sub(repl, got) - - return want, got - - def check_output(self, want, got, optionflags): - if got == want: - return True - - want, got = self._transform(want, got) - if got == want: - return True - - return doctest.OutputChecker.check_output(self, want, got, optionflags) - - def output_difference(self, example, got, optionflags): - - want = example.want - - # If want is empty, use original outputter. This is useful - # when setting up tests for the first time. In that case, we - # generally use the differencer to display output, which we evaluate - # by hand. - if not want.strip(): - return doctest.OutputChecker.output_difference( - self, example, got, optionflags) - - # Dang, this isn't as easy to override as we might wish - original = want - want, got = self._transform(want, got) - - # temporarily hack example with normalized want: - example.want = want - result = doctest.OutputChecker.output_difference( - self, example, got, optionflags) - example.want = original - - return result - - -def test_suite(): - return unittest.TestSuite(( - doctest.DocFileSuite( - 'easy_install.txt', - setUp=easy_install_SetUp, - tearDown=zc.buildout.testing.buildoutTearDown, - - checker=PythonNormalizing([ - (re.compile("'" - "(\w:)?" - "[%(sep)s/]\S+sample-install[%(sep)s/]" - "[%(sep)s/]?(dist" - "[%(sep)s/])?" - % dict(sep=os_path_sep)), - '/sample-eggs/'), - (re.compile("([d-] ((ext)?demo(needed)?|other)" - "-\d[.]\d-py)\d[.]\d(-[^. \t\n]+)?[.]egg"), - '\\1V.V.egg'), - (re.compile('(\n?)- ([a-zA-Z_.-]+)-script.py\n- \\2.exe\n'), - '\\1- \\2\n'), - (re.compile('extdemo-1[.]4[.]tar[.]gz'), 'extdemo-1.4.zip'), - (re.compile('#!\S+python\S+'), '#!python'), - ]), - ), - )) - -if __name__ == '__main__': - unittest.main(defaultTest='test_suite') - -- 2.30.9