Files
eco/scripts/eco-docs-install-user-service
Henrik Lemke 276aa974d2 eco-docs: build from a checkout owned by another account; units wait for /sf at boot
A local source checkout (the shared gac-bernina one) is owned by another
account, which git refuses as dubious ownership: allow exactly that
directory per command and clone with --no-local.

The units now wait for the launcher on /sf before exec'ing it and never stop
retrying - at boot /sf can still be missing, which is how the status
server's user unit on saresb-cons-04 failed with 203/EXEC and gave up.
2026-10-25 14:36:05 +01:00

147 lines
4.4 KiB
Bash
Executable File

#!/bin/bash
# Install the eco documentation site as *user* systemd units on this host:
#
# eco-docs.service serves the current build (python -m http.server)
# eco-docs-build.service one rebuild (fetch, sphinx-build, atomic swap)
# eco-docs-build.timer runs that rebuild periodically
#
# Same approach as eco-status-server-install-user-service: no root needed,
# runs as the invoking account (whose git credentials fetch the repository).
# Both units just call `eco-docs`, so the interactive command and the
# service run exactly the same thing.
set -euo pipefail
SELF_DIR="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)"
LAUNCHER="${ECO_DOCS_LAUNCHER:-$SELF_DIR/eco-docs}"
UNIT_DIR="$HOME/.config/systemd/user"
ENV_FILE="${ECO_DOCS_ENV:-$HOME/.config/eco-docs.env}"
INTERVAL="15min"
usage() {
cat <<EOF
usage: $(basename "$0") [--launcher PATH] [--env-file PATH] [--interval 15min] [--force]
Writes:
$UNIT_DIR/eco-docs.service
$UNIT_DIR/eco-docs-build.service
$UNIT_DIR/eco-docs-build.timer
and, if it does not exist yet, a template environment file at
$ENV_FILE
Then prints the commands to do the first build and start everything.
EOF
}
FORCE=0
while [ $# -gt 0 ]; do
case "$1" in
--launcher) LAUNCHER="$2"; shift 2 ;;
--env-file) ENV_FILE="$2"; shift 2 ;;
--interval) INTERVAL="$2"; shift 2 ;;
--force) FORCE=1; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "unknown option: $1" >&2; usage; exit 2 ;;
esac
done
[ -x "$LAUNCHER" ] || { echo "launcher not executable: $LAUNCHER" >&2; exit 1; }
mkdir -p "$UNIT_DIR" "$(dirname "$ENV_FILE")"
if [ ! -e "$ENV_FILE" ]; then
{
echo "# Environment for the eco docs site (systemd EnvironmentFile"
echo "# syntax: KEY=value, no export, no shell expansion). Edit to taste."
"$LAUNCHER" config
} > "$ENV_FILE"
echo "wrote template $ENV_FILE - check it before starting the services"
else
echo "keeping existing $ENV_FILE"
fi
for unit in eco-docs.service eco-docs-build.service eco-docs-build.timer; do
if [ -e "$UNIT_DIR/$unit" ] && [ "$FORCE" -eq 0 ]; then
echo "$UNIT_DIR/$unit already exists; re-run with --force to overwrite" >&2
exit 1
fi
done
cat > "$UNIT_DIR/eco-docs.service" <<EOF
[Unit]
Description=eco documentation site (static HTTP server)
After=network-online.target
Wants=network-online.target
# Never give up restarting: a docs site that stays down after a hiccup
# helps nobody, and a restart costs nothing.
StartLimitIntervalSec=0
[Service]
Type=simple
EnvironmentFile=$ENV_FILE
# The launcher usually lives on /sf (NFS), which can still be missing when
# user services start at boot; exec'ing it then fails with 203/EXEC and the
# unit gives up after its start limit. Wait for it instead (up to 10 min).
ExecStartPre=/usr/bin/timeout 600 /bin/sh -c 'until [ -x "$LAUNCHER" ]; do sleep 5; done'
TimeoutStartSec=11min
ExecStart=$LAUNCHER serve
Restart=on-failure
RestartSec=30
[Install]
WantedBy=default.target
EOF
cat > "$UNIT_DIR/eco-docs-build.service" <<EOF
[Unit]
Description=eco documentation site: fetch and rebuild if changed
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
EnvironmentFile=$ENV_FILE
# The launcher usually lives on /sf (NFS), which can still be missing when
# user services start at boot; exec'ing it then fails with 203/EXEC and the
# unit gives up after its start limit. Wait for it instead (up to 10 min).
ExecStartPre=/usr/bin/timeout 600 /bin/sh -c 'until [ -x "$LAUNCHER" ]; do sleep 5; done'
TimeoutStartSec=11min
ExecStart=$LAUNCHER build
# A full build takes a minute or two; be gentle on a shared console.
Nice=10
EOF
cat > "$UNIT_DIR/eco-docs-build.timer" <<EOF
[Unit]
Description=eco documentation site: periodic rebuild
[Timer]
OnBootSec=2min
OnUnitActiveSec=$INTERVAL
Persistent=true
[Install]
WantedBy=timers.target
EOF
echo "wrote eco-docs.service, eco-docs-build.service, eco-docs-build.timer in $UNIT_DIR"
cat <<EOF
Next steps:
# let the services keep running when you are not logged in
loginctl enable-linger $USER
# sphinx & co. present in the configured python? (else: pip install -r docs/requirements.txt)
$LAUNCHER check
# first build by hand, so problems show up right here
$LAUNCHER build
systemctl --user daemon-reload
systemctl --user enable --now eco-docs.service eco-docs-build.timer
$LAUNCHER status
# logs
journalctl --user -u eco-docs -u eco-docs-build -f
EOF