#! /bin/bash set -e # shell opt/var {{{ # Executable command for markdown declare -r MARKDOWN_BIN="markdown -f fencedcode,autolink,alphalist,autolink,footnote,definitionlist" # Directory for input/output declare -r INPUT_DIR=${INPUT_DIR:?ENV \"INPUT_DIR\" is not set} declare -r OUTPUT_DIR=${OUTPUT_DIR:?ENV \"OUTPUT_DIR\" is not set} declare -r ASSET_DIR=${ASSET_DIR:-`pwd`/assets} declare -r TEMPLATE_DIR=${TEMPLATE_DIR:-`pwd`/templates} declare -r RSSFILE=feed.rss declare -r HOST=${HOST:?} # }}} # functions {{{ # add indent for each line except
{{{
indent() {
indent="$(printf "%${1}s")"
sed "/^$/ !s/^/${indent}/; //!b; :pre; N; /<\/pre>/!b pre"
}
# }}}
# print comment block {{{
comment_block() {
[ "$comment" = true ] || return 0
<<-COMMENT cat
COMMENT
}
# }}}
# generate html by heredoc from .md file and templates {{{
html() {
<<-END_OF_HTML sed '1d;$d'
$(echo "$HEAD" | { [ -z "${title}" ] && cat || sed "/^ */c \ \ ${title} "; } )
${HEADER}
$(sed -E 's/\[([^]]+)\]\(\)/[\1](\1)/g' | ${MARKDOWN_BIN} | indent 4)
$(comment_block | indent 2)
${FOOTER}
END_OF_HTML
}
# }}}
# list of latest posts in markdown format {{{
latest_posts() {
(IFS=$'\n'; echo "${index_list[*]}") | sort -r | head -20 | while read date path title; do
echo "- [$title](/$path)"
done
}
# }}}
# process frontmatter {{{
get_frontmatter() {
sed -n '1 {//q; s/"//g; s/://p'
}
check_frontmatter() {
unset title public index type date draft
# define local variables for frontmatter
while read key value; do
[ -n "$key" ] || continue
export ${key,,}="$value"
done <<<"$(get_frontmatter)"
# don't process draft after function call
test "$draft" != "" && return 1
# skip making index in some cases
test "$title" = "" && return 0
test "$public" = false && return 0
test "$index" = false && return 0
test "$type" = demo && return 0
iso8601=$(date --iso --date "${date:-NULL}" 2>/dev/null)
test "$iso8601" = "" && return 0
# put frontmatter info into variable "index" if title and date are valid
index_list+=("$iso8601 $path $title")
}
# }}}
# remove SGML comments but keep the top one as frontmatter {{{
ignore_comment() {
sed '1! { /^$/ d }'
}
# }}}
# RSS Feed {{{
get_channel_item() {
path=${1#${OUTPUT_DIR}}
<<-ITEM cat
-
$(grep -Po '
.+ ' ${1} | head -1)
https://${HOST}${path}
$(md5sum ${1} | cut -d' ' -f1)
$(date --rfc-email -r ${1})
ITEM
}
make_rss() {
# Use modified time to get latest html files
items="$(
ls -1t $OUTPUT_DIR/**/**html \
| head -10 \
| while read html_file; do
get_channel_item $html_file
done \
| indent 2 \
)"
<<-RSS cat
Dummy Website
https://${HOST}
$global_description
zh-tw
$(date --rfc-email)
https://www.rssboard.org/rss-specification
${items}
RSS
}
# }}}
# }}}
# prepare directory for outputs {{{
mkdir -p $OUTPUT_DIR/
rm -rf $OUTPUT_DIR/**{md,html,css}
rsync -avrh --delete $ASSET_DIR/ $OUTPUT_DIR/assets/
rsync -avrh --delete $INPUT_DIR/scripts/ $OUTPUT_DIR/scripts/
if [ -f $ASSET_DIR/top.list ]; then
while read file; do
ln -sf assets/$file $OUTPUT_DIR/$file
done <$ASSET_DIR/top.list
fi
# }}}
# content of templates {{{
declare -r HEAD="$(cat $TEMPLATE_DIR/head.html)"
declare -r HEADER="$(<$TEMPLATE_DIR/header.html indent 2)"
declare -r FOOTER="$(<$TEMPLATE_DIR/footer.html indent 2)"
declare -r INDEX_TEMPLATE="$(cat $TEMPLATE_DIR/index.md)"
index_list=()
# }}}
# For each markdown file {{{
files="$(find "$INPUT_DIR" -type f -name '*md' -not -path './templates/*')"
total=$(wc -l <<<"$files")
declare -i counter
for file in $files; do
# set variables
path=$(<<<"$file" sed "s#^${INPUT_DIR}/##; s/\.md$//").html; mkdir -p $(dirname $OUTPUT_DIR/$path)
content="$(<${file} ignore_comment)"
# use frontmatter to decide making html file or not
<<<"$content" check_frontmatter || continue
# log
echo -e "\033[1K\r$((counter+=1))/$total\t\tprocessing $path"
# add original content to $OUTPUT_DIR
# and generate html file with
echo "$content" \
| tee $OUTPUT_DIR/${file#${INPUT_DIR}/} \
| { [ -n "$title" ] && echo "# $title"; cat; } \
| html >$OUTPUT_DIR/$path
# Set modified time for index/RSS
mtime='@0'
[ ! "$public" = false ] && [ -n "$iso8601" ] && mtime="$iso8601"
touch -m -d "$mtime" $OUTPUT_DIR/$path
unset h1 comment
done
echo
# }}}
# make index.html {{{
echo -en "Making\t\tindex.html"
export title=""
{
echo "${INDEX_TEMPLATE}"
echo -e '
\n\n'
latest_posts
} \
| tee $OUTPUT_DIR/index.md \
| html >$OUTPUT_DIR/index.html
touch -m -d @0 $OUTPUT_DIR/index.html
echo -e "\tgenerated"
# }}}
# make RSS file {{{
echo -en "Making\t\tRSS"
make_rss >$OUTPUT_DIR/$RSSFILE
echo -e "\t\tgenerated"
# }}}
# vim: fdm=marker fdl=0