Remove the custom pyinstaller support code needed for Salt < 3006.x

Signed-off-by: Pedro Algarvio <palgarvio@vmware.com>
This commit is contained in:
Pedro Algarvio 2023-11-19 19:43:35 +00:00 committed by Pedro Algarvio
parent 5463132e9d
commit 43e17e62ac
11 changed files with 0 additions and 545 deletions

View file

@ -1,21 +0,0 @@
"""
This module exists to help PyInstaller bundle Salt
"""
import pathlib
PYINSTALLER_UTILS_DIR_PATH = pathlib.Path(__file__).resolve().parent
def get_hook_dirs():
"""
Return a list of paths that PyInstaller can search for hooks.
"""
hook_dirs = {PYINSTALLER_UTILS_DIR_PATH}
for path in PYINSTALLER_UTILS_DIR_PATH.iterdir():
if not path.is_dir():
continue
if "__pycache__" in path.parts:
continue
hook_dirs.add(path)
return sorted(str(p) for p in hook_dirs)

View file

@ -1,146 +0,0 @@
# pylint: disable=3rd-party-module-not-gated
import logging
import pathlib
import sys
from PyInstaller.utils import hooks
log = logging.getLogger(__name__)
def _filter_stdlib_tests(name):
"""
Filter out non useful modules from the stdlib
"""
if ".test." in name:
return False
if ".tests." in name:
return False
if ".idle_test" in name:
return False
return True
def _python_stdlib_path():
"""
Return the path to the standard library folder
"""
base_exec_prefix = pathlib.Path(sys.base_exec_prefix)
log.info("Grabbing 'base_exec_prefix' for platform: %s", sys.platform)
if not sys.platform.lower().startswith("win"):
return base_exec_prefix / "lib" / "python{}.{}".format(*sys.version_info)
return base_exec_prefix / "Lib"
def _collect_python_stdlib_hidden_imports():
"""
Collect all of the standard library(most of it) as hidden imports.
"""
_hidden_imports = set()
stdlib = _python_stdlib_path()
if not stdlib.exists():
log.error("The path '%s' does not exist", stdlib)
return list(_hidden_imports)
log.info(
"Collecting hidden imports from the python standard library at: %s",
stdlib,
)
for path in stdlib.glob("*"):
if path.is_dir():
if path.name in (
"__pycache__",
"site-packages",
"test",
"turtledemo",
"ensurepip",
):
continue
if path.joinpath("__init__.py").is_file():
log.info("Collecting: %s", path.name)
try:
_module_hidden_imports = hooks.collect_submodules(
path.name, filter=_filter_stdlib_tests
)
log.debug("Collected(%s): %s", path.name, _module_hidden_imports)
_hidden_imports.update(set(_module_hidden_imports))
except Exception as exc: # pylint: disable=broad-except
log.error("Failed to collect %r: %s", path.name, exc)
continue
if path.suffix not in (".py", ".pyc", ".pyo"):
continue
_hidden_imports.add(path.stem)
log.info("Collected stdlib hidden imports: %s", sorted(_hidden_imports))
return sorted(_hidden_imports)
def _collect_python_stdlib_dynamic_libraries():
"""
Collect all of the standard library(most of it) dynamic libraries.
"""
_dynamic_libs = set()
stdlib = _python_stdlib_path()
if not stdlib.exists():
log.error("The path '%s' does not exist", stdlib)
return list(_dynamic_libs)
log.info(
"Collecting dynamic libraries from the python standard library at: %s",
stdlib,
)
for path in stdlib.glob("*"):
if not path.is_dir():
continue
if path.name in (
"__pycache__",
"site-packages",
"test",
"turtledemo",
"ensurepip",
):
continue
if path.joinpath("__init__.py").is_file():
log.info("Collecting: %s", path.name)
try:
_module_dynamic_libs = hooks.collect_dynamic_libs(path.name, path.name)
log.debug("Collected(%s): %s", path.name, _module_dynamic_libs)
_dynamic_libs.update(set(_module_dynamic_libs))
except Exception as exc: # pylint: disable=broad-except
log.error("Failed to collect %r: %s", path.name, exc)
log.info("Collected stdlib dynamic libs: %s", sorted(_dynamic_libs))
return sorted(_dynamic_libs)
def _filter_submodules(name):
# this should never happen, but serves as a place-holder for when/if we have to filter
if not name.startswith("salt"):
return False
return True
# Collect Salt datas, binaries(should be None) and hidden imports
SALT_DATAS, SALT_BINARIES, SALT_HIDDENIMPORTS = hooks.collect_all(
"salt",
include_py_files=True,
filter_submodules=_filter_submodules,
)
# In case there's salt-extensions installed, collect their datas and hidden imports
SALT_EXTENSIONS_DATAS, SALT_EXTENSIONS_HIDDENIMPORTS = hooks.collect_entry_point(
"salt.loader"
)
# PyInstaller attributes
datas = sorted(set(SALT_DATAS + SALT_EXTENSIONS_DATAS))
binaries = sorted(set(SALT_BINARIES))
hiddenimports = sorted(
set(
SALT_HIDDENIMPORTS
+ SALT_EXTENSIONS_HIDDENIMPORTS
+ _collect_python_stdlib_hidden_imports()
)
)

