Commit 6547430b authored by Jason R. Coombs's avatar Jason R. Coombs Committed by GitHub

Merge pull request #616 from fkrull/issue398

Fix "failed to create process" issue on Windows
parents 0269eaa5 31328335
......@@ -1986,9 +1986,18 @@ class CommandSpec(list):
def as_header(self):
return self._render(self + list(self.options))
@staticmethod
def _strip_quotes(item):
_QUOTES = '"\''
for q in _QUOTES:
if item.startswith(q) and item.endswith(q):
return item[1:-1]
return item
@staticmethod
def _render(items):
cmdline = subprocess.list2cmdline(items)
cmdline = subprocess.list2cmdline(
CommandSpec._strip_quotes(item.strip()) for item in items)
return '#!' + cmdline + '\n'
......
from distutils import log
import distutils.command.install_scripts as orig
import os
import sys
from pkg_resources import Distribution, PathMetadata, ensure_directory
......@@ -37,6 +38,10 @@ class install_scripts(orig.install_scripts):
if is_wininst:
exec_param = "python.exe"
writer = ei.WindowsScriptWriter
if exec_param == sys.executable:
# In case the path to the Python executable contains a space, wrap
# it so it's not split up.
exec_param = [exec_param]
# resolve the writer to the environment
writer = writer.best()
cmd = writer.command_spec_class.best().from_param(exec_param)
......
......@@ -30,7 +30,7 @@ import setuptools.command.easy_install as ei
from setuptools.command.easy_install import PthDistributions
from setuptools.command import easy_install as easy_install_pkg
from setuptools.dist import Distribution
from pkg_resources import working_set
from pkg_resources import normalize_path, working_set
from pkg_resources import Distribution as PRDistribution
import setuptools.tests.server
import pkg_resources
......@@ -126,9 +126,10 @@ class TestEasyInstallTest:
get_site_dirs should always return site dirs reported by
site.getsitepackages.
"""
mock_gsp = lambda: ['/setuptools/test/site-packages']
path = normalize_path('/setuptools/test/site-packages')
mock_gsp = lambda: [path]
monkeypatch.setattr(site, 'getsitepackages', mock_gsp, raising=False)
assert '/setuptools/test/site-packages' in ei.get_site_dirs()
assert path in ei.get_site_dirs()
def test_all_site_dirs_works_without_getsitepackages(self, monkeypatch):
monkeypatch.delattr(site, 'getsitepackages', raising=False)
......@@ -532,29 +533,32 @@ def make_trivial_sdist(dist_path, setup_py):
dist.addfile(setup_py_file, fileobj=setup_py_bytes)
@pytest.mark.skipif(
sys.platform.startswith('java') and ei.is_sh(sys.executable),
reason="Test cannot run under java when executable is sh"
)
class TestScriptHeader:
non_ascii_exe = '/Users/José/bin/python'
exe_with_spaces = r'C:\Program Files\Python33\python.exe'
@pytest.mark.skipif(
sys.platform.startswith('java') and ei.is_sh(sys.executable),
reason="Test cannot run under java when executable is sh"
)
def test_get_script_header(self):
expected = '#!%s\n' % ei.nt_quote_arg(os.path.normpath(sys.executable))
actual = ei.ScriptWriter.get_script_header('#!/usr/local/bin/python')
assert actual == expected
def test_get_script_header_args(self):
expected = '#!%s -x\n' % ei.nt_quote_arg(os.path.normpath
(sys.executable))
actual = ei.ScriptWriter.get_script_header('#!/usr/bin/python -x')
assert actual == expected
def test_get_script_header_non_ascii_exe(self):
actual = ei.ScriptWriter.get_script_header('#!/usr/bin/python',
executable=self.non_ascii_exe)
expected = '#!%s -x\n' % self.non_ascii_exe
assert actual == expected
def test_get_script_header_exe_with_spaces(self):
actual = ei.ScriptWriter.get_script_header('#!/usr/bin/python',
executable='"' + self.exe_with_spaces + '"')
expected = '#!"%s"\n' % self.exe_with_spaces
......@@ -596,15 +600,6 @@ class TestCommandSpec:
assert len(cmd) == 2
assert '"' not in cmd.as_header()
def test_sys_executable(self):
"""
CommandSpec.from_string(sys.executable) should contain just that param.
"""
writer = ei.ScriptWriter.best()
cmd = writer.command_spec_class.from_string(sys.executable)
assert len(cmd) == 1
assert cmd[0] == sys.executable
class TestWindowsScriptWriter:
......
"""install_scripts tests
"""
import io
import sys
import pytest
from setuptools.command.install_scripts import install_scripts
from setuptools.dist import Distribution
from . import contexts
class TestInstallScripts:
settings = dict(
name='foo',
entry_points={'console_scripts': ['foo=foo:foo']},
version='0.0',
)
unix_exe = '/usr/dummy-test-path/local/bin/python'
unix_spaces_exe = '/usr/bin/env dummy-test-python'
win32_exe = 'C:\\Dummy Test Path\\Program Files\\Python 3.3\\python.exe'
def _run_install_scripts(self, install_dir, executable=None):
dist = Distribution(self.settings)
dist.script_name = 'setup.py'
cmd = install_scripts(dist)
cmd.install_dir = install_dir
if executable is not None:
bs = cmd.get_finalized_command('build_scripts')
bs.executable = executable
cmd.ensure_finalized()
with contexts.quiet():
cmd.run()
@pytest.mark.skipif(sys.platform == 'win32', reason='non-Windows only')
def test_sys_executable_escaping_unix(self, tmpdir, monkeypatch):
"""
Ensure that shebang is not quoted on Unix when getting the Python exe
from sys.executable.
"""
expected = '#!%s\n' % self.unix_exe
monkeypatch.setattr('sys.executable', self.unix_exe)
with tmpdir.as_cwd():
self._run_install_scripts(str(tmpdir))
with io.open(str(tmpdir.join('foo')), 'r') as f:
actual = f.readline()
assert actual == expected
@pytest.mark.skipif(sys.platform != 'win32', reason='Windows only')
def test_sys_executable_escaping_win32(self, tmpdir, monkeypatch):
"""
Ensure that shebang is quoted on Windows when getting the Python exe
from sys.executable and it contains a space.
"""
expected = '#!"%s"\n' % self.win32_exe
monkeypatch.setattr('sys.executable', self.win32_exe)
with tmpdir.as_cwd():
self._run_install_scripts(str(tmpdir))
with io.open(str(tmpdir.join('foo-script.py')), 'r') as f:
actual = f.readline()
assert actual == expected
@pytest.mark.skipif(sys.platform == 'win32', reason='non-Windows only')
def test_executable_with_spaces_escaping_unix(self, tmpdir):
"""
Ensure that shebang on Unix is not quoted, even when a value with spaces
is specified using --executable.
"""
expected = '#!%s\n' % self.unix_spaces_exe
with tmpdir.as_cwd():
self._run_install_scripts(str(tmpdir), self.unix_spaces_exe)
with io.open(str(tmpdir.join('foo')), 'r') as f:
actual = f.readline()
assert actual == expected
@pytest.mark.skipif(sys.platform != 'win32', reason='Windows only')
def test_executable_arg_escaping_win32(self, tmpdir):
"""
Ensure that shebang on Windows is quoted when getting a path with spaces
from --executable, that is itself properly quoted.
"""
expected = '#!"%s"\n' % self.win32_exe
with tmpdir.as_cwd():
self._run_install_scripts(str(tmpdir), '"' + self.win32_exe + '"')
with io.open(str(tmpdir.join('foo-script.py')), 'r') as f:
actual = f.readline()
assert actual == expected
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment