mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-18 02:00:09 +08:00
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:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user