View file

@ -1,4 +0,0 @@
{
"subprocess": ["pyi_rth_subprocess.py"],
"salt.utils.vt": ["pyi_rth_salt.utils.vt.py"],
}

View file

@ -1,3 +0,0 @@
"""
This package contains support code to package Salt with PyInstaller.
"""

View file

@ -1,84 +0,0 @@
"""
This package contains the runtime hooks support code for when Salt is pacakged with PyInstaller.
"""
import io
import logging
import os
import subprocess
import sys
import salt.utils.vt
log = logging.getLogger(__name__)
def clean_pyinstaller_vars(environ):
"""
Restore or cleanup PyInstaller specific environent variable behavior.
"""
if environ is None:
environ = dict(os.environ)
# When Salt is bundled with tiamat, it MUST NOT contain LD_LIBRARY_PATH
# when shelling out, or, at least the value of LD_LIBRARY_PATH set by
# pyinstaller.
# See:
# https://pyinstaller.readthedocs.io/en/stable/runtime-information.html#ld-library-path-libpath-considerations
for varname in ("LD_LIBRARY_PATH", "LIBPATH"):
original_varname = "{}_ORIG".format(varname)
if varname in environ and environ[varname] == sys._MEIPASS:
# If we find the varname on the user provided environment we need to at least
# check if it's not the value set by PyInstaller, if it is, remove it.
log.debug(
"User provided environment variable %r with value %r which is "
"the value that PyInstaller set's. Removing it",
varname,
environ[varname],
)
environ.pop(varname)
if original_varname in environ and varname not in environ:
# We found the original variable set by PyInstaller, and we didn't find
# any user provided variable, let's rename it.
log.debug(
"The %r variable was found in the passed environment, renaming it to %r",
original_varname,
varname,
)
environ[varname] = environ.pop(original_varname)
if varname not in environ:
if original_varname in os.environ:
log.debug(
"Renaming environment variable %r to %r", original_varname, varname
)
environ[varname] = os.environ[original_varname]
elif varname in os.environ:
# Override the system environ variable with an empty one
log.debug("Setting environment variable %r to an empty string", varname)
environ[varname] = ""
return environ
class PyinstallerPopen(subprocess.Popen):
def __init__(self, *args, **kwargs):
kwargs["env"] = clean_pyinstaller_vars(kwargs.pop("env", None))
super().__init__(*args, **kwargs)
# From https://github.com/pyinstaller/pyinstaller/blob/v5.1/PyInstaller/hooks/rthooks/pyi_rth_subprocess.py
#
# In windowed mode, force any unused pipes (stdin, stdout and stderr) to be DEVNULL instead of inheriting the
# invalid corresponding handles from this parent process.
if sys.platform == "win32" and not isinstance(sys.stdout, io.IOBase):
def _get_handles(self, stdin, stdout, stderr):
stdin, stdout, stderr = (
subprocess.DEVNULL if pipe is None else pipe
for pipe in (stdin, stdout, stderr)
)
return super()._get_handles(stdin, stdout, stderr)
class PyinstallerTerminal(salt.utils.vt.Terminal): # pylint: disable=abstract-method
def __init__(self, *args, **kwargs):
kwargs["env"] = clean_pyinstaller_vars(kwargs.pop("env", None))
super().__init__(*args, **kwargs)

View file

