Splux Linux

source-based Linux using SPS

splux-site · log · files · refs · tags · releases · people · languages · GitHub · commit

bc6be95


Fill the news page from GitHub releases and git history

Date
Commitbc6be9551be9269a437466ef81f59a261c5bc0bf
GitHubmirror

Parents

Stat

 .github/workflows/pages.yml |  14 +++++-
 README.md                   |  27 +++++++++--
 site/assets/style.css       |  39 ++++++++++++++++
 site/index.html             |   8 ++++
 site/news/index.html        |  12 +++--
 tools/build-site.sh         |  76 ++++++++++++++++++++++++++-----
 tools/collect-news.sh       |  88 ++++++++++++++++++++++++++++++++++++
 tools/news.awk              | 108 ++++++++++++++++++++++++++++++++++++++++++++
 tools/subst.awk             |  23 ++++++++++
 9 files changed, 374 insertions(+), 21 deletions(-)

Diff

diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml
index 217703b..82557d3 100644
--- a/.github/workflows/pages.yml
+++ b/.github/workflows/pages.yml
@@ -4,8 +4,10 @@ on:
   push:
     branches: [main]
   schedule:
-    - cron: "17 * * * *"
+    - cron: "7,27,47 * * * *"
   workflow_dispatch:
+  repository_dispatch:
+    types: [rebuild]
 
 permissions:
   contents: read
@@ -21,19 +23,29 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
+        with:
+          fetch-depth: 25
       - uses: actions/checkout@v4
         with:
           repository: RobertFlexx/sps-core
           path: vendor/core
+          fetch-depth: 25
       - uses: actions/checkout@v4
         with:
           repository: RobertFlexx/sps-extra
           path: vendor/extra
+          fetch-depth: 25
+      - uses: actions/checkout@v4
+        with:
+          repository: RobertFlexx/SPS
+          path: vendor/sps
+          fetch-depth: 25
       - name: Build site
         env:
           GH_TOKEN: ${{ github.token }}
           CORE: vendor/core
           EXTRA: vendor/extra
+          SPS: vendor/sps
           SITE_PREFIX: ""
         run: sh tools/build-site.sh
       - uses: actions/upload-pages-artifact@v3
diff --git a/README.md b/README.md
index 0e4e0ad..2928e8e 100644
--- a/README.md
+++ b/README.md
@@ -7,12 +7,11 @@ This site was fully handmade by RobertFlexx.
 ## Build
 
 ```sh
-CORE=/tmp/sps-core EXTRA=/tmp/sps-extra ./tools/build-site.sh
+CORE=/tmp/sps-core EXTRA=/tmp/sps-extra SPS=/path/to/SPS ./tools/build-site.sh
 ```
 
-If `CORE` and `EXTRA` are unset, the script clones
-`https://github.com/RobertFlexx/sps-core` and
-`https://github.com/RobertFlexx/sps-extra` into `vendor/`.
+If `CORE`, `EXTRA`, or `SPS` are unset, the script clones
+`sps-core`, `sps-extra`, and `SPS` into `vendor/`.
 
 Output is `_site/`. Preview:
 
@@ -33,9 +32,27 @@ ISO names are stable:
 
 The visible tag name is filled at build time from the GitHub Releases API.
 
+## News
+
+`news/` is generated at build time from GitHub, not edited by hand:
+
+- SPS live ISO releases (`RobertFlexx/SPS` GitHub Releases)
+- recent commits on SPS, sps-core, sps-extra, and this repository
+
+The Pages workflow rebuilds about every twenty minutes, and also on
+push and `workflow_dispatch`. A new ISO tag shows up here without
+committing to splux-site. Atom feed: `/news/atom.xml`.
+
+To rebuild immediately from another repository, send a
+`repository_dispatch` of type `rebuild` to `RobertFlexx/splux-site`.
+SPS does that after a live ISO release when the `SPLUX_SITE_TOKEN`
+secret is set (a PAT that can dispatch workflows on this repo).
+Without that secret, the schedule still picks releases up.
+
 ## GitHub Pages
 
-The workflow rebuilds the package index on a schedule and on push to `main`.
+The workflow rebuilds the package index and news feed on a schedule
+and on push to `main`.
 The custom domain is `https://splux.robertflexx.dev`. Point a DNS CNAME
 for `splux` at `robertflexx.github.io`, then GitHub Pages serves this
 repository there. `SITE_PREFIX` stays empty so links are rooted at `/`.
diff --git a/site/assets/style.css b/site/assets/style.css
index bdac5fc..ed5878f 100644
--- a/site/assets/style.css
+++ b/site/assets/style.css
@@ -252,6 +252,45 @@ footer p {
 	margin: 0.2rem 0;
 }
 
+.feed {
+	margin: 0.75rem 0 0;
+}
+
+.feed .item {
+	margin: 0 0 1rem;
+	padding: 0 0 1rem;
+	border-bottom: 1px solid var(--rule);
+}
+
+.feed .item:last-child {
+	border-bottom: 0;
+}
+
+.feed .item h3 {
+	margin: 0.15rem 0 0;
+	font-size: 1rem;
+	font-weight: 700;
+}
+
+.feed .meta {
+	color: var(--muted);
+	margin: 0;
+	font-size: 0.9rem;
+}
+
+.feed .kind {
+	color: var(--accent);
+}
+
+.feed .summary {
+	margin: 0.35rem 0 0;
+	color: var(--fg);
+}
+
+.info {
+	margin: 0.75rem 0 1.25rem;
+}
+
 .dl-row {
 	display: grid;
 	grid-template-columns: 12rem 1fr;
diff --git a/site/index.html b/site/index.html
index 11e27dd..dbb4a4b 100644
--- a/site/index.html
+++ b/site/index.html
@@ -10,6 +10,7 @@
 <meta property="og:image" content="../../../../assets/sps.png">
 <link rel="icon" href="../../../../assets/favicon.png" type="image/png">
 <link rel="stylesheet" href="../../../../assets/style.css">
+<link rel="alternate" type="application/atom+xml" href="../../../../news/atom.xml" title="Splux Linux news">
 </head>
 <body>
 <a class="skip" href="#main">Skip to content</a>
@@ -98,6 +99,13 @@ this website
 <hr class="rule">
 <p>Splux is under active development. SPS 1.0 is usable and the official package repositories are being built out. Live images exist so the installer can be tested. Splux is not a stable release yet.</p>
 
+<h2 id="news"><span class="num">[008]</span> News</h2>
+<hr class="rule">
+@@NEWS_INFO@@
+@@NEWS_BRIEF@@
+<p><a href="../../../../news/">Full news feed</a> · <a href="../../../../news/atom.xml">Atom</a></p>
+<p class="note">The feed is generated from GitHub when this site builds. New ISO releases and git commits appear here without a manual site edit.</p>
+
 </main>
 @@FOOTER@@
 </div>
diff --git a/site/news/index.html b/site/news/index.html
index 9d5356b..bbea957 100644
--- a/site/news/index.html
+++ b/site/news/index.html
@@ -4,9 +4,10 @@
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1">
 <title>News - Splux Linux</title>
-<meta name="description" content="Splux Linux news.">
+<meta name="description" content="Splux Linux news from ISO releases and git history.">
 <link rel="icon" href="../../../../assets/favicon.png" type="image/png">
 <link rel="stylesheet" href="../../../../assets/style.css">
+<link rel="alternate" type="application/atom+xml" href="../../../../news/atom.xml" title="Splux Linux news">
 </head>
 <body>
 <a class="skip" href="#main">Skip to content</a>
@@ -15,9 +16,12 @@
 <main id="main">
 <h2>News</h2>
 <hr class="rule">
-<p>2026-08-31 Website brought online.</p>
-<p>2026-08-31 Live ISO snapshots published from <a href="https://github.com/RobertFlexx/SPS/releases">SPS releases</a>.</p>
-<p>Release notes stay on GitHub rather than being copied here.</p>
+<p>This page is filled from GitHub when the site builds: SPS live ISO releases, plus recent commits on SPS, sps-core, sps-extra, and this website. Nobody has to edit it for a new snapshot or commit to show up.</p>
+<p class="note">The Pages workflow rebuilds on a schedule and on push. <a href="../../../../news/atom.xml">Atom feed</a>.</p>
+@@NEWS_INFO@@
+<h2>Feed</h2>
+<hr class="rule">
+@@NEWS@@
 </main>
 @@FOOTER@@
 </div>
diff --git a/tools/build-site.sh b/tools/build-site.sh
index ce8b413..a64ddab 100755
--- a/tools/build-site.sh
+++ b/tools/build-site.sh
@@ -9,24 +9,38 @@ cd "$(CDPATH= cd -P "$(dirname "$0")/.." && pwd)" || exit 1
 
 CORE=${CORE:-vendor/core}
 EXTRA=${EXTRA:-vendor/extra}
+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}
 SPS_GIT=${SPS_GIT:-https://github.com/RobertFlexx/SPS}
+SITE_URL=${SITE_URL:-https://splux.robertflexx.dev}
 
-if [ ! -d "$CORE" ] || [ ! -d "$EXTRA" ]; then
-	mkdir -p vendor
-	if [ ! -d "$CORE" ]; then
-		printf '%s\n' "cloning sps-core" >&2
-		git clone --depth 1 "$CORE_GIT.git" vendor/core
-		CORE=vendor/core
-	fi
-	if [ ! -d "$EXTRA" ]; then
-		printf '%s\n' "cloning sps-extra" >&2
-		git clone --depth 1 "$EXTRA_GIT.git" vendor/extra
-		EXTRA=vendor/extra
+clone_tree() {
+	url=$1
+	dest=$2
+	depth=${3:-25}
+	if [ -d "$dest" ]; then
+		return 0
 	fi
+	mkdir -p vendor
+	printf '%s\n' "cloning $url" >&2
+	git clone --depth "$depth" "$url" "$dest"
+}
+
+if [ ! -d "$CORE" ]; then
+	clone_tree "$CORE_GIT.git" vendor/core 25
+	CORE=vendor/core
+fi
+if [ ! -d "$EXTRA" ]; then
+	clone_tree "$EXTRA_GIT.git" vendor/extra 25
+	EXTRA=vendor/extra
+fi
+if [ ! -d "$SPS" ]; then
+	clone_tree "$SPS_GIT.git" vendor/sps 25
+	SPS=vendor/sps
 fi
 
 rm -rf "$OUT"
@@ -168,6 +182,40 @@ generated=$(date -u '+%Y-%m-%d %H:%M UTC' 2>/dev/null || date)
 printf '%s\n' "{\"tag\":\"$tag\",\"date\":\"$date\",\"iso_tty\":\"$SPS_GIT/releases/latest/download/sps-live-tty.iso\"}" \
 	>"$OUT/data/release.json"
 
+short_sha() {
+	git -C "$1" rev-parse --short HEAD 2>/dev/null || printf '%s\n' unknown
+}
+
+export CORE EXTRA SPS SITE
+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=html "$tmp/news.tsv" >"$tmp/news.html"
+awk -f tools/news.awk -v mode=brief "$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"
+cp "$tmp/news.tsv" "$OUT/data/news.tsv"
+
+sps_sha=$(short_sha "$SPS")
+core_sha=$(short_sha "$CORE")
+extra_sha=$(short_sha "$EXTRA")
+site_sha=$(short_sha "$SITE")
+
+cat >"$tmp/news-info.html" <<EOF
+<div class="info">
+<div class="dl-row"><span class="muted">Latest ISO</span><span><a href="$SPS_GIT/releases/latest">$tag</a> ($date)</span></div>
+<div class="dl-row"><span class="muted">SPS</span><span><a href="$SPS_GIT/commit/$sps_sha">$sps_sha</a></span></div>
+<div class="dl-row"><span class="muted">sps-core</span><span><a href="$CORE_GIT/commit/$core_sha">$core_sha</a></span></div>
+<div class="dl-row"><span class="muted">sps-extra</span><span><a href="$EXTRA_GIT/commit/$extra_sha">$extra_sha</a></span></div>
+<div class="dl-row"><span class="muted">Packages</span><span>$npkgs ($ncore core, $nextra extra)</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
@@ -179,6 +227,9 @@ subst() {
 		-v headerfile="$tmp/header.html" \
 		-v footerfile="$tmp/footer.html" \
 		-v rowsfile="$tmp/rows.html" \
+		-v newsfile="$tmp/news.html" \
+		-v brieffile="$tmp/news-brief.html" \
+		-v infofile="$tmp/news-info.html" \
 		-v root="$root" \
 		-v tag="$tag" \
 		-v date="$date" \
@@ -237,6 +288,9 @@ do
 		-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" \
diff --git a/tools/collect-news.sh b/tools/collect-news.sh
new file mode 100644
index 0000000..f911828
--- /dev/null
+++ b/tools/collect-news.sh
@@ -0,0 +1,88 @@
+#!/bin/sh
+# Collect Splux releases and git history into TSV for the news page.
+# Fields: epoch iso kind repo url title summary
+# Env: CORE EXTRA SPS SITE (git work trees). GH_TOKEN optional via gh.
+
+set -eu
+
+CORE=${CORE:-vendor/core}
+EXTRA=${EXTRA:-vendor/extra}
+SPS=${SPS:-vendor/sps}
+SITE=${SITE:-.}
+
+tab=$(printf '\t')
+out=$(mktemp "${TMPDIR:-/tmp}/splux-news.XXXXXX") || exit 1
+trap 'rm -f "$out" "$rel"' 0 HUP INT TERM
+rel=
+
+emit() {
+	epoch=$1
+	iso=$2
+	kind=$3
+	repo=$4
+	url=$5
+	title=$6
+	summary=${7-}
+	title=$(printf '%s' "$title" | tr '\t\r\n' '   ')
+	summary=$(printf '%s' "$summary" | tr '\t\r\n' '   ')
+	printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
+		"$epoch" "$iso" "$kind" "$repo" "$url" "$title" "$summary" >>"$out"
+}
+
+epoch_of() {
+	iso=$1
+	day=${iso%%T*}
+	if date -u -d "$iso" +%s >/dev/null 2>&1; then
+		date -u -d "$iso" +%s
+		return 0
+	fi
+	awk -v d="$day" 'BEGIN {
+		n = split(d, a, "-")
+		if (n != 3) { print 0; exit }
+		print mktime(a[1] " " a[2] " " a[3] " 12 0 0") + 0
+	}'
+}
+
+git_commits() {
+	dir=$1
+	repo=$2
+	baseurl=$3
+	n=${4:-12}
+	git -C "$dir" rev-parse --is-inside-work-tree >/dev/null 2>&1 || return 0
+	git -C "$dir" log -n "$n" --format='%ct%x09%cI%x09%H%x09%s' 2>/dev/null |
+	while IFS=$tab read -r epoch iso hash subject || [ -n "${epoch-}" ]
+	do
+		[ -n "${epoch-}" ] || continue
+		[ -n "${iso-}" ] || continue
+		[ -n "${hash-}" ] || continue
+		emit "$epoch" "$iso" commit "$repo" \
+			"$baseurl/commit/$hash" "$subject" ""
+	done
+}
+
+git_commits "$SPS" SPS https://github.com/RobertFlexx/SPS 15
+git_commits "$CORE" sps-core https://github.com/RobertFlexx/sps-core 15
+git_commits "$EXTRA" sps-extra https://github.com/RobertFlexx/sps-extra 15
+git_commits "$SITE" splux-site https://github.com/RobertFlexx/splux-site 8
+
+if command -v gh >/dev/null 2>&1; then
+	rel=$(mktemp "${TMPDIR:-/tmp}/splux-rel.XXXXXX") || exit 1
+	if gh api "repos/RobertFlexx/SPS/releases?per_page=25" --jq \
+		'.[] | select(.draft == false) | [
+			.published_at,
+			.html_url,
+			(.name // .tag_name),
+			((.body // "") | gsub("[\r\t]"; " ") | gsub("\n+"; " ") | .[0:900])
+		] | @tsv' >"$rel" 2>/dev/null
+	then
+		while IFS=$tab read -r published url name body || [ -n "${published-}" ]
+		do
+			[ -n "${published-}" ] || continue
+			[ -n "${url-}" ] || continue
+			epoch=$(epoch_of "$published")
+			emit "$epoch" "$published" release SPS "$url" "$name" "$body"
+		done <"$rel"
+	fi
+fi
+
+LC_ALL=C sort -t "$tab" -k1,1nr "$out"
diff --git a/tools/news.awk b/tools/news.awk
new file mode 100644
index 0000000..fcbff6f
--- /dev/null
+++ b/tools/news.awk
@@ -0,0 +1,108 @@
+# Turn collect-news.sh TSV into HTML or Atom.
+# Fields: epoch iso kind repo url title summary
+# -v mode=html|brief|atom  -v siteurl=  -v feedupdated=
+
+BEGIN {
+	FS = "\t"
+	if (mode == "")
+		mode = "html"
+	if (siteurl == "")
+		siteurl = "https://splux.robertflexx.dev"
+	html_limit = (mode == "brief") ? 8 : 60
+	atom_limit = 40
+}
+
+function esc(s) {
+	gsub(/&/, "\\&amp;", s)
+	gsub(/</, "\\&lt;", s)
+	gsub(/>/, "\\&gt;", s)
+	gsub(/"/, "\\&quot;", s)
+	return s
+}
+
+function day_of(iso,    d) {
+	d = iso
+	sub(/T.*/, "", d)
+	return d
+}
+
+function kind_label(k) {
+	if (k == "release")
+		return "release"
+	return "commit"
+}
+
+{
+	n++
+	epoch[n] = $1
+	iso[n] = $2
+	kind[n] = $3
+	repo[n] = $4
+	url[n] = $5
+	title[n] = $6
+	summary[n] = $7
+}
+
+END {
+	if (mode == "atom") {
+		print_atom()
+		exit
+	}
+	if (n == 0) {
+		print "<p class=\"note\">No GitHub events were available when this page was built.</p>"
+		exit
+	}
+	print "<div class=\"feed\">"
+	limit = html_limit
+	if (n < limit)
+		limit = n
+	for (i = 1; i <= limit; i++) {
+		print_item(i, mode == "brief")
+	}
+	print "</div>"
+}
+
+function print_item(i, brief,    k, when, s) {
+	when = esc(day_of(iso[i]))
+	k = esc(kind_label(kind[i]))
+	print "<article class=\"item\">"
+	printf "<p class=\"meta\"><time datetime=\"%s\">%s</time> <span class=\"kind\">%s</span> %s</p>\n", \
+		esc(iso[i]), when, k, esc(repo[i])
+	printf "<h3><a href=\"%s\">%s</a></h3>\n", esc(url[i]), esc(title[i])
+	if (!brief) {
+		s = summary[i]
+		if (s != "")
+			printf "<p class=\"summary\">%s</p>\n", esc(s)
+	}
+	print "</article>"
+}
+
+function print_atom(    i, limit, updated, id) {
+	updated = feedupdated
+	if (updated == "" && n > 0)
+		updated = iso[1]
+	if (updated == "")
+		updated = "1970-01-01T00:00:00Z"
+	print "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+	print "<feed xmlns=\"http://www.w3.org/2005/Atom\">"
+	print "<title>Splux Linux news</title>"
+	printf "<link rel=\"self\" href=\"%s/news/atom.xml\"/>\n", esc(siteurl)
+	printf "<link href=\"%s/news/\"/>\n", esc(siteurl)
+	printf "<updated>%s</updated>\n", esc(updated)
+	printf "<id>%s/news/</id>\n", esc(siteurl)
+	print "<author><name>RobertFlexx</name></author>"
+	limit = atom_limit
+	if (n < limit)
+		limit = n
+	for (i = 1; i <= limit; i++) {
+		print "<entry>"
+		printf "<title>%s</title>\n", esc(title[i])
+		printf "<link href=\"%s\"/>\n", esc(url[i])
+		printf "<id>%s</id>\n", esc(url[i])
+		printf "<updated>%s</updated>\n", esc(iso[i])
+		printf "<category term=\"%s\"/>\n", esc(kind[i])
+		printf "<summary>%s</summary>\n", esc(repo[i] ": " title[i])
+		print "</entry>"
+	}
+	print "</feed>"
+}
diff --git a/tools/subst.awk b/tools/subst.awk
index eab5188..0b49d9c 100644
--- a/tools/subst.awk
+++ b/tools/subst.awk
@@ -1,6 +1,14 @@
 # Replace @@HEADER@@ / @@FOOTER@@ / ../../../../ and other tokens.
 # headerfile, footerfile, root, rowsfile, and token variables are -v flags.
 
+function dump_file(path,    line) {
+	if (path == "")
+		return
+	while ((getline line < path) > 0)
+		print line
+	close(path)
+}
+
 BEGIN {
 	if (headerfile != "") {
 		while ((getline line < headerfile) > 0)
@@ -35,6 +43,21 @@ $0 == "@@PKG_ROWS@@" {
 	next
 }
 
+$0 == "@@NEWS@@" {
+	dump_file(newsfile)
+	next
+}
+
+$0 == "@@NEWS_BRIEF@@" {
+	dump_file(brieffile)
+	next
+}
+
+$0 == "@@NEWS_INFO@@" {
+	dump_file(infofile)
+	next
+}
+
 {
 	gsub(/../../../..//, root)
 	gsub(/live-2026-09-06-1/, tag)