75 lines
2.3 KiB
Python
75 lines
2.3 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
from typing import Any, Mapping, Optional, Union
|
|
|
|
from .exceptions import ClientConfigurationError
|
|
|
|
ConfigPath = Union[str, Path]
|
|
|
|
DEFAULT_BASE_URL_FALLBACK = "https://brecaldevel.bsmd-emswe.eu"
|
|
CONFIG_FILENAME = "client.json"
|
|
|
|
|
|
def _default_config_path() -> Path:
|
|
xdg = Path(os.environ.get("XDG_CONFIG_HOME", Path.home() / ".config"))
|
|
return (xdg / "brecal" / CONFIG_FILENAME).expanduser()
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class ClientConfig:
|
|
base_url: str
|
|
environment: Optional[str] = None
|
|
|
|
@classmethod
|
|
def from_mapping(cls, data: Mapping[str, Any]) -> "ClientConfig":
|
|
environment = data.get("environment")
|
|
base_url = data.get("base_url")
|
|
endpoints = data.get("endpoints")
|
|
|
|
if isinstance(endpoints, Mapping):
|
|
if environment and environment in endpoints:
|
|
base_url = endpoints[environment]
|
|
elif not base_url and endpoints:
|
|
# Pick the first entry as a last resort
|
|
_, base_url = next(iter(endpoints.items()))
|
|
|
|
if not base_url:
|
|
raise ClientConfigurationError(
|
|
"Client configuration requires either 'base_url' or an "
|
|
"'endpoints' mapping."
|
|
)
|
|
|
|
return cls(
|
|
base_url=str(base_url).rstrip("/"),
|
|
environment=str(environment) if environment else None,
|
|
)
|
|
|
|
@classmethod
|
|
def load(cls, path: Optional[ConfigPath] = None) -> "ClientConfig":
|
|
file_path = Path(path) if path else _default_config_path()
|
|
data = json.loads(file_path.read_text(encoding="utf-8"))
|
|
return cls.from_mapping(data)
|
|
|
|
|
|
def get_default_base_url(path: Optional[ConfigPath] = None) -> str:
|
|
"""Resolve the default base URL using env vars or ~/.config/brecal/client.json."""
|
|
env_override = os.getenv("BRECAL_BASE_URL")
|
|
if env_override:
|
|
return env_override.rstrip("/")
|
|
|
|
try:
|
|
config = ClientConfig.load(path=path)
|
|
return config.base_url
|
|
except FileNotFoundError:
|
|
return DEFAULT_BASE_URL_FALLBACK
|
|
except ClientConfigurationError:
|
|
raise
|
|
except Exception as exc:
|
|
raise ClientConfigurationError(
|
|
f"Failed to load BreCal client configuration: {exc}"
|
|
) from exc
|