#!/bin/sh
trampoline=; define()(:) # -*- makefile -*-
###########################################
## C H U M : Code Htmlizer Using Make(1) ##
## Make a website out of a code repo, ez ##
## Quickstart: cd project; vi .chum ---> ##
## [change variables given below]. see ##
## README for details #####################
###########################################
define trampoline
if command -v gmake >/dev/null 2>&1
then exec gmake -kr -f "$0" "$@"
else exec make -kr -f "$0" "$@"
fi
endef
####################### code starts here ##
# Project metadata
NAME = $(notdir $(PWD))
AUTHOR =
DESCRIPTION =
# Build config
OUTDIR = out
SERVER = @printf 'Generated files are in %s/\n'
VDUMPF = # used by chums
# Project files
SOURCES =
README =
READMEFILTER = cat
LICENSE =
TARBALL = $(OUTDIR)/$(NAME).tar.gz
STATICS =
# Project web stuff
REMOTE =
URL_ROOT = /
URL_CLONE =
URL_DOWNLOAD = $(URL_ROOT)$(notdir $(TARBALL))
define TEMPLATE =
{{FILENAME}}
{{DIRECTORY}}/{{FILENAME}}
{{DESCRIPTION}}
{{CONTENT}}
endef
define STYLE =
.ll{display:inline-block;width:3em;
padding-right:0.5em;margin-right:0.5em;}
endef
# Internal stuff
-include .chum
_FILES = $(README) $(LICENSE) $(SOURCES)
define _CHUM
BEGIN {
if (template) TEMPLATE = template
else TEMPLATE = "{{FILENAME}}
{{CONTENT}}"
TMPLV["STYLE"] = style
TMPLV["CLONE"] = "$(URL_CLONE)"
TMPLV["DOWNLOAD"] = "$(URL_DOWNLOAD)"
TMPLV["DESCRIPTION"] = "$(DESCRIPTION)"
TMPLV["AUTHOR"] = "$(AUTHOR)"
TMPLV["ROOT"] = "$(URL_ROOT)"
"pwd" | getline TMPLV["DIRECTORY"]; close("pwd")
TMPLV["DIRECTORY"] = outfn(TMPLV["DIRECTORY"], 3)
for (f in ARGV)
if (f && system("test -f " ARGV[f]))
delete ARGV[f]
}
FNR == 1 {
if (NR > 1) finish()
OUTFILE = outfn(FILENAME)
sub(/^\.\.?\//, "", FILENAME)
TMPLV["FILENAME"] = FILENAME
TMPLV["OUTFILE"] = OUTFILE
FILES[f++] = FILENAME
printf("%-24s -> %s\n", FILENAME, OUTFILE)
if (system("mkdir -p $(OUTDIR)/" outfn(FILENAME, 2)))
die(1, "Can't make directory: " outfn(FILENAME, 2))
if (!system("cp " FILENAME " " outfn(FILENAME, 4) ".txt"))
TMPLV["RAWFILE"] = outfn(FILENAME, 3) ".txt"
OUTSTR = ""
}
END {
if (dead) exit dead
finish()
doindex()
copy_statics()
}
{
gsub(/&/, "\\&"); gsub(/, "\\<"); gsub(/>/, "\\>")
OUTSTR = OUTSTR sprintf("" \
"%d" \
"%s\n",
FNR, FNR, FNR, $$0)
}
function slurp (file, o) {
if (!file) return 0
while ((getline < file) > 0)
o = o (o?"\n":"") $$0
return o
}
function outfn (file, mod) {
if (!mod) { # foo.txt => $(OUTDIR)/foo.txt.html
sub(/^/, "$(OUTDIR)/", file)
sub(/$$/, ".html", file)
} else if (mod == 1) { # foo.txt => foo.txt.html
sub(/$$/, ".html", file)
} else if (mod == 2) { # foo.txt => / ; foo/bar.txt => foo/
if (!sub(/\/[^\/]*$$/, "/", file))
file = "/"
} else if (mod == 3) { # foo/bar.txt => bar.txt (basename)
sub(/.*\//, "", file)
} else if (mod == 4) { # foo/bar.txt => $(OUTDIR)/foo/bar.txt
sub(/^/, "$(OUTDIR)/", file)
}
return file
}
function template_replace (str) {
if (OUTFILE == "$(OUTDIR)/index.html") {
gsub(//, "", str)
} else {
gsub(//, "", str)
}
for (ts in TMPLV) {
gsub("{{"ts"}}", TMPLV[ts], str)
}
gsub(/&/, "\\\\&", OUTSTR)
sub("{{CONTENT}}", OUTSTR, str)
return str
}
function finish () {
sub("\n$$", "", OUTSTR)
if (OUTFILE == "$(OUTDIR)/index.html") {
TMPLV["FILENAME"] = TMPLV["DIRECTORY"]
OUTSTR = ""
if ("$(README)") {
OUTSTR = OUTSTR ""
while ((("$(READMEFILTER) $(README)") | getline) > 0)
OUTSTR = OUTSTR "\n" $$0
OUTSTR = OUTSTR ""
}
} else {
OUTSTR = "" OUTSTR "
"
}
print(template_replace(TEMPLATE)) > OUTFILE
close(OUTFILE)
}
function doindex () {
OUTFILE = "$(OUTDIR)/index.html"
OUTSTR = ""
printf("[build] %s\n", OUTFILE)
for (f in FILES) {
OUTSTR = OUTSTR \
sprintf("%s\n",
outfn(FILES[f], 1), FILES[f])
}
finish()
}
function die(code, message) {
print(message) > "/dev/stderr"
dead = code
exit code
}
function copy_statics () {
split(static, STATICS, / */)
for (s in STATICS) {
printf("Copying %s\n", STATICS[s])
if (system("cp " STATICS[s] " $(OUTDIR)/" outfn(STATICS[s], 3)))
die(2, "Can't copy static file: " STATICS[s])
}
}
endef
# Internal recipes
$(OUTDIR): export _TMPL:=-vtemplate=$(TEMPLATE)
$(OUTDIR): export _STYLE:=-vstyle=$(STYLE)
$(OUTDIR): export _STATICS:=-vstatic=$(STATICS)
$(OUTDIR): export _CHUM:=$(_CHUM)
$(OUTDIR): $(_FILES) .chum
@awk "$${_TMPL}" "$${_STYLE}" "$${_STATICS}" "$${_CHUM}" $(_FILES)
ifdef VDUMPF
printf '%s\t%s\t%s\n' $(NAME) $(URL_ROOT) "$(DESCRIPTION)" >> $(VDUMPF)
endif
$(TARBALL): $(_FILES) .chum
@printf '[build] %s\n' $(TARBALL)
@tar -cf $@ $(_FILES)
.PHONY: build serve publish clean
build: $(OUTDIR) $(TARBALL)
serve: $(OUTDIR)
$(SERVER) $(OUTDIR)
publish: $(TARBALL)
rsync -zaP $(OUTDIR)/ $(REMOTE)/
clean:
rm -rf $(OUTDIR)