splux-site · log · files · refs · tags · releases · people · languages · GitHub · file
tools/build-site.sh
14762 bytes at 4c4f12c · GitHub
#!/bin/sh
# Build the static Splux website from official SPS recipe trees.
# Usage: ./tools/build-site.sh
# Optional: CORE EXTRA COMMUNITY SPS SITE_PREFIX OUT
set -eu
cd "$(CDPATH= cd -P "$(dirname "$0")/.." && pwd)" || exit 1
CORE=${CORE:-vendor/core}
EXTRA=${EXTRA:-vendor/extra}
COMMUNITY=${COMMUNITY:-vendor/community}
SPS=${SPS:-vendor/sps}
SITE=${SITE:-.}
OUT=${OUT:-_site}
SITE_PREFIX=${SITE_PREFIX-}
CORE_GIT=${CORE_GIT:-https://github.com/RobertFlexx/sps-core}
EXTRA_GIT=${EXTRA_GIT:-https://github.com/RobertFlexx/sps-extra}
COMMUNITY_GIT=${COMMUNITY_GIT:-https://github.com/RobertFlexx/sps-community}
SPS_GIT=${SPS_GIT:-https://github.com/RobertFlexx/SPS}
SITE_URL=${SITE_URL:-https://splux.robertflexx.dev}
GIT_HOST=${GIT_HOST:-https://splux.robertflexx.dev/git}
clone_tree() {
url=$1
dest=$2
if [ -d "$dest" ]; then
return 0
fi
mkdir -p vendor
printf '%s\n' "cloning $url" >&2
git clone "$url" "$dest"
}
if [ ! -d "$CORE" ]; then
clone_tree "$CORE_GIT.git" vendor/core
CORE=vendor/core
fi
if [ ! -d "$EXTRA" ]; then
clone_tree "$EXTRA_GIT.git" vendor/extra
EXTRA=vendor/extra
fi
if [ ! -d "$COMMUNITY" ]; then
clone_tree "$COMMUNITY_GIT.git" vendor/community
COMMUNITY=vendor/community
fi
if [ ! -d "$SPS" ]; then
clone_tree "$SPS_GIT.git" vendor/sps
SPS=vendor/sps
fi
rm -rf "$OUT"
mkdir -p "$OUT/assets" "$OUT/data" "$OUT/download" "$OUT/packages" \
"$OUT/install" "$OUT/docs" "$OUT/docs/images" "$OUT/docs/sps" \
"$OUT/docs/community" "$OUT/docs/first-boot" "$OUT/source" "$OUT/news" "$OUT/git"
cp -a site/assets/. "$OUT/assets/"
if [ -f CNAME ]; then
cp CNAME "$OUT/CNAME"
fi
write_header() {
root=$1
cat <<EOF
<header class="top">
<img class="logo" src="${root}assets/sps.png" width="96" height="96" alt="SPS">
<div class="identity">
<h1>Splux Linux</h1>
<p>source-based Linux using SPS</p>
</div>
</header>
<nav class="row" aria-label="Site">
<a href="${root}">home</a>
<a href="${root}download/">download</a>
<a href="${root}packages/">packages</a>
<a href="${root}install/">install</a>
<a href="${root}docs/">docs</a>
<a href="${root}git/">git</a>
<a href="${root}source/">source</a>
<a href="${root}news/">news</a>
</nav>
EOF
}
write_footer() {
root=$1
cat <<EOF
<footer>
<p>Splux Linux</p>
<p><a href="${root}">home</a> · <a href="${root}packages/">packages</a> · <a href="${root}git/">git</a> · <a href="${root}docs/">documentation</a></p>
<p>This site was fully handmade by <a href="https://github.com/RobertFlexx">RobertFlexx</a>.</p>
</footer>
EOF
}
write_docs_nav() {
root=$1
cur=$2
printf '%s\n' '<nav class="docs-side" aria-label="Handbook">'
printf '%s\n' '<p class="docs-kicker">Handbook</p>'
printf '%s\n' '<ul class="docs-toc">'
set -- \
overview "${root}docs/" "Overview" \
images "${root}docs/images/" "Live images" \
install "${root}install/" "Install" \
sps "${root}docs/sps/" "SPS tools" \
community "${root}docs/community/" "Community" \
firstboot "${root}docs/first-boot/" "After first boot" \
git "${root}git/" "Git"
while [ "$#" -ge 3 ]
do
if [ "$cur" = "$1" ]; then
printf '<li><a href="%s" aria-current="page">%s</a></li>\n' \
"$2" "$3"
else
printf '<li><a href="%s">%s</a></li>\n' "$2" "$3"
fi
shift 3
done
printf '%s\n' '</ul>'
printf '%s\n' '</nav>'
}
tmp=$(mktemp -d "${TMPDIR:-/tmp}/splux-site.XXXXXX") || exit 1
trap 'rm -rf "$tmp"' 0 HUP INT TERM
tsv=$tmp/packages.tsv
: >"$tsv"
nwarn=0
scan_tree() {
repo=$1
rootdir=$2
github=$3
mirror=${4-}
if [ ! -d "$rootdir" ]; then
printf '%s\n' "warning: missing recipe tree $rootdir" >&2
return 0
fi
find "$rootdir" -name recipe -type f | LC_ALL=C sort | while IFS= read -r rec
do
rel=${rec#"$rootdir"/}
case $rel in
recipe) pkgpath=. ;;
*/recipe) pkgpath=${rel%/recipe} ;;
*) continue ;;
esac
if ! awk -f tools/packages.awk \
-v repo="$repo" \
-v pkgpath="$pkgpath" \
-v github="$github" \
-v mirror="$mirror" \
-v outdir="$OUT" \
"$rec" >>"$tsv"
then
printf '%s\n' "warning: skipped $rec" >&2
nwarn=$((nwarn + 1))
fi
done
}
printf '%s\n' "reading recipes" >&2
scan_tree core "$CORE" "$GIT_HOST/sps-core" "https://github.com/RobertFlexx/sps-core"
scan_tree extra "$EXTRA" "$GIT_HOST/sps-extra" "https://github.com/RobertFlexx/sps-extra"
scan_tree community "$COMMUNITY" "$GIT_HOST/sps-community" "https://github.com/RobertFlexx/sps-community"
LC_ALL=C sort -t "$(printf '\t')" -k1,1 -k5,5 "$tsv" >"$tmp/sorted.tsv"
mv "$tmp/sorted.tsv" "$tsv"
npkgs=$(awk 'END { print NR + 0 }' "$tsv")
ncore=$(awk -F '\t' '$5 == "core" { n++ } END { print n + 0 }' "$tsv")
nextra=$(awk -F '\t' '$5 == "extra" { n++ } END { print n + 0 }' "$tsv")
ncommunity=$(awk -F '\t' '$5 == "community" { n++ } END { print n + 0 }' "$tsv")
curlver=$(awk -F '\t' '$1 == "curl" { print $2 "-" $3; exit }' "$tsv")
[ -n "$curlver" ] || curlver="8.21.0-1"
awk -F '\t' '
function esc(s) {
gsub(/&/, "\\&", s)
gsub(/</, "\\<", s)
gsub(/>/, "\\>", s)
gsub(/"/, "\\"", s)
return s
}
{
name=$1; ver=$2; rel=$3; repo=$5; cat=$6; desc=$7; path=$8
search = tolower(name " " desc " " cat " " repo)
href = "../../../../../packages/" repo "/" path "/"
printf "<tr data-repo=\"%s\" data-search=\"%s\">", esc(repo), esc(search)
printf "<td><a class=\"name\" href=\"%s\">%s</a></td>", href, esc(name)
printf "<td>%s-%s</td>", esc(ver), esc(rel)
printf "<td>%s</td>", esc(repo)
printf "<td>%s</td></tr>\n", esc(cat)
}
' "$tsv" >"$tmp/rows.html"
awk -F '\t' '
function jesc(s) {
gsub(/\\/, "\\\\", s)
gsub(/"/, "\\\"", s)
return s
}
BEGIN { print "[" }
{
if (NR > 1) print ","
printf "{\"name\":\"%s\",\"version\":\"%s\",\"release\":\"%s\",\"arch\":\"%s\",\"repo\":\"%s\",\"category\":\"%s\",\"description\":\"%s\",\"path\":\"%s\"}", \
jesc($1), jesc($2), jesc($3), jesc($4), jesc($5), jesc($6), jesc($7), jesc($8)
}
END { print "\n]" }
' "$tsv" >"$OUT/data/packages.json"
# GitHub's "latest" flag can lag. Pick the highest live-YYYY-MM-DD[-N]
# tag by numeric suffix. String sort ranks -9 above -15.
pick_live_release() {
gh api "repos/RobertFlexx/SPS/releases?per_page=100" --jq '
def rank:
capture("^live-(?<y>[0-9]+)-(?<m>[0-9]+)-(?<d>[0-9]+)(?:-(?<n>[0-9]+))?$")
| [(.y|tonumber), (.m|tonumber), (.d|tonumber), ((.n // "0")|tonumber)];
[.[] | select(.draft == false) | select(.tag_name | test("^live-[0-9]{4}-[0-9]{2}-[0-9]{2}(-[0-9]+)?$"))]
| if length == 0 then empty else max_by(.tag_name | rank) end
| [.tag_name, .published_at] | @tsv
' 2>/dev/null
}
tag=unknown
date=unknown
published=
if command -v gh >/dev/null 2>&1; then
picked=$(pick_live_release || true)
if [ -n "$picked" ]; then
tag=${picked%% *}
published=${picked#* }
date=${published%%T*}
fi
if [ "$tag" = unknown ] || [ -z "$tag" ]; then
tag=$(gh release view -R RobertFlexx/SPS --json tagName --jq .tagName 2>/dev/null) || tag=unknown
published=$(gh release view -R RobertFlexx/SPS --json publishedAt --jq .publishedAt 2>/dev/null) || published=
date=${published%%T*}
fi
fi
if [ "$tag" = unknown ] || [ -z "$tag" ]; then
tag=latest
date="see GitHub"
published=
fi
generated=$(date -u '+%Y-%m-%d %H:%M UTC' 2>/dev/null || date)
iso_base=$SPS_GIT/releases/latest/download
notes_url=$SPS_GIT/releases/latest
case $tag in
latest|unknown) ;;
*)
iso_base=$SPS_GIT/releases/download/$tag
notes_url=$SPS_GIT/releases/tag/$tag
;;
esac
printf '%s\n' "{\"tag\":\"$tag\",\"date\":\"$date\",\"published_at\":\"$published\",\"iso_tty\":\"$iso_base/sps-live-tty.iso\",\"iso_slim\":\"$iso_base/sps-live-tty-slim.iso\",\"iso_plasma\":\"$iso_base/sps-live-plasma.iso\",\"sha256sums\":\"$iso_base/SHA256SUMS\"}" \
>"$OUT/data/release.json"
short_sha() {
git -C "$1" rev-parse --short HEAD 2>/dev/null || printf '%s\n' unknown
}
export CORE EXTRA COMMUNITY SPS SITE GIT_HOST
if ! sh tools/collect-news.sh >"$tmp/news.tsv"
then
printf '%s\n' "warning: news collection failed" >&2
: >"$tmp/news.tsv"
fi
awk -f tools/news.awk -v mode=brief -v gitusers="$GIT_HOST/users" "$tmp/news.tsv" >"$tmp/news-brief.html"
generated_iso=$(date -u '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null || date -u '+%Y-%m-%dT00:00:00Z')
awk -f tools/news.awk -v mode=atom -v siteurl="$SITE_URL" \
-v feedupdated="$generated_iso" \
"$tmp/news.tsv" >"$OUT/news/atom.xml"
awk -f tools/news.awk -v mode=json "$tmp/news.tsv" >"$OUT/data/news.json"
cp "$tmp/news.tsv" "$OUT/data/news.tsv"
news_per=20
nnews=$(awk 'END { print NR + 0 }' "$tmp/news.tsv")
if [ "$nnews" -lt 1 ]; then
news_pages=1
else
news_pages=$(( (nnews + news_per - 1) / news_per ))
fi
: >"$tmp/pager.html"
: >"$tmp/news.html"
pagetitle=
sps_sha=$(short_sha "$SPS")
core_sha=$(short_sha "$CORE")
extra_sha=$(short_sha "$EXTRA")
community_sha=$(short_sha "$COMMUNITY")
site_sha=$(short_sha "$SITE")
livesig=${site_sha}-$(date -u '+%Y%m%d%H%M%S' 2>/dev/null || date +%Y%m%d%H%M%S)
cat >"$tmp/news-info.html" <<EOF
<div class="info">
<div class="dl-row"><span class="muted">Latest ISO</span><span id="live-iso"><a href="$notes_url">$tag</a> ($date)</span></div>
<div class="dl-row"><span class="muted">SPS</span><span id="live-sps"><a href="$GIT_HOST/SPS/commit/$sps_sha/">$sps_sha</a></span></div>
<div class="dl-row"><span class="muted">sps-core</span><span id="live-core"><a href="$GIT_HOST/sps-core/commit/$core_sha/">$core_sha</a></span></div>
<div class="dl-row"><span class="muted">sps-extra</span><span id="live-extra"><a href="$GIT_HOST/sps-extra/commit/$extra_sha/">$extra_sha</a></span></div>
<div class="dl-row"><span class="muted">sps-community</span><span id="live-community"><a href="$GIT_HOST/sps-community/commit/$community_sha/">$community_sha</a></span></div>
<div class="dl-row"><span class="muted">Packages</span><span>$npkgs ($ncore core, $nextra extra, $ncommunity community)</span></div>
<div class="dl-row"><span class="muted">Site build</span><span>$generated ($site_sha)</span></div>
</div>
EOF
subst() {
src=$1
dest=$2
root=$3
docscurrent=${4-}
write_header "$root" >"$tmp/header.html"
write_footer "$root" >"$tmp/footer.html"
write_docs_nav "$root" "$docscurrent" >"$tmp/docsnav.html"
mkdir -p "$(dirname "$dest")"
awk -f tools/subst.awk \
-v headerfile="$tmp/header.html" \
-v footerfile="$tmp/footer.html" \
-v docsnavfile="$tmp/docsnav.html" \
-v rowsfile="$tmp/rows.html" \
-v newsfile="$tmp/news.html" \
-v brieffile="$tmp/news-brief.html" \
-v infofile="$tmp/news-info.html" \
-v pagerfile="$tmp/pager.html" \
-v pagetitle="$pagetitle" \
-v root="$root" \
-v tag="$tag" \
-v date="$date" \
-v npkgs="$npkgs" \
-v ncore="$ncore" \
-v nextra="$nextra" \
-v ncommunity="$ncommunity" \
-v generated="$generated" \
-v livesig="$livesig" \
-v curlver="$curlver" \
-v githost="$GIT_HOST" \
"$src" >"$dest"
}
# Static pages
subst site/index.html "$OUT/index.html" "./"
subst site/download/index.html "$OUT/download/index.html" "../"
subst site/packages/index.html "$OUT/packages/index.html" "../"
subst site/install/index.html "$OUT/install/index.html" "../" install
subst site/docs/index.html "$OUT/docs/index.html" "../" overview
subst site/docs/images/index.html "$OUT/docs/images/index.html" "../../" images
subst site/docs/sps/index.html "$OUT/docs/sps/index.html" "../../" sps
subst site/docs/community/index.html "$OUT/docs/community/index.html" "../../" community
subst site/docs/first-boot/index.html "$OUT/docs/first-boot/index.html" "../../" firstboot
subst site/source/index.html "$OUT/source/index.html" "../"
export OUT CORE EXTRA COMMUNITY SPS SITE GIT_HOST SITE_URL
sh tools/build-git.sh
find "$OUT/git" -name index.html >"$tmp/gitpages"
while IFS= read -r page
do
[ -n "$page" ] || continue
rel=${page#"$OUT"/}
depth=0
rest=$rel
while [ "$rest" != "${rest#*/}" ]
do
depth=$((depth + 1))
rest=${rest#*/}
done
root=""
i=0
while [ "$i" -lt "$depth" ]
do
root="../$root"
i=$((i + 1))
done
write_header "$root" >"$tmp/hgit.html"
write_footer "$root" >"$tmp/fgit.html"
awk -f tools/subst.awk \
-v headerfile="$tmp/hgit.html" \
-v footerfile="$tmp/fgit.html" \
-v rowsfile="" \
-v newsfile="" \
-v brieffile="" \
-v infofile="" \
-v root="$root" \
-v tag="$tag" \
-v date="$date" \
-v npkgs="$npkgs" \
-v ncore="$ncore" \
-v nextra="$nextra" \
-v ncommunity="$ncommunity" \
-v generated="$generated" \
-v livesig="$livesig" \
-v curlver="$curlver" \
-v githost="$GIT_HOST" \
"$page" >"$tmp/gpage.html"
mv "$tmp/gpage.html" "$page"
done <"$tmp/gitpages"
awk -f tools/news.awk -v mode=html -v page=1 -v per="$news_per" \
-v gitusers="$GIT_HOST/users" \
"$tmp/news.tsv" >"$tmp/news.html"
awk -f tools/news.awk -v mode=pager -v page=1 -v pages="$news_pages" \
-v per="$news_per" -v nest=0 "$tmp/news.tsv" >"$tmp/pager.html"
pagetitle=
subst site/news/index.html "$OUT/news/index.html" "../"
news_p=2
while [ "$news_p" -le "$news_pages" ]
do
awk -f tools/news.awk -v mode=html -v page="$news_p" -v per="$news_per" \
-v gitusers="$GIT_HOST/users" \
"$tmp/news.tsv" >"$tmp/news.html"
awk -f tools/news.awk -v mode=pager -v page="$news_p" -v pages="$news_pages" \
-v per="$news_per" -v nest=1 "$tmp/news.tsv" >"$tmp/pager.html"
pagetitle=" page $news_p"
subst site/news/index.html "$OUT/news/$news_p/index.html" "../../"
news_p=$((news_p + 1))
done
pagetitle=
: >"$tmp/pager.html"
# 404 must use an absolute prefix so nested missing URLs still load CSS.
if [ -n "$SITE_PREFIX" ]; then
abs=${SITE_PREFIX%/}/
else
abs=/
fi
subst site/404.html "$OUT/404.html" "$abs"
# Detail pages already contain @@HEADER@@ / @@FOOTER@@ and baked asset paths.
# Re-run subst with a per-directory root of "".
# Their <head> links already use ../ prefixes from packages.awk.
find "$OUT/packages" -name index.html | while IFS= read -r page
do
case $page in
*/packages/index.html) continue ;;
esac
# Count depth below _site for nav ROOT (packages/core/cat/pkg = 4)
rel=${page#"$OUT"/}
depth=0
rest=$rel
while [ "$rest" != "${rest#*/}" ]
do
depth=$((depth + 1))
rest=${rest#*/}
done
root=""
i=0
while [ "$i" -lt "$depth" ]
do
root="../$root"
i=$((i + 1))
done
write_header "$root" >"$tmp/h2.html"
write_footer "$root" >"$tmp/f2.html"
awk -f tools/subst.awk \
-v headerfile="$tmp/h2.html" \
-v footerfile="$tmp/f2.html" \
-v rowsfile="" \
-v newsfile="" \
-v brieffile="" \
-v infofile="" \
-v root="$root" \
-v tag="$tag" \
-v date="$date" \
-v npkgs="$npkgs" \
-v ncore="$ncore" \
-v nextra="$nextra" \
-v ncommunity="$ncommunity" \
-v generated="$generated" \
-v livesig="$livesig" \
-v curlver="$curlver" \
-v githost="$GIT_HOST" \
"$page" >"$tmp/page.html"
mv "$tmp/page.html" "$page"
done
printf '%s\n' "built $OUT ($npkgs packages, $ncore core, $nextra extra, $ncommunity community, tag $tag)" >&2