diff --git a/etc/gniza.conf.example b/etc/gniza.conf.example index 7f0c5e8..d3c6be4 100644 --- a/etc/gniza.conf.example +++ b/etc/gniza.conf.example @@ -32,3 +32,7 @@ SSH_RETRIES=3 # Extra rsync options (careful: validated for safe characters) RSYNC_EXTRA_OPTS="" + +# Work directory for temporary files (MySQL dumps, rclone configs, etc.) +# Default: /usr/local/gniza/workdir (root) or ~/.local/state/gniza/workdir (user) +#WORK_DIR="/usr/local/gniza/workdir" diff --git a/lib/config.sh b/lib/config.sh index 00ebb44..8c87add 100644 --- a/lib/config.sh +++ b/lib/config.sh @@ -55,6 +55,9 @@ load_config() { SSH_RETRIES="${SSH_RETRIES:-$DEFAULT_SSH_RETRIES}" RSYNC_EXTRA_OPTS="${RSYNC_EXTRA_OPTS:-}" + # WORK_DIR can be overridden in config; re-export if changed + export WORK_DIR + # --debug flag overrides config [[ "${GNIZA4LINUX_DEBUG:-false}" == "true" ]] && LOG_LEVEL="debug" diff --git a/lib/mysql.sh b/lib/mysql.sh index 87a5a21..5f78bee 100644 --- a/lib/mysql.sh +++ b/lib/mysql.sh @@ -147,7 +147,7 @@ mysql_dump_databases() { fi # Create temp directory - MYSQL_DUMP_DIR=$(mktemp -d "${TMPDIR:-/tmp}/gniza-mysql-XXXXXX") + MYSQL_DUMP_DIR=$(mktemp -d "${WORK_DIR}/gniza-mysql-XXXXXX") mkdir -p "$MYSQL_DUMP_DIR/_mysql" # Parse extra opts into array diff --git a/lib/rclone.sh b/lib/rclone.sh index a7bf45c..4705799 100644 --- a/lib/rclone.sh +++ b/lib/rclone.sh @@ -17,7 +17,7 @@ _build_rclone_config() { local old_umask old_umask=$(umask) umask 077 - tmpfile=$(mktemp /tmp/gniza-rclone-XXXXXX.conf) || { + tmpfile=$(mktemp "${WORK_DIR}/gniza-rclone-XXXXXX.conf") || { umask "$old_umask" log_error "Failed to create temp rclone config" return 1 diff --git a/lib/utils.sh b/lib/utils.sh index 2ac9c1c..f5fc213 100644 --- a/lib/utils.sh +++ b/lib/utils.sh @@ -85,14 +85,16 @@ detect_mode() { GNIZA_MODE="root" CONFIG_DIR="/etc/gniza" LOG_DIR="/var/log/gniza" + WORK_DIR="/usr/local/gniza/workdir" LOCK_FILE="/var/run/gniza.lock" else GNIZA_MODE="user" CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/gniza" LOG_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/gniza/log" + WORK_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/gniza/workdir" LOCK_FILE="${XDG_RUNTIME_DIR:-/tmp}/gniza-${EUID}.lock" fi - export GNIZA_MODE CONFIG_DIR LOG_DIR LOCK_FILE + export GNIZA_MODE CONFIG_DIR LOG_DIR WORK_DIR LOCK_FILE } ensure_dirs() { @@ -101,4 +103,5 @@ ensure_dirs() { mkdir -p "$CONFIG_DIR/remotes.d" || die "Cannot create remotes.d directory" mkdir -p "$CONFIG_DIR/schedules.d" || die "Cannot create schedules.d directory" mkdir -p "$LOG_DIR" || die "Cannot create log directory: $LOG_DIR" + mkdir -p "$WORK_DIR" || die "Cannot create work directory: $WORK_DIR" } diff --git a/scripts/install.sh b/scripts/install.sh index f0cc386..ceea0bb 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -22,12 +22,14 @@ if [[ $EUID -eq 0 ]]; then BIN_LINK="/usr/local/bin/gniza" CONFIG_DIR="/etc/gniza" LOG_DIR="/var/log/gniza" + WORK_DIR="/usr/local/gniza/workdir" else MODE="user" INSTALL_DIR="$HOME/.local/share/gniza" BIN_LINK="$HOME/.local/bin/gniza" CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/gniza" LOG_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/gniza/log" + WORK_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/gniza/workdir" fi info "Install mode: ${C_BOLD}${MODE}${C_RESET}" @@ -135,6 +137,10 @@ fi info "Setting up log directory: $LOG_DIR" mkdir -p "$LOG_DIR" +# ── Create work directory ─────────────────────────────────── +info "Setting up work directory: $WORK_DIR" +mkdir -p "$WORK_DIR" + # ── Copy example configs (if not already present) ──────────── if [[ ! -f "$CONFIG_DIR/gniza.conf" ]]; then cp "$INSTALL_DIR/etc/gniza.conf.example" "$CONFIG_DIR/gniza.conf" @@ -153,9 +159,10 @@ done echo "" echo "${C_GREEN}${C_BOLD}Installation complete!${C_RESET}" echo "" -echo " Binary: $BIN_LINK" -echo " Config: $CONFIG_DIR/gniza.conf" -echo " Logs: $LOG_DIR" +echo " Binary: $BIN_LINK" +echo " Config: $CONFIG_DIR/gniza.conf" +echo " Logs: $LOG_DIR" +echo " Work dir: $WORK_DIR" echo "" echo "Get started:" echo " gniza --help Show CLI help" diff --git a/tui/config.py b/tui/config.py index 0356504..bac25ae 100644 --- a/tui/config.py +++ b/tui/config.py @@ -20,8 +20,16 @@ def _get_log_dir() -> Path: return Path(xdg) / "gniza" / "log" +def _get_work_dir() -> Path: + if os.geteuid() == 0: + return Path("/usr/local/gniza/workdir") + xdg = os.environ.get("XDG_STATE_HOME", os.path.expanduser("~/.local/state")) + return Path(xdg) / "gniza" / "workdir" + + CONFIG_DIR = _get_config_dir() LOG_DIR = _get_log_dir() +WORK_DIR = _get_work_dir() def parse_conf(filepath: Path) -> dict[str, str]: diff --git a/tui/models.py b/tui/models.py index 952511e..9e46568 100644 --- a/tui/models.py +++ b/tui/models.py @@ -199,6 +199,7 @@ class AppSettings: ssh_timeout: str = "30" ssh_retries: str = "3" rsync_extra_opts: str = "" + work_dir: str = "/usr/local/gniza/workdir" @classmethod def from_conf(cls, data: dict[str, str]) -> "AppSettings": @@ -219,6 +220,7 @@ class AppSettings: ssh_timeout=data.get("SSH_TIMEOUT", "30"), ssh_retries=data.get("SSH_RETRIES", "3"), rsync_extra_opts=data.get("RSYNC_EXTRA_OPTS", ""), + work_dir=data.get("WORK_DIR", "/usr/local/gniza/workdir"), ) def to_conf(self) -> dict[str, str]: @@ -239,4 +241,5 @@ class AppSettings: "SSH_TIMEOUT": self.ssh_timeout, "SSH_RETRIES": self.ssh_retries, "RSYNC_EXTRA_OPTS": self.rsync_extra_opts, + "WORK_DIR": self.work_dir, } diff --git a/tui/screens/settings.py b/tui/screens/settings.py index 0a07904..bd73fc8 100644 --- a/tui/screens/settings.py +++ b/tui/screens/settings.py @@ -59,6 +59,8 @@ class SettingsScreen(Screen): yield Input(value=settings.ssh_retries, id="set-sshretries") yield Static("Extra rsync options:") yield Input(value=settings.rsync_extra_opts, id="set-rsyncopts") + yield Static("Work Directory:") + yield Input(value=settings.work_dir, placeholder="/usr/local/gniza/workdir", id="set-workdir") with Horizontal(id="set-buttons"): yield Button("Save", variant="primary", id="btn-save") yield Button("Back", id="btn-back") @@ -91,6 +93,7 @@ class SettingsScreen(Screen): ssh_timeout=self.query_one("#set-sshtimeout", Input).value.strip() or "30", ssh_retries=self.query_one("#set-sshretries", Input).value.strip() or "3", rsync_extra_opts=self.query_one("#set-rsyncopts", Input).value.strip(), + work_dir=self.query_one("#set-workdir", Input).value.strip() or "/usr/local/gniza/workdir", ) conf_path = CONFIG_DIR / "gniza.conf" write_conf(conf_path, settings.to_conf())