106 lines
3.1 KiB
Python
106 lines
3.1 KiB
Python
"""Read-only host and configured environment inspection."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import asdict, dataclass
|
|
from datetime import datetime
|
|
import os
|
|
from pathlib import Path
|
|
import platform
|
|
import shutil
|
|
import sys
|
|
from typing import Any
|
|
|
|
from .config import AppConfig
|
|
from .prefix import proton_wineserver_candidates
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class EnvironmentCheck:
|
|
name: str
|
|
ok: bool
|
|
value: str
|
|
required: bool = True
|
|
|
|
def to_dict(self) -> dict[str, str | bool]:
|
|
return asdict(self)
|
|
|
|
|
|
def collect_environment(config: AppConfig) -> dict[str, Any]:
|
|
checks = environment_checks(config)
|
|
return {
|
|
"collected_at": datetime.now().astimezone().isoformat(),
|
|
"host": {
|
|
"platform": platform.platform(),
|
|
"machine": platform.machine(),
|
|
"python": sys.version,
|
|
"executable": sys.executable,
|
|
"cwd": os.getcwd(),
|
|
},
|
|
"config": config.to_dict(),
|
|
"checks": [check.to_dict() for check in checks],
|
|
"ok": all(check.ok for check in checks if check.required),
|
|
}
|
|
|
|
|
|
def environment_checks(config: AppConfig) -> list[EnvironmentCheck]:
|
|
checks = [
|
|
_path_check("app_root", config.paths.app_root, "directory"),
|
|
_path_check("live_prefix", config.paths.live_prefix, "directory"),
|
|
_path_check("live_game", config.paths.live_game, "directory"),
|
|
_path_check("logs", config.paths.logs, "directory"),
|
|
_path_check("native_logs", config.paths.native_logs, "directory"),
|
|
_path_check("proton7", config.proton7.proton, "file"),
|
|
_any_path_check("proton7_wineserver", proton_wineserver_candidates(config)),
|
|
_path_check("steam_root", config.proton7.steam_root, "directory"),
|
|
_path_check("compat", config.proton7.compat, "directory"),
|
|
_path_check("dedicated_prefix", config.proton7.prefix, "directory"),
|
|
_path_check("game_exe", config.paths.live_game / config.game.exe, "file"),
|
|
EnvironmentCheck(
|
|
"game_argument",
|
|
config.game.args == ("PTEU_REBORN",),
|
|
" ".join(config.game.args),
|
|
),
|
|
EnvironmentCheck(
|
|
"virtual_desktop",
|
|
config.game.virtual_desktop == "1600x900",
|
|
config.game.virtual_desktop,
|
|
),
|
|
_tool_check("strace", required=False),
|
|
_tool_check("gdb", required=False),
|
|
_i386_vulkan_check(),
|
|
]
|
|
return checks
|
|
|
|
|
|
def _path_check(name: str, path: Path, kind: str) -> EnvironmentCheck:
|
|
ok = path.is_file() if kind == "file" else path.is_dir()
|
|
return EnvironmentCheck(name, ok, str(path))
|
|
|
|
|
|
def _tool_check(name: str, required: bool) -> EnvironmentCheck:
|
|
path = shutil.which(name)
|
|
return EnvironmentCheck(name, path is not None, path or "not found", required)
|
|
|
|
|
|
def _any_path_check(name: str, candidates: tuple[Path, ...]) -> EnvironmentCheck:
|
|
found = next((path for path in candidates if path.is_file()), None)
|
|
return EnvironmentCheck(
|
|
name,
|
|
found is not None,
|
|
str(found) if found is not None else "not found: " + ", ".join(map(str, candidates)),
|
|
)
|
|
|
|
|
|
def _i386_vulkan_check() -> EnvironmentCheck:
|
|
candidates = (
|
|
Path("/usr/lib/i386-linux-gnu/libvulkan.so.1"),
|
|
Path("/usr/lib/i386-linux-gnu/libvulkan.so"),
|
|
)
|
|
found = next((path for path in candidates if path.exists()), None)
|
|
return EnvironmentCheck(
|
|
"i386_vulkan_loader",
|
|
found is not None,
|
|
str(found) if found is not None else "not found",
|
|
)
|