75 lines
2.1 KiB
Python
75 lines
2.1 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
|
|
def is_frozen() -> bool:
|
|
return getattr(sys, "frozen", False)
|
|
|
|
|
|
def _find_app_bundle_root(exe_path: Path) -> Optional[Path]:
|
|
for parent in exe_path.parents:
|
|
if parent.suffix.lower() == ".app":
|
|
return parent
|
|
return None
|
|
|
|
|
|
def _pick_runtime_root(exe_path: Path) -> Path:
|
|
candidates: list[Path] = []
|
|
app_root = _find_app_bundle_root(exe_path)
|
|
if app_root is not None:
|
|
candidates.append(app_root.parent)
|
|
candidates.append(exe_path.parent)
|
|
for candidate in candidates:
|
|
if (candidate / "conf" / "factory_private.json.enc").exists():
|
|
return candidate
|
|
if (candidate / "conf").exists() or (candidate / "bin").exists() or (candidate / "keys").exists():
|
|
return candidate
|
|
return exe_path.parent
|
|
|
|
|
|
def venv_python(base_dir: Path) -> Path:
|
|
scripts = "Scripts" if os.name == "nt" else "bin"
|
|
exe = "python.exe" if os.name == "nt" else "python3"
|
|
return base_dir / ".venv" / scripts / exe
|
|
|
|
|
|
def resolve_python(base_dir: Path) -> Path:
|
|
venv_py = venv_python(base_dir)
|
|
if venv_py.exists():
|
|
return venv_py
|
|
raise FileNotFoundError(
|
|
"未找到当前目录的虚拟环境:\n"
|
|
f"{venv_py}\n"
|
|
"请先创建并安装依赖:\n"
|
|
f" python3 -m venv {base_dir / '.venv'}\n"
|
|
f" {venv_py} -m pip install -r {base_dir / 'requirements.txt'}"
|
|
)
|
|
|
|
|
|
def get_base_dir() -> Path:
|
|
if is_frozen():
|
|
return _pick_runtime_root(Path(sys.executable).resolve())
|
|
return Path(__file__).resolve().parent.parent
|
|
|
|
|
|
def resolve_bin_dir(base_dir: Path, configured: Path) -> Path:
|
|
if configured.is_absolute():
|
|
return configured
|
|
return base_dir / configured
|
|
|
|
|
|
def select_bin_dir(base_dir: Path, configured: Path) -> Path:
|
|
return resolve_bin_dir(base_dir, configured)
|
|
|
|
|
|
def _display_path(base_dir: Path, path: Path) -> str:
|
|
try:
|
|
rel = path.relative_to(base_dir)
|
|
return str(rel)
|
|
except ValueError:
|
|
return path.name
|