stagit-update (5689B)
1 #!/bin/sh 2 # Regenerate stagit HTML for one repo (arg) or all (no args). Rebuilds indexes 3 # and mirrors public repos into ~/repos/www-public/ for Bunny sync. 4 set -eu 5 6 REPOS=$HOME/repos 7 ASSETS=$REPOS/assets 8 PRIV=$REPOS/www 9 PUB=$REPOS/www-public 10 CACHE=$REPOS/.stagit-cache 11 12 mkdir -p "$PRIV" "$PUB" "$PUB/git" "$CACHE" 13 14 link_assets() { 15 out=$1 16 for f in style.css logo.png favicon.png; do 17 if [ -f "$ASSETS/$f" ]; then 18 ln -sfn "../$f" "$out/$f" 19 fi 20 done 21 } 22 23 is_empty() { 24 ! git --git-dir="$1" rev-parse HEAD >/dev/null 2>&1 25 } 26 27 # For every .md file stagit rendered into $out/file/, replace the <pre id="blob"> 28 # block with md4c-rendered HTML. Source comes from git HEAD (same content stagit 29 # saw), not the escaped HTML. No-op if md2html isn't installed. 30 render_markdown() { 31 out=$1 32 repo=$2 33 command -v md2html >/dev/null 2>&1 || return 0 34 [ -d "$out/file" ] || return 0 35 find "$out/file" -type f -name '*.md.html' | while read -r html; do 36 rel=${html#"$out/file/"} 37 rel=${rel%.html} 38 tmp=$(mktemp) 39 if git --git-dir="$repo" show "HEAD:$rel" 2>/dev/null | md2html --github > "$tmp" 2>/dev/null; then 40 awk -v mdfile="$tmp" ' 41 /<pre id="blob">/ { 42 print "<div id=\"md\">" 43 while ((getline line < mdfile) > 0) print line 44 close(mdfile) 45 print "</div>" 46 skip=1 47 next 48 } 49 skip && /<\/pre>/ { skip=0; next } 50 !skip { print } 51 ' "$html" > "$html.tmp" && mv "$html.tmp" "$html" 52 fi 53 rm -f "$tmp" 54 done 55 } 56 57 # Replace stagit's flat <table id="files"> in files.html with a collapsible 58 # <details> directory tree built from git HEAD (via bin/filetree-html). No-op if 59 # files.html or the helper is missing. 60 render_file_tree() { 61 out=$1 62 repo=$2 63 [ -f "$out/files.html" ] || return 0 64 [ -x "$REPOS/bin/filetree-html" ] || return 0 65 tmp=$(mktemp) 66 "$REPOS/bin/filetree-html" "$repo" > "$tmp" 2>/dev/null || { rm -f "$tmp"; return 0; } 67 awk -v frag="$tmp" ' 68 !done && /<table id="files">/ { 69 while ((getline line < frag) > 0) print line 70 close(frag); skip=1; done=1; next 71 } 72 skip && /<\/table>/ { skip=0; next } 73 skip { next } 74 { print } 75 ' "$out/files.html" > "$out/files.html.tmp" && mv "$out/files.html.tmp" "$out/files.html" 76 rm -f "$tmp" 77 } 78 79 build_one() { 80 repo=$1 81 [ -d "$repo" ] || return 0 82 # Skip repos with no commits yet — stagit errors on them, and there's 83 # nothing meaningful to render until the first push. 84 is_empty "$repo" && return 0 85 name=$(basename "$repo" .git) 86 87 # Per-output cache files — stagit's -c caches commit HTMLs, keyed to the 88 # output dir that stagit wrote them to, so PRIV and PUB need separate caches. 89 out=$PRIV/$name 90 mkdir -p "$out" 91 (cd "$out" && stagit -c "$CACHE/$name.priv.cache" "$repo") 92 link_assets "$out" 93 render_markdown "$out" "$repo" 94 render_file_tree "$out" "$repo" 95 96 if [ -f "$repo/public" ]; then 97 out=$PUB/$name 98 mkdir -p "$out" 99 (cd "$out" && stagit -c "$CACHE/$name.pub.cache" "$repo") 100 link_assets "$out" 101 render_markdown "$out" "$repo" 102 render_file_tree "$out" "$repo" 103 # bare repo mirror for `git clone` (skip server-side bits) 104 mkdir -p "$PUB/git/$name.git" 105 rsync -a --delete --exclude=hooks --exclude=public "$repo/" "$PUB/git/$name.git/" 106 # github-style archive tarballs (with .b2 sidecars) under <name>/archive/ 107 "$REPOS/bin/archive-refs" "$repo" 108 else 109 # drop public copy if marker was removed (archive-refs handles its own) 110 rm -rf "$PUB/$name" "$PUB/git/$name.git" 111 fi 112 } 113 114 if [ $# -ge 1 ]; then 115 build_one "$REPOS/$1.git" 116 else 117 for r in "$REPOS"/*.git; do build_one "$r"; done 118 fi 119 120 # shared assets at tree root 121 for f in style.css logo.png favicon.png; do 122 [ -f "$ASSETS/$f" ] || continue 123 cp -u "$ASSETS/$f" "$PRIV/" 124 cp -u "$ASSETS/$f" "$PUB/" 125 done 126 127 # shared fonts at tree root (referenced as /fonts/* from style.css) 128 if [ -d "$ASSETS/fonts" ]; then 129 mkdir -p "$PRIV/fonts" "$PUB/fonts" 130 for f in "$ASSETS/fonts"/*; do 131 [ -f "$f" ] || continue 132 cp -u "$f" "$PRIV/fonts/" 133 cp -u "$f" "$PUB/fonts/" 134 done 135 fi 136 137 # indexes 138 all_list="" 139 pub_list="" 140 for r in "$REPOS"/*.git; do 141 [ -d "$r" ] || continue 142 is_empty "$r" && continue 143 all_list="$all_list $r" 144 if [ -f "$r/public" ]; then 145 pub_list="$pub_list $r" 146 fi 147 done 148 149 # After stagit-index runs, point each repo's row link at file/README.md.html 150 # instead of log.html when a rendered README exists. 151 readme_link_rewrite() { 152 idx=$1; base=$2; shift 2 153 [ -f "$idx" ] || return 0 154 for repo in "$@"; do 155 name=$(basename "$repo" .git) 156 [ -f "$base/$name/file/README.md.html" ] || continue 157 sed -i "s|href=\"$name/log\\.html\"|href=\"$name/file/README.md.html\"|g" "$idx" 158 done 159 } 160 161 if [ -n "$all_list" ]; then 162 # shellcheck disable=SC2086 163 stagit-index $all_list > "$PRIV/index.html" 164 # shellcheck disable=SC2086 165 readme_link_rewrite "$PRIV/index.html" "$PRIV" $all_list 166 else 167 : > "$PRIV/index.html" 168 fi 169 170 if [ -n "$pub_list" ]; then 171 # shellcheck disable=SC2086 172 stagit-index $pub_list > "$PUB/index.html" 173 # shellcheck disable=SC2086 174 readme_link_rewrite "$PUB/index.html" "$PUB" $pub_list 175 else 176 : > "$PUB/index.html" 177 fi 178 179 # optional: user-customizable hook for pushing $PUB to Bunny 180 [ -x "$REPOS/bin/publish-public" ] && "$REPOS/bin/publish-public" || true