Always copy executable on Windows 3+ (#1977)

This commit is contained in:
Bernát Gábor 2020-10-12 12:53:13 +01:00 committed by GitHub
parent ced984abfd
commit 43a5e0383b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 28 additions and 31 deletions

View file

@ -42,18 +42,19 @@ class CPythonPosix(CPython, PosixSupports):
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):

View file

@ -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
@ -56,29 +55,21 @@ class CPython3Windows(CPythonWindows, CPython3):
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
@classmethod
def _executables(cls, interpreter):
system_exe = Path(interpreter.system_executable)
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
return interpreter.version_info.minor >= 7
@classmethod
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
# 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):

View file

@ -4,7 +4,7 @@ from abc import ABCMeta
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
@ -89,7 +89,12 @@ class ViaGlobalRefVirtualenvBuiltin(ViaGlobalRefApi, VirtualenvBuiltin):
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