@ -1,13 +0,0 @@
"""
PyInstaller runtime hook to patch salt.utils.vt.Terminal
"""
import logging
import salt.utils.vt
from salt.utils.pyinstaller.rthooks._overrides import PyinstallerTerminal
log = logging.getLogger(__name__)
# Patch salt.utils.vt.Terminal when running within a pyinstalled bundled package
salt.utils.vt.Terminal = PyinstallerTerminal
log.debug("Replaced 'salt.utils.vt.Terminal' with 'PyinstallerTerminal'")

View file

@ -1,13 +0,0 @@
"""
PyInstaller runtime hook to patch subprocess.Popen
"""
import logging
import subprocess
from salt.utils.pyinstaller.rthooks._overrides import PyinstallerPopen
log = logging.getLogger(__name__)
# Patch subprocess.Popen when running within a pyinstalled bundled package
subprocess.Popen = PyinstallerPopen
log.debug("Replaced 'subprocess.Popen' with 'PyinstallerTerminal'")

View file

@ -1,146 +0,0 @@
import json
import os
import sys
import pytest
import salt.utils.pyinstaller.rthooks._overrides as overrides
from tests.support import mock
from tests.support.helpers import PatchedEnviron
pytestmark = [
pytest.mark.skip(reason="PyInstaller is no longer used."),
]
@pytest.fixture(params=("LD_LIBRARY_PATH", "LIBPATH"))
def envvar(request):
return request.param
@pytest.fixture
def meipass(envvar):
with mock.patch("salt.utils.pyinstaller.rthooks._overrides.sys") as patched_sys:
patched_sys._MEIPASS = "{}_VALUE".format(envvar)
assert overrides.sys._MEIPASS == "{}_VALUE".format(envvar)
yield "{}_VALUE".format(envvar)
assert not hasattr(sys, "_MEIPASS")
assert not hasattr(overrides.sys, "_MEIPASS")
def test_vt_terminal_environ_cleanup_original(envvar, meipass):
orig_envvar = "{}_ORIG".format(envvar)
with PatchedEnviron(**{orig_envvar: meipass}):
original_env = dict(os.environ)
assert orig_envvar in original_env
instance = overrides.PyinstallerTerminal(
[
sys.executable,
"-c",
"import os, json; print(json.dumps(dict(os.environ)))",
],
stream_stdout=False,
stream_stderr=False,
)
buffer_o = buffer_e = ""
while instance.has_unread_data:
stdout, stderr = instance.recv()
if stdout:
buffer_o += stdout
if stderr:
buffer_e += stderr
instance.terminate()
assert instance.exitstatus == 0
returned_env = json.loads(buffer_o)
assert returned_env != original_env
assert envvar in returned_env
assert orig_envvar not in returned_env
assert returned_env[envvar] == meipass
def test_vt_terminal_environ_cleanup_original_passed_directly(envvar, meipass):
orig_envvar = "{}_ORIG".format(envvar)
env = {
orig_envvar: meipass,
}
original_env = dict(os.environ)
instance = overrides.PyinstallerTerminal(
[sys.executable, "-c", "import os, json; print(json.dumps(dict(os.environ)))"],
env=env.copy(),
stream_stdout=False,
stream_stderr=False,
)
buffer_o = buffer_e = ""
while instance.has_unread_data:
stdout, stderr = instance.recv()
if stdout:
buffer_o += stdout
if stderr:
buffer_e += stderr
instance.terminate()
assert instance.exitstatus == 0
returned_env = json.loads(buffer_o)
assert returned_env != original_env
assert envvar in returned_env
assert orig_envvar not in returned_env
assert returned_env[envvar] == meipass
def test_vt_terminal_environ_cleanup(envvar, meipass):
with PatchedEnviron(**{envvar: meipass}):
original_env = dict(os.environ)
assert envvar in original_env
instance = overrides.PyinstallerTerminal(
[
sys.executable,
"-c",
"import os, json; print(json.dumps(dict(os.environ)))",
],
stream_stdout=False,
stream_stderr=False,
)
buffer_o = buffer_e = ""
while instance.has_unread_data:
stdout, stderr = instance.recv()
if stdout:
buffer_o += stdout
if stderr:
buffer_e += stderr
instance.terminate()
assert instance.exitstatus == 0
returned_env = json.loads(buffer_o)
assert returned_env != original_env
assert envvar in returned_env
assert returned_env[envvar] == ""
def test_vt_terminal_environ_cleanup_passed_directly_not_removed(envvar, meipass):
env = {
envvar: envvar,
}
original_env = dict(os.environ)
instance = overrides.PyinstallerTerminal(
[sys.executable, "-c", "import os, json; print(json.dumps(dict(os.environ)))"],
env=env.copy(),
stream_stdout=False,
stream_stderr=False,
)
buffer_o = buffer_e = ""
while instance.has_unread_data:
stdout, stderr = instance.recv()
if stdout:
buffer_o += stdout
if stderr:
buffer_e += stderr
instance.terminate()
assert instance.exitstatus == 0
returned_env = json.loads(buffer_o)
assert returned_env != original_env
assert envvar in returned_env
assert returned_env[envvar] == envvar

View file

@ -1,115 +0,0 @@
import json
import os
import subprocess
import sys
import pytest
import salt.utils.pyinstaller.rthooks._overrides as overrides
from tests.support import mock
from tests.support.helpers import PatchedEnviron
pytestmark = [
pytest.mark.skip(reason="PyInstaller is no longer used."),
]
@pytest.fixture(params=("LD_LIBRARY_PATH", "LIBPATH"))
def envvar(request):
return request.param
@pytest.fixture
def meipass(envvar):
with mock.patch("salt.utils.pyinstaller.rthooks._overrides.sys") as patched_sys:
patched_sys._MEIPASS = "{}_VALUE".format(envvar)
assert overrides.sys._MEIPASS == "{}_VALUE".format(envvar)
yield "{}_VALUE".format(envvar)
assert not hasattr(sys, "_MEIPASS")
assert not hasattr(overrides.sys, "_MEIPASS")
def test_subprocess_popen_environ_cleanup_original(envvar, meipass):
orig_envvar = "{}_ORIG".format(envvar)
with PatchedEnviron(**{orig_envvar: meipass}):
original_env = dict(os.environ)
assert orig_envvar in original_env
instance = overrides.PyinstallerPopen(
[
sys.executable,
"-c",
"import os, json; print(json.dumps(dict(os.environ)))",
],
stdout=subprocess.PIPE,
universal_newlines=True,
)
stdout, _ = instance.communicate()
assert instance.returncode == 0
returned_env = json.loads(stdout)
assert returned_env != original_env
assert envvar in returned_env
assert orig_envvar not in returned_env
assert returned_env[envvar] == meipass
def test_subprocess_popen_environ_cleanup_original_passed_directly(envvar, meipass):
orig_envvar = "{}_ORIG".format(envvar)
env = {
orig_envvar: meipass,
}
original_env = dict(os.environ)
instance = overrides.PyinstallerPopen(
[sys.executable, "-c", "import os, json; print(json.dumps(dict(os.environ)))"],
env=env.copy(),
stdout=subprocess.PIPE,
universal_newlines=True,
)
stdout, _ = instance.communicate()
assert instance.returncode == 0
returned_env = json.loads(stdout)
assert returned_env != original_env
assert envvar in returned_env
assert orig_envvar not in returned_env
assert returned_env[envvar] == meipass
def test_subprocess_popen_environ_cleanup(envvar, meipass):
with PatchedEnviron(**{envvar: meipass}):
original_env = dict(os.environ)
assert envvar in original_env
instance = overrides.PyinstallerPopen(
[
sys.executable,
"-c",
"import os, json; print(json.dumps(dict(os.environ)))",
],
stdout=subprocess.PIPE,
universal_newlines=True,
)
stdout, _ = instance.communicate()
assert instance.returncode == 0
returned_env = json.loads(stdout)
assert returned_env != original_env
assert envvar in returned_env
assert returned_env[envvar] == ""
def test_subprocess_popen_environ_cleanup_passed_directly_not_removed(envvar, meipass):
env = {
envvar: envvar,
}
original_env = dict(os.environ)
instance = overrides.PyinstallerPopen(
[sys.executable, "-c", "import os, json; print(json.dumps(dict(os.environ)))"],
env=env.copy(),
stdout=subprocess.PIPE,
universal_newlines=True,
)
stdout, _ = instance.communicate()
assert instance.returncode == 0
returned_env = json.loads(stdout)
assert returned_env != original_env
assert envvar in returned_env
assert returned_env[envvar] == envvar