fix: handle pip install execution in frozen runtime (#4985)

* fix: handle pip install execution in frozen runtime

* fix: harden pip subprocess fallback handling
This commit is contained in:
エイカク
2026-02-09 16:19:01 +09:00
committed by GitHub
parent 06b2c7cb16
commit 2afb08d8b2

View File

@@ -5,7 +5,9 @@ import io
import locale
import logging
import os
import shutil
import sys
from pathlib import Path
from astrbot.core.utils.astrbot_path import get_astrbot_site_packages_path
@@ -34,6 +36,28 @@ def _is_frozen_runtime() -> bool:
return bool(getattr(sys, "frozen", False))
def _get_pip_subprocess_executable() -> str | None:
candidates = [
getattr(sys, "_base_executable", None),
sys.executable,
shutil.which("python3"),
shutil.which("python"),
]
for candidate in candidates:
if not candidate:
continue
candidate_path = Path(candidate)
with contextlib.suppress(OSError):
candidate_path = candidate_path.resolve()
if candidate_path.is_file() and os.access(candidate_path, os.X_OK):
return str(candidate_path)
return None
def _get_pip_main():
try:
from pip._internal.cli.main import main as pip_main
@@ -92,13 +116,26 @@ class PipInstaller:
logger.info(f"Pip 包管理器: pip {' '.join(args)}")
result_code = None
if _is_frozen_runtime():
result_code = await self._run_pip_in_process(args)
else:
subprocess_executable = _get_pip_subprocess_executable()
if subprocess_executable:
try:
result_code = await self._run_pip_subprocess(args)
except FileNotFoundError:
result_code = await self._run_pip_in_process(args)
result_code = await self._run_pip_subprocess(
subprocess_executable, args
)
except OSError as exc:
logger.warning(
"Failed to launch pip subprocess (%r). Falling back to in-process pip: %s",
subprocess_executable,
exc,
)
else:
logger.debug(
"No suitable Python executable found for pip subprocess; using in-process pip"
)
if result_code is None:
result_code = await self._run_pip_in_process(args)
if result_code != 0:
raise Exception(f"安装失败,错误码:{result_code}")
@@ -107,9 +144,9 @@ class PipInstaller:
sys.path.insert(0, target_site_packages)
importlib.invalidate_caches()
async def _run_pip_subprocess(self, args: list[str]) -> int:
async def _run_pip_subprocess(self, executable: str, args: list[str]) -> int:
process = await asyncio.create_subprocess_exec(
sys.executable,
executable,
"-m",
"pip",
*args,