#!/usr/bin/env bash # # volumen one-shot installer for Linux + systemd. # # Run from a cloned repository as root: # sudo ./install.sh # # The Ruby toolchain is installed automatically from the distro repositories on # Fedora and openEuler; on other distributions the script prints guidance and # expects Ruby >= 3.3 with a C toolchain to be present already. # # FreeBSD uses rc.d instead of systemd — see docs/deployment.md. set -euo pipefail VOLUMEN_USER="volumen" CONFIG_DIR="/etc/volumen" CONFIG_FILE="${CONFIG_DIR}/config.toml" DATA_DIR="/var/lib/volumen" CONTENT_DIR="${DATA_DIR}/posts" USERS_FILE="${DATA_DIR}/users.toml" SERVICE_FILE="/etc/systemd/system/volumen.service" MIN_RUBY="3.3" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" APP_DIR="${SCRIPT_DIR}" log() { printf '\033[1;34m==>\033[0m %s\n' "$*"; } warn() { printf '\033[1;33mWARN:\033[0m %s\n' "$*" >&2; } die() { printf '\033[1;31mERROR:\033[0m %s\n' "$*" >&2; exit 1; } require_root() { [ "$(id -u)" -eq 0 ] || die "Run as root: sudo ./install.sh" } detect_distro() { [ -r /etc/os-release ] || { printf 'unknown'; return; } # shellcheck disable=SC1091 . /etc/os-release printf '%s' "$(printf '%s' "${ID:-unknown}" | tr '[:upper:]' '[:lower:]')" } install_toolchain() { case "$1" in fedora) log "Installing Ruby toolchain via dnf (Fedora)…" dnf install -y ruby ruby-devel gcc gcc-c++ make redhat-rpm-config openssl-devel ;; openeuler) log "Installing Ruby toolchain via dnf (openEuler)…" dnf install -y ruby ruby-devel gcc gcc-c++ make openssl-devel ;; *) warn "Automatic toolchain install is wired only for Fedora and openEuler." cat >&2 <<'EOF' Install Ruby >= 3.3 and a C toolchain manually, then re-run this script: Debian/Ubuntu: apt install ruby-full build-essential libssl-dev Arch: pacman -S ruby base-devel openssl openSUSE: zypper install ruby ruby-devel gcc make libopenssl-devel EOF ;; esac } check_ruby() { command -v ruby >/dev/null 2>&1 || die "Ruby not found; install Ruby >= ${MIN_RUBY} and re-run." local version version="$(ruby -e 'print RUBY_VERSION')" if ! MIN="$MIN_RUBY" ruby -e 'exit(Gem::Version.new(RUBY_VERSION) >= Gem::Version.new(ENV["MIN"]))'; then die "Ruby ${version} is too old; volumen needs >= ${MIN_RUBY}." fi log "Ruby ${version} OK." } ensure_bundler() { if ! command -v bundle >/dev/null 2>&1; then log "Installing bundler…" gem install --no-document bundler fi } create_user() { if id "$VOLUMEN_USER" >/dev/null 2>&1; then log "User ${VOLUMEN_USER} already exists." else log "Creating system user ${VOLUMEN_USER}…" useradd --system --home "$DATA_DIR" --shell /usr/sbin/nologin "$VOLUMEN_USER" fi } create_dirs() { log "Creating ${CONFIG_DIR} and ${CONTENT_DIR}…" mkdir -p "$CONFIG_DIR" "$CONTENT_DIR" chown -R "$VOLUMEN_USER:$VOLUMEN_USER" "$DATA_DIR" } install_gems() { log "Installing gem dependencies…" ( cd "$APP_DIR" && bundle install ) } generate_config() { if [ -f "$CONFIG_FILE" ]; then log "Config ${CONFIG_FILE} already exists; leaving it untouched." return fi log "Generating ${CONFIG_FILE}…" ( cd "$APP_DIR" && bundle exec ruby -Ilib -rvolumen/config \ -e 'Volumen::Config.generate_default(ARGV[0])' "$CONFIG_FILE" ) sed -i 's/^host = .*/host = "127.0.0.1"/' "$CONFIG_FILE" sed -i "s#^content_dir = .*#content_dir = \"${CONTENT_DIR}\"#" "$CONFIG_FILE" sed -i "s#^users_file = .*#users_file = \"${USERS_FILE}\"#" "$CONFIG_FILE" chown "$VOLUMEN_USER:$VOLUMEN_USER" "$CONFIG_FILE" chmod 600 "$CONFIG_FILE" } install_service() { log "Installing systemd unit ${SERVICE_FILE}…" cat > "$SERVICE_FILE" <