#!/bin/sh
# mkws - build the website
#
#   mkws [-f] [-q] url [srcdir]
#
# Walks srcdir (default .) and turns every page into html next to its
# source, wrapped in share/l.upphtml:
#
#   foo.upphtml   -> foo.html     a template, see bin/pp
#   foo.uppxml    -> foo.xml      a template without the layout
#   foo.md        -> foo.html     markdown, rendered through share/md.upphtml,
#                                 or _md.upphtml in the same directory if
#                                 there is one (skipped when foo.upphtml exists)
#
# A page is only rebuilt when it is missing or older than its source,
# the layout, the helper library, or any file in its own directory tree.
# A page may list extra directories or files it depends on, relative to
# itself, in an html comment:  <!-- deps: ../Pictures ../Uploads -->
#
# Directories whose name starts with "." or "_", directories that contain
# a file named .nomkws, and bin, share and staging are left alone.  Files named README* or
# starting with "_" are never pages, so they can be included by other
# pages without becoming pages themselves.
#
# After the pages it writes sitemap.xml, Notes/rss.xml and the plain
# text copies of the posts in Notes/ascii/ for the gopher hole.
#
#   -f   rebuild everything
#   -q   be quiet
#
# url is the absolute url the site is served from, without a trailing
# slash, e.g. https://dflund.se/~getz

usage() { printf 'usage: mkws [-f] [-q] url [srcdir]\n' >&2; exit 1; }

force=0 quiet=0 status=0
while getopts fq opt; do
	case $opt in
	f) force=1 ;;
	q) quiet=1 ;;
	*) usage ;;
	esac
done
shift $((OPTIND - 1))
[ $# -ge 1 ] || usage

URL=${1%/}
cd "${2:-.}" || exit 1
SRC=$(pwd)
SITE=${MKWS_SITE:-"~getz"}
SHARE=${MKWS_SHARE:-share}
POSTS=${MKWS_POSTS:-Notes}
LAYOUT=$SHARE/l.upphtml
PPLIB=$SRC/$SHARE/lib.sh
PATH=$SRC/bin:$PATH
export URL SRC SITE SHARE PPLIB PATH

# directories with a .nomkws file, as a find(1) expression for srcprune
NOMKWS_EXPR="-o -name staging $(find . -name .nomkws | sed 's|/\.nomkws$||; s|.*/||; s|^|-o -name |' | tr '\n' ' ')"
export NOMKWS_EXPR

[ -f index.upphtml ] || [ -f index.md ] || { printf 'mkws: no index page in %s\n' "$SRC" >&2; exit 1; }
. "$PPLIB"

log() { [ $quiet = 1 ] || printf '%s\n' "$*"; }

# needs_build OUT PATH...   true when OUT is missing or any PATH (a file,
# or a directory searched recursively for source files) is newer
needs_build() {
	out=$1; shift
	[ $force = 1 ] && return 0
	[ -f "$out" ] || return 0
	for p; do
		if [ -d "$p" ]; then
			[ -n "$(srcfind "$p" -type f -newer "$out" -print | head -n 1)" ] && return 0
		elif [ "$p" -nt "$out" ]; then
			return 0
		fi
	done
	return 1
}

# deps FILE   directories and files FILE declares it depends on
deps() {
	sed -n 's/.*<!-- *deps: *\(.*[^ ]\) *-->.*/\1/p' "$1" | tr ' ' '\n' | while read -r d; do
		[ -n "$d" ] && printf '%s\n' "$(dirname "$1")/$d"
	done
}

# title FILE   the page title: title: metadata of a markdown file or its
# first heading, a <!-- title: ... --> comment in a template, else the
# directory name (nothing for the root)
title() {
	case $1 in
	*.md) t=$(meta "$1" title) || t=$(sed -n 's/^# \{1,\}//p' "$1" | head -n 1) ;;
	*) t=$(sed -n 's/.*<!-- *title: *\(.*[^ ]\) *-->.*/\1/p' "$1" | head -n 1) ;;
	esac
	if [ -z "$t" ]; then
		t=$(cd "$(dirname "$1")" && pwd); t=${t##*/}
		[ "$t" = "${SRC##*/}" ] && t=
	fi
	printf '%s' "$t"
}

# render OUT TEMPLATE ARG...
render() {
	out=$1; shift
	log "$out"
	if pp "$@" | sed -e '/^<!-- title: .* -->$/d' -e '/^<!-- deps: .* -->$/d' > "$out.tmp"; then
		mv "$out.tmp" "$out"
	else
		rm -f "$out.tmp"
		printf 'mkws: failed to build %s\n' "$out" >&2
		status=1
	fi
}

build_template() {
	src=$1 dir=$2
	ext=${src##*.upp}
	out=${src%.upp*}.$ext
	# shellcheck disable=SC2046
	needs_build "$out" "$dir" "$src" "$LAYOUT" "$PPLIB" $(deps "$src") || return 0
	TITLE=$(title "$src") DIR=$dir MD=; export TITLE DIR MD
	if [ "$ext" = html ]; then
		render "$out" "$LAYOUT" "$src" "$dir" "$URL"
	else
		render "$out" "$src" "$dir" "$URL"
	fi
}

build_markdown() {
	src=$1 dir=$2
	out=${src%.md}.html
	wrapper=$SHARE/md.upphtml
	[ -f "$dir/_md.upphtml" ] && wrapper=$dir/_md.upphtml
	# shellcheck disable=SC2046
	needs_build "$out" "$dir" "$src" "$LAYOUT" "$PPLIB" "$wrapper" $(deps "$wrapper") || return 0
	TITLE=$(title "$src") DIR=$dir MD=$src; export TITLE DIR MD
	render "$out" "$LAYOUT" "$wrapper" "$dir" "$URL"
}

skip_dir() {
	case ${1##*/} in .*|_*|bin|staging|"$SHARE") return 0 ;; esac
	[ -e "$1/.nomkws" ]
}

walk() {
	for f in "$1"/*.upp*; do
		[ -f "$f" ] || continue
		case ${f##*/} in README*|_*) continue ;; esac
		build_template "$f" "$1"
	done
	for f in "$1"/*.md; do
		[ -f "$f" ] || continue
		case ${f##*/} in README*|_*) continue ;; esac
		[ -f "${f%.md}.upphtml" ] && continue
		build_markdown "$f" "$1"
	done
	for d in "$1"/*/; do
		d=${d%/}
		[ -d "$d" ] && ! skip_dir "$d" && walk "$d"
	done
	return 0
}

walk .

log sitemap.xml
sitemap > sitemap.xml
if [ -d "$POSTS" ]; then
	log "$POSTS/rss.xml"
	rss "$POSTS" > "$POSTS/rss.xml"
	log "$POSTS/ascii/"
	gopher "$POSTS"
fi
exit $status
