[OCaml] High Intensity Training Online
refactor Consolidate setup scripts into one
Replace setup-root, fix-layout-root, and reset-srv-hito-root with a single setup.sh exposing install, deploy, and reset subcommands over shared building blocks. The one-time fix-layout corrective is dropped; reset supersedes it.
Changed files
deploy/fix-layout-root.sh
@@ -1,119 +0,0 @@
1
Removed:
#!/usr/bin/env bash
2
Removed:
# Corrective root script for the hito deploy layout.
3
Removed:
#
4
Removed:
# A manual seed nested shared/ and releases/ INSIDE the live release, so the
5
Removed:
# unit's /srv/hito/shared/hito.sqlite path vanished and SQLite could not open
6
Removed:
# the DB. This restores the intended sibling layout:
7
Removed:
#
8
Removed:
# /srv/hito/shared/{hito.sqlite,_opam} (never inside a release)
9
Removed:
# /srv/hito/releases/<ts>/ (the app tree)
10
Removed:
# /srv/hito/current -> releases/<ts>
11
Removed:
#
12
Removed:
# Run as root: sudo bash fix-layout-root.sh
13
Removed:
# Idempotent and conservative: it moves, never deletes, the database.
14
Removed:
set -euo pipefail
15
Removed:
16
Removed:
SRV=/srv/hito
17
Removed:
DEPLOY_USER=mpeter
18
Removed:
DEPLOY_GROUP=git
19
Removed:
20
Removed:
# The release that is currently live (resolve the symlink, strip trailing /).
21
Removed:
LIVE=$(readlink -f "$SRV/current")
22
Removed:
echo "live release: $LIVE"
23
Removed:
[ -d "$LIVE" ] || { echo "current does not resolve to a directory"; exit 1; }
24
Removed:
25
Removed:
echo "== 1. restore top-level shared/ =="
26
Removed:
mkdir -p "$SRV/shared"
27
Removed:
# Move the DB back to the top-level shared dir if it drifted into the release.
28
Removed:
if [ -f "$LIVE/shared/hito.sqlite" ] && [ ! -e "$SRV/shared/hito.sqlite" ]; then
29
Removed:
mv "$LIVE/shared/hito.sqlite" "$SRV/shared/hito.sqlite"
30
Removed:
echo " moved DB -> $SRV/shared/hito.sqlite"
31
Removed:
fi
32
Removed:
# Move the shared opam switch back up if it drifted into the release.
33
Removed:
if [ -d "$LIVE/shared/_opam" ] && [ ! -e "$SRV/shared/_opam" ]; then
34
Removed:
mv "$LIVE/shared/_opam" "$SRV/shared/_opam"
35
Removed:
echo " moved shared switch -> $SRV/shared/_opam"
36
Removed:
fi
37
Removed:
38
Removed:
echo "== 2. relocate the live release under releases/ =="
39
Removed:
mkdir -p "$SRV/releases"
40
Removed:
# Drop the nested shared/ and releases/ that the manual seed pulled in.
41
Removed:
rm -rf "$LIVE/shared" "$LIVE/releases"
42
Removed:
base=$(basename "$LIVE")
43
Removed:
if [ "$(dirname "$LIVE")" != "$SRV/releases" ]; then
44
Removed:
mv "$LIVE" "$SRV/releases/$base"
45
Removed:
LIVE="$SRV/releases/$base"
46
Removed:
echo " moved release -> $LIVE"
47
Removed:
fi
48
Removed:
49
Removed:
echo "== 3. ownership and current symlink =="
50
Removed:
chown -R "$DEPLOY_USER:$DEPLOY_GROUP" "$SRV/shared" "$SRV/releases"
51
Removed:
ln -sfn "$LIVE" "$SRV/current.tmp"
52
Removed:
mv -T "$SRV/current.tmp" "$SRV/current"
53
Removed:
chown -h "$DEPLOY_USER:$DEPLOY_GROUP" "$SRV/current"
54
Removed:
echo " current -> $LIVE"
55
Removed:
56
Removed:
echo "== 4. wire DB into the release and reinstall the corrected hook =="
57
Removed:
ln -sfn "$SRV/shared/hito.sqlite" "$LIVE/hito.sqlite"
58
Removed:
install -o "$DEPLOY_USER" -g "$DEPLOY_GROUP" -m 0755 \
59
Removed:
"$(dirname "$0")/post-receive" /srv/git/hito.git/hooks/post-receive
60
Removed:
61
Removed:
echo "== 5. remove the obsolete top-level working clone =="
62
Removed:
# /srv/hito must contain only shared/, releases/, and current. A pre-pipeline
63
Removed:
# in-place clone still lives at the top level and makes dune see the hito
64
Removed:
# package twice (top-level dune-project AND current/dune-project). Its content
65
Removed:
# is fully preserved in the bare repo and in every release, and the only unique
66
Removed:
# runtime state (the DB) is already in shared/. Remove ONLY known clone
67
Removed:
# entries; never touch shared/, releases/, or current.
68
Removed:
for entry in ARCHITECTURE.org RAIL.org REQUESTS.org bin lib test site \
69
Removed:
dune dune-project hito.opam hito.sqlite LICENSE \
70
Removed:
_build .git .gitignore .ocamlformat .envrc .cache .kiro; do
71
Removed:
target="$SRV/$entry"
72
Removed:
if [ -e "$target" ] || [ -L "$target" ]; then
73
Removed:
rm -rf "$target"
74
Removed:
echo " removed $target"
75
Removed:
fi
76
Removed:
done
77
Removed:
# Guard: the three managed entries must survive.
78
Removed:
for keep in shared releases current; do
79
Removed:
[ -e "$SRV/$keep" ] || { echo "FATAL: $SRV/$keep missing after cleanup"; exit 1; }
80
Removed:
done
81
Removed:
82
Removed:
echo "== 6. deploy master as a fresh release, built on the shared switch =="
83
Removed:
# Build in a staging dir OUTSIDE /srv/hito so dune's upward project-root search
84
Removed:
# never sees the current symlink or any sibling release (which would make the
85
Removed:
# hito package appear twice). Move the built tree into releases/ only after a
86
Removed:
# clean build, then flip current.
87
Removed:
NEW_TS=$(date -u +"%Y-%m-%dT%H-%M-%SZ")
88
Removed:
NEW_REL="$SRV/releases/$NEW_TS"
89
Removed:
STAGE=$(sudo -u "$DEPLOY_USER" mktemp -d "/tmp/hito-stage.XXXXXX")
90
Removed:
sha=$(git --git-dir=/srv/git/hito.git rev-parse refs/heads/master)
91
Removed:
git --git-dir=/srv/git/hito.git archive "$sha" | tar -x -C "$STAGE"
92
Removed:
chown -R "$DEPLOY_USER:$DEPLOY_GROUP" "$STAGE"
93
Removed:
sudo -u "$DEPLOY_USER" -H bash -lc "
94
Removed:
set -euo pipefail
95
Removed:
export OPAMROOT=/home/$DEPLOY_USER/.opam
96
Removed:
cd '$STAGE'
97
Removed:
eval \"\$(opam env --switch='$SRV/shared' --set-switch)\"
98
Removed:
opam install . --deps-only --with-test -y
99
Removed:
dune build @check
100
Removed:
dune runtest
101
Removed:
dune build
102
Removed:
"
103
Removed:
# Publish the built tree as the new release.
104
Removed:
mkdir -p "$SRV/releases"
105
Removed:
mv "$STAGE" "$NEW_REL"
106
Removed:
ln -sfn "$SRV/shared/hito.sqlite" "$NEW_REL/hito.sqlite"
107
Removed:
chown -R "$DEPLOY_USER:$DEPLOY_GROUP" "$NEW_REL"
108
Removed:
ln -sfn "$NEW_REL" "$SRV/current.tmp"
109
Removed:
mv -T "$SRV/current.tmp" "$SRV/current"
110
Removed:
chown -h "$DEPLOY_USER:$DEPLOY_GROUP" "$SRV/current"
111
Removed:
echo " current -> $NEW_REL (master ${sha:0:12})"
112
Removed:
113
Removed:
echo "== 7. restart =="
114
Removed:
systemctl restart hito
115
Removed:
sleep 1
116
Removed:
systemctl is-active hito && echo "hito is active" || {
117
Removed:
echo "still failing; recent journal:"; journalctl -u hito -n 15 --no-pager; exit 1;
118
Removed:
}
119
Removed:
echo "Done. /srv/hito holds shared/, releases/, current; live release is master."
deploy/reset-srv-hito-root.sh
@@ -1,114 +0,0 @@
1
Removed:
#!/usr/bin/env bash
2
Removed:
# Full reset of /srv/hito to the clean release layout.
3
Removed:
#
4
Removed:
# Wipes everything under /srv/hito EXCEPT the database and the shared opam
5
Removed:
# switch, which are preserved (the DB is the only unique runtime state; the
6
Removed:
# switch is expensive to rebuild). Result:
7
Removed:
#
8
Removed:
# /srv/hito/shared/{hito.sqlite,_opam}
9
Removed:
# /srv/hito/releases/<ts>/ (master, freshly built)
10
Removed:
# /srv/hito/current -> releases/<ts>
11
Removed:
#
12
Removed:
# Run as root: sudo bash reset-srv-hito-root.sh
13
Removed:
set -euo pipefail
14
Removed:
15
Removed:
SRV=/srv/hito
16
Removed:
DEPLOY_USER=mpeter
17
Removed:
DEPLOY_GROUP=git
18
Removed:
BARE=/srv/git/hito.git
19
Removed:
DB="$SRV/shared/hito.sqlite"
20
Removed:
SWITCH="$SRV/shared/_opam"
21
Removed:
22
Removed:
[ -f "$DB" ] || { echo "FATAL: database not found at $DB; aborting before any wipe"; exit 1; }
23
Removed:
24
Removed:
echo "== 1. stop the service =="
25
Removed:
systemctl stop hito || true
26
Removed:
27
Removed:
echo "== 2. back up and set aside the database and shared switch =="
28
Removed:
STASH=$(mktemp -d /root/hito-reset-stash.XXXXXX)
29
Removed:
cp -a "$DB" "$STASH/hito.sqlite" # safety copy
30
Removed:
echo " DB backed up to $STASH/hito.sqlite"
31
Removed:
mv "$DB" "$STASH/hito.sqlite.live"
32
Removed:
[ -d "$SWITCH" ] && mv "$SWITCH" "$STASH/_opam" && echo " switch set aside"
33
Removed:
34
Removed:
echo "== 3. wipe everything under /srv/hito (contents only, keep the dir) =="
35
Removed:
# Remove all entries, including dotfiles, without following into the stash.
36
Removed:
find "$SRV" -mindepth 1 -maxdepth 1 -exec rm -rf {} +
37
Removed:
echo " /srv/hito emptied"
38
Removed:
39
Removed:
echo "== 4. rebuild the clean skeleton =="
40
Removed:
mkdir -p "$SRV/shared" "$SRV/releases"
41
Removed:
mv "$STASH/hito.sqlite.live" "$DB"
42
Removed:
[ -d "$STASH/_opam" ] && mv "$STASH/_opam" "$SWITCH"
43
Removed:
chown -R "$DEPLOY_USER:$DEPLOY_GROUP" "$SRV/shared" "$SRV/releases"
44
Removed:
echo " restored shared/ (DB + switch) and empty releases/"
45
Removed:
46
Removed:
echo "== 5. deploy master as the first clean release =="
47
Removed:
# Build in a staging dir OUTSIDE /srv/hito so dune's project-root search never
48
Removed:
# sees current or a sibling release. Publish only after a clean build.
49
Removed:
start=$SECONDS
50
Removed:
TS=$(date -u +"%Y-%m-%dT%H-%M-%SZ")
51
Removed:
REL="$SRV/releases/$TS"
52
Removed:
STAGE=$(sudo -u "$DEPLOY_USER" mktemp -d /tmp/hito-stage.XXXXXX)
53
Removed:
sha=$(git --git-dir="$BARE" rev-parse refs/heads/master)
54
Removed:
git --git-dir="$BARE" archive "$sha" | tar -x -C "$STAGE"
55
Removed:
chown -R "$DEPLOY_USER:$DEPLOY_GROUP" "$STAGE"
56
Removed:
sudo -u "$DEPLOY_USER" -H bash -lc "
57
Removed:
set -euo pipefail
58
Removed:
export OPAMROOT=/home/$DEPLOY_USER/.opam
59
Removed:
cd '$STAGE'
60
Removed:
eval \"\$(opam env --switch='$SRV/shared' --set-switch)\"
61
Removed:
opam install . --deps-only --with-test -y 2>&1 | tee deploy.log
62
Removed:
dune build @check 2>&1 | tee -a deploy.log
63
Removed:
dune runtest 2>&1 | tee -a deploy.log
64
Removed:
dune build 2>&1 | tee -a deploy.log
65
Removed:
"
66
Removed:
build_secs=$((SECONDS - start))
67
Removed:
mv "$STAGE" "$REL"
68
Removed:
ln -sfn "$SRV/shared/hito.sqlite" "$REL/hito.sqlite"
69
Removed:
70
Removed:
# Deploy metadata, matching the hook: provenance in the release and a durable
71
Removed:
# history line under shared/.
72
Removed:
subject=$(git --git-dir="$BARE" log -1 --format=%s "$sha")
73
Removed:
cat >"$REL/deploy-info.json" <<JSON
74
Removed:
{
75
Removed:
"commit": "$sha",
76
Removed:
"subject": $(printf '%s' "$subject" | sed 's/\\/\\\\/g; s/"/\\"/g; s/.*/"&"/'),
77
Removed:
"branch": "master",
78
Removed:
"deployed_at": "$TS",
79
Removed:
"build_seconds": $build_secs,
80
Removed:
"release": "$REL"
81
Removed:
}
82
Removed:
JSON
83
Removed:
printf '%s\t%s\t%ss\t%s\t%s\n' \
84
Removed:
"$TS" "${sha:0:12}" "$build_secs" "master" "$subject" \
85
Removed:
>>"$SRV/shared/deploy-history.tsv"
86
Removed:
87
Removed:
chown -R "$DEPLOY_USER:$DEPLOY_GROUP" "$REL"
88
Removed:
chown "$DEPLOY_USER:$DEPLOY_GROUP" "$SRV/shared/deploy-history.tsv"
89
Removed:
ln -sfn "$REL" "$SRV/current.tmp"
90
Removed:
mv -T "$SRV/current.tmp" "$SRV/current"
91
Removed:
chown -h "$DEPLOY_USER:$DEPLOY_GROUP" "$SRV/current"
92
Removed:
echo " current -> $REL (master ${sha:0:12}, built in ${build_secs}s)"
93
Removed:
94
Removed:
echo "== 6. start the service and health-check =="
95
Removed:
systemctl start hito
96
Removed:
HEALTH_URL="http://127.0.0.1:8080/login"
97
Removed:
healthy=false
98
Removed:
for _ in $(seq 1 10); do
99
Removed:
if curl -sf -o /dev/null --max-time 3 "$HEALTH_URL"; then healthy=true; break; fi
100
Removed:
sleep 1
101
Removed:
done
102
Removed:
if $healthy; then
103
Removed:
echo " hito is healthy at $HEALTH_URL"
104
Removed:
else
105
Removed:
echo " FAILED health check; recent journal:"
106
Removed:
journalctl -u hito -n 15 --no-pager
107
Removed:
exit 1
108
Removed:
fi
109
Removed:
110
Removed:
echo
111
Removed:
echo "Done. /srv/hito now holds only shared/, releases/, current."
112
Removed:
echo "Safety backup of the DB remains at $STASH/hito.sqlite"
113
Removed:
echo "Remove it once you have confirmed the app works: rm -rf $STASH"
114
Removed:
ls -la "$SRV"
deploy/setup-root.sh
@@ -1,69 +0,0 @@
1
Removed:
#!/usr/bin/env bash
2
Removed:
# One-time root setup for the hito push-to-deploy pipeline on the VPS.
3
Removed:
# Run as root: sudo bash setup-root.sh
4
Removed:
#
5
Removed:
# Idempotent: safe to re-run. It does not touch the live release or the
6
Removed:
# database beyond moving the DB once into the shared directory.
7
Removed:
set -euo pipefail
8
Removed:
9
Removed:
DEPLOY_USER=mpeter
10
Removed:
DEPLOY_GROUP=git
11
Removed:
SRV=/srv/hito
12
Removed:
BARE=/srv/git/hito.git
13
Removed:
UNIT=/etc/systemd/system/hito.service
14
Removed:
SUDOERS=/etc/sudoers.d/hito-deploy
15
Removed:
SHARED="$SRV/shared"
16
Removed:
RELEASES="$SRV/releases"
17
Removed:
18
Removed:
echo "== 1. release and shared directories =="
19
Removed:
mkdir -p "$RELEASES" "$SHARED"
20
Removed:
# Move the live database under shared/ exactly once. The unit is edited below
21
Removed:
# to read it from there, so a new release never orphans the data.
22
Removed:
if [ -f "$SRV/hito.sqlite" ] && [ ! -e "$SHARED/hito.sqlite" ]; then
23
Removed:
mv "$SRV/hito.sqlite" "$SHARED/hito.sqlite"
24
Removed:
echo " moved hito.sqlite -> $SHARED/hito.sqlite"
25
Removed:
fi
26
Removed:
chown -R "$DEPLOY_USER:$DEPLOY_GROUP" "$RELEASES" "$SHARED"
27
Removed:
28
Removed:
echo "== 2. shared opam switch (matches existing 5.5.0) =="
29
Removed:
# Built once as the deploy user, reused by every release unless hito.opam
30
Removed:
# changes. Kept outside releases so pruning a release never deletes it.
31
Removed:
if [ ! -d "$SHARED/_opam" ]; then
32
Removed:
sudo -u "$DEPLOY_USER" -H bash -lc "
33
Removed:
export OPAMROOT=/home/$DEPLOY_USER/.opam
34
Removed:
opam switch create '$SHARED' ocaml-base-compiler.5.5.0 --no-install -y
35
Removed:
"
36
Removed:
echo " created shared switch at $SHARED/_opam"
37
Removed:
else
38
Removed:
echo " shared switch already present"
39
Removed:
fi
40
Removed:
41
Removed:
echo "== 3. post-receive hook =="
42
Removed:
install -o "$DEPLOY_USER" -g "$DEPLOY_GROUP" -m 0755 \
43
Removed:
"$(dirname "$0")/post-receive" "$BARE/hooks/post-receive"
44
Removed:
echo " installed $BARE/hooks/post-receive"
45
Removed:
46
Removed:
echo "== 4. scoped sudoers for restart =="
47
Removed:
cat > "$SUDOERS" <<SUDO
48
Removed:
$DEPLOY_USER ALL=(root) NOPASSWD: /usr/bin/systemctl restart hito
49
Removed:
SUDO
50
Removed:
chmod 0440 "$SUDOERS"
51
Removed:
visudo -c -f "$SUDOERS"
52
Removed:
53
Removed:
echo "== 5. systemd unit -> current/ =="
54
Removed:
# Point ExecStart and WorkingDirectory at the current symlink, read the DB
55
Removed:
# from shared/, and keep the existing hardening (ReadWritePaths already /srv/hito).
56
Removed:
cp -a "$UNIT" "$UNIT.bak.$(date +%s)"
57
Removed:
sed -i \
58
Removed:
-e 's#^ExecStart=.*#ExecStart=/srv/hito/current/_build/default/bin/main.exe#' \
59
Removed:
-e 's#^WorkingDirectory=.*#WorkingDirectory=/srv/hito/current#' \
60
Removed:
-e 's#^Environment=HITO_DB=.*#Environment=HITO_DB=sqlite3:/srv/hito/shared/hito.sqlite#' \
61
Removed:
"$UNIT"
62
Removed:
systemctl daemon-reload
63
Removed:
echo " unit updated (backup kept alongside)."
64
Removed:
65
Removed:
echo
66
Removed:
echo "Done. The service still runs the old in-place build until the first"
67
Removed:
echo "successful push flips /srv/hito/current. To go live now without a push:"
68
Removed:
echo " 1) su - $DEPLOY_USER and run deploy/first-release.sh (creates current/)"
69
Removed:
echo " 2) sudo systemctl restart hito"
deploy/setup.sh
@@ -0,0 +1,208 @@
1
Added:
#!/usr/bin/env bash
2
Added:
# hito deployment setup — one root script, three subcommands.
3
Added:
#
4
Added:
# sudo bash setup.sh install One-time host setup: shared switch, hook,
5
Added:
# scoped sudoers, and systemd unit pointed at
6
Added:
# current/. Idempotent. Does NOT create a
7
Added:
# release; the first push (or `deploy`) does.
8
Added:
#
9
Added:
# sudo bash setup.sh deploy Build master as a fresh release on the shared
10
Added:
# switch and flip current. Health-checks and
11
Added:
# rolls back on failure. Use to go live without
12
Added:
# a push, or after `install`.
13
Added:
#
14
Added:
# sudo bash setup.sh reset Wipe /srv/hito to the clean layout, preserving
15
Added:
# the database and the shared switch, then run
16
Added:
# `deploy`. Destructive: everything else under
17
Added:
# /srv/hito is removed.
18
Added:
#
19
Added:
# The hook (post-receive) beside this script is the per-push equivalent of
20
Added:
# `deploy`; `install` copies it into the bare repo.
21
Added:
set -euo pipefail
22
Added:
23
Added:
DEPLOY_USER=mpeter
24
Added:
DEPLOY_GROUP=git
25
Added:
SRV=/srv/hito
26
Added:
BARE=/srv/git/hito.git
27
Added:
UNIT=/etc/systemd/system/hito.service
28
Added:
SUDOERS=/etc/sudoers.d/hito-deploy
29
Added:
SHARED="$SRV/shared"
30
Added:
RELEASES="$SRV/releases"
31
Added:
DB="$SHARED/hito.sqlite"
32
Added:
SWITCH="$SHARED/_opam"
33
Added:
OCAML_COMPILER=ocaml-base-compiler.5.5.0
34
Added:
HEALTH_URL="http://127.0.0.1:8080/login"
35
Added:
HERE=$(cd "$(dirname "$0")" && pwd)
36
Added:
37
Added:
require_root() { [ "$(id -u)" -eq 0 ] || { echo "run as root"; exit 1; }; }
38
Added:
39
Added:
# --- shared building blocks -------------------------------------------------
40
Added:
41
Added:
ensure_switch() {
42
Added:
if [ ! -d "$SWITCH" ]; then
43
Added:
echo " creating shared switch ($OCAML_COMPILER)"
44
Added:
sudo -u "$DEPLOY_USER" -H bash -lc "
45
Added:
export OPAMROOT=/home/$DEPLOY_USER/.opam
46
Added:
opam switch create '$SHARED' '$OCAML_COMPILER' --no-install -y
47
Added:
"
48
Added:
else
49
Added:
echo " shared switch present"
50
Added:
fi
51
Added:
}
52
Added:
53
Added:
install_hook() {
54
Added:
install -o "$DEPLOY_USER" -g "$DEPLOY_GROUP" -m 0755 \
55
Added:
"$HERE/post-receive" "$BARE/hooks/post-receive"
56
Added:
echo " installed $BARE/hooks/post-receive"
57
Added:
}
58
Added:
59
Added:
install_sudoers() {
60
Added:
cat >"$SUDOERS" <<SUDO
61
Added:
$DEPLOY_USER ALL=(root) NOPASSWD: /usr/bin/systemctl restart hito
62
Added:
SUDO
63
Added:
chmod 0440 "$SUDOERS"
64
Added:
visudo -c -f "$SUDOERS" >/dev/null && echo " sudoers valid"
65
Added:
}
66
Added:
67
Added:
point_unit_at_current() {
68
Added:
cp -a "$UNIT" "$UNIT.bak.$(date +%s)"
69
Added:
sed -i \
70
Added:
-e 's#^ExecStart=.*#ExecStart=/srv/hito/current/_build/default/bin/main.exe#' \
71
Added:
-e 's#^WorkingDirectory=.*#WorkingDirectory=/srv/hito/current#' \
72
Added:
-e 's#^Environment=HITO_DB=.*#Environment=HITO_DB=sqlite3:/srv/hito/shared/hito.sqlite#' \
73
Added:
"$UNIT"
74
Added:
systemctl daemon-reload
75
Added:
echo " unit points at current/ (backup kept alongside)"
76
Added:
}
77
Added:
78
Added:
# Build master in a staging dir OUTSIDE /srv/hito (so dune's project-root search
79
Added:
# never sees current or a sibling release), publish it, flip current, restart,
80
Added:
# health-check, and roll back on failure. Records deploy metadata.
81
Added:
build_and_flip() {
82
Added:
local start ts rel stage sha subject build_secs prev
83
Added:
start=$SECONDS
84
Added:
ts=$(date -u +"%Y-%m-%dT%H-%M-%SZ")
85
Added:
rel="$RELEASES/$ts"
86
Added:
prev=$(readlink -f "$SRV/current" 2>/dev/null || true)
87
Added:
sha=$(git --git-dir="$BARE" rev-parse refs/heads/master)
88
Added:
stage=$(sudo -u "$DEPLOY_USER" mktemp -d /tmp/hito-stage.XXXXXX)
89
Added:
90
Added:
echo " building master ${sha:0:12}"
91
Added:
git --git-dir="$BARE" archive "$sha" | tar -x -C "$stage"
92
Added:
chown -R "$DEPLOY_USER:$DEPLOY_GROUP" "$stage"
93
Added:
sudo -u "$DEPLOY_USER" -H bash -lc "
94
Added:
set -euo pipefail
95
Added:
export OPAMROOT=/home/$DEPLOY_USER/.opam
96
Added:
cd '$stage'
97
Added:
eval \"\$(opam env --switch='$SHARED' --set-switch)\"
98
Added:
opam install . --deps-only --with-test -y 2>&1 | tee deploy.log
99
Added:
dune build @check 2>&1 | tee -a deploy.log
100
Added:
dune runtest 2>&1 | tee -a deploy.log
101
Added:
dune build 2>&1 | tee -a deploy.log
102
Added:
"
103
Added:
build_secs=$((SECONDS - start))
104
Added:
105
Added:
mkdir -p "$RELEASES"
106
Added:
mv "$stage" "$rel"
107
Added:
ln -sfn "$DB" "$rel/hito.sqlite"
108
Added:
109
Added:
subject=$(git --git-dir="$BARE" log -1 --format=%s "$sha")
110
Added:
cat >"$rel/deploy-info.json" <<JSON
111
Added:
{
112
Added:
"commit": "$sha",
113
Added:
"subject": $(printf '%s' "$subject" | sed 's/\\/\\\\/g; s/"/\\"/g; s/.*/"&"/'),
114
Added:
"branch": "master",
115
Added:
"deployed_at": "$ts",
116
Added:
"build_seconds": $build_secs,
117
Added:
"release": "$rel"
118
Added:
}
119
Added:
JSON
120
Added:
printf '%s\t%s\t%ss\t%s\t%s\n' \
121
Added:
"$ts" "${sha:0:12}" "$build_secs" "master" "$subject" \
122
Added:
>>"$SHARED/deploy-history.tsv"
123
Added:
124
Added:
chown -R "$DEPLOY_USER:$DEPLOY_GROUP" "$rel"
125
Added:
chown "$DEPLOY_USER:$DEPLOY_GROUP" "$SHARED/deploy-history.tsv"
126
Added:
ln -sfn "$rel" "$SRV/current.tmp"
127
Added:
mv -T "$SRV/current.tmp" "$SRV/current"
128
Added:
chown -h "$DEPLOY_USER:$DEPLOY_GROUP" "$SRV/current"
129
Added:
echo " current -> $rel (built in ${build_secs}s)"
130
Added:
131
Added:
systemctl restart hito
132
Added:
if health_ok; then
133
Added:
echo " healthy at $HEALTH_URL"
134
Added:
elif [ -n "$prev" ] && [ -d "$prev" ]; then
135
Added:
echo " health check failed; rolling back to $prev"
136
Added:
ln -sfn "$prev" "$SRV/current.tmp"
137
Added:
mv -T "$SRV/current.tmp" "$SRV/current"
138
Added:
systemctl restart hito || true
139
Added:
echo " rolled back; recent journal:"; journalctl -u hito -n 15 --no-pager
140
Added:
exit 1
141
Added:
else
142
Added:
echo " health check failed and no previous release; journal:"
143
Added:
journalctl -u hito -n 15 --no-pager; exit 1
144
Added:
fi
145
Added:
}
146
Added:
147
Added:
health_ok() {
148
Added:
local i
149
Added:
for i in $(seq 1 10); do
150
Added:
curl -sf -o /dev/null --max-time 3 "$HEALTH_URL" && return 0
151
Added:
sleep 1
152
Added:
done
153
Added:
return 1
154
Added:
}
155
Added:
156
Added:
# --- subcommands ------------------------------------------------------------
157
Added:
158
Added:
cmd_install() {
159
Added:
echo "== shared and releases directories =="
160
Added:
mkdir -p "$RELEASES" "$SHARED"
161
Added:
# Adopt a pre-existing in-place DB exactly once.
162
Added:
if [ -f "$SRV/hito.sqlite" ] && [ ! -e "$DB" ]; then
163
Added:
mv "$SRV/hito.sqlite" "$DB"; echo " adopted existing hito.sqlite -> $DB"
164
Added:
fi
165
Added:
chown -R "$DEPLOY_USER:$DEPLOY_GROUP" "$RELEASES" "$SHARED"
166
Added:
echo "== shared opam switch =="; ensure_switch
167
Added:
echo "== post-receive hook =="; install_hook
168
Added:
echo "== scoped sudoers =="; install_sudoers
169
Added:
echo "== systemd unit =="; point_unit_at_current
170
Added:
echo
171
Added:
echo "Done. Run 'sudo bash setup.sh deploy' to build the first release,"
172
Added:
echo "or push master to trigger the hook."
173
Added:
}
174
Added:
175
Added:
cmd_deploy() {
176
Added:
[ -d "$SWITCH" ] || { echo "FATAL: no shared switch; run 'install' first"; exit 1; }
177
Added:
echo "== deploy master =="; build_and_flip
178
Added:
}
179
Added:
180
Added:
cmd_reset() {
181
Added:
[ -f "$DB" ] || { echo "FATAL: no database at $DB; aborting before wipe"; exit 1; }
182
Added:
echo "== stop service =="; systemctl stop hito || true
183
Added:
echo "== stash DB and switch =="
184
Added:
local stash; stash=$(mktemp -d /root/hito-reset-stash.XXXXXX)
185
Added:
cp -a "$DB" "$stash/hito.sqlite" # safety copy, never removed by us
186
Added:
mv "$DB" "$stash/hito.sqlite.live"
187
Added:
[ -d "$SWITCH" ] && mv "$SWITCH" "$stash/_opam"
188
Added:
echo " DB backup at $stash/hito.sqlite"
189
Added:
echo "== wipe /srv/hito contents =="
190
Added:
find "$SRV" -mindepth 1 -maxdepth 1 -exec rm -rf {} +
191
Added:
echo "== rebuild skeleton =="
192
Added:
mkdir -p "$SHARED" "$RELEASES"
193
Added:
mv "$stash/hito.sqlite.live" "$DB"
194
Added:
[ -d "$stash/_opam" ] && mv "$stash/_opam" "$SWITCH"
195
Added:
chown -R "$DEPLOY_USER:$DEPLOY_GROUP" "$SHARED" "$RELEASES"
196
Added:
ensure_switch
197
Added:
echo "== deploy master =="; build_and_flip
198
Added:
echo
199
Added:
echo "Done. Safety DB backup remains at $stash/hito.sqlite (remove when confident)."
200
Added:
}
201
Added:
202
Added:
require_root
203
Added:
case "${1:-}" in
204
Added:
install) cmd_install ;;
205
Added:
deploy) cmd_deploy ;;
206
Added:
reset) cmd_reset ;;
207
Added:
*) echo "usage: sudo bash setup.sh {install|deploy|reset}"; exit 2 ;;
208
Added:
esac