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,43 @@
+#!python
+
+#############################################################################
+#
+# 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.
+#
+##############################################################################
+
+"""
+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()
+

Property changes on: src\zc\buildout\jython_compat.py
___________________________________________________________________
Added: svn:keywords
   + Id Rev Author Date

Index: src/zc/buildout/easy_install.py
===================================================================
--- src/zc/buildout/easy_install.py	(revision 92054)
+++ src/zc/buildout/easy_install.py	(working copy)
@@ -31,12 +31,15 @@
 import setuptools.command.setopt
 import setuptools.package_index
 import shutil
+import subprocess
 import sys
 import tempfile
 import urlparse
 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)))
@@ -50,14 +53,7 @@
 
 url_match = re.compile('[a-z0-9+.-]+://').match
 
-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
@@ -78,16 +74,40 @@
     try:
         return _versions[executable]
     except KeyError:
-        i, o = os.popen4(_safe_arg(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)
+        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):
@@ -122,17 +142,11 @@
 
 clear_index_cache = _indexes.clear
 
-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
+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:
 
@@ -296,7 +310,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()
@@ -305,28 +319,19 @@
             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(
                 [tmp],
@@ -867,9 +872,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()
@@ -881,10 +886,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)
 
@@ -958,7 +962,7 @@
         dest += '-script.py'
 
     contents = script_template % dict(
-        python = _safe_arg(executable),
+        python = subprocess.list2cmdline([executable]),
         path = path,
         module_name = module_name,
         attrs = attrs,
@@ -1015,7 +1019,7 @@
         dest += '-script.py'
 
     contents = py_script_template % dict(
-        python = _safe_arg(executable),
+        python = subprocess.list2cmdline([executable]),
         path = path,
         )
     changed = not (os.path.exists(dest) and open(dest).read() == contents)
@@ -1163,8 +1167,4 @@
                     args.append('-O')
                 args.extend(['-m', 'py_compile', filepath])
                 
-                if is_jython:
-                    subprocess.call([sys.executable, args])
-                else:
-                    os.spawnv(os.P_WAIT, sys.executable, args)
-                    
+                subprocess.call(args)
