website/build.sh

184 lines
5.4 KiB
Bash

#!/bin/sh
__BASE="${SHP_BASE:-"$PWD"}"
export _INCDIR="${SHP_INCDIR:-"${__BASE}/include"}"
export _BUILDDIR="${SHP_BUILDDIR:-"${__BASE}/build"}"
export _SRCDIR="${SHP_SRCDIR:-"${__BASE}/src"}"
export _NL="
"
# process an html formatted file either given or from stdin and output to stdout
# if a file is given, stdin is free to be used by any shp files it encounters
__process_shp() {
__SHLVL=$((__SHLVL + 1))
eval '__SH_FLAG'$__SHLVL'=""
__LINE_EXEC_'$__SHLVL'=""
while IFS= read -r __LINE'$__SHLVL'; do
if [ -z "$__SH_FLAG'$__SHLVL'" ]; then
case "$__LINE'$__SHLVL'" in
*"<?shp"*)
printf "%s" "${__LINE'$__SHLVL'%%<\?shp*}"
__LINE'$__SHLVL'="${__LINE'$__SHLVL'#*<\?shp}"
__SH_FLAG'$__SHLVL'=1
;;
*) echo "$__LINE'$__SHLVL'" ;;
esac
fi
if [ -n "$__SH_FLAG'$__SHLVL'" ]; then
__LINE_EXEC_'$__SHLVL'="$__LINE_EXEC_'$__SHLVL'$_NL$__LINE'$__SHLVL'"
case "$__LINE'$__SHLVL'" in
*"?>"*)
eval "${__LINE_EXEC_'$__SHLVL'%%\?>*}"
printf "%s" "${__LINE'$__SHLVL'#*\?>}"
__SH_FLAG'$__SHLVL'=""
__LINE_EXEC_'$__SHLVL'=""
;;
*) ;;
esac
fi
done '"${1:+"< \"\$1\""}"'
[ $__SH_FLAG'$__SHLVL' ] && eval "$__LINE_EXEC_'$__SHLVL'"'
__SHLVL=$((__SHLVL - 1))
}
__SHLVL=0
# lowdown wrapper function
__lowdown() {
lowdown --html-no-owasp --html-no-skiphtml --html-no-escapehtml --html-no-num-ent "$@" | \
sed -E '
s/&[lr]squo;/\&apos;/g
s/&ndash;/--/g
s/&[lr]dquo;/\&quot;/g
'
}
# process a pure markdown file
# uses a special file in _INCDIR, `markdown-template.sh` to create the html
__process_md() {
eval ' {
set_md_metadata
__process_shp "$_INCDIR"/_markdown-template.shp
}'"${1:+"< \"\$1\""}"
}
# to call when including a markdown file because we don't want to *process* the whole thing
__include_md() {
eval ' {
set_md_metadata
__lowdown
}'"${1:+"< \"\$1\""}"
}
# standard library
include() {
# if the path contains a slash, then treat it as-is
# else, try getting it from $_INCDIR
case "$1" in
*/*.md) __include_md "$1" ;;
*.md) __include_md "$_INCDIR"/"$1" ;;
*/*) __process_shp "$1" ;;
*) __process_shp "$_INCDIR"/"$1" ;;
esac
}
# set markdown metadata either given or from stdin
# why do we have this big eval here--why not use /dev/stdin?
# using /dev/stdin makes the input behave Very Weirdly, I can't really explain
# what is going on but it just doesn't work how one would expect
# this eval prevents a lengthy if-else statement
# I adapted this method to all other stuff that either accepts stdin or an argument
# for maximum portability, I guess. even though every relevant unix has /dev/stdin
# I guess it's paranoia for the accidentally swallowing stdin thing as well. whatever
set_md_metadata() {
eval ' {
# if 1st line isnt all -, skip setting metadata
IFS= read -r __first
case "$__first" in
*[!-]*) return ;;
esac
while IFS=" =" read -r __key __val; do
case "$__key" in
*[!-]*) eval "$__key=\$__val" ;;
*) return ;;
esac
done
} '"${1:+"< \"\$1\""}"
}
# good for inputs without many chars to escape
# so most titles, strings, etc.
# this is why it only accepts an argument and not stdin
escape() {
__ESC_STR=$*
# do this first to not create an infinite loop
while :; do
case "$__ESC_STR" in
*\&*) __ESC_STR_INT="${__ESC_STR%%&*}&amp;"; __ESC_STR="${__ESC_STR#*&}" ;;
*) __ESC_STR_INT="$__ESC_STR_INT$__ESC_STR"; break ;;
esac
done
__ESC_STR=$__ESC_STR_INT
while :; do
case "$__ESC_STR" in
*\<*) __ESC_STR="${__ESC_STR%<*}&lt;${__ESC_STR##*<}" ;;
*\>*) __ESC_STR="${__ESC_STR%>*}&gt;${__ESC_STR##*>}" ;;
*\"*) __ESC_STR="${__ESC_STR%\"*}&quot;${__ESC_STR##*\"}" ;;
*\'*) __ESC_STR="${__ESC_STR%\'*}&apos;${__ESC_STR##*\'}" ;;
*) break;
esac
done
printf '%s\n' "$__ESC_STR"
}
# good for large inputs with lots of chars to escape
# this means mostly full files, entire posts for putting in content for a feed
escapepipe() {
sed -e 's/&/\&amp;/g' -e 's/</\&lt;/g' -e 's/>/\&gt;/g' -e 's/"/\&quot;/g' -e "s/'/\\&apos;/g"
}
# build folder structure
find "$_SRCDIR" -type d -exec sh -c 'for d; do mkdir -p "$_BUILDDIR"/"${d#"$_SRCDIR"}"; done' sh {} +
# it's parallel time baby
# hopefully portable enough to not be an issue
__THREADS="$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null)"
[ $? -ne 0 ] \
&& echo 'unable to find number of cores! defaulting to 1 thread unless otherwise specified...' >&2 \
&& __THREADS=1
# make a parallel fifo/file descriptor we need
__fifo_para="$(mktemp -u -t "shpbuild.XXXXXX")"
mkfifo "$__fifo_para"
exec 9<>"$__fifo_para"
rm -f "$__fifo_para"
while [ "$__THREADS" -gt 0 ]; do
printf "\n" >&9 # start with THREADS amount of lines in fd 9 for later
__THREADS="$((__THREADS - 1))"
done
# read each line from fd 9, launch new program for each line
# print a line after program finished such that another one can take its place
__run_in_parallel() {
read -r __ <&9
{
"$@"
printf '\n' >&9
} &
}
while IFS= read -r _FILE; do
cd "${_FILE%/*}"
export _OUTFILE="$_BUILDDIR/${_FILE#"$_SRCDIR/"}"
case "${_FILE##*/}" in
*.[hH][tT][mM][lL]|*.[sS][hH][pP]) ( __run_in_parallel __process_shp "$_FILE" ) > "${_OUTFILE%.*}.html" ;;
*.[mM][dD]) ( __run_in_parallel __process_md "$_FILE" ) > "${_OUTFILE%.*}.html" ;;
*.[sS][hH]) ( __run_in_parallel . "$_FILE" ) ;; # don't autocopy. this is for code :)
*) __run_in_parallel cp -p "$_FILE" "$_OUTFILE" ;;
esac
done <<-EOF
$(find "$_SRCDIR" -type f)
EOF
[ -f "$_INCDIR/_postbuild.sh" ] && . "$_INCDIR/_postbuild.sh"