"""Pydantic coercers for Linux / remote path fields (wraps posix_paths).""" from __future__ import annotations from server.utils.posix_paths import PosixPathError, normalize_remote_abs_path, to_posix def coerce_optional_remote_abs_path(value: str | None) -> str | None: """Optional remote absolute path (e.g. server.target_path).""" if value is None: return None text = str(value).strip() if not text: return None try: return normalize_remote_abs_path(text) except PosixPathError as exc: raise ValueError(str(exc)) from exc def coerce_remote_abs_path(value: str) -> str: """Required remote absolute path.""" try: return normalize_remote_abs_path(str(value).strip()) except PosixPathError as exc: raise ValueError(str(exc)) from exc def coerce_remote_abs_path_list(values: list[str]) -> list[str]: return [coerce_remote_abs_path(v) for v in values] def coerce_nexus_host_abs_path(value: str) -> str: """Nexus 主机上的绝对路径(推送源、上传暂存区等)。""" text = str(value).strip() if not text: raise ValueError("路径不能为空") if "\\" in text or "\0" in text: raise ValueError("路径必须使用 Linux 路径(不允许反斜杠)") path = to_posix(text) if not path.startswith("/"): raise ValueError("路径必须为绝对路径") parts = [p for p in path.split("/") if p and p != "."] if ".." in parts: raise ValueError("路径不允许包含 '..'") normalized = "/" + "/".join(parts) if parts else "/" if len(normalized) > 1 and normalized.endswith("/"): normalized = normalized.rstrip("/") return normalized or "/" def coerce_remote_relative_path(value: str) -> str: """远程目录下的相对路径(不含前导 /)。""" rel = to_posix(str(value).strip()).lstrip("/") if not rel or ".." in rel.split("/"): raise ValueError("相对路径无效") if "\\" in str(value): raise ValueError("路径必须使用 Linux 路径(不允许反斜杠)") return rel