diff --git a/.gitea/workflows/docs.yml b/.gitea/workflows/docs.yml
index 0a33ea6..0ae5138 100644
--- a/.gitea/workflows/docs.yml
+++ b/.gitea/workflows/docs.yml
@@ -16,35 +16,15 @@ jobs:
steps:
- uses: actions/checkout@v4
- - name: Write the channel switcher
- run: |
- cat > "${{ gitea.workspace }}/docs-banner.html" <<'HTML'
-
- HTML
-
- name: Build the API docs
env:
- RUSTDOCFLAGS: "--html-before-content ${{ gitea.workspace }}/docs-banner.html"
+ RUSTDOCFLAGS: "--html-before-content ${{ gitea.workspace }}/scripts/docs-banner.html"
run: |
pixi install --locked
pixi run doc-build
- - name: Redirect the channel root to the crate page
- run: |
- printf '%s\n' "" > target/doc/index.html
+ - name: Flatten so the crate sits at the channel root
+ run: bash scripts/flatten-docs.sh
- name: Publish the channel to /srv/www
run: |
@@ -52,16 +32,7 @@ jobs:
refs/tags/*) channel=release ;;
*) channel=nightly ;;
esac
- dest="/srv/www/${SITE_SLUG}/${channel}"
- mkdir -p "$dest"
- rsync -a --delete "target/doc/" "$dest/"
+ bash scripts/publish-docs.sh "$channel"
- name: Point the site root at the latest release, else nightly
- run: |
- root="/srv/www/${SITE_SLUG}"
- if [ -d "$root/release/${CRATE}" ]; then
- target="release/${CRATE}/"
- else
- target="nightly/${CRATE}/"
- fi
- printf '%s\n' "" > "$root/index.html"
+ run: bash scripts/redirect-docs.sh
diff --git a/scripts/flatten-docs.sh b/scripts/flatten-docs.sh
new file mode 100755
index 0000000..6f5dd34
--- /dev/null
+++ b/scripts/flatten-docs.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+# Flatten rustdoc output so the crate serves at the doc root rather than under
+# /. Moves the crate's pages up to the doc root and drops one ../ from
+# each page's references to the shared assets (CSS/JS, search index, source),
+# scaled to the page's depth.
+# Env: DOCROOT (default target/doc), CRATE (default coursebank).
+set -euo pipefail
+docroot="${DOCROOT:-target/doc}"
+crate="${CRATE:-coursebank}"
+[ -d "$docroot/$crate" ] || { echo "no $docroot/$crate; did you build the docs?" >&2; exit 1; }
+cp -a "$docroot/$crate/." "$docroot/"
+rm -rf "${docroot:?}/${crate:?}"
+resources='static\.files/\|crates\.js\|search-index\|search\.desc/\|src/\|settings\.html\|help\.html\|trait\.impl/\|type\.impl/'
+while IFS= read -r -d '' f; do
+ rel="${f#"$docroot"/}"
+ depth=$(printf '%s' "$rel" | tr -cd '/' | wc -c)
+ pat=''; for ((i=0; i<=depth; i++)); do pat="\\.\\./$pat"; done
+ rep=''; for ((i=0; i [-d docroot] [-w www_root] [-s site_slug]
+# Env: DOCROOT (default target/doc), WWW_ROOT (default /srv/www),
+# SITE_SLUG (default coursebank).
+# Flags, if given, override the corresponding env var / default.
+set -euo pipefail
+
+usage() {
+ echo "Usage: $0 [-d docroot] [-w www_root] [-s site_slug]" >&2
+ exit 1
+}
+
+channel="${1:?usage: publish-docs.sh [-d docroot] [-w www_root] [-s site_slug]}"
+shift
+
+docroot="${DOCROOT:-target/doc}"
+www_root="${WWW_ROOT:-/srv/www}"
+site_slug="${SITE_SLUG:-coursebank}"
+
+while getopts "d:w:s:" opt; do
+ case "$opt" in
+ d) docroot="$OPTARG" ;;
+ w) www_root="$OPTARG" ;;
+ s) site_slug="$OPTARG" ;;
+ *) usage ;;
+ esac
+done
+
+dest="${www_root}/${site_slug}/${channel}"
+mkdir -p "$dest"
+rsync -a --delete "$docroot/" "$dest/"
+echo "published $docroot -> $dest"
\ No newline at end of file
diff --git a/scripts/redirect-docs.sh b/scripts/redirect-docs.sh
new file mode 100755
index 0000000..33aa968
--- /dev/null
+++ b/scripts/redirect-docs.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+# Point the site root at the latest release, falling back to nightly.
+# Env: WWW_ROOT (default /srv/www), SITE_SLUG (default coursebank).
+set -euo pipefail
+root="${WWW_ROOT:-/srv/www}/${SITE_SLUG:-coursebank}"
+if [ -e "$root/release/index.html" ]; then target="release/"; else target="nightly/"; fi
+printf '%s\n' "" > "$root/index.html"
+echo "site root -> $target"