Source code for mmirage.cli_utils.runtime
"""Runtime/path helpers for the MMIRAGE CLI."""
from __future__ import annotations
import logging
import os
from pathlib import Path
from typing import Optional, Sequence
from mmirage.config.config import MMirageConfig
logger = logging.getLogger(__name__)
[docs]
def expand_path(path: str, project_root: Optional[str] = None) -> str:
"""Expand environment variables, user home and relative paths."""
expanded = Path(os.path.expandvars(os.path.expanduser(path)))
if not expanded.is_absolute() and project_root:
expanded = Path(project_root) / expanded
return str(expanded.resolve())
[docs]
def get_project_root(cfg: MMirageConfig) -> str:
"""Return the configured project root, or the current working directory."""
project_root = cfg.execution_params.project_root
if project_root:
return expand_path(project_root)
return os.getcwd()
[docs]
def create_directories(paths: Sequence[str]) -> None:
"""Create directories if they do not already exist."""
for path in paths:
Path(path).mkdir(parents=True, exist_ok=True)
[docs]
def validate_edf_env_path(cfg: MMirageConfig) -> None:
"""Validate the optional EDF environment file path."""
edf_env = cfg.execution_params.edf_env
if not edf_env:
return
resolved = expand_path(edf_env, get_project_root(cfg))
if not Path(resolved).is_file():
raise FileNotFoundError(f"EDF environment file not found: {resolved}")
[docs]
def add_file_logging(log_file: str, level: str) -> None:
"""Add a file handler so logs are also written to disk."""
resolved_log_file = Path(expand_path(log_file))
try:
resolved_log_file.parent.mkdir(parents=True, exist_ok=True)
except OSError as exc:
logger.warning("Unable to create log directory for %s: %s", resolved_log_file, exc)
return
root_logger = logging.getLogger()
for handler in root_logger.handlers:
if isinstance(handler, logging.FileHandler) and Path(handler.baseFilename).resolve() == resolved_log_file:
return
try:
file_handler = logging.FileHandler(resolved_log_file, mode="a", encoding="utf-8")
except OSError as exc:
logger.warning("Unable to open log file %s: %s", resolved_log_file, exc)
return
file_handler.setLevel(getattr(logging, level.upper(), logging.INFO))
file_handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(name)s: %(message)s"))
root_logger.addHandler(file_handler)
[docs]
def setup_runtime(cfg: MMirageConfig, log_level: str) -> None:
"""Initialize runtime-level logging."""
report_dir = Path(expand_path(cfg.execution_params.report_dir, get_project_root(cfg)))
log_file = report_dir / f"{cfg.execution_params.job_name}.out"
add_file_logging(str(log_file), log_level)
logger.info("Writing logs to %s", log_file)