Pipeline: parse HTML presets, compare modlists, download from Caddy file server, create junctions/symlinks to Arma 3 Server directory. Includes update/sync flows, missing-mod reporting, OS compat layer, shared config, dep checker, comprehensive test suite (71 tests). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
109 lines
3.3 KiB
Python
109 lines
3.3 KiB
Python
"""
|
|
arma_modlist_tools.compat
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
OS detection and cross-platform utilities shared by all CLI scripts.
|
|
|
|
Supported platforms:
|
|
- Windows / Windows Server (sys.platform == "win32")
|
|
- Ubuntu / Ubuntu Server (sys.platform == "linux")
|
|
|
|
Typical usage::
|
|
|
|
from arma_modlist_tools.compat import is_windows, get_os_label, fix_console_encoding
|
|
|
|
fix_console_encoding() # call once at script start on Windows
|
|
print(get_os_label()) # "Windows Server", "Ubuntu", etc.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import io
|
|
import platform
|
|
import sys
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Platform detection
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def is_windows() -> bool:
|
|
"""Return ``True`` on Windows and Windows Server."""
|
|
return sys.platform == "win32"
|
|
|
|
|
|
def is_linux() -> bool:
|
|
"""Return ``True`` on Linux (Ubuntu, Ubuntu Server, and other distros)."""
|
|
return sys.platform == "linux"
|
|
|
|
|
|
def get_os_label() -> str:
|
|
"""
|
|
Return a human-readable OS label.
|
|
|
|
Possible values: ``"Windows"``, ``"Windows Server"``, ``"Ubuntu"``,
|
|
``"Ubuntu Server"``, ``"Linux"``, ``"Unknown"``.
|
|
"""
|
|
if is_windows():
|
|
ver = platform.version()
|
|
# Windows Server versions contain "Server" in the version string
|
|
# e.g. "10.0.17763 ... Windows Server 2019 ..."
|
|
if "Server" in platform.version() or "Server" in platform.uname().version:
|
|
return "Windows Server"
|
|
return "Windows"
|
|
|
|
if is_linux():
|
|
# Read /etc/os-release for distro name
|
|
os_release = _read_os_release()
|
|
name = os_release.get("NAME", "").lower()
|
|
|
|
if "ubuntu" in name:
|
|
# Distinguish desktop vs server: server images have no display server
|
|
if _is_headless():
|
|
return "Ubuntu Server"
|
|
return "Ubuntu"
|
|
|
|
return "Linux"
|
|
|
|
return "Unknown"
|
|
|
|
|
|
def _read_os_release() -> dict[str, str]:
|
|
"""Parse /etc/os-release into a dict (Linux only)."""
|
|
result: dict[str, str] = {}
|
|
try:
|
|
with open("/etc/os-release", encoding="utf-8") as f:
|
|
for line in f:
|
|
line = line.strip()
|
|
if "=" in line and not line.startswith("#"):
|
|
k, _, v = line.partition("=")
|
|
result[k] = v.strip('"')
|
|
except OSError:
|
|
pass
|
|
return result
|
|
|
|
|
|
def _is_headless() -> bool:
|
|
"""Return True if no graphical display server is detected (headless/server)."""
|
|
import os
|
|
# Check for common display environment variables
|
|
return not (os.environ.get("DISPLAY") or os.environ.get("WAYLAND_DISPLAY"))
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Console encoding
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def fix_console_encoding() -> None:
|
|
"""
|
|
Force UTF-8 output on Windows terminals that default to cp1252.
|
|
|
|
Call once at the top of any CLI script that uses Unicode characters
|
|
(checkmarks, arrows, etc.). No-op on Linux.
|
|
"""
|
|
if not is_windows():
|
|
return
|
|
if sys.stdout.encoding and sys.stdout.encoding.lower() == "utf-8":
|
|
return
|
|
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
|
|
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8", errors="replace")
|