diff options
-rwxr-xr-x | vienna | 566 |
1 files changed, 284 insertions, 282 deletions
diff --git a/vienna b/vienna index 54f5297..3d6de65 100755 --- a/vienna +++ b/vienna | |||
@@ -6,7 +6,7 @@ | |||
6 | ### Entry point | 6 | ### Entry point |
7 | 7 | ||
8 | usage() { | 8 | usage() { |
9 | cat <<EOF | 9 | cat <<EOF |
10 | VIENNA: a tiny, tasty ssg | 10 | VIENNA: a tiny, tasty ssg |
11 | by C. Duckworth <acdw@acdw.net> | 11 | by C. Duckworth <acdw@acdw.net> |
12 | 12 | ||
@@ -38,194 +38,196 @@ which by default is ./.vienna.sh. vienna uses heredoc-inspired templating, so | |||
38 | you can include shell snippets and variables by doubling the dollar signs. | 38 | you can include shell snippets and variables by doubling the dollar signs. |
39 | 39 | ||
40 | EOF | 40 | EOF |
41 | exit "${1:-0}" | 41 | exit "${1:-0}" |
42 | } | 42 | } |
43 | 43 | ||
44 | configure() { | 44 | configure() { |
45 | ## Set up environment | 45 | ## Set up environment |
46 | URL_ROOT="${VIENNA_URL_ROOT:-https://www.example.com}" | 46 | URL_ROOT="${VIENNA_URL_ROOT:-https://www.example.com}" |
47 | TEMPDIR="${VIENNA_TEMPDIR:-/tmp/vienna}" | 47 | TEMPDIR="${VIENNA_TEMPDIR:-/tmp/vienna}" |
48 | WORKDIR="${VIENNA_WORKDIR:-$PWD}" | 48 | WORKDIR="${VIENNA_WORKDIR:-$PWD}" |
49 | OUTDIR="${VIENNA_OUTDIR:-out}" | 49 | OUTDIR="${VIENNA_OUTDIR:-out}" |
50 | PLUGINDIR="${VIENNA_PLUGINDIR:-.plugins}" | 50 | PLUGINDIR="${VIENNA_PLUGINDIR:-.plugins}" |
51 | CONFIG="${VIENNA_CONFIG:-./.vienna.sh}" | 51 | CONFIG="${VIENNA_CONFIG:-./.vienna.sh}" |
52 | # Templates | 52 | # Templates |
53 | PAGE_TEMPLATE="${VIENNA_PAGE_TEMPLATE:-.page.tmpl.html}" | 53 | PAGE_TEMPLATE="${VIENNA_PAGE_TEMPLATE:-.page.tmpl.html}" |
54 | INDEX_TEMPLATE="${VIENNA_INDEX_TEMPLATE:-.index.tmpl.html}" | 54 | INDEX_TEMPLATE="${VIENNA_INDEX_TEMPLATE:-.index.tmpl.html}" |
55 | FEED_TEMPLATE="${VIENNA_FEED_TEMPLATE:-.feed.tmpl.xml}" | 55 | FEED_TEMPLATE="${VIENNA_FEED_TEMPLATE:-.feed.tmpl.xml}" |
56 | # Options | 56 | # Options |
57 | PHTML_OPTIONS="${VIENNA_PHTML_OPTIONS:-expand entities}" | 57 | PHTML_OPTIONS="${VIENNA_PHTML_OPTIONS:-expand entities}" |
58 | # File extensions | 58 | # File extensions |
59 | RAW_PAGE_EXTENSION="${VIENNA_RAW_PAGE_EXTENSION:-htm}" | 59 | RAW_PAGE_EXTENSION="${VIENNA_RAW_PAGE_EXTENSION:-htm}" |
60 | # Logging | 60 | # Logging |
61 | LOG=true | 61 | LOG=true |
62 | ## Parse command line arguments | 62 | ## Parse command line arguments |
63 | while getopts hqC:c:o:r: opt; do | 63 | while getopts hqC:c:o:r: opt; do |
64 | case "$opt" in | 64 | case "$opt" in |
65 | h) usage 0 ;; | 65 | h) usage 0 ;; |
66 | q) LOG=false ;; | 66 | q) LOG=false ;; |
67 | C) WORKDIR="$OPTARG" ;; | 67 | C) WORKDIR="$OPTARG" ;; |
68 | c) | 68 | c) |
69 | CONFIG="$OPTARG" | 69 | CONFIG="$OPTARG" |
70 | # To error later if a config is specified on the command | 70 | # To error later if a config is specified on the command |
71 | # line but doesn't exist. | 71 | # line but doesn't exist. |
72 | CONFIG_ARG=1 | 72 | CONFIG_ARG=1 |
73 | ;; | 73 | ;; |
74 | o) OUTDIR="$OPTARG" ;; | 74 | o) OUTDIR="$OPTARG" ;; |
75 | r) URL_ROOT="$OPTARG" ;; | 75 | r) URL_ROOT="$OPTARG" ;; |
76 | *) exit 1 ;; | 76 | *) exit 1 ;; |
77 | esac | 77 | esac |
78 | done | 78 | done |
79 | ## Initialize state | 79 | ## Initialize state |
80 | FILE= | 80 | FILE= |
81 | ## Cleanup after we're done | 81 | ## Cleanup after we're done |
82 | trap cleanup INT QUIT | 82 | trap cleanup INT QUIT |
83 | } | 83 | } |
84 | 84 | ||
85 | main() { | 85 | main() { |
86 | # State predicates | 86 | # State predicates |
87 | alias pagep=false indexp=false feedp=false | 87 | alias pagep=false indexp=false feedp=false |
88 | # Convenience aliases | 88 | # Convenience aliases |
89 | alias body=cat title='meta title' pubdate='meta date' | 89 | alias body=cat title='meta title' pubdate='meta date' |
90 | # Configure | 90 | # Configure |
91 | configure "$@" | 91 | configure "$@" |
92 | shift "$((OPTIND - 1))" | 92 | shift "$((OPTIND - 1))" |
93 | # Prepare | 93 | # Prepare |
94 | cd "$WORKDIR" || exit 2 | 94 | cd "$WORKDIR" || exit 2 |
95 | # Source config | 95 | # Source config |
96 | if test -f "$CONFIG"; then | 96 | if test -f "$CONFIG"; then |
97 | # Source ./.vienna.sh, if it exists. | 97 | # Source ./.vienna.sh, if it exists. |
98 | . "$CONFIG" | 98 | . "$CONFIG" |
99 | elif test -n "$CONFIG_ARG"; then | 99 | elif test -n "$CONFIG_ARG"; then |
100 | # If a -c option was passed on the command line but the file | 100 | # If a -c option was passed on the command line but the file |
101 | # doesn't exist, that's an error. If we're just looking for the | 101 | # doesn't exist, that's an error. If we're just looking for the |
102 | # default file, however, there is no error---the user might want | 102 | # default file, however, there is no error---the user might want |
103 | # to use the default configuration. | 103 | # to use the default configuration. |
104 | log error "Can't find configuration \`$CONFIG'." | 104 | log error "Can't find configuration \`$CONFIG'." |
105 | exit 2 | 105 | exit 2 |
106 | else | ||
107 | print >&2 "I'm not sure this is a \`vienna' site directory." | ||
108 | if yornp "Initialize? (y/N)"; then | ||
109 | initialize | ||
110 | else | 106 | else |
111 | yornp "Continue building? (y/N)" || exit 2 | 107 | print >&2 "I'm not sure this is a \`vienna' site directory." |
108 | if yornp "Initialize? (y/N)"; then | ||
109 | initialize | ||
110 | else | ||
111 | yornp "Continue building? (y/N)" || exit 2 | ||
112 | fi | ||
112 | fi | 113 | fi |
113 | fi | 114 | # Further argument processing --- pre-build |
114 | # Further argument processing --- pre-build | 115 | preprocess "$@" || shift |
115 | preprocess "$@" || shift | 116 | log vienna config |
116 | log vienna config | 117 | # Log configuration variables |
117 | # Log configuration variables | 118 | log config 'base url': "$URL_ROOT" |
118 | log config 'base url': "$URL_ROOT" | 119 | log config 'work dir': "$WORKDIR" |
119 | log config 'work dir': "$WORKDIR" | 120 | log config output: "$OUTDIR" |
120 | log config output: "$OUTDIR" | 121 | log template page: "$PAGE_TEMPLATE" |
121 | log template page: "$PAGE_TEMPLATE" | 122 | log template index: "$INDEX_TEMPLATE" |
122 | log template index: "$INDEX_TEMPLATE" | 123 | log template feed: "$FEED_TEMPLATE" |
123 | log template feed: "$FEED_TEMPLATE" | 124 | # Plugins |
124 | # Plugins | 125 | for plugin in "$PLUGINDIR"/*.sh; do |
125 | for plugin in "$PLUGINDIR"/*.sh; do | 126 | test -f "$plugin" || continue |
126 | test -f "$plugin" || continue | 127 | log plugin "$plugin" |
127 | log plugin "$plugin" | 128 | . "$plugin" |
128 | . "$plugin" | 129 | done |
129 | done | 130 | # Prepare output directories |
130 | # Prepare output directories | 131 | mkdir -p "$OUTDIR" || exit 2 |
131 | mkdir -p "$OUTDIR" || exit 2 | 132 | mkdir -p "$TEMPDIR" || exit 2 |
132 | mkdir -p "$TEMPDIR" || exit 2 | 133 | log vienna build |
133 | log vienna build | 134 | # Build pages |
134 | # Build pages | 135 | alias pagep=true |
135 | alias pagep=true | 136 | genpage *."$RAW_PAGE_EXTENSION" || exit 2 |
136 | genpage *."$RAW_PAGE_EXTENSION" || exit 2 | 137 | alias pagep=false |
137 | alias pagep=false | 138 | # Build index |
138 | # Build index | 139 | alias indexp=true |
139 | alias indexp=true | 140 | genlist index_item "$INDEX_TEMPLATE" *."$RAW_PAGE_EXTENSION" >"$OUTDIR/index.html" || exit 2 |
140 | genlist index_item "$INDEX_TEMPLATE" *."$RAW_PAGE_EXTENSION" >"$OUTDIR/index.html" || exit 2 | 141 | alias indexp=false |
141 | alias indexp=false | 142 | # Build feed |
142 | # Build feed | 143 | alias feedp=true |
143 | alias feedp=true | 144 | genlist feed_item "$FEED_TEMPLATE" *."$RAW_PAGE_EXTENSION" >"$OUTDIR/feed.xml" || exit 2 |
144 | genlist feed_item "$FEED_TEMPLATE" *."$RAW_PAGE_EXTENSION" >"$OUTDIR/feed.xml" || exit 2 | 145 | alias feedp=false |
145 | alias feedp=false | 146 | # Copy static files |
146 | # Copy static files | 147 | static * || exit 2 |
147 | static * || exit 2 | 148 | # Further argument processing --- post-build |
148 | # Further argument processing --- post-build | 149 | postprocess "$@" |
149 | postprocess "$@" | ||
150 | } | 150 | } |
151 | 151 | ||
152 | preprocess() { | 152 | preprocess() { |
153 | case "${1:-ok}" in | 153 | case "${1:-ok}" in |
154 | ok) ;; | 154 | ok) ;; |
155 | init) | 155 | init) |
156 | shift | 156 | shift |
157 | initialize "$@" # exit | 157 | initialize "$@" # exit |
158 | ;; | 158 | ;; |
159 | clean) | 159 | clean) |
160 | log vienna clean | 160 | log vienna clean |
161 | rm -r "$OUTDIR" | 161 | rm -r "$OUTDIR" |
162 | cleanup | 162 | cleanup |
163 | if [ $# -eq 0 ]; then | 163 | if [ $# -eq 0 ]; then |
164 | exit # Quit when only cleaning | 164 | exit # Quit when only cleaning |
165 | else | 165 | else |
166 | return 1 # Otherwise, continue processing | 166 | return 1 # Otherwise, continue processing |
167 | fi | 167 | fi |
168 | ;; | 168 | ;; |
169 | esac | 169 | esac |
170 | } | 170 | } |
171 | 171 | ||
172 | postprocess() { | 172 | postprocess() { |
173 | case "${1:-ok}" in | 173 | case "${1:-ok}" in |
174 | ok) ;; | 174 | ok) ;; |
175 | publish) | 175 | publish) |
176 | log vienna publish | 176 | log vienna publish |
177 | publish "$OUTDIR" | 177 | publish "$OUTDIR" |
178 | ;; | 178 | ;; |
179 | preview) | 179 | preview) |
180 | log vienna preview | 180 | log vienna preview |
181 | preview "$OUTDIR" | 181 | preview "$OUTDIR" |
182 | ;; | 182 | ;; |
183 | *) | 183 | *) |
184 | log error "Don't know command \`$1'." | 184 | log error "Don't know command \`$1'." |
185 | exit 1 | 185 | exit 1 |
186 | ;; | 186 | ;; |
187 | esac | 187 | esac |
188 | } | 188 | } |
189 | 189 | ||
190 | cleanup() { | 190 | cleanup() { |
191 | test -z "$DEBUG" && | 191 | test -z "$DEBUG" && |
192 | test -z "$NODEP_RM" && | 192 | test -z "$NODEP_RM" && |
193 | rm -r "$TEMPDIR" | 193 | rm -r "$TEMPDIR" |
194 | } | 194 | } |
195 | 195 | ||
196 | _publish() { | 196 | _publish() { |
197 | cat <<EOF >&2 | 197 | cat <<EOF >&2 |
198 | 198 | ||
199 | I want to publish your website but I don't know how. | 199 | I want to publish your website but I don't know how. |
200 | $(if test -f "$CONFIG"; | 200 | $(if test -f "$CONFIG"; then |
201 | then echo "Edit the"; | 201 | echo "Edit the" |
202 | else echo "Write a"; | 202 | else |
203 | fi) \`publish' function in the \`$CONFIG' file in this | 203 | echo "Write a" |
204 | fi) \`publish' function in the \`$CONFIG' file in this | ||
204 | directory that tells me what to do. | 205 | directory that tells me what to do. |
205 | 206 | ||
206 | EOF | 207 | EOF |
207 | exit 3 | 208 | exit 3 |
208 | } | 209 | } |
209 | publish() { _publish; } | 210 | publish() { _publish; } |
210 | 211 | ||
211 | _preview() { | 212 | _preview() { |
212 | cat <<EOF >&2 | 213 | cat <<EOF >&2 |
213 | 214 | ||
214 | I want to show you a preview of your website but I don't | 215 | I want to show you a preview of your website but I don't |
215 | know how. $(if test -f "$CONFIG"; | 216 | know how. $(if test -f "$CONFIG"; then |
216 | then echo "Edit the"; | 217 | echo "Edit the" |
217 | else echo "Write a"; | 218 | else |
218 | fi) \`preview' function in the \`$CONFIG' file | 219 | echo "Write a" |
220 | fi) \`preview' function in the \`$CONFIG' file | ||
219 | in this directory that tells me what to do. | 221 | in this directory that tells me what to do. |
220 | 222 | ||
221 | EOF | 223 | EOF |
222 | exit 3 | 224 | exit 3 |
223 | } | 225 | } |
224 | preview() { _preview; } | 226 | preview() { _preview; } |
225 | 227 | ||
226 | initialize() { # initialize | 228 | initialize() { # initialize |
227 | log init "$CONFIG" | 229 | log init "$CONFIG" |
228 | cat >"$CONFIG" <<EOF | 230 | cat >"$CONFIG" <<EOF |
229 | # .vienna.sh | 231 | # .vienna.sh |
230 | 232 | ||
231 | # Basic configuration variables | 233 | # Basic configuration variables |
@@ -268,21 +270,21 @@ SERVER_ROOT= | |||
268 | # fi | 270 | # fi |
269 | # } | 271 | # } |
270 | EOF | 272 | EOF |
271 | log init "$PAGE_TEMPLATE" | 273 | log init "$PAGE_TEMPLATE" |
272 | cat >"$PAGE_TEMPLATE" <<\EOF | 274 | cat >"$PAGE_TEMPLATE" <<\EOF |
273 | <title>$$(title)</title> | 275 | <title>$$(title)</title> |
274 | $$(body) | 276 | $$(body) |
275 | EOF | 277 | EOF |
276 | log init "$INDEX_TEMPLATE" | 278 | log init "$INDEX_TEMPLATE" |
277 | cat >"$INDEX_TEMPLATE" <<\EOF | 279 | cat >"$INDEX_TEMPLATE" <<\EOF |
278 | <title>a home page!</title> | 280 | <title>a home page!</title> |
279 | <h1>hey! it's a home page of some sort!</h1> | 281 | <h1>hey! it's a home page of some sort!</h1> |
280 | <ul> | 282 | <ul> |
281 | $$(body) | 283 | $$(body) |
282 | </ul> | 284 | </ul> |
283 | EOF | 285 | EOF |
284 | log init "$FEED_TEMPLATE" | 286 | log init "$FEED_TEMPLATE" |
285 | cat >"$FEED_TEMPLATE" <<\EOF | 287 | cat >"$FEED_TEMPLATE" <<\EOF |
286 | <rss version="2.0"> | 288 | <rss version="2.0"> |
287 | <channel> | 289 | <channel> |
288 | <title>a feed!</title> | 290 | <title>a feed!</title> |
@@ -291,32 +293,32 @@ EOF | |||
291 | </channel> | 293 | </channel> |
292 | </rss> | 294 | </rss> |
293 | EOF | 295 | EOF |
294 | exit | 296 | exit |
295 | } | 297 | } |
296 | 298 | ||
297 | ### Utility | 299 | ### Utility |
298 | 300 | ||
299 | log() { | 301 | log() { |
300 | if "$LOG"; then | 302 | if "$LOG"; then |
301 | printf >&2 '[%s] ' "$1" | 303 | printf >&2 '[%s] ' "$1" |
302 | shift | 304 | shift |
303 | printf >&2 "%s\t" "$@" | 305 | printf >&2 "%s\t" "$@" |
304 | echo >&2 | 306 | echo >&2 |
305 | fi | 307 | fi |
306 | } | 308 | } |
307 | 309 | ||
308 | print() { | 310 | print() { |
309 | printf '%s\n' "$*" | 311 | printf '%s\n' "$*" |
310 | } | 312 | } |
311 | 313 | ||
312 | yornp() { # yornp PROMPT | 314 | yornp() { # yornp PROMPT |
313 | printf >&2 '%s \n' "$@" | 315 | printf >&2 '%s \n' "$@" |
314 | read -r yn | 316 | read -r yn |
315 | case "$yn" in | 317 | case "$yn" in |
316 | [Nn]*) return 1 ;; | 318 | [Nn]*) return 1 ;; |
317 | [Yy]*) return 0 ;; | 319 | [Yy]*) return 0 ;; |
318 | *) return 2 ;; | 320 | *) return 2 ;; |
319 | esac | 321 | esac |
320 | } | 322 | } |
321 | 323 | ||
322 | ### File processing | 324 | ### File processing |
@@ -324,43 +326,43 @@ yornp() { # yornp PROMPT | |||
324 | ## Building block functions | 326 | ## Building block functions |
325 | 327 | ||
326 | shellfix() { # shellfix FILE... | 328 | shellfix() { # shellfix FILE... |
327 | ## Replace ` with \`, $ with \$, and $$ with $ | 329 | ## Replace ` with \`, $ with \$, and $$ with $ |
328 | # shellcheck disable=2016 | 330 | # shellcheck disable=2016 |
329 | sed -E \ | 331 | sed -E \ |
330 | -e 's/`/\\`/g' \ | 332 | -e 's/`/\\`/g' \ |
331 | -e 's/\$\$\$/\\&/g' \ | 333 | -e 's/\$\$\$/\\&/g' \ |
332 | -e 's/(^|[^\$])\$([^\$]|$)/\1\\$\2/g' \ | 334 | -e 's/(^|[^\$])\$([^\$]|$)/\1\\$\2/g' \ |
333 | -e 's/\$\$/$/g' \ | 335 | -e 's/\$\$/$/g' \ |
334 | "$@" | 336 | "$@" |
335 | } | 337 | } |
336 | 338 | ||
337 | expand() { # expand TEMPLATE... < INPUT | 339 | expand() { # expand TEMPLATE... < INPUT |
338 | ## Print TEMPLATE to stdout, expanding shell constructs. | 340 | ## Print TEMPLATE to stdout, expanding shell constructs. |
339 | end="expand_:_${count:=0}_:_end" | 341 | end="expand_:_${count:=0}_:_end" |
340 | eval "$( | 342 | eval "$( |
341 | echo "cat<<$end" | 343 | echo "cat<<$end" |
342 | shellfix "$@" | 344 | shellfix "$@" |
343 | echo | 345 | echo |
344 | echo "$end" | 346 | echo "$end" |
345 | )" && count=$((count + 1)) | 347 | )" && count=$((count + 1)) |
346 | } | 348 | } |
347 | 349 | ||
348 | phtml() { # phtml < INPUT | 350 | phtml() { # phtml < INPUT |
349 | ## Output HTML, pretty much. | 351 | ## Output HTML, pretty much. |
350 | # Paragraphs unadorned with html tags will be wrapped in <p> tags, and | 352 | # Paragraphs unadorned with html tags will be wrapped in <p> tags, and |
351 | # &, <, > will be escaped unless prepended with \. Paragraphs where the | 353 | # &, <, > will be escaped unless prepended with \. Paragraphs where the |
352 | # first character is < will be left as-is, excepting indentation on the | 354 | # first character is < will be left as-is, excepting indentation on the |
353 | # first line (an implementation detail). | 355 | # first line (an implementation detail). |
354 | case "$PHTML_OPTIONS" in | 356 | case "$PHTML_OPTIONS" in |
355 | *entities*) | 357 | *entities*) |
356 | _entities='s#([^\\])&#\1\&#g; | 358 | _entities='s#([^\\])&#\1\&#g; |
357 | s#([^\\])<#\1\<#g; | 359 | s#([^\\])<#\1\<#g; |
358 | s#([^\\])>#\1\>#g; | 360 | s#([^\\])>#\1\>#g; |
359 | s#\\([&<>])#\1#g;' | 361 | s#\\([&<>])#\1#g;' |
360 | ;; | 362 | ;; |
361 | *) _entities= | 363 | *) _entities= ;; |
362 | esac | 364 | esac |
363 | sed -E ' | 365 | sed -E ' |
364 | /./ {H;$!d}; x | 366 | /./ {H;$!d}; x |
365 | s#^[ \n\t]+([^<].*)#\1# | 367 | s#^[ \n\t]+([^<].*)#\1# |
366 | t par; b end | 368 | t par; b end |
@@ -374,123 +376,123 @@ phtml() { # phtml < INPUT | |||
374 | } | 376 | } |
375 | 377 | ||
376 | meta_init() { # meta_init FILE | 378 | meta_init() { # meta_init FILE |
377 | ## Extract metadata from FILE for later processing. | 379 | ## Extract metadata from FILE for later processing. |
378 | # Metadata should exist as colon-separated data in HTML comments in the | 380 | # Metadata should exist as colon-separated data in HTML comments in the |
379 | # input file. | 381 | # input file. |
380 | m=false | 382 | m=false |
381 | t=false | 383 | t=false |
382 | while read -r line; do | 384 | while read -r line; do |
383 | case "$line" in | 385 | case "$line" in |
384 | '<!--') m=true ;; | 386 | '<!--') m=true ;; |
385 | '-->') m=false ;; | 387 | '-->') m=false ;; |
386 | *title:*) t=true && print "$line" ;; | 388 | *title:*) t=true && print "$line" ;; |
387 | *) "$m" && print "$line" ;; | 389 | *) "$m" && print "$line" ;; |
388 | esac | 390 | esac |
389 | done <"$1" | 391 | done <"$1" |
390 | if ! "$t"; then | 392 | if ! "$t"; then |
391 | title="${1##*/}" | 393 | title="${1##*/}" |
392 | title="${title%.*}" | 394 | title="${title%.*}" |
393 | print "title: ${title%.*}" | 395 | print "title: ${title%.*}" |
394 | fi | 396 | fi |
395 | } | 397 | } |
396 | 398 | ||
397 | meta() { # meta FIELD [FILE] | 399 | meta() { # meta FIELD [FILE] |
398 | ## Extract metadata FIELDS from INPUT. | 400 | ## Extract metadata FIELDS from INPUT. |
399 | # FILE gives the filename to save metadata to in the $WORKDIR. It | 401 | # FILE gives the filename to save metadata to in the $WORKDIR. It |
400 | # defaults to the current value for $FILE. | 402 | # defaults to the current value for $FILE. |
401 | # | 403 | # |
402 | # Metadata should exist as colon-separated data in an HTML comment at | 404 | # Metadata should exist as colon-separated data in an HTML comment at |
403 | # the beginning of an input file. | 405 | # the beginning of an input file. |
404 | sed -n "s/^[ \t]*$1:[ \t]*//p" <"${2:-$META}" | 406 | sed -n "s/^[ \t]*$1:[ \t]*//p" <"${2:-$META}" |
405 | } | 407 | } |
406 | 408 | ||
407 | ## Customizable bits | 409 | ## Customizable bits |
408 | 410 | ||
409 | filters() { # filters < INPUT | 411 | filters() { # filters < INPUT |
410 | ## The filters to run input through. | 412 | ## The filters to run input through. |
411 | # This is a good candidate for customization in .vienna.sh. | 413 | # This is a good candidate for customization in .vienna.sh. |
412 | phtml | | 414 | phtml | |
413 | case "$PHTML_OPTIONS" in | 415 | case "$PHTML_OPTIONS" in |
414 | *expand*) expand ;; | 416 | *expand*) expand ;; |
415 | *) cat ;; | 417 | *) cat ;; |
416 | esac | 418 | esac |
417 | } | 419 | } |
418 | 420 | ||
419 | ### Site building | 421 | ### Site building |
420 | 422 | ||
421 | genpage() { # genpage PAGE... | 423 | genpage() { # genpage PAGE... |
422 | ## Compile PAGE(s) into $OUTDIR for publication. | 424 | ## Compile PAGE(s) into $OUTDIR for publication. |
423 | # Outputs a file of the format $OUTDIR/<PAGE>/index.html. | 425 | # Outputs a file of the format $OUTDIR/<PAGE>/index.html. |
424 | test -f "$PAGE_TEMPLATE" || return 1 | 426 | test -f "$PAGE_TEMPLATE" || return 1 |
425 | for FILE; do | 427 | for FILE; do |
426 | test -f "$FILE" || continue | 428 | test -f "$FILE" || continue |
427 | log genpage "$FILE" | 429 | log genpage "$FILE" |
428 | outd="$OUTDIR/${FILE%.$RAW_PAGE_EXTENSION}" | 430 | outd="$OUTDIR/${FILE%.$RAW_PAGE_EXTENSION}" |
429 | outf="$outd/index.html" | 431 | outf="$outd/index.html" |
430 | tmpf="$TEMPDIR/$FILE.tmp" | 432 | tmpf="$TEMPDIR/$FILE.tmp" |
431 | META="$TEMPDIR/$FILE.meta" | 433 | META="$TEMPDIR/$FILE.meta" |
432 | mkdir -p "$outd" | 434 | mkdir -p "$outd" |
433 | meta_init "$FILE" >"$META" | 435 | meta_init "$FILE" >"$META" |
434 | filters <"$FILE" >"$tmpf" | 436 | filters <"$FILE" >"$tmpf" |
435 | expand "$PAGE_TEMPLATE" <"$tmpf" >"$outf" | 437 | expand "$PAGE_TEMPLATE" <"$tmpf" >"$outf" |
436 | done | 438 | done |
437 | } | 439 | } |
438 | 440 | ||
439 | genlist() { # genlist PERITEM_FUNC TEMPLATE_FILE PAGE... | 441 | genlist() { # genlist PERITEM_FUNC TEMPLATE_FILE PAGE... |
440 | ## Generate a list. | 442 | ## Generate a list. |
441 | peritem_func="$1" | 443 | peritem_func="$1" |
442 | template_file="$2" | 444 | template_file="$2" |
443 | tmpf="$TEMPDIR/$1" | 445 | tmpf="$TEMPDIR/$1" |
444 | shift 2 || return 2 | 446 | shift 2 || return 2 |
445 | test -f "$template_file" || return 1 | 447 | test -f "$template_file" || return 1 |
446 | printf '%s\n' "$@" | sort_items | | 448 | printf '%s\n' "$@" | sort_items | |
447 | while read -r FILE; do | 449 | while read -r FILE; do |
448 | test -f "$FILE" || continue | 450 | test -f "$FILE" || continue |
449 | log genlist "$peritem_func:" "$FILE" | 451 | log genlist "$peritem_func:" "$FILE" |
450 | LINK="$URL_ROOT${URL_ROOT:+/}${FILE%.$RAW_PAGE_EXTENSION}" | 452 | LINK="$URL_ROOT${URL_ROOT:+/}${FILE%.$RAW_PAGE_EXTENSION}" |
451 | META="$TEMPDIR/$FILE.meta" | 453 | META="$TEMPDIR/$FILE.meta" |
452 | "$peritem_func" "$FILE" | 454 | "$peritem_func" "$FILE" |
453 | done | expand "$template_file" | 455 | done | expand "$template_file" |
454 | } | 456 | } |
455 | 457 | ||
456 | sort_items() { # sort_items < ITEMS | 458 | sort_items() { # sort_items < ITEMS |
457 | ## Sort ITEMS separated by newlines. | 459 | ## Sort ITEMS separated by newlines. |
458 | # This function assumes that no ITEM contains a newline. | 460 | # This function assumes that no ITEM contains a newline. |
459 | cat | 461 | cat |
460 | } | 462 | } |
461 | 463 | ||
462 | index_item() { # index_item PAGE | 464 | index_item() { # index_item PAGE |
463 | ## Construct a single item in an index.html. | 465 | ## Construct a single item in an index.html. |
464 | print "<li><a href=\"$LINK\">$(meta title "$1")</a></li>" | 466 | print "<li><a href=\"$LINK\">$(meta title "$1")</a></li>" |
465 | } | 467 | } |
466 | 468 | ||
467 | feed_item() { # feed_item PAGE | 469 | feed_item() { # feed_item PAGE |
468 | ## Construct a single item in an RSS feed. | 470 | ## Construct a single item in an RSS feed. |
469 | date="$(meta date "$1")" | 471 | date="$(meta date "$1")" |
470 | cat <<EOF | 472 | cat <<EOF |
471 | <item> | 473 | <item> |
472 | <title>$(meta title "$1")</title> | 474 | <title>$(meta title "$1")</title> |
473 | <link>$LINK</link> | 475 | <link>$LINK</link> |
474 | <guid>$LINK</guid> | 476 | <guid>$LINK</guid> |
475 | $(test -n "$date" && print "<pubDate>$date</pubDate>") | 477 | $(test -n "$date" && print "<pubDate>$date</pubDate>") |
476 | <description><![CDATA[$(filters<"$1")]]></description> | 478 | <description><![CDATA[$(filters <"$1")]]></description> |
477 | </item> | 479 | </item> |
478 | EOF | 480 | EOF |
479 | } | 481 | } |
480 | 482 | ||
481 | static() { # static FILE... | 483 | static() { # static FILE... |
482 | ## Copy static FILE(s) to $OUTDIR as-is. | 484 | ## Copy static FILE(s) to $OUTDIR as-is. |
483 | # Performs a simple heuristic to determine whether to copy a file or | 485 | # Performs a simple heuristic to determine whether to copy a file or |
484 | # not. | 486 | # not. |
485 | for FILE; do | 487 | for FILE; do |
486 | test -f "$FILE" || continue | 488 | test -f "$FILE" || continue |
487 | case "$FILE" in | 489 | case "$FILE" in |
488 | .*) continue ;; | 490 | .*) continue ;; |
489 | *.htm) continue ;; | 491 | *.htm) continue ;; |
490 | "$OUTDIR") continue ;; | 492 | "$OUTDIR") continue ;; |
491 | *) cp -r "$FILE" "$OUTDIR/" ;; | 493 | *) cp -r "$FILE" "$OUTDIR/" ;; |
492 | esac | 494 | esac |
493 | done | 495 | done |
494 | } | 496 | } |
495 | 497 | ||
496 | ### Do the thing! | 498 | ### Do the thing! |