fix: restore environment before launching external programs (#707)

* rename promptless_Popen

* linux: restore env before calling popen

* windows: set dll directory to default before calling popen

* ruff formatting suggestions

* edited silent_popen docstring
This commit is contained in:
mashed5894
2025-01-24 23:56:35 +02:00
committed by GitHub
parent 0ead238aac
commit 2a41c152b3
5 changed files with 31 additions and 16 deletions

View File

@@ -11,6 +11,7 @@ from pathlib import Path
import structlog
from PySide6.QtCore import Qt
from PySide6.QtWidgets import QLabel
from src.qt.helpers.silent_popen import silent_Popen
logger = structlog.get_logger(__name__)
@@ -38,7 +39,7 @@ def open_file(path: str | Path, file_manager: bool = False):
# For some reason, if the args are passed in a list, this will error when the
# path has spaces, even while surrounded in double quotes.
subprocess.Popen(
silent_Popen(
command_name + command_arg,
shell=True,
close_fds=True,
@@ -47,7 +48,7 @@ def open_file(path: str | Path, file_manager: bool = False):
)
else:
command = f'"{normpath}"'
subprocess.Popen(
silent_Popen(
command,
shell=True,
close_fds=True,
@@ -79,7 +80,7 @@ def open_file(path: str | Path, file_manager: bool = False):
command_args = [str(path)]
command = shutil.which(command_name)
if command is not None:
subprocess.Popen([command] + command_args, close_fds=True)
silent_Popen([command] + command_args, close_fds=True)
else:
logger.info("Could not find command on system PATH", command=command_name)
except Exception:

View File

@@ -1,13 +1,15 @@
# Copyright (C) 2024 Travis Abendshien (CyanVoxel).
# Licensed under the GPL-3.0 License.
# Created for TagStudio: https://github.com/CyanVoxel/TagStudio
import os
import subprocess
import sys
"""Implementation of subprocess.Popen that does not spawn console windows or log output."""
"""Implementation of subprocess.Popen that does not spawn console windows or log output
and sanitizes pyinstall environment variables."""
def promptless_Popen( # noqa: N802
def silent_Popen( # noqa: N802
args,
bufsize=-1,
executable=None,
@@ -21,6 +23,7 @@ def promptless_Popen( # noqa: N802
env=None,
universal_newlines=None,
startupinfo=None,
creationflags=0,
restore_signals=True,
start_new_session=False,
pass_fds=(),
@@ -36,9 +39,20 @@ def promptless_Popen( # noqa: N802
process_group=None,
):
"""Call subprocess.Popen without creating a console window."""
creation_flags = 0
if sys.platform == "win32":
creation_flags = subprocess.CREATE_NO_WINDOW
creationflags |= subprocess.CREATE_NO_WINDOW
import ctypes
ctypes.windll.kernel32.SetDllDirectoryW(None)
elif (
sys.platform == "linux"
or sys.platform.startswith("freebsd")
or sys.platform.startswith("openbsd")
):
# pass clean environment to the subprocess
env = os.environ
original_env = env.get("LD_LIBRARY_PATH_ORIG")
env["LD_LIBRARY_PATH"] = original_env if original_env else ""
return subprocess.Popen(
args=args,
@@ -54,7 +68,7 @@ def promptless_Popen( # noqa: N802
env=env,
universal_newlines=universal_newlines,
startupinfo=startupinfo,
creationflags=creation_flags,
creationflags=creationflags,
restore_signals=restore_signals,
start_new_session=start_new_session,
pass_fds=pass_fds,

View File

@@ -9,7 +9,7 @@ import subprocess
import ffmpeg
import structlog
from src.qt.helpers.silent_popen import promptless_Popen
from src.qt.helpers.silent_popen import silent_Popen
logger = structlog.get_logger(__name__)
@@ -44,7 +44,7 @@ def _probe(filename, cmd=FFPROBE_CMD, timeout=None, **kwargs):
args += [filename]
# PATCHED
p = promptless_Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p = silent_Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
communicate_kwargs = {}
if timeout is not None:
communicate_kwargs["timeout"] = timeout

View File

@@ -40,7 +40,7 @@ from pydub.utils import (
get_encoder_name,
ratio_to_db,
)
from src.qt.helpers.silent_popen import promptless_Popen
from src.qt.helpers.silent_popen import silent_Popen
from src.qt.helpers.vendored.pydub.utils import _mediainfo_json
basestring = str
@@ -606,7 +606,7 @@ class _AudioSegment:
with open(os.devnull, "rb") as devnull:
# PATCHED
p = promptless_Popen(
p = silent_Popen(
conversion_command, stdin=devnull, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
p_out, p_err = p.communicate()
@@ -785,7 +785,7 @@ class _AudioSegment:
log_conversion(conversion_command)
# PATCHED
p = promptless_Popen(
p = silent_Popen(
conversion_command,
stdin=stdin_parameter,
stdout=subprocess.PIPE,
@@ -1012,7 +1012,7 @@ class _AudioSegment:
# read stdin / write stdout
with open(os.devnull, "rb") as devnull:
# PATCHED
p = promptless_Popen(
p = silent_Popen(
conversion_command, stdin=devnull, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
p_out, p_err = p.communicate()

View File

@@ -8,7 +8,7 @@ from pydub.utils import (
get_extra_info,
get_prober_name,
)
from src.qt.helpers.silent_popen import promptless_Popen
from src.qt.helpers.silent_popen import silent_Popen
def _mediainfo_json(filepath, read_ahead_limit=-1):
@@ -38,7 +38,7 @@ def _mediainfo_json(filepath, read_ahead_limit=-1):
command = [prober, "-of", "json"] + command_args
# PATCHED
res = promptless_Popen(
res = silent_Popen(
command, stdin=stdin_parameter, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
output, stderr = res.communicate(input=stdin_data)