Commit 9271e08b1a

9271e08b1a930bf19160d3df7a35840e2b9732a9

parent: e34bd53ac2

Unsigned

cmc <hello@cleberg.net> · 2025-06-03 23:45 UTC

feat: build script now automatically updates index posts

Layout: unified · split

build.sh +122 −50
@@ -1,56 +1,128 @@
1#!/bin/bash 1#!/usr/bin/env bash
2 2set -e
3# Ensure the latest post is included on the home page 3
4printf "Did you update the 'Recent Blog Posts' section? [yn] " 4# -----------------------------------------------------------------------------
5read answer 5# Function: generate_recent_posts
6 6# After publishing to .build/, finds the 3 newest HTML files under .build/blog
7# Only continue if latest post is included on the home page 7# (excluding blog index.html), extracts each post’s date/title/tags by:
8if [[ "$answer" =~ ^[Yy]$ ]]; then 8# - <time datetime="...">
9 # Check if the environment flag is set to PROD 9# - <h1>…</h1>
10 if [[ "$ENV" == "prod" ]]; then 10# - <span class="tag">…</span> lines
11 echo "Environment: Production" 11# Replaces everything between <!-- RECENT-POSTS-START --> and
12 12# <!-- RECENT-POSTS-END --> in .build/index.html.
13 # Check if publishing via LAN or remotely 13# Tested on macOS.
14 printf "Publishing on remote or LAN? [r|l] " 14# -----------------------------------------------------------------------------
15 15generate_recent_posts() {
16 # Update ubuntu_server variable based on answer 16 BUILD_DIR="${SCRIPT_DIR}/.build"
17 read method 17 INDEXFILE="$BUILD_DIR/index.html"
18 if [[ "$method" =~ ^[Rr]$ ]]; then 18 BLOGDIR="$BUILD_DIR/blog"
19 ubuntu_server="ubuntu-remote" 19 TMPFILE="$(mktemp)"
20 elif [[ "$method" =~ ^[Ll]$ ]]; then 20 MARKER_START="<!-- RECENT-POSTS-START -->"
21 ubuntu_server="ubuntu" 21 MARKER_END="<!-- RECENT-POSTS-END -->"
22 else 22
23 echo "Invalid input. Assuming LAN (ubuntu)" 23 # 1) Verify generated index.html exists
24 ubuntu_server="ubuntu" 24 if [[ ! -f "$INDEXFILE" ]]; then
25 fi 25 echo "Error: Generated index.html not found at $INDEXFILE" >&2
26 26 exit 1
27 # Remove previous build 27 fi
28 rm -rf .build/* 28
29 29 # 2) Verify .build/blog exists
30 # Minify CSS 30 if [[ ! -d "$BLOGDIR" ]]; then
31 minify -o theme/static/styles.min.css theme/static/styles.css 31 echo "Error: Generated blog directory not found at $BLOGDIR" >&2
32 32 exit 1
33 # Run publishing script 33 fi
34 emacs --script publish.el &>/dev/null 34
35 35 # 3) Collect the three newest post HTML files, excluding /index.html
36 # Deploy changes 36 POSTS=()
37 rsync -r --delete-before .build/* $ubuntu_server:/var/www/cleberg.net/ 37 for FILEPATH in $(ls -1t "$BLOGDIR"/*.html 2>/dev/null | grep -v "/index.html\$" | head -n 3); do
38 else 38 [[ -f "$FILEPATH" ]] && POSTS+=("$FILEPATH")
39 echo "Environment: Development" 39 done
40
41 # 4) Build the HTML snippet into TMPFILE
42 {
43 for POST in "${POSTS[@]}"; do
44 BASENAME="$(basename "$POST")"
45 URL="/blog/${BASENAME}"
46
47 # 4a) DATE: extract from first <time datetime="...">
48 POST_DATE_FULL="$(sed -n 's/.*<time datetime="\([^"]*\)".*/\1/p' "$POST" | head -n1)"
49 if [[ -n "$POST_DATE_FULL" ]]; then
50 POST_DATE="${POST_DATE_FULL%% *}"
51 else
52 POST_DATE="$(stat -f "%Sm" -t "%Y-%m-%d" "$POST")"
53 fi
54
55 # 4b) TITLE: extract from first <h1>…</h1>
56 TITLE="$(sed -n 's/.*<h1[^>]*>\(.*\)<\/h1>.*/\1/p' "$POST" | head -n1)"
57 if [[ -z "$TITLE" ]]; then
58 TITLE="${BASENAME%.html}"
59 fi
40 60
41 # Remove previous build 61 # 4c) TAGS: extract each <span class="tag">…</span> line, re-indent by 6 spaces
42 rm -rf .build/* 62 TAGSPAN="$(grep -o '^[[:space:]]*<span class="tag">[^<]*</span>' "$POST" \
63 | sed 's/^[[:space:]]*/ /' || true)"
43 64
44 # Minify CSS 65 # 4d) Emit one <div class="post">…</div> block
45 minify -o theme/static/styles.min.css theme/static/styles.css 66 cat <<EOF
67 <div class="post">
68 <time datetime="${POST_DATE}">${POST_DATE}</time>
69 <div class="post-content">
70 <a href="${URL}">${TITLE}</a>
71 <div class="post-tags">
72 $(printf "%s\n" "$TAGSPAN")
73 </div>
74 </div>
75 </div>
76EOF
77 done
78 } > "$TMPFILE"
46 79
47 # Run publishing script 80 # 5) Replace everything between the markers in .build/index.html (keeping markers)
48 emacs --script publish.el 81 sed -i '' -e "/${MARKER_START}/,/${MARKER_END}/{
82 /${MARKER_START}/{p; r $TMPFILE
83 };
84 /${MARKER_END}/p;
85 d
86 }" "$INDEXFILE"
49 87
50 # Launch development web server 88 rm "$TMPFILE"
51 cd .build/ 89 echo "→ Injected up to 3 newest posts into $INDEXFILE"
52 python3 -m http.server 90}
91
92
93# -------------------- Main build.sh logic --------------------
94SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
95
96# Step 1: Clean previous build
97rm -rf "${SCRIPT_DIR}/.build"/*
98
99# Step 2: Minify CSS
100minify -o "${SCRIPT_DIR}/theme/static/styles.min.css" "${SCRIPT_DIR}/theme/static/styles.css"
101
102# Step 3: Run Emacs publish.el (outputs into .build/)
103emacs --script "${SCRIPT_DIR}/publish.el" &>/dev/null
104
105# Step 4: Inject the “Recent Blog Posts” section into the generated index.html
106generate_recent_posts
107
108if [[ "$ENV" == "prod" ]]; then
109 echo "Environment: Production"
110 printf "Publishing on remote or LAN? [r|l] "
111 read -r method
112 if [[ "$method" =~ ^[Rr]$ ]]; then
113 ubuntu_server="ubuntu-remote"
114 elif [[ "$method" =~ ^[Ll]$ ]]; then
115 ubuntu_server="ubuntu"
116 else
117 echo "Invalid input. Assuming LAN (ubuntu)"
118 ubuntu_server="ubuntu"
53 fi 119 fi
120
121 # Step 5: Deploy via rsync
122 rsync -r --delete-before "${SCRIPT_DIR}/.build/" "$ubuntu_server":/var/www/cleberg.net/
54else 123else
55 echo "Please update the 'Recent Blog Posts' section before publishing!" 124 echo "Environment: Development"
56fi 125 # Step 5: Launch local HTTP server from .build/
126 cd "${SCRIPT_DIR}/.build/" || exit
127 python3 -m http.server
128fi\ No newline at end of file
theme/templates/index.html +3 −39
@@ -8,45 +8,9 @@ sub rsa4096 2022-11-16 [E]</pre>
8</section> 8</section>
9<section> 9<section>
10 <h2>Recent Blog Posts</h2> 10 <h2>Recent Blog Posts</h2>
11 11 <!-- RECENT-POSTS-START -->
12 12 <!-- RECENT-POSTS-END -->
13 <div class="post"> 13 <br>
14 <time datetime="2025-06-02 15:26:05">2025-06-02</time>
15 <div class="post-content">
16 <a href="/blog/private-ios-apps.html">Selection of Privacy-Focused iOS Applications for Minimalist Users</a>
17 <div class="post-tags">
18 <span class="tag">ios</span>
19 <span class="tag">privacy</span>
20 <span class="tag">security</span>
21 </div>
22 </div>
23 </div>
24
25 <div class="post">
26 <time datetime="2025-05-30 10:53:28">2025-05-30</time>
27 <div class="post-content">
28 <a href="/blog/it-audit-career.html">Career Advancement through Mastery of Emerging Technologies in IT Audit</a>
29 <div class="post-tags">
30 <span class="tag">audit</span>
31 <span class="tag">technology</span>
32 <span class="tag">career</span>
33 </div>
34 </div>
35 </div>
36
37 <div class="post">
38 <time datetime="2025-05-02 Fri 21:10:00">2025-05-02</time>
39 <div class="post-content">
40 <a href="/blog/asahi-linux.html">Performance and Compatibility Report of Asahi Linux on Apple M2 MacBook Pro 16"</a>
41 <div class="post-tags">
42 <span class="tag">mac</span>
43 <span class="tag">apple</span>
44 <span class="tag">linux</span>
45 </div>
46 </div>
47 </div>
48
49 <br />
50 <a href="/blog/">All Posts →</a> 14 <a href="/blog/">All Posts →</a>
51</section> 15</section>
52 16