From e94aa713d4ce61666b521b174b9981b957b48ec7 Mon Sep 17 00:00:00 2001 From: Case Duckworth Date: Sun, 7 Aug 2022 00:49:11 -0500 Subject: "Real" initial commit --- feed.tmpl.xml | 12 +++ footer.htm | 1 - header.htm | 2 - ht | 287 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ht.sh | 60 ------------ index.tmpl.htm | 12 +++ page.tmpl.htm | 10 ++ test.ht | 32 ------- 8 files changed, 321 insertions(+), 95 deletions(-) create mode 100644 feed.tmpl.xml delete mode 100644 footer.htm delete mode 100644 header.htm create mode 100755 ht delete mode 100755 ht.sh create mode 100644 index.tmpl.htm create mode 100644 page.tmpl.htm delete mode 100644 test.ht diff --git a/feed.tmpl.xml b/feed.tmpl.xml new file mode 100644 index 0000000..13182b3 --- /dev/null +++ b/feed.tmpl.xml @@ -0,0 +1,12 @@ + + + acdw + a home on the web + + + $BASEURL + ht + https://acdw.casa/gcl/ + $(date -R) + $(cat) + diff --git a/footer.htm b/footer.htm deleted file mode 100644 index 0ceac0f..0000000 --- a/footer.htm +++ /dev/null @@ -1 +0,0 @@ - diff --git a/header.htm b/header.htm deleted file mode 100644 index 14eeb22..0000000 --- a/header.htm +++ /dev/null @@ -1,2 +0,0 @@ - -${title} diff --git a/ht b/ht new file mode 100755 index 0000000..c8cef5c --- /dev/null +++ b/ht @@ -0,0 +1,287 @@ +#!/bin/sh + +### Code: + +usage() { + cat <<\EOF +ht: Build a website +Usage: ht -h + ht [OPTIONS...] FILE... + +FLAGS: + -h Show this help and exit. + -B Treat all targets as "new" (like in `make'). + +OPTIONS: + -u BASEURL The base URL of the built site. Default: https://example.com + -o OUTD Output built files to OUTD. Default: ./out/ + -w WORKD Use WORKD as the working directory. Default: /tmp/ht/ + -p PROC Use PROC to process each input file. Default: ./ht.awk + -P TEMPLATE Use TEMPLATE as the page template. Default: ./page.tmpl.htm + -i ITEMFMT Format individual items with ITEMFMT in the site index. + -I TEMPLATE Use TEMPLATE as the index template. Default: ./index.tmpl.htm + -f ITEMFMT Format individual items with ITEMFMT in the site feed. + -F TEMPLATE Use TEMPLATE as the feed template. Default: ./feed.tmpl.xml + -s DIRECTORY The DIRECTORY holding static files (images, css, etc.). + Default: ./static/ + -S DIRECTORY The DIRECTORY to copy static files to. Default: ./out/static. + +PARAMETERS: + FILE... The list of files to include in the website. +EOF + exit "${1:-0}" +} + +main() { + configure "$@" + shift $((OPTIND - 1)) + prepare + static_copy + + for input; do + page_write "$PAGE_TEMPLATE" "$input" + done + + if [ -n "$INDEXEACH" ]; then + index_write "$INDEX_TEMPLATE" "$INDEXEACH" "$OUTD/$INDEXNAME" + fi + if [ -n "$FEEDEACH" ]; then + index_write "$FEED_TEMPLATE" "$FEEDEACH" "$OUTD/$FEEDNAME" + fi + printf 'Done. ' >&2 + if test -f "$WORKD/ok"; then + eprint "No errors reported." + else + eprint "There were errors." + fi +} + +configure() { + OUTD="${HT_OUT_DIR:-./out}" + WORKD="${HT_WORKD:-/tmp/ht}" + PROC="${HT_PROC:-./ht.awk}" # XXX: Needs better resolution + BASEURL="${HT_BASEURL:-https://example.com}" + PAGE_TEMPLATE="${HT_PAGE_TEMPLATE:-./page.tmpl.htm}" + INDEX_TEMPLATE="${HT_INDEX_TEMPLATE:-./index.tmpl.htm}" + FEED_TEMPLATE="${HT_FEED_TEMPLATE:-./feed.tmpl.xml}" + ALLNEW=false + STATICD="${HT_STATIC_DIR:-./static}" + STATICOUT="${HT_STATIC_OUTPUT_DIR:-${OUTD}/static}" + + INDEXNAME="${HT_INDEX_NAME:-index.html}" + if [ -n "$HT_INDEX_ITEM_FORMAT" ]; then + INDEXEACH="$HT_INDEX_ITEM_FORMAT" + else + # shellcheck disable=2016 + INDEXEACH='
  • ${title}
  • ' + fi + + FEEDNAME="${HT_FEED_NAME:-feed.xml}" + if [ -n "$HT_FEED_ITEM_FORMAT" ]; then + FEEDEACH="$HT_FEED_ITEM_FORMAT" + else + # shellcheck disable=2016 + FEEDEACH=' + $BASEURL/$file + + ${title} + $(date -u -d "@${time}" -R) + $AUTHOR + + + + ' + fi + + # shellcheck disable=2034 # BASEURL is used in templates + while getopts hBo:w:p:i:I:f:F:u:s:S: opt; do + case "$opt" in + h) usage ;; + o) OUTD="$OPTARG" ;; + w) WORKD="$OPTARG" ;; + p) PROC="$OPTARG" ;; + P) PAGE_TEMPLATE="$OPTARG" ;; + i) INDEXEACH="$OPTARG" ;; + I) INDEX_TEMPLATE="$OPTARG" ;; + f) FEEDEACH="$OPTARG" ;; + F) FEED_TEMPLATE="$OPTARG" ;; + u) BASEURL="$OPTARG" ;; + B) ALLNEW=true ;; + s) STATICD="$OPTARG" ;; + S) STATICOUT="$OPTARG" ;; + *) usage 1 ;; + esac + done + + INDEX="$WORKD/index.txt" +} + +prepare() { + test -n "$WORKD" && rm -rf "$WORKD" + mkdir -p "$OUTD" "$WORKD" + test -x "$PROC" || { + eprint "Can't find processor: $PROC" + exit 2 + } + touch "$WORKD/ok" +} + +### Utilities + +print() { + printf '%s\n' "$*" +} + +eprint() { + print "$@" >&2 +} + +olderp() { # olderp REF OTHER + # Is REF older than OTHER ? Necessary b/c test -ot is not POSIX. + a="$1" + b="$2" + + if a_age="$(stat -c%Y "$a" 2>/dev/null)"; then + a_exist=true + else + a_exist=false + fi + if b_age="$(stat -c%Y "$b" 2>/dev/null)"; then + b_exist=true + else + b_exist=false + fi + + if $a_exist && ! $b_exist; then + # B doesn't exist -- so B is newer + # eprint "$a is older than $b (doesn't exist)" + return 0 + elif ! $a_exist && $b_exist; then + # A doesn't exist -- so A is newer + # eprint "$a (doesn't exist) is newer than $b" + return 1 + else + # A's age > B's age ? + # eprint "$a ($a_age) <= $b ($b_age)?" + test "$a_age" -le "$b_age" + fi +} + +uptodate() { # uptodate FILE DEPENDENCIES... # && return + # Check if FILE is up-to-date with DEPENDENCIES. + $ALLNEW && return 1 + uptodate=1 + file="$1" + shift + for dep in "$@"; do + olderp "$dep" "$file" && uptodate=0 + done + return $uptodate +} + +### File conversion + +template_expand() { # template_expand TEMPLATES... + end="tmpl_$(date +%s)_${count:=0}" + eval "$( + print "cat <<$end" + cat "$@" + print + print "$end" + )" + count=$((count + 1)) +} + +meta_save() { # meta_save [-c COMMENTCH] [-m METACH] META_FILE < INPUT + COMMENTCH=';' + METACH='@' + while getopts c:m: opt; do + case "$opt" in + c) COMMENTCH="$OPTARG" ;; + m) METACH="$OPTARG" ;; + *) ;; + esac + done + shift $((OPTIND - 1)) + sed -n "s/^${COMMENTCH}${COMMENTCH}${METACH}//p" 2>/dev/null | tee "$1" +} + +meta_clear() { # meta_clear META_FILE + while read -r line; do + case "$line" in + *'()'*) unset -f "${line%()*}" ;; + *=*) unset -v "${line%=*}" ;; + *) ;; + esac + done <"$1" 2>/dev/null +} + +page_write() { # html_write TEMPLATE INPUT + template="$1" + file="$2" + + fn="${file##*/}" + fn="${fn%%.*}" + out="${OUTD}/${fn}/index.html" + mkdir -p "${out%/*}" + meta="$WORKD/${fn}.meta" + + eval "$(meta_save "$meta" <"$file")" + stat -c "%Y ${fn} $meta" "$file" >>"$INDEX" + + uptodate "$out" "$template" "$file" && return + + eprint "Page: $file -> $out" + if + ! "$PROC" "$file" | + tee "$WORKD/${fn}.body" | + template_expand "$template" >"$out" + then + eprint "$file -> $out ... ERROR!" + rm "$WORKD/ok" + return + fi + meta_clear "$meta" +} + +index_write() { # index_write TEMPLATE EACH OUTFILE + template="$1" + each="$2" + out="$3" + + test -f "$INDEX" || return 1 + uptodate "$out" "$template" "$INDEX" && return + + eprint "Index: $out" + # shellcheck disable=2034 # file and time can be used in `each' + sort -k1,1 -nr "$INDEX" | + while IFS=' ' read -r time file meta; do + # shellcheck disable=1090 + . "$meta" + if ! item="$(eval print "\"$each\"")"; then + eprint "ERROR: couldn't add '$file' to $out" + rm "$WORKD/ok" + fi + print "$item" + meta_clear "$meta" + done | + template_expand "$template" >"$out" +} + +### Static files + +static_copy() { # static_copy + test -d "$STATICD" || return 1 + if command -v rsync 2>/dev/null; then + eprint rsync -avz "$STATICD/" "$STATICOUT/" + rsync -avz "$STATICD/" "$STATICOUT/" + else + eprint cp -r "$STATICD"/* "$STATICOUT/" + cp -r "$STATICD"/* "$STATICOUT/" + fi +} + +### Do the thing + +test "$DEBUG" && set -x +test "$SOURCE" || main "$@" diff --git a/ht.sh b/ht.sh deleted file mode 100755 index 7f20255..0000000 --- a/ht.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/sh -# ht.sh -# *.ht -> *html - -# config -header_file=header.htm -footer_file=footer.htm -meta_file=meta.sh - -print() { - printf '%s\n' "$*" -} - -htt() { # htt FILE - # Like `cat`, but with templating. - : "${HT_TMPL_COUNT:=0}" - ht_end="ht_main_$(date +%s)_${HT_TMPL_COUNT}" # be extra double sure - eval "$( - print "cat <<$ht_end" - cat "$@" - print - print "$ht_end" - )" - HT_TMPL_COUNT=$((HT_TMPL_COUNT + 1)) -} - -htmeta_clear() { - # Generate metadata-clearing commands from $meta_file. - while read -r line; do - case "$line" in - *'()'*) # function - unset -f "${line%()*}" - ;; - *=*) # variable assignment - unset -v "${line%=*}" - ;; - *) # other -- XXX: Don't know what to do - ;; - esac - done <"$meta_file" 2>/dev/null -} - -htmeta() { # htmeta FILE - # Collect metadata from FILE. - # Metadata looks like this: `;;@` - sed -n 's/^;;@//p' "$1" 2>/dev/null | tee "$meta_file" -} - -main() { - # Make two passes over each input file, collecting metadata and content. - # Of course, this isn't safe, but you trust yourself, right? - for file; do - eval "$(htmeta_clear)" - eval "$(htmeta "$file")" - ./ht.awk <"$file" | htt "$header_file" - "$footer_file" - done -} - -test "$DEBUG" && set -x -test "$SOURCE" || main "$@" diff --git a/index.tmpl.htm b/index.tmpl.htm new file mode 100644 index 0000000..5884af5 --- /dev/null +++ b/index.tmpl.htm @@ -0,0 +1,12 @@ + + + + acdw! + + + + + + diff --git a/page.tmpl.htm b/page.tmpl.htm new file mode 100644 index 0000000..6655494 --- /dev/null +++ b/page.tmpl.htm @@ -0,0 +1,10 @@ + + + + ${title} + + + $(cat) + + + diff --git a/test.ht b/test.ht deleted file mode 100644 index 58125a8..0000000 --- a/test.ht +++ /dev/null @@ -1,32 +0,0 @@ -# ht: a bespoke document preparation system -;;@title="ht: a bespoke document preparation system" -;; comments are like this. -;; they're a good time. - -`ht -is a quasi-line-based markup language that takes inspiration from -@https://gemini.circumlunar.space/docs/gemtext.gmi gemtext\ -, -@https://daringfireball.net/projects/markdown/ markdown\ -, and others. -Its aim is to be somewhat easy to read while being fairly easy to parse. - -In fact, -`ht -is a simple awk script. - -## Usage - -- one -- two -- three - -ordered list: - -% one -% two -% three - -``` -./ht.awk source.ht -``` -- cgit 1.4.1-21-gabe81