Index: src/zc/buildout/easy_install.py =================================================================== --- src/zc/buildout/easy_install.py (revision 98281) +++ src/zc/buildout/easy_install.py (working copy) @@ -38,6 +38,8 @@ import zc.buildout import zipimport +from zc.buildout.jython_compat import * + _oprp = getattr(os.path, 'realpath', lambda path: path) def realpath(path): return os.path.normcase(os.path.abspath(_oprp(path))) @@ -52,14 +54,7 @@ url_match = re.compile('[a-z0-9+.-]+://').match is_win32 = sys.platform == 'win32' -is_jython = sys.platform.startswith('java') -if is_jython: - import subprocess - import java.lang.System - jython_os_name = (java.lang.System.getProperties()['os.name']).lower() - - setuptools_loc = pkg_resources.working_set.find( pkg_resources.Requirement.parse('setuptools') ).location @@ -80,23 +75,40 @@ try: return _versions[executable] except KeyError: - cmd = _safe_arg(executable) + ' -V' - p = subprocess.Popen(cmd, - shell=True, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - close_fds=not is_win32) - i, o = (p.stdin, p.stdout) - i.close() - version = o.read().strip() - o.close() - pystring, version = version.split() - assert pystring == 'Python' - version = re.match('(\d[.]\d)([.].*\d)?$', version).group(1) + version_string = _get_executable_version(executable) + version = _parse_python_version(version_string) _versions[executable] = version return version +def _get_executable_version(executable_path): + """ + Given a Python executable, retrieve the version string (as returned by -V) + """ + args = (executable_path, '-V') + proc = subprocess.Popen(args, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, # redirect stderr to stdout + ) + version_string = proc.stdout.read() + assert proc.wait() == 0, "Error getting version string for executable %s" % executable_path + return version_string + +def _parse_python_version(version_string): + """ + >>> _parse_python_version('Python 2.4.4') + '2.4' + + I'm not sure the following use case is correct + >>> _parse_python_version('Python 2.4.a4') + '2.4' + """ + version = stream.read().strip() + pystring, version = version.split() + assert pystring in ('Python',), "This method only supports CPython" + pattern = re.compile('(\d[.]\d)([.].*\d)?$') + result = re.match(version).group(1) + return result + FILE_SCHEME = re.compile('file://', re.I).match class AllowHostsPackageIndex(setuptools.package_index.PackageIndex): @@ -131,17 +143,11 @@ clear_index_cache = _indexes.clear -if is_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 +def _safe_arg(arg): + return subprocess.list2cmdline([arg]) -_easy_install_cmd = _safe_arg( +_easy_install_cmd = \ 'from setuptools.command.easy_install import main; main()' - ) class Installer: @@ -305,7 +311,7 @@ ws, False, )[0].location - args = ('-c', _easy_install_cmd, '-mUNxd', _safe_arg(tmp)) + args = ('-c', _easy_install_cmd, '-mUNxd', tmp) if self._always_unzip: args += ('-Z', ) level = logger.getEffectiveLevel() @@ -314,27 +320,18 @@ elif level < 0: args += ('-v', ) - args += (_safe_arg(spec), ) + args += (spec, ) if level <= logging.DEBUG: logger.debug('Running easy_install:\n%s "%s"\npath=%s\n', self._executable, '" "'.join(args), path) - if is_jython: - extra_env = dict(os.environ, PYTHONPATH=path) - else: - args += (dict(os.environ, PYTHONPATH=path), ) + extra_env = dict(os.environ, PYTHONPATH=path) sys.stdout.flush() # We want any pending output first - if is_jython: - exit_code = subprocess.Popen( - [_safe_arg(self._executable)] + list(args), - env=extra_env).wait() - else: - exit_code = os.spawnle( - os.P_WAIT, self._executable, _safe_arg (self._executable), - *args) + args = (self._executable, ) + args + exit_code = subprocess.Popen(args, env=extra_env).wait() dists = [] env = pkg_resources.Environment( @@ -876,9 +873,9 @@ undo.append(lambda : shutil.rmtree(tmp3)) args = [ - zc.buildout.easy_install._safe_arg(tsetup), + tsetup, '-q', 'develop', '-mxN', - '-d', _safe_arg(tmp3), + '-d', tmp3, ] log_level = logger.getEffectiveLevel() @@ -890,11 +887,9 @@ if log_level < logging.DEBUG: logger.debug("in: %r\n%s", directory, ' '.join(args)) - if is_jython: - assert subprocess.Popen([_safe_arg(executable)] + args).wait() == 0 - else: - assert os.spawnl(os.P_WAIT, executable, _safe_arg(executable), - *args) == 0 + args = [executable] + args + proc_result = subprocess.Popen(args).wait() + assert proc_result == 0, "error (%d) executing %s" % (proc_result, args) return _copyeggs(tmp3, dest, '.egg-link', undo) @@ -1033,7 +1028,7 @@ dest += '-script.py' contents = script_template % dict( - python = _safe_arg(executable), + python = subprocess.list2cmdline([executable]), path = path, module_name = module_name, attrs = attrs, @@ -1064,12 +1059,10 @@ generated.append(dest) return generated -if is_jython and jython_os_name == 'linux': - script_header = '#!/usr/bin/env %(python)s' -else: - script_header = '#!%(python)s' +# script_header may be defined by +# platform-specific modules +globals().setdefault('script_header', '#!%(python)s') - script_template = script_header + '''\ %(relative_paths_setup)s @@ -1092,7 +1085,7 @@ dest += '-script.py' contents = py_script_template % dict( - python = _safe_arg(executable), + python = subprocess.list2cmdline([executable]), path = path, relative_paths_setup = rsetup, ) @@ -1236,13 +1229,9 @@ logger.warning("Couldn't compile %s", filepath) else: # Recompile under other optimization. :) - args = [_safe_arg(sys.executable)] + args = [sys.executable] if __debug__: args.append('-O') args.extend(['-m', 'py_compile', _safe_arg(filepath)]) - if is_jython: - subprocess.call([sys.executable, args]) - else: - os.spawnv(os.P_WAIT, sys.executable, args) - + subprocess.call(args) \ No newline at end of file Index: src/zc/buildout/jython_compat.py =================================================================== --- src/zc/buildout/jython_compat.py (revision 0) +++ src/zc/buildout/jython_compat.py (revision 0) @@ -0,0 +1,45 @@ +#!python + +############################################################################# +# +# Copyright (c) 2009 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. +# +############################################################################## + +""" +Jython support functions for zc.buildout + +$Id$ +""" + +import sys + +def check_jython_version(): + """ + check the Jython version (2.5 or later is required because + of reliance on subprocess. + """ + assert sys.version >= '2.5', "Jython 2.5 or later is required" + +def load_os_name(): + global jython_os_name + import java.lang.System # should always be present in Jython + jython_os_name = (java.lang.System.getProperties()['os.name']).lower() + + +is_jython = sys.platform.startswith('java') + +if is_jython: + check_jython_version() + load_os_name() + +if is_jython and jython_os_name == 'linux': + script_header = '#!/usr/bin/env %(python)s' Property changes on: src\zc\buildout\jython_compat.py ___________________________________________________________________ Added: svn:keywords + Id Rev Author Date