Skip to content

Commit

Permalink
Always copy executable on Windows 3+ (#1977)
Browse files Browse the repository at this point in the history
  • Loading branch information
gaborbernat authored Oct 12, 2020
1 parent ced984a commit 43a5e03
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 30 deletions.
19 changes: 10 additions & 9 deletions src/virtualenv/create/via_global_ref/builtin/cpython/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,19 @@ def _executables(cls, interpreter):
class CPythonWindows(CPython, WindowsSupports):
@classmethod
def _executables(cls, interpreter):
executables = cls._win_executables(Path(interpreter.system_executable), interpreter, RefWhen.ANY)
for src, targets, must, when in executables:
yield src, targets, must, when

@classmethod
def _win_executables(cls, host, interpreter, when):
must = RefMust.COPY if interpreter.version_info.major == 2 else RefMust.NA
# symlink of the python executables does not work reliably, copy always instead
# - https://bugs.python.org/issue42013
# - venv
host = cls.host_python(interpreter)
for path in (host.parent / n for n in {"python.exe", host.name}):
yield host, [path.name], must, when
yield host, [path.name], RefMust.COPY, RefWhen.ANY
# for more info on pythonw.exe see https://stackoverflow.com/a/30313091
python_w = host.parent / "pythonw.exe"
yield python_w, [python_w.name], must, when
yield python_w, [python_w.name], RefMust.COPY, RefWhen.ANY

@classmethod
def host_python(cls, interpreter):
return Path(interpreter.system_executable)


def is_mac_os_framework(interpreter):
Expand Down
29 changes: 10 additions & 19 deletions src/virtualenv/create/via_global_ref/builtin/cpython/cpython3.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
from __future__ import absolute_import, unicode_literals

import abc
from itertools import chain
from textwrap import dedent

from six import add_metaclass

from virtualenv.create.describe import Python3Supports
from virtualenv.create.via_global_ref.builtin.ref import PathRefToDest, RefMust, RefWhen
from virtualenv.create.via_global_ref.builtin.ref import PathRefToDest
from virtualenv.create.via_global_ref.store import is_store_python
from virtualenv.util.path import Path

Expand Down Expand Up @@ -56,29 +55,21 @@ def setup_meta(cls, interpreter):
def sources(cls, interpreter):
for src in super(CPython3Windows, cls).sources(interpreter):
yield src
if cls.venv_37p(interpreter):
for dll in (i for i in Path(interpreter.system_executable).parent.iterdir() if i.suffix == ".dll"):
yield PathRefToDest(dll, cls.to_bin, RefMust.SYMLINK, RefWhen.SYMLINK)
else:
if not cls.venv_37p(interpreter):
for src in cls.include_dll_and_pyd(interpreter):
yield src

@staticmethod
def venv_37p(interpreter):
return interpreter.version_info.minor >= 7

@classmethod
def _executables(cls, interpreter):
system_exe = Path(interpreter.system_executable)
def host_python(cls, interpreter):
if cls.venv_37p(interpreter):
# starting with CPython 3.7 Windows ships with a venvlauncher.exe that avoids the need for dll/pyd copies
launcher = Path(interpreter.system_stdlib) / "venv" / "scripts" / "nt" / "python.exe"
executables = cls._win_executables(launcher, interpreter, RefWhen.COPY)
executables = chain(executables, cls._win_executables(system_exe, interpreter, RefWhen.SYMLINK))
else:
executables = cls._win_executables(system_exe, interpreter, RefWhen.ANY)
for src, targets, must, when in executables:
yield src, targets, must, when

@staticmethod
def venv_37p(interpreter):
return interpreter.version_info.minor > 6
# it also means the wrapper must be copied to avoid bugs such as https://bugs.python.org/issue42013
return Path(interpreter.system_stdlib) / "venv" / "scripts" / "nt" / "python.exe"
return super(CPython3Windows, cls).host_python(interpreter)

@classmethod
def include_dll_and_pyd(cls, interpreter):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from six import add_metaclass

from virtualenv.create.via_global_ref.builtin.ref import ExePathRefToDest, RefMust
from virtualenv.create.via_global_ref.builtin.ref import ExePathRefToDest, RefMust, RefWhen
from virtualenv.util.path import ensure_dir

from ..api import ViaGlobalRefApi, ViaGlobalRefMeta
Expand Down Expand Up @@ -89,7 +89,12 @@ def create(self):
try:
self.enable_system_site_package = False
for src in self._sources:
src.run(self, self.symlinks)
if (
src.when == RefWhen.ANY
or (src.when == RefWhen.SYMLINK and self.symlinks is True)
or (src.when == RefWhen.COPY and self.symlinks is False)
):
src.run(self, self.symlinks)
finally:
if true_system_site != self.enable_system_site_package:
self.enable_system_site_package = true_system_site
Expand Down

0 comments on commit 43a5e03

Please sign in to comment.