mirror of
https://github.com/SikongJueluo/Mini-Nav.git
synced 2026-07-12 20:15:31 +08:00
- Move load_env_file, parse_timeout_seconds, build_remote_script, and build_ssh_command to scripts/common.py - Update remote_docker_run.py to import from common module - Improves code organization and reusability
111 lines
2.5 KiB
Python
111 lines
2.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Shared utilities for remote Docker / SSH scripts."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import shlex
|
|
from pathlib import Path
|
|
|
|
|
|
def load_env_file(path: Path) -> None:
|
|
if not path.exists():
|
|
return
|
|
|
|
for raw_line in path.read_text(encoding="utf-8").splitlines():
|
|
line = raw_line.strip()
|
|
|
|
if not line or line.startswith("#") or "=" not in line:
|
|
continue
|
|
|
|
key, value = line.split("=", 1)
|
|
key = key.strip()
|
|
value = value.strip()
|
|
|
|
if not key or key in os.environ:
|
|
continue
|
|
|
|
if len(value) >= 2 and value[0] == value[-1] and value[0] in {"'", '"'}:
|
|
value = value[1:-1]
|
|
|
|
os.environ[key] = value
|
|
|
|
|
|
def parse_timeout_seconds(value: str) -> float:
|
|
value = value.strip().lower()
|
|
|
|
if value.endswith("ms"):
|
|
return float(value[:-2]) / 1000
|
|
if value.endswith("s"):
|
|
return float(value[:-1])
|
|
if value.endswith("m"):
|
|
return float(value[:-1]) * 60
|
|
if value.endswith("h"):
|
|
return float(value[:-1]) * 3600
|
|
|
|
return float(value)
|
|
|
|
|
|
def build_remote_script(container: str, workdir: str, command: str) -> str:
|
|
q_container = shlex.quote(container)
|
|
q_workdir = shlex.quote(workdir)
|
|
|
|
inner_command = (
|
|
"set -Eeuo pipefail; "
|
|
'if [ -f "$HOME/.bashrc" ]; then source "$HOME/.bashrc"; fi; '
|
|
"if command -v direnv >/dev/null 2>&1 && [ -f .envrc ]; then "
|
|
" direnv allow . >/dev/null 2>&1 || true; "
|
|
' eval "$(direnv export bash)"; '
|
|
"fi; "
|
|
f"{command}"
|
|
)
|
|
q_command = shlex.quote(inner_command)
|
|
|
|
return f"""
|
|
set -Eeuo pipefail
|
|
|
|
if ! command -v docker >/dev/null 2>&1; then
|
|
echo 'error: docker not found on remote host' >&2
|
|
exit 127
|
|
fi
|
|
|
|
if ! docker inspect {q_container} >/dev/null 2>&1; then
|
|
echo 'error: docker container not found: {container}' >&2
|
|
exit 127
|
|
fi
|
|
|
|
if [ "$(docker inspect -f '{{{{.State.Running}}}}' {q_container})" != "true" ]; then
|
|
echo 'error: docker container is not running: {container}' >&2
|
|
exit 127
|
|
fi
|
|
|
|
docker exec -i \\
|
|
-w {q_workdir} \\
|
|
{q_container} \\
|
|
bash -lc {q_command}
|
|
""".strip()
|
|
|
|
|
|
def build_ssh_command(
|
|
*,
|
|
ssh_target: str,
|
|
ssh_port: str,
|
|
ssh_opts: str,
|
|
) -> list[str]:
|
|
ssh_cmd = [
|
|
"ssh",
|
|
"-p",
|
|
ssh_port,
|
|
"-o",
|
|
"BatchMode=yes",
|
|
"-o",
|
|
"StrictHostKeyChecking=accept-new",
|
|
]
|
|
|
|
if ssh_opts:
|
|
ssh_cmd.extend(shlex.split(ssh_opts))
|
|
|
|
ssh_cmd.extend([ssh_target, "bash", "-s", "--"])
|
|
|
|
return ssh_cmd
|