"""Shared configuration loader for bootstrap and CI.""" import re from pathlib import Path from typing import NamedTuple import tomllib class BuildConfig(NamedTuple): """Build configuration extracted from pyproject.toml.""" alfred_version: str python_version: str python_version_short: str runner: str image_name: str service_name: str librechat_version: str rag_version: str def extract_python_version(version_string: str) -> tuple[str, str]: """ Extract Python version from poetry dependency string. Examples: "==3.14.2" -> ("3.14.2", "3.14") "^3.14.2" -> ("3.14.2", "3.14") "~3.14.2" -> ("3.14.2", "3.14") "3.14.2" -> ("3.14.2", "3.14") """ clean_version = re.sub(r"^[=^~><]+", "", version_string.strip()) parts = clean_version.split(".") if len(parts) >= 2: full_version = clean_version short_version = f"{parts[0]}.{parts[1]}" return full_version, short_version else: raise ValueError(f"Invalid Python version format: {version_string}") def load_build_config(base_dir: Path | None = None) -> BuildConfig: """Load build configuration from pyproject.toml.""" if base_dir is None: base_dir = Path(__file__).resolve().parent.parent toml_path = base_dir / "pyproject.toml" if not toml_path.exists(): raise FileNotFoundError(f"pyproject.toml not found: {toml_path}") with open(toml_path, "rb") as f: data = tomllib.load(f) settings_keys = data["tool"]["alfred"]["settings"] dependencies = data["tool"]["poetry"]["dependencies"] alfred_version = data["tool"]["poetry"]["version"] python_version_full, python_version_short = extract_python_version( dependencies["python"] ) return BuildConfig( alfred_version=alfred_version, python_version=python_version_full, python_version_short=python_version_short, runner=settings_keys["runner"], image_name=settings_keys["image_name"], service_name=settings_keys["service_name"], librechat_version=settings_keys["librechat_version"], rag_version=settings_keys["rag_version"], ) def write_env_make(config: BuildConfig, base_dir: Path | None = None) -> None: """Write .env.make file for Makefile.""" if base_dir is None: base_dir = Path(__file__).resolve().parent.parent env_make_path = base_dir / ".env.make" with open(env_make_path, "w", encoding="utf-8") as f: f.write("# Auto-generated from pyproject.toml\n") f.write(f"export ALFRED_VERSION={config.alfred_version}\n") f.write(f"export PYTHON_VERSION={config.python_version}\n") f.write(f"export PYTHON_VERSION_SHORT={config.python_version_short}\n") f.write(f"export RUNNER={config.runner}\n") f.write(f"export IMAGE_NAME={config.image_name}\n") f.write(f"export SERVICE_NAME={config.service_name}\n") f.write(f"export LIBRECHAT_VERSION={config.librechat_version}\n") f.write(f"export RAG_VERSION={config.rag_version}\n")