custom configuration support
- custom extensions - custom filters - ignore files matching given patterns
This commit is contained in:
parent
f7affcaca7
commit
ad7a86f1c5
6
Makefile
6
Makefile
@ -7,20 +7,20 @@ all:
|
|||||||
@echo Compiled
|
@echo Compiled
|
||||||
|
|
||||||
install: all
|
install: all
|
||||||
@echo Installing zod executables to ${PREFIX}/bin
|
@echo Installing zod executable to ${PREFIX}/bin
|
||||||
@mkdir -p ${PREFIX}/bin
|
@mkdir -p ${PREFIX}/bin
|
||||||
@cp bin/zod ${PREFIX}/bin
|
@cp bin/zod ${PREFIX}/bin
|
||||||
@cp bin/zod_render ${PREFIX}/bin
|
|
||||||
@echo Installing awk lib files to ${AWKLIB}
|
@echo Installing awk lib files to ${AWKLIB}
|
||||||
@mkdir -p ${AWKLIB}
|
@mkdir -p ${AWKLIB}
|
||||||
@cp lib/render.awk ${AWKLIB}
|
@cp lib/render.awk ${AWKLIB}
|
||||||
@cp lib/markdown.awk ${AWKLIB}
|
@cp lib/markdown.awk ${AWKLIB}
|
||||||
|
@cp lib/config.awk ${AWKLIB}
|
||||||
|
@cp lib/opt_builder.awk ${AWKLIB}
|
||||||
@echo Installation Complete
|
@echo Installation Complete
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
@echo Uninstalling zod executable
|
@echo Uninstalling zod executable
|
||||||
@rm ${PREFIX}/bin/zod
|
@rm ${PREFIX}/bin/zod
|
||||||
@rm ${PREFIX}/bin/zod_render
|
|
||||||
@echo Uninstalling awk lib files
|
@echo Uninstalling awk lib files
|
||||||
@rm -rf ${AWKLIB}
|
@rm -rf ${AWKLIB}
|
||||||
@echo Uninstallation Complete
|
@echo Uninstallation Complete
|
||||||
|
92
bin/zod.template
Normal file → Executable file
92
bin/zod.template
Normal file → Executable file
@ -13,12 +13,94 @@ _zod_error() {
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_zod_config() {
|
||||||
|
cat - "$cfg" <<!
|
||||||
|
[parse]
|
||||||
|
htm,html
|
||||||
|
[parse_convert]
|
||||||
|
md awk -f "$zod_lib/markdown.awk"
|
||||||
|
[ignore]
|
||||||
|
helpers.awk
|
||||||
|
*.layout
|
||||||
|
*.meta
|
||||||
|
config
|
||||||
|
!
|
||||||
|
}
|
||||||
|
|
||||||
|
_zod_find_opt_builder() {
|
||||||
|
phase="$1"
|
||||||
|
_zod_config |
|
||||||
|
awk -f "$zod_lib/config.awk" \
|
||||||
|
-f "$zod_lib/opt_builder.awk" \
|
||||||
|
-v phase="$phase"
|
||||||
|
}
|
||||||
|
|
||||||
|
_zod_destination() {
|
||||||
|
file="$1"
|
||||||
|
# Find the target directory if one must be created
|
||||||
|
subdir="${file%/*}"
|
||||||
|
subdir="${subdir#$proj}"
|
||||||
|
if [ "$subdir" ]; then
|
||||||
|
destination="$target$subdir"
|
||||||
|
mkdir -p "$destination"
|
||||||
|
else
|
||||||
|
# There is no directory to create in target,
|
||||||
|
# i.e. file is in the root of the project
|
||||||
|
destination="$target"
|
||||||
|
fi
|
||||||
|
echo $destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
_zod_render() {
|
||||||
|
file="$1"
|
||||||
|
ext="${file##*.}"
|
||||||
|
meta="${file%.$ext}.meta"
|
||||||
|
|
||||||
|
set -- -f "$zod_lib/config.awk"
|
||||||
|
set -- "$@" -f "$zod_lib/render.awk"
|
||||||
|
[ -f "$proj/helpers.awk" ] && set -- "$@" -f "$proj/helpers.awk"
|
||||||
|
set -- "$@" -
|
||||||
|
[ -f "$proj/global.meta" ] && set -- "$@" "$proj/global.meta"
|
||||||
|
[ -f "$meta" ] && set -- "$@" "$meta"
|
||||||
|
set -- "$@" "$file"
|
||||||
|
[ -f "$proj/main.layout" ] && set -- "$@" "$proj/main.layout"
|
||||||
|
|
||||||
|
page="${file##*/}"
|
||||||
|
page="${page%.$ext}.html"
|
||||||
|
destination=$(_zod_destination "$file")
|
||||||
|
_zod_config | awk "$@" > "$destination/$page"
|
||||||
|
}
|
||||||
|
|
||||||
|
_zod_copy() {
|
||||||
|
file="$1"
|
||||||
|
destination="$(_zod_destination "$file")"
|
||||||
|
cp "$file" "$destination"
|
||||||
|
}
|
||||||
|
|
||||||
|
_zod_exec() {
|
||||||
|
phase="$@"
|
||||||
|
set -- "$proj" -type f
|
||||||
|
for instruction in $(_zod_find_opt_builder "$phase" "$cfg"); do
|
||||||
|
inst=$(echo $instruction | sed 's/"//g')
|
||||||
|
case $inst in
|
||||||
|
or ) set -- "$@" -o;;
|
||||||
|
not ) set -- "$@" !;;
|
||||||
|
* ) set -- "$@" -name "$inst";;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
find "$@" | while read -r file; do
|
||||||
|
case "$phase" in
|
||||||
|
render ) _zod_render "$file";;
|
||||||
|
copy ) _zod_copy "$file";;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
[ "$#" -ne 2 ] && { echo "usage: zod projectdir targetdir"; exit; }
|
[ "$#" -ne 2 ] && { echo "usage: zod projectdir targetdir"; exit; }
|
||||||
[ ! -d "$proj" ] && _zod_error "project directory does not exist"
|
[ ! -d "$proj" ] && _zod_error "project directory does not exist"
|
||||||
[ ! -d "$target" ] && _zod_error "target directory does not exist"
|
[ ! -d "$target" ] && _zod_error "target directory does not exist"
|
||||||
|
|
||||||
find "$proj" -type f \
|
[ -f "$proj/.zod/config" ] && cfg="$proj/.zod/config"
|
||||||
! -name "*.layout" \
|
|
||||||
! -name "*.meta" \
|
_zod_exec "render"
|
||||||
! -name "helpers.awk" \
|
_zod_exec "copy"
|
||||||
-exec zod_render "$zod_lib" "$proj" "$target" {} \;
|
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
# render a zodiac page
|
|
||||||
# zod_render zodlibdir projdir targetdir md_builtin [files]
|
|
||||||
|
|
||||||
zod_lib="$1"
|
|
||||||
proj="$2"
|
|
||||||
target="$3"
|
|
||||||
md_builtin="$4"
|
|
||||||
f="$5"
|
|
||||||
|
|
||||||
# source zod sh functions
|
|
||||||
. $zod_lib/zod_functions
|
|
||||||
|
|
||||||
ext=${f##*.}
|
|
||||||
meta=${f%.$ext}.meta
|
|
||||||
|
|
||||||
set -- -f "$zod_lib/render.awk"
|
|
||||||
[ -f "$proj/helpers.awk" ] && set -- "$@" -f "$proj/helpers.awk"
|
|
||||||
set -- "$@" -v markdown_filter_cmd="$md_builtin"
|
|
||||||
[ -f "$proj/global.meta" ] && set -- "$@" $proj/global.meta
|
|
||||||
[ -f "$meta" ] && set -- "$@" $meta
|
|
||||||
set -- "$@" "$f"
|
|
||||||
|
|
||||||
find "$proj" -type f -name "*.partial" -o -name "*.layout"
|
|
||||||
while read -r part; do
|
|
||||||
set -- "$@" "$part"
|
|
||||||
done
|
|
||||||
|
|
||||||
page=${f##*/}
|
|
||||||
page=${page%.$ext}.html
|
|
||||||
__zod_destination "$proj" "$target" "$f"
|
|
||||||
awk "$@" > "$destination/$page"
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# return a list of all supported file extensions
|
|
||||||
|
|
||||||
zod_lib="$1"
|
|
||||||
filter_opts="$2"
|
|
||||||
|
|
||||||
awk -f "$zod_lib/supported_extensions.awk" "$filter_opts"
|
|
@ -5,9 +5,10 @@ function load_helpers() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function page_title( title) {
|
function page_title( title) {
|
||||||
if ("title" in data) {
|
if (data["title"]) {
|
||||||
return data["title"] " - " data["site_title"]
|
title = data["title"] " - " data["site_title"]
|
||||||
} else {
|
} else {
|
||||||
return data["site_title"]
|
title = data["site_title"]
|
||||||
}
|
}
|
||||||
|
return title
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,14 @@
|
|||||||
<title>{{page_title}}</title>
|
<title>{{page_title}}</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{{>header}}
|
<header>
|
||||||
|
<h1><a href="/">{{site_title}}</a></h1>
|
||||||
|
</header>
|
||||||
<article>
|
<article>
|
||||||
{{{yield}}}
|
{{{yield}}}
|
||||||
</article>
|
</article>
|
||||||
{{>footer}}
|
<footer>
|
||||||
|
<p>powered by static files</p>
|
||||||
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
44
lib/config.awk
Normal file
44
lib/config.awk
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#
|
||||||
|
# Parse zodiac config
|
||||||
|
#
|
||||||
|
|
||||||
|
# Ignore comments and empty lines
|
||||||
|
action == "config" && (NF == 0 || /^;/) {
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get the current section
|
||||||
|
action == "config" && (/^\[/ && match($0, /\[([[:alnum:]_]).*\]/)) {
|
||||||
|
section = substr($0, (RSTART + 1), (RLENGTH - 2))
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get filters in the parse section
|
||||||
|
action == "config" && section == "parse" {
|
||||||
|
n = split($0, exts, ",")
|
||||||
|
for (i in exts) {
|
||||||
|
ext = exts[i]
|
||||||
|
gsub(/ /, "", ext)
|
||||||
|
filter[ext] = "none"
|
||||||
|
}
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get filters in the parse_convert section
|
||||||
|
action == "config" && section == "parse_convert" && (NF > 1) {
|
||||||
|
ext_list = $1
|
||||||
|
cmd = $2
|
||||||
|
n = split(ext_list, exts, ",")
|
||||||
|
for (i in exts) {
|
||||||
|
ext = exts[i]
|
||||||
|
gsub(/ /, "", ext)
|
||||||
|
filter[ext] = cmd
|
||||||
|
}
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get ignore patterns
|
||||||
|
action == "config" && section == "ignore" {
|
||||||
|
ignore[ignore_count++] = $0
|
||||||
|
next
|
||||||
|
}
|
35
lib/opt_builder.awk
Normal file
35
lib/opt_builder.awk
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#
|
||||||
|
# Build find options
|
||||||
|
#
|
||||||
|
|
||||||
|
BEGIN {
|
||||||
|
section = "none"
|
||||||
|
action = "config"
|
||||||
|
}
|
||||||
|
|
||||||
|
END {
|
||||||
|
for (ext in filter) {
|
||||||
|
exts[ext_count++] = "\"" "*." ext "\""
|
||||||
|
}
|
||||||
|
for (i = 0; i < length(ignore); i++) {
|
||||||
|
instructions[inst_count++] = "not"
|
||||||
|
instructions[inst_count++] = "\"" ignore[i] "\""
|
||||||
|
}
|
||||||
|
if (phase == "render") {
|
||||||
|
instructions[inst_count++] = exts[0]
|
||||||
|
for (i = 1; i < length(exts); i++) {
|
||||||
|
instructions[inst_count++] = "or"
|
||||||
|
instructions[inst_count++] = exts[i]
|
||||||
|
}
|
||||||
|
} else if (phase == "copy") {
|
||||||
|
for (i = 0; i < length(exts); i++) {
|
||||||
|
instructions[inst_count++] = "not"
|
||||||
|
instructions[inst_count++] = exts[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# print all instructions
|
||||||
|
for (i = 0; i < length(instructions); i++) {
|
||||||
|
instruction = instruction " " instructions[i]
|
||||||
|
}
|
||||||
|
print instruction
|
||||||
|
}
|
@ -1,47 +1,30 @@
|
|||||||
# render.awk - Awk-based templating
|
#
|
||||||
|
# Render a zodiac page
|
||||||
|
#
|
||||||
|
|
||||||
BEGIN {
|
BEGIN {
|
||||||
action = "none"
|
action = "none"
|
||||||
ext = "none"
|
ext = "none"
|
||||||
main_content_type = "_main"
|
main = "_main"
|
||||||
helpers_loaded = "no"
|
helpers_loaded = "no"
|
||||||
layout = ""
|
layout = ""
|
||||||
filter_cmds["htm"] = "none"
|
|
||||||
filter_cmds["html"] = "none"
|
|
||||||
filter_cmds["md"] = markdown_filter_cmd
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
split(FILENAME, parts, ".")
|
split(FILENAME, parts, ".")
|
||||||
ext = parts[length(parts)]
|
ext = parts[length(parts)]
|
||||||
if (ext == "config") {
|
if ((FILENAME == "config") || (FILENAME == "-")) {
|
||||||
action = "config"
|
action = "config"
|
||||||
} else if (ext == "meta") {
|
} else if (ext == "meta") {
|
||||||
action = "meta"
|
action = "meta"
|
||||||
} else if (ext == "layout") {
|
} else if (ext == "layout") {
|
||||||
action = "layout"
|
action = "layout"
|
||||||
} else {
|
} else {
|
||||||
# not a known extension, assuming this line
|
|
||||||
# is from a page
|
|
||||||
content_extension = ext
|
|
||||||
action = "page"
|
action = "page"
|
||||||
|
filter_ext = ext
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Process lines from config
|
|
||||||
# Also ignore comments and empty lines
|
|
||||||
action == "config" && (NF > 0) && (!/^;.*/) {
|
|
||||||
split($0, filter_kv, ": ")
|
|
||||||
split(filter_kv[1], filter_extensions, ",")
|
|
||||||
filter_cmd = filter_kv[2]
|
|
||||||
|
|
||||||
for (i = 1; i <= length(filter_extensions); i++) {
|
|
||||||
filter_cmds[filter_extensions[i]] = filter_cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
next
|
|
||||||
}
|
|
||||||
|
|
||||||
# Process lines from meta files
|
# Process lines from meta files
|
||||||
action == "meta" {
|
action == "meta" {
|
||||||
split($0, kv, ": ")
|
split($0, kv, ": ")
|
||||||
@ -58,14 +41,14 @@ action != "meta" && helpers_loaded == "no" && helpers == "yes" {
|
|||||||
|
|
||||||
# Process lines from the page
|
# Process lines from the page
|
||||||
action == "page" {
|
action == "page" {
|
||||||
if (!contents[main_content_type]) {
|
if (!contents[main]) {
|
||||||
contents[main_content_type] = bind_data($0)
|
contents[main] = bind_data($0)
|
||||||
|
|
||||||
# save the extension for this content type
|
# save the extension for this content type
|
||||||
# to find the appropriate filter to render it
|
# to find the appropriate filter to render it
|
||||||
content_extensions[main_content_type] = ext
|
filter_exts[main] = ext
|
||||||
} else {
|
} else {
|
||||||
contents[main_content_type] = contents[main_content_type] "\n" bind_data($0)
|
contents[main] = contents[main] "\n" bind_data($0)
|
||||||
}
|
}
|
||||||
next
|
next
|
||||||
}
|
}
|
||||||
@ -75,7 +58,7 @@ action == "layout" {
|
|||||||
|
|
||||||
# replace yield with rendered content
|
# replace yield with rendered content
|
||||||
if (match($0, /{{{yield}}}/)) {
|
if (match($0, /{{{yield}}}/)) {
|
||||||
sub(/{{{yield}}}/, render_content(main_content_type))
|
sub(/{{{yield}}}/, render_content(main))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (layout == "") {
|
if (layout == "") {
|
||||||
@ -89,14 +72,14 @@ END {
|
|||||||
if (layout != "") {
|
if (layout != "") {
|
||||||
print layout
|
print layout
|
||||||
} else {
|
} else {
|
||||||
print render_content(main_content_type)
|
print render_content(main)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function bind_data(txt, tag, key) {
|
function bind_data(txt, tag, key) {
|
||||||
if (match(txt, /{{([^}]*)}}/)) {
|
if (match(txt, /{{([^}]*)}}/)) {
|
||||||
tag = substr(txt, RSTART, RLENGTH)
|
tag = substr(txt, RSTART, RLENGTH)
|
||||||
match(tag, /(\w|[?]).*[^}]/)
|
match(tag, /([[:alnum:]_]|[?]).*[^}]/)
|
||||||
key = substr(tag, RSTART, RLENGTH)
|
key = substr(tag, RSTART, RLENGTH)
|
||||||
gsub(tag, data[key], txt)
|
gsub(tag, data[key], txt)
|
||||||
return bind_data(txt, data)
|
return bind_data(txt, data)
|
||||||
@ -105,14 +88,14 @@ function bind_data(txt, tag, key) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function render_content(type, ext_key, content_extension, filter_cmd, txt) {
|
function render_content(type, ext_key, filter_ext, filter_cmd, txt) {
|
||||||
ext_key = type "_ext"
|
ext_key = type "_ext"
|
||||||
|
|
||||||
# Get the extension of the content type
|
# Get the extension of the content type
|
||||||
content_extension = content_extensions[type]
|
filter_ext = filter_exts[type]
|
||||||
|
|
||||||
# Get the appropriate filter command for this extension
|
# Get the appropriate filter command for this extension
|
||||||
filter_cmd = filter_cmds[content_extension]
|
filter_cmd = filter[filter_ext]
|
||||||
|
|
||||||
# Get the text of the content for the given type
|
# Get the text of the content for the given type
|
||||||
txt = contents[type]
|
txt = contents[type]
|
||||||
@ -125,6 +108,7 @@ function render_content(type, ext_key, content_extension, filter_cmd, txt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function run_filter(cmd, txt, rand_date, tmpfile, rendered_txt, date_cmd, markdown_cmd, line) {
|
function run_filter(cmd, txt, rand_date, tmpfile, rendered_txt, date_cmd, markdown_cmd, line) {
|
||||||
|
# TODO use mktemp instead
|
||||||
date_cmd = "date +%Y%m%d%H%M%S"
|
date_cmd = "date +%Y%m%d%H%M%S"
|
||||||
date_cmd | getline rand_date
|
date_cmd | getline rand_date
|
||||||
close(date_cmd)
|
close(date_cmd)
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
BEGIN {
|
|
||||||
extensions="md html"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Process lines from config
|
|
||||||
# Also ignore comments and empty lines
|
|
||||||
(NF > 0) && (!/^;.*/) {
|
|
||||||
split($0, filter_kv, ": ")
|
|
||||||
split(filter_kv[1], filter_extensions, ",")
|
|
||||||
|
|
||||||
for (i = 1; i <= length(filter_extensions); i++) {
|
|
||||||
ext = filter_extensions[i]
|
|
||||||
if (!match(extensions, ext)) {
|
|
||||||
extensions = extensions " " ext
|
|
||||||
}
|
|
||||||
}
|
|
||||||
next
|
|
||||||
}
|
|
||||||
|
|
||||||
END {
|
|
||||||
print extensions
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user