gitserver

self-hosted git server tooling
git clone https://git.ryansepassi.com/git/gitserver.git
Log | Files | Refs | README

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