Files
odysseus/src/workspace_paths.py
T

65 lines
2.1 KiB
Python

"""Workspace path mapping for host-driven clients and Docker backends."""
from __future__ import annotations
import os
from pathlib import PurePosixPath
def _clean_path(value: str | None) -> str:
text = str(value or "").strip()
if not text or "\n" in text or "\r" in text:
return ""
return os.path.abspath(os.path.expanduser(text))
def _path_pairs() -> list[tuple[str, str]]:
pairs: list[tuple[str, str]] = []
mapping = os.environ.get("ODYSSEUS_WORKSPACE_MOUNTS", "")
for item in mapping.replace(";", ",").split(","):
if not item.strip() or "=" not in item:
continue
host, container = item.split("=", 1)
host_path = _clean_path(host)
container_path = _clean_path(container)
if host_path and container_path:
pairs.append((host_path, container_path))
host_root = _clean_path(os.environ.get("ODYSSEUS_WORKSPACE_HOST_ROOT"))
container_root = _clean_path(
os.environ.get("ODYSSEUS_WORKSPACE_CONTAINER_ROOT") or "/workspace"
)
if host_root and container_root:
pairs.append((host_root, container_root))
pairs.sort(key=lambda pair: len(pair[0]), reverse=True)
return pairs
def workspace_mount_pairs() -> list[tuple[str, str]]:
"""Configured (host_root, container_root) mount pairs, longest-first."""
return _path_pairs()
def backend_workspace_path(path: str | None) -> str:
"""Translate a user-facing host workspace path into a backend-visible path."""
original = str(path or "").strip()
if not original or "\n" in original or "\r" in original:
return ""
expanded = os.path.abspath(os.path.expanduser(original))
for host_root, container_root in _path_pairs():
try:
common = os.path.commonpath([host_root, expanded])
except ValueError:
continue
if common != host_root:
continue
rel = os.path.relpath(expanded, host_root)
if rel == ".":
return container_root
return str(PurePosixPath(container_root) / rel)
return expanded