add new install commands so they align better with the doctor code and will set the bin to the correct path
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
@@ -41,6 +42,24 @@ DEFAULT_RSYNC_ARGS = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# NOTE: This wrapper exists so cron can reliably call /opt/pobsync/bin/pobsync.
|
||||||
|
# It forwards to the "real" pobsync on PATH when possible, and falls back to python -m pobsync.
|
||||||
|
WRAPPER_SH_TEMPLATE = """#!/bin/sh
|
||||||
|
# managed-by=pobsync
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
SELF="{self_path}"
|
||||||
|
REAL="$(command -v pobsync || true)"
|
||||||
|
|
||||||
|
# Avoid recursion if PATH includes /opt/pobsync/bin
|
||||||
|
if [ -n "${{REAL}}" ] && [ "${{REAL}}" != "${{SELF}}" ]; then
|
||||||
|
exec "${{REAL}}" "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec python3 -m pobsync "$@"
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def build_default_global_config(pobsync_home: Path, backup_root: str, retention: dict[str, int]) -> dict[str, Any]:
|
def build_default_global_config(pobsync_home: Path, backup_root: str, retention: dict[str, int]) -> dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
"backup_root": backup_root,
|
"backup_root": backup_root,
|
||||||
@@ -99,6 +118,63 @@ def write_yaml(path: Path, data: dict[str, Any], dry_run: bool, force: bool) ->
|
|||||||
return f"write {path}"
|
return f"write {path}"
|
||||||
|
|
||||||
|
|
||||||
|
def _write_text_file(path: Path, content: str, dry_run: bool, force: bool) -> str:
|
||||||
|
"""
|
||||||
|
Write a plain text file with optional backup behavior similar to write_yaml().
|
||||||
|
"""
|
||||||
|
if path.exists() and not force:
|
||||||
|
return f"skip existing {path}"
|
||||||
|
if path.exists() and force:
|
||||||
|
bak = path.with_suffix(path.suffix + ".bak")
|
||||||
|
if not dry_run:
|
||||||
|
bak.write_text(path.read_text(encoding="utf-8"), encoding="utf-8")
|
||||||
|
if not dry_run:
|
||||||
|
path.write_text(content, encoding="utf-8")
|
||||||
|
return f"overwrite {path} (backup {bak})"
|
||||||
|
|
||||||
|
if not dry_run:
|
||||||
|
path.write_text(content, encoding="utf-8")
|
||||||
|
return f"write {path}"
|
||||||
|
|
||||||
|
|
||||||
|
def _install_wrapper(prefix: Path, dry_run: bool, force: bool) -> list[str]:
|
||||||
|
"""
|
||||||
|
Ensure prefix/bin/pobsync exists so cron entries can use it.
|
||||||
|
"""
|
||||||
|
actions: list[str] = []
|
||||||
|
|
||||||
|
bin_dir = prefix / "bin"
|
||||||
|
actions.append(f"mkdir -p {bin_dir}")
|
||||||
|
if not dry_run:
|
||||||
|
ensure_dir(bin_dir)
|
||||||
|
|
||||||
|
wrapper_path = bin_dir / "pobsync"
|
||||||
|
content = WRAPPER_SH_TEMPLATE.format(self_path=str(wrapper_path))
|
||||||
|
actions.append(_write_text_file(wrapper_path, content, dry_run=dry_run, force=force))
|
||||||
|
|
||||||
|
actions.append(f"chmod 0755 {wrapper_path}")
|
||||||
|
if not dry_run:
|
||||||
|
os.chmod(wrapper_path, 0o755)
|
||||||
|
|
||||||
|
return actions
|
||||||
|
|
||||||
|
|
||||||
|
def _ensure_system_log_dir(dry_run: bool) -> list[str]:
|
||||||
|
"""
|
||||||
|
Best-effort: create /var/log/pobsync to match cron redirection.
|
||||||
|
Not fatal if it fails (e.g., insufficient permissions in a non-root install attempt).
|
||||||
|
"""
|
||||||
|
actions: list[str] = []
|
||||||
|
log_dir = Path("/var/log/pobsync")
|
||||||
|
actions.append(f"mkdir -p {log_dir}")
|
||||||
|
if not dry_run:
|
||||||
|
try:
|
||||||
|
ensure_dir(log_dir)
|
||||||
|
except OSError as e:
|
||||||
|
actions.append(f"warn: cannot create {log_dir}: {e}")
|
||||||
|
return actions
|
||||||
|
|
||||||
|
|
||||||
def run_install(
|
def run_install(
|
||||||
prefix: Path,
|
prefix: Path,
|
||||||
backup_root: str | None,
|
backup_root: str | None,
|
||||||
@@ -118,6 +194,10 @@ def run_install(
|
|||||||
global_cfg = build_default_global_config(paths.home, backup_root=backup_root, retention=retention)
|
global_cfg = build_default_global_config(paths.home, backup_root=backup_root, retention=retention)
|
||||||
actions.append(write_yaml(paths.global_config_path, global_cfg, dry_run=dry_run, force=force))
|
actions.append(write_yaml(paths.global_config_path, global_cfg, dry_run=dry_run, force=force))
|
||||||
|
|
||||||
|
# Install polish: make cron-compatible wrapper path and cron log directory.
|
||||||
|
actions.extend(_install_wrapper(prefix, dry_run=dry_run, force=force))
|
||||||
|
actions.extend(_ensure_system_log_dir(dry_run=dry_run))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"ok": True,
|
"ok": True,
|
||||||
"actions": actions,
|
"actions": actions,
|
||||||
|
|||||||
Reference in New Issue
Block a user