Source code for rath.config.paths

"""Resolve where ``config.json`` lives on disk.

Three-tier precedence — first hit wins:

1. ``OPENRATH_HOME`` environment variable (explicit override; tilde expanded).
2. ``./.openrath/`` directory in :func:`Path.cwd` (project-local marker).
3. ``~/.openrath/`` (user-level default).

Pure functions: no side-effects beyond reading the env and CWD; no directory
creation. ``ConfigStore.save`` handles the ``mkdir`` when writing.
"""

from __future__ import annotations

import os
from pathlib import Path

__all__ = [
    "OPENRATH_HOME_ENV",
    "CONFIG_FILENAME",
    "PROJECT_MARKER_DIR",
    "USER_DIR_NAME",
    "resolve_config_dir",
    "resolve_config_path",
    "is_project_local",
]

OPENRATH_HOME_ENV = "OPENRATH_HOME"
CONFIG_FILENAME = "config.json"
PROJECT_MARKER_DIR = ".openrath"
USER_DIR_NAME = ".openrath"


[docs] def resolve_config_dir() -> Path: """Return the directory that holds ``config.json``. Raises :class:`FileNotFoundError` only when ``OPENRATH_HOME`` is set but points at a non-directory path that already exists (e.g. a regular file). A missing target is fine — the caller will create it on first save. """ env_value = os.environ.get(OPENRATH_HOME_ENV, "").strip() if env_value: path = Path(env_value).expanduser().resolve() if path.exists() and not path.is_dir(): raise FileNotFoundError( f"{OPENRATH_HOME_ENV}={env_value!r} exists but is not a directory", ) return path cwd_local = Path.cwd() / PROJECT_MARKER_DIR if cwd_local.is_dir(): return cwd_local.resolve() return Path.home() / USER_DIR_NAME
[docs] def resolve_config_path() -> Path: """Return the full path to ``config.json`` under the resolved config dir.""" return resolve_config_dir() / CONFIG_FILENAME
[docs] def is_project_local(config_dir: Path) -> bool: """Return whether ``config_dir`` is the project-local ``./.openrath/``. Used by :mod:`rath.config.secrets` to decide whether to also append ``.openrath/`` to the surrounding project's ``.gitignore`` on save. """ try: return config_dir.resolve() == (Path.cwd() / PROJECT_MARKER_DIR).resolve() except (OSError, RuntimeError): return False