From fc6bca9c0359884fdba4f7fc1261afdf8d6e3543 Mon Sep 17 00:00:00 2001 From: LeRatierBretonnier Date: Wed, 19 Aug 2026 13:32:40 +0200 Subject: [PATCH] feat: add systemd install script for daemon-only deployment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The daemon already handles bidirectional sync (SVN→Git polling and Git→SVN push), so a single systemd service is sufficient. The script creates a venv, generates svn-mirror.service, and enables it for a given user (default: gitea). README updated accordingly. Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe --- README.md | 53 ++++++++++++++-- deploy/install.sh | 152 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 200 insertions(+), 5 deletions(-) create mode 100644 deploy/install.sh diff --git a/README.md b/README.md index db879c3..dda9398 100644 --- a/README.md +++ b/README.md @@ -235,14 +235,57 @@ it fetches the new commits from Gitea and runs `sync_git_to_svn`. - Secret: same as `webhook_secret` in config - Events: "Push" -### Mode C: Both (recommended) +### Mode C: systemd service (recommended) -Run daemon AND webhook. The daemon handles SVN→Git polling; the webhook -handles instant Git→SVN on developer push. +The daemon handles **bidirectional** sync: SVN→Git polling AND Git→SVN push +on each cycle. One service is all you need. + +#### Quick install via script + +Use the provided install script to generate and enable the systemd service +running as a given user (e.g. `gitea`): ```bash -screen -dmS daemon python3.11 -m svn_mirror daemon --config /etc/svn-mirror/config.yml -screen -dmS webhook python3.11 -m svn_mirror webhook --config /etc/svn-mirror/config.yml +sudo ./deploy/install.sh --install-dir /opt/svn-git-server --user gitea +``` + +This will: +- Create a Python virtualenv at `/.venv` and install deps +- Generate `svn-mirror.service` +- Enable the service (auto-start on boot) + +Options: + +| Option | Default | Description | +|--------|---------|-------------| +| `--install-dir DIR` | *(required)* | Where the code is installed | +| `--user USER` | `gitea` | System user to run the service as | +| `--config FILE` | `/config.yml` | Config file path | +| `--venv DIR` | `/.venv` | Virtualenv path | +| `--uninstall` | — | Remove service instead of installing | + +After install, start the service: + +```bash +sudo systemctl start svn-mirror +``` + +Check logs: + +```bash +journalctl -u svn-mirror -f +``` + +To uninstall: + +```bash +sudo ./deploy/install.sh --uninstall +``` + +#### Manual setup (screen/tmux) + +```bash +screen -dmS svn-mirror python3.11 -m svn_mirror daemon --config /etc/svn-mirror/config.yml ``` ### Mode D: Gitea post-receive hook (filesystem) diff --git a/deploy/install.sh b/deploy/install.sh new file mode 100644 index 0000000..0811bbd --- /dev/null +++ b/deploy/install.sh @@ -0,0 +1,152 @@ +#!/bin/bash +# +# Install svn-git-server as a systemd service (daemon). +# +# The daemon handles bidirectional sync: SVN->Git polling AND Git->SVN push. +# +# Usage: +# sudo ./deploy/install.sh --install-dir /opt/svn-git-server --user gitea +# +# Options: +# --install-dir DIR Path where the code is installed (required) +# --user USER System user to run the service as (default: gitea) +# --config FILE Config file path (default: /config.yml) +# --venv DIR Virtualenv path (default: /.venv) +# --uninstall Remove service instead of installing +# + +set -euo pipefail + +INSTALL_DIR="" +SERVICE_USER="gitea" +CONFIG_FILE="" +VENV_DIR="" +UNINSTALL=false + +# ── Parse args ────────────────────────────────────────────── +while [[ $# -gt 0 ]]; do + case "$1" in + --install-dir) INSTALL_DIR="$2"; shift 2 ;; + --user) SERVICE_USER="$2"; shift 2 ;; + --config) CONFIG_FILE="$2"; shift 2 ;; + --venv) VENV_DIR="$2"; shift 2 ;; + --uninstall) UNINSTALL=true; shift ;; + -h|--help) + grep -E '^#( |$)' "$0" | sed 's/^# \?//' + exit 0 + ;; + *) + echo "Unknown option: $1" >&2 + exit 1 + ;; + esac +done + +if [[ "$UNINSTALL" == true ]]; then + echo "Removing svn-mirror service..." + systemctl disable --now svn-mirror.service 2>/dev/null || true + rm -f /etc/systemd/system/svn-mirror.service + systemctl daemon-reload + echo "Done. Service removed." + exit 0 +fi + +if [[ -z "$INSTALL_DIR" ]]; then + echo "Error: --install-dir is required" >&2 + echo "Usage: sudo $0 --install-dir /opt/svn-git-server --user gitea" >&2 + exit 1 +fi + +# Resolve to absolute path +INSTALL_DIR="$(cd "$INSTALL_DIR" 2>/dev/null && pwd)" || { + echo "Error: install-dir '$INSTALL_DIR' does not exist" >&2 + exit 1 +} + +CONFIG_FILE="${CONFIG_FILE:-$INSTALL_DIR/config.yml}" +VENV_DIR="${VENV_DIR:-$INSTALL_DIR/.venv}" + +echo "=== svn-mirror install ===" +echo " Install dir: $INSTALL_DIR" +echo " User: $SERVICE_USER" +echo " Config: $CONFIG_FILE" +echo " Venv: $VENV_DIR" +echo "" + +# ── Checks ────────────────────────────────────────────────── +if [[ "$EUID" -ne 0 ]]; then + echo "Error: must run as root (use sudo)" >&2 + exit 1 +fi + +if ! id "$SERVICE_USER" &>/dev/null; then + echo "Error: user '$SERVICE_USER' does not exist" >&2 + exit 1 +fi + +if [[ ! -f "$CONFIG_FILE" ]]; then + echo "Warning: config file '$CONFIG_FILE' not found" + echo " You can create it later before starting the service." +fi + +if [[ ! -d "$VENV_DIR" ]]; then + echo "Creating virtualenv at $VENV_DIR ..." + python3 -m venv "$VENV_DIR" + chown -R "$SERVICE_USER":"$SERVICE_USER" "$VENV_DIR" + sudo -u "$SERVICE_USER" "$VENV_DIR/bin/pip" install --quiet --upgrade pip + sudo -u "$SERVICE_USER" "$VENV_DIR/bin/pip" install --quiet -r "$INSTALL_DIR/requirements.txt" + echo " Virtualenv created." +else + echo "Virtualenv already exists at $VENV_DIR" +fi + +# Make sure the install dir is owned by the service user +chown -R "$SERVICE_USER":"$SERVICE_USER" "$INSTALL_DIR" + +# ── Generate systemd unit ─────────────────────────────────── +SERVICE_UNIT="/etc/systemd/system/svn-mirror.service" + +cat > "$SERVICE_UNIT" <Git sync) +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +User=$SERVICE_USER +Group=$SERVICE_USER +WorkingDirectory=$INSTALL_DIR +ExecStart=$VENV_DIR/bin/python -m svn_mirror daemon --config $CONFIG_FILE +Restart=always +RestartSec=10 +StandardOutput=journal +StandardError=journal + +# Ensure UTF-8 locale for SVN with non-ASCII filenames +Environment=LC_ALL=en_US.UTF-8 +Environment=LANG=en_US.UTF-8 + +[Install] +WantedBy=multi-user.target +EOF + +echo "Created service file:" +echo " $SERVICE_UNIT" + +# ── Reload and enable ─────────────────────────────────────── +systemctl daemon-reload + +systemctl enable svn-mirror.service + +echo "" +echo "Service enabled. Start it with:" +echo " systemctl start svn-mirror" +echo "" +echo "Check logs with:" +echo " journalctl -u svn-mirror -f" +echo "" +echo "Status:" +echo " systemctl status svn-mirror"