From ffb64c45b42dda1edf44a0fbaf42c78f790d6869 Mon Sep 17 00:00:00 2001 From: Andrew Branson Date: Sun, 9 Aug 2026 17:37:37 +0200 Subject: Keep machine-local MCP config untracked Track a generic config.py.template and ignore the operational config.py so machine-specific build host defaults remain local. Document the bootstrap copy and replace personal OBS and Android test fixtures with neutral examples. --- src/sailfish_devel_mcp/config.py | 284 --------------------------------------- 1 file changed, 284 deletions(-) delete mode 100644 src/sailfish_devel_mcp/config.py (limited to 'src/sailfish_devel_mcp/config.py') diff --git a/src/sailfish_devel_mcp/config.py b/src/sailfish_devel_mcp/config.py deleted file mode 100644 index 198b09d..0000000 --- a/src/sailfish_devel_mcp/config.py +++ /dev/null @@ -1,284 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass, field -import json -import os -from pathlib import Path -from typing import Any, Mapping - - -DEFAULT_RUNTIME_DIR = "/run/user/100000" -DEFAULT_BUS_ADDRESS = "unix:path=/run/user/100000/dbus/user_bus_socket" -BUNDLED_BUILD_HELPER = ( - Path(__file__).resolve().parent / "vendor" / "build_sailfishos.py" -) -DEFAULT_ANDROID_BUILD_HOST = "android-builder" -DEFAULT_ANDROID_BUILD_SSH_TARGET = "builder@example.invalid" -DEFAULT_ANDROID_BUILD_PROJECT_DIR = "" -DEFAULT_ANDROID_BUILD_STATE_DIR = "/tmp/sailfish-devel-mcp/android-builds" - - -@dataclass(frozen=True) -class DeviceConfig: - name: str - ssh_target: str - username: str = "defaultuser" - architecture: str = "" - release: str = "" - user_bus_runtime_dir: str = DEFAULT_RUNTIME_DIR - user_bus_address: str = DEFAULT_BUS_ADDRESS - - def public_dict(self) -> dict[str, object]: - return { - "name": self.name, - "ssh_target": self.ssh_target, - "username": self.username, - "architecture": self.architecture, - "release": self.release, - "user_bus_runtime_dir": self.user_bus_runtime_dir, - "user_bus_address": self.user_bus_address, - } - - -@dataclass(frozen=True) -class AndroidBuildHostConfig: - name: str - ssh_target: str - project_dir: str - state_dir: str = DEFAULT_ANDROID_BUILD_STATE_DIR - - def public_dict(self) -> dict[str, object]: - return { - "name": self.name, - "ssh_target": self.ssh_target, - "project_dir": self.project_dir, - "state_dir": self.state_dir, - } - - -def default_android_build_hosts() -> dict[str, AndroidBuildHostConfig]: - return { - DEFAULT_ANDROID_BUILD_HOST: AndroidBuildHostConfig( - name=DEFAULT_ANDROID_BUILD_HOST, - ssh_target=DEFAULT_ANDROID_BUILD_SSH_TARGET, - project_dir=DEFAULT_ANDROID_BUILD_PROJECT_DIR, - state_dir=DEFAULT_ANDROID_BUILD_STATE_DIR, - ) - } - - -@dataclass(frozen=True) -class PathConfig: - git_root: Path = Path.home() / "git" - obs_root: Path = Path.home() / "OBS" - ssh_config: Path = Path.home() / ".ssh" / "config" - build_sailfishos: Path = BUNDLED_BUILD_HELPER - local_sdk: Path | None = None - osc_api_alias: str = "" - - def public_dict(self) -> dict[str, str | None]: - return { - "git_root": str(self.git_root), - "obs_root": str(self.obs_root), - "ssh_config": str(self.ssh_config), - "build_sailfishos": str(self.build_sailfishos), - "local_sdk": str(self.local_sdk) if self.local_sdk else None, - "osc_api_alias": self.osc_api_alias, - } - - -@dataclass(frozen=True) -class Config: - path: Path | None - default_device: str - devices: Mapping[str, DeviceConfig] = field(default_factory=dict) - paths: PathConfig = field(default_factory=PathConfig) - default_android_build_host: str = DEFAULT_ANDROID_BUILD_HOST - android_build_hosts: Mapping[str, AndroidBuildHostConfig] = field( - default_factory=default_android_build_hosts - ) - - def device(self, name: str | None = None) -> DeviceConfig: - key = name or self.default_device - if key in self.devices: - return self.devices[key] - if name and "@" in name: - return DeviceConfig(name=name, ssh_target=name) - raise KeyError(f"unknown Sailfish device: {key}") - - def android_build_host(self, name: str | None = None) -> AndroidBuildHostConfig: - key = name or self.default_android_build_host - if key in self.android_build_hosts: - return self.android_build_hosts[key] - if name and "@" in name: - return AndroidBuildHostConfig( - name=name, - ssh_target=name, - project_dir=DEFAULT_ANDROID_BUILD_PROJECT_DIR, - ) - raise KeyError(f"unknown Android build host: {key}") - - def public_dict(self) -> dict[str, Any]: - return { - "path": str(self.path) if self.path else None, - "default_device": self.default_device, - "devices": { - name: device.public_dict() for name, device in self.devices.items() - }, - "paths": self.paths.public_dict(), - "default_android_build_host": self.default_android_build_host, - "android_build_hosts": { - name: host.public_dict() - for name, host in self.android_build_hosts.items() - }, - } - - -def default_config_path() -> Path: - if "SAILFISH_MCP_CONFIG" in os.environ: - return Path(os.environ["SAILFISH_MCP_CONFIG"]).expanduser() - return Path.home() / ".config" / "sailfish-devel-mcp" / "config.json" - - -def load_config(path: str | os.PathLike[str] | None = None) -> Config: - config_path = Path(path).expanduser() if path else default_config_path() - raw: dict[str, Any] = {} - - if config_path.exists(): - with config_path.open("r", encoding="utf-8") as handle: - loaded = json.load(handle) - if not isinstance(loaded, dict): - raise ValueError(f"{config_path} must contain a JSON object") - raw = loaded - - devices = _load_devices(raw.get("devices", {})) - if not devices: - default_name = os.environ.get("SAILFISH_MCP_DEFAULT_DEVICE", "device") - devices = { - default_name: DeviceConfig( - name=default_name, - ssh_target=os.environ.get("SAILFISH_MCP_SSH_TARGET", "root@device"), - ) - } - - default_device = str(raw.get("default_device") or next(iter(devices))) - paths = _load_paths(raw.get("paths", {})) - android_build_hosts = _load_android_build_hosts(raw.get("android_build_hosts", {})) - default_android_build_host = str( - raw.get("default_android_build_host") or next(iter(android_build_hosts)) - ) - return Config( - path=config_path if config_path.exists() else None, - default_device=default_device, - devices=devices, - paths=paths, - default_android_build_host=default_android_build_host, - android_build_hosts=android_build_hosts, - ) - - -def _load_devices(raw_devices: Any) -> dict[str, DeviceConfig]: - if not isinstance(raw_devices, dict): - raise ValueError("devices must be a JSON object") - - devices: dict[str, DeviceConfig] = {} - for name, value in raw_devices.items(): - if isinstance(value, str): - value = {"ssh_target": value} - if not isinstance(value, dict): - raise ValueError(f"device {name!r} must be a string or object") - ssh_target = str(value.get("ssh_target") or name) - devices[str(name)] = DeviceConfig( - name=str(name), - ssh_target=ssh_target, - username=str(value.get("username") or "defaultuser"), - architecture=str(value.get("architecture") or ""), - release=str(value.get("release") or ""), - user_bus_runtime_dir=str( - value.get("user_bus_runtime_dir") or DEFAULT_RUNTIME_DIR - ), - user_bus_address=str(value.get("user_bus_address") or DEFAULT_BUS_ADDRESS), - ) - return devices - - -def _load_android_build_hosts(raw_hosts: Any) -> dict[str, AndroidBuildHostConfig]: - if not isinstance(raw_hosts, dict): - raise ValueError("android_build_hosts must be a JSON object") - - hosts: dict[str, AndroidBuildHostConfig] = {} - for name, value in raw_hosts.items(): - if isinstance(value, str): - value = {"ssh_target": value} - if not isinstance(value, dict): - raise ValueError(f"android build host {name!r} must be a string or object") - hosts[str(name)] = AndroidBuildHostConfig( - name=str(name), - ssh_target=str(value.get("ssh_target") or name), - project_dir=str( - value.get("project_dir") or DEFAULT_ANDROID_BUILD_PROJECT_DIR - ), - state_dir=str(value.get("state_dir") or DEFAULT_ANDROID_BUILD_STATE_DIR), - ) - - if not hosts: - name = os.environ.get("SAILFISH_MCP_ANDROID_BUILD_HOST", DEFAULT_ANDROID_BUILD_HOST) - hosts[name] = AndroidBuildHostConfig( - name=name, - ssh_target=os.environ.get( - "SAILFISH_MCP_ANDROID_BUILD_SSH_TARGET", - DEFAULT_ANDROID_BUILD_SSH_TARGET, - ), - project_dir=os.environ.get( - "SAILFISH_MCP_ANDROID_BUILD_PROJECT_DIR", - DEFAULT_ANDROID_BUILD_PROJECT_DIR, - ), - state_dir=os.environ.get( - "SAILFISH_MCP_ANDROID_BUILD_STATE_DIR", - DEFAULT_ANDROID_BUILD_STATE_DIR, - ), - ) - return hosts - - -def _load_paths(raw_paths: Any) -> PathConfig: - if not isinstance(raw_paths, dict): - raise ValueError("paths must be a JSON object") - defaults = PathConfig() - raw_local_sdk = raw_paths.get("local_sdk") or os.environ.get("SAILFISH_MCP_LOCAL_SDK") - return PathConfig( - git_root=Path( - str( - raw_paths.get("git_root") - or os.environ.get("SAILFISH_MCP_GIT_ROOT") - or defaults.git_root - ) - ).expanduser(), - obs_root=Path( - str( - raw_paths.get("obs_root") - or os.environ.get("SAILFISH_MCP_OBS_ROOT") - or defaults.obs_root - ) - ).expanduser(), - ssh_config=Path( - str( - raw_paths.get("ssh_config") - or os.environ.get("SAILFISH_MCP_SSH_CONFIG") - or defaults.ssh_config - ) - ).expanduser(), - build_sailfishos=Path( - str( - raw_paths.get("build_sailfishos") - or os.environ.get("SAILFISH_MCP_BUILD_HELPER") - or defaults.build_sailfishos - ) - ).expanduser(), - local_sdk=Path(str(raw_local_sdk)).expanduser() if raw_local_sdk else None, - osc_api_alias=str( - raw_paths.get("osc_api_alias") - or os.environ.get("SAILFISH_MCP_OSC_API_ALIAS") - or defaults.osc_api_alias - ), - ) -- cgit v1.2.3