shmage-site

scripts and documents that generate shmage.xyz
git clone git://git.shmage.xyz/shmage-site.git
Log | Files | Refs

ssg5 (6421B)


      1 #!/bin/sh -e
      2 #
      3 # https://rgz.ee/bin/ssg5
      4 # Copyright 2018-2019 Roman Zolotarev <hi@romanzolotarev.com>
      5 #
      6 # Permission to use, copy, modify, and/or distribute this software for any
      7 # purpose with or without fee is hereby granted, provided that the above
      8 # copyright notice and this permission notice appear in all copies.
      9 #
     10 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     15 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     16 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17 #
     18 
     19 main() {
     20 	test -n "$1" || usage
     21 	test -n "$2" || usage
     22 	test -n "$3" || usage
     23 	test -n "$4" || usage
     24  	test -d "$1" || no_dir "$1"
     25  	test -d "$2" || no_dir "$2"
     26 
     27 	src=$(readlink_f "$1")
     28 	dst=$(readlink_f "$2")
     29 
     30 	IGNORE=$(
     31 		if ! test -f "$src/.ssgignore"
     32 		then
     33 			printf ' ! -path "*/.*"'
     34 			return
     35 		fi
     36 		while read -r x
     37 		do
     38 			test -n "$x" || continue
     39 			printf ' ! -path "*/%s*"' "$x"
     40 		done < "$src/.ssgignore"
     41 	)
     42 
     43 	# files
     44 
     45 	title="$3"
     46 
     47 	h_file="$src/_header.html"
     48 	h_index_file="$src/_header-index.html"
     49 	f_file="$src/_footer.html"
     50 	f_index_file="$src/_footer-index.html"
     51 	test -f "$f_file" && DEFFOOTER=$(cat "$f_file") && export DEFFOOTER
     52 	test -f "$f_index_file" && INDEXFOOTER=$(cat "$f_index_file") && export INDEXFOOTER
     53 	test -f "$h_file" && DEFHEADER=$(cat "$h_file") && export DEFHEADER
     54 	test -f "$h_index_file" && INDEXHEADER=$(cat "$h_index_file") && export INDEXHEADER
     55 
     56 	list_dirs "$src" |
     57 	(cd "$src" && cpio -pdu "$dst")
     58 
     59 	fs=$(
     60  	if test -f "$dst/.files"
     61 	then list_affected_files "$src" "$dst/.files"
     62 	else list_files "$1"
     63 	fi
     64 	)
     65 
     66 	if test -n "$fs"
     67 	then
     68 		echo "$fs" | tee "$dst/.files"
     69 
     70 		if echo "$fs" | grep -q '\.md$'
     71 		then
     72 			if test -x "$(which lowdown 2> /dev/null)"
     73 			then
     74 				echo "$fs" | grep '\.md$' |
     75 				render_md_files_lowdown "$src" "$dst" "$title"
     76 			else
     77 				if test -x "$(which markdown 2> /dev/null)"
     78 				then
     79 					echo "$fs" | grep '\.md$' |
     80 					render_md_files_markdown "$src" "$dst" "$title"
     81 				else
     82 					echo "couldn't find lowdown nor markdown"
     83 					exit 3
     84 				fi
     85 			fi
     86 		fi
     87 
     88 		echo "$fs" | grep '\.html$' |
     89 		render_html_files "$src" "$dst" "$title"
     90 
     91 		echo "$fs" | grep -Ev '\.md$|\.html$' |
     92 		(cd "$src" && cpio -pu "$dst")
     93 	fi
     94 
     95 	printf '[ssg] ' >&2
     96 	print_status 'file, ' 'files, ' "$fs" >&2
     97 
     98 
     99 	# sitemap
    100 
    101 	base_url="$4"
    102 	date=$(date +%Y-%m-%d)
    103  	urls=$(list_pages "$src")
    104 
    105 	test -n "$urls" &&
    106 	render_sitemap "$urls" "$base_url" "$date" > "$dst/sitemap.xml"
    107 
    108 	print_status 'url' 'urls' "$urls" >&2
    109 	echo >&2
    110 }
    111 
    112 
    113 readlink_f() {
    114 	file="$1"
    115 	cd "$(dirname "$file")"
    116 	file=$(basename "$file")
    117 	while test -L "$file"
    118 	do
    119 		file=$(readlink "$file")
    120 		cd "$(dirname "$file")"
    121 		file=$(basename "$file")
    122 	done
    123 	dir=$(pwd -P)
    124 	echo "$dir/$file"
    125 }
    126 
    127 
    128 print_status() {
    129 	test -z "$3" && printf 'no %s' "$2" && return
    130 
    131 	echo "$3" | awk -v singular="$1" -v plural="$2" '
    132 	END {
    133 		if (NR==1) printf NR " " singular
    134 		if (NR>1) printf NR " " plural
    135 	}'
    136 }
    137 
    138 
    139 usage() {
    140 	echo "usage: ${0##*/} src dst title base_url" >&2
    141 	exit 1
    142 }
    143 
    144 
    145 no_dir() {
    146 	echo "${0##*/}: $1: No such directory" >&2
    147 	exit 2
    148 }
    149 
    150 list_dirs() {
    151 	cd "$1" && eval "find . -type d ! -name '.' ! -path '*/_*' $IGNORE"
    152 }
    153 
    154 
    155 list_files() {
    156 	cd "$1" && eval "find . -type f ! -name '.' ! -path '*/_*' $IGNORE"
    157 }
    158 
    159 
    160 list_dependant_files () {
    161  	e="\\( -name '*.html' -o -name '*.md' -o -name '*.css' -o -name '*.js' \\)"
    162 	cd "$1" && eval "find . -type f ! -name '.' ! -path '*/_*' $IGNORE $e"
    163 }
    164 
    165 list_newer_files() {
    166 	cd "$1" && eval "find . -type f ! -name '.' $IGNORE -newer $2"
    167 }
    168 
    169 
    170 has_partials() {
    171 	grep -qE '^./_.*\.html$|^./_.*\.js$|^./_.*\.css$'
    172 }
    173 
    174 
    175 list_affected_files() {
    176 	fs=$(list_newer_files "$1" "$2")
    177 
    178 	if echo "$fs" | has_partials
    179 	then list_dependant_files "$1"
    180 	else echo "$fs"
    181 	fi
    182 }
    183 
    184 
    185 render_html_files() {
    186 	while read -r f
    187 	do 
    188 		if $(echo "$1/$f" | grep "index.html" > /dev/null); then
    189 		    HEADER="$INDEXHEADER" && export HEADER
    190 		    FOOTER="$INDEXFOOTER" && export FOOTER
    191 		else
    192 		    HEADER="$DEFHEADER" && export HEADER
    193 		    FOOTER="$DEFFOOTER" && export FOOTER
    194 		fi
    195 		render_html_file "$3" < "$1/$f" > "$2/$f"
    196 	done
    197 }
    198 
    199 
    200 render_md_files_lowdown() {
    201 	while read -r f
    202 	do
    203 		lowdown \
    204 		-D html-skiphtml \
    205 		-d metadata \
    206 		-d autolink < "$1/$f" |
    207 		render_html_file "$3" \
    208 		> "$2/${f%\.md}.html"
    209 	done
    210 }
    211 
    212 
    213 render_md_files_markdown() {
    214 	while read -r f
    215 	do
    216 		if $(echo "$1/$f" | grep "index.md" > /dev/null); then
    217 		    HEADER="$INDEXHEADER" && export HEADER
    218 		    FOOTER="$INDEXFOOTER" && export FOOTER
    219 		else
    220 		    HEADER="$DEFHEADER" && export HEADER
    221 		    FOOTER="$DEFFOOTER" && export FOOTER
    222 		fi
    223 		markdown < "$1/$f" |
    224 		render_html_file "$3" \
    225 		> "$2/${f%\.md}.html"
    226 	done
    227 }
    228 
    229 
    230 render_html_file() {
    231 	# h/t Devin Teske
    232 	awk -v title="$1" '
    233 	{ body = body "\n" $0 }
    234 	END {
    235 		body = substr(body, 2)
    236 		if (body ~ /<[Hh][Tt][Mm][Ll]/) {
    237 			print body
    238 			exit
    239 		}
    240 		if (match(body, /<[[:space:]]*[Hh]1(>|[[:space:]][^>]*>)/)) {
    241 			t = substr(body, RSTART + RLENGTH)
    242 			sub("<[[:space:]]*/[[:space:]]*[Hh]1.*", "", t)
    243 			gsub(/^[[:space:]]*|[[:space:]]$/, "", t)
    244 			if (t) title = t " &mdash; " title
    245 		}
    246 		n = split(ENVIRON["HEADER"], header, /\n/)
    247 		for (i = 1; i <= n; i++) {
    248 			if (match(tolower(header[i]), "<title></title>")) {
    249 				head = substr(header[i], 1, RSTART - 1)
    250 				tail = substr(header[i], RSTART + RLENGTH)
    251 				print head "<title>" title "</title>" tail
    252 			} else print header[i]
    253 		}
    254 		print body
    255 		print ENVIRON["FOOTER"]
    256 	}'
    257 }
    258 
    259 
    260 list_pages() {
    261 	e="\\( -name '*.html' -o -name '*.md' \\)"
    262 	cd "$1" && eval "find . -type f ! -path '*/.*' ! -path '*/_*' $IGNORE $e" |
    263 	sed 's#^./##;s#.md$#.html#;s#/index.html$#/#'
    264 }
    265 
    266 
    267 render_sitemap() {
    268 	urls="$1"
    269 	base_url="$2"
    270 	date="$3"
    271 
    272 	echo '<?xml version="1.0" encoding="UTF-8"?>'
    273 	echo '<urlset'
    274 	echo 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'
    275 	echo 'xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9'
    276 	echo 'http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"'
    277 	echo 'xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'
    278 	echo "$urls" |
    279 	sed -E 's#^(.*)$#<url><loc>'"$base_url"'/\1</loc><lastmod>'\
    280 "$date"'</lastmod><priority>1.0</priority></url>#'
    281 	echo '</urlset>'
    282 }
    283 
    284 main "$@"