.POSIX:
DATE         = 1970-01-01
VERSION      = 0.1.0
NAME         = euandre.org
NAME_UC      = $(NAME)
LANGUAGES    = en
## Installation prefix.  Defaults to "/usr".
PREFIX       = /usr
BINDIR       = $(PREFIX)/bin
LIBDIR       = $(PREFIX)/lib
INCLUDEDIR   = $(PREFIX)/include
SRCDIR       = $(PREFIX)/src/$(NAME)
SHAREDIR     = $(PREFIX)/share
LOCALEDIR    = $(SHAREDIR)/locale
MANDIR       = $(SHAREDIR)/man
DOCDIR       = $(SHAREDIR)/doc/$(NAME)
HTMLDIR      = $(SHAREDIR)/html/$(NAME)
EXEC         = ./
## Where to store the installation.  Empty by default.
DESTDIR      =
LDLIBS       =
PUBURL       = public.asc.txt
FFMFLAGS     = -y -hide_banner -loglevel warning
BASEURL      = /



.SUFFIXES:
.SUFFIXES: .adoc .conf .snippets .indexentry .feedentry .mapentry .sortdata .xml
.SUFFIXES: .htmlbody .htmlheader .htmlfooter .htmllisting .html .links .caslinks
.SUFFIXES: .txt .categorydata .gz .torrent .flac .ogg .ps .pdf

.adoc.conf:
	mkwb conf src/global.conf $< > $@

.adoc.htmlbody:
	mkwb htmlbody     $< > $@

.htmlbody.html:
	mkwb html         $< > $@

.conf.htmlheader:
	mkwb html -H      $< > $@

.conf.htmlfooter:
	mkwb html -F      $< > $@

.adoc.snippets:
	mkwb snippets     $< > $@

.conf.indexentry:
	mkwb indexentry   $< > $@

.htmlbody.feedentry:
	mkwb feedentry    $< > $@

.conf.mapentry:
	mkwb mapentry     $< > $@

.conf.sortdata:
	mkwb sortdata     $< > $@

.conf.categorydata:
	mkwb categorydata $< > $@

.adoc.links:
	mkwb links        $< > $@

.links.caslinks:
	grep -Ev '^(link|image):' $< | xargs -I_ sh -c '\
		printf "%s\n" "_" | sha256sum | \
		printf "%s\t%s\n" "`cut -d" " -f1`" "_"' > $@

.flac.ogg:
	ffmpeg $(FFMFLAGS) -i $< -ar 48000 -vn -c:a libvorbis -b:a 320k $@

.adoc.ps:
	eslaides < $< > $@

.ps.pdf:
	ps2pdf - < $< > $@



all:
include deps.mk


listings.adoc          = $(categories.adoc) $(indexes.adoc)
sources.adoc           = $(articles.adoc) $(listings.adoc) $(pages.adoc)
sources.htmlbody       = $(sources.adoc:.adoc=.htmlbody)
sources.html           = $(sources.adoc:.adoc=.html)
sources.snippets       = $(sources.adoc:.adoc=.snippets)
sources.snippets.gz    = $(sources.adoc:.adoc=.snippets.gz)
sources.conf           = $(sources.adoc:.adoc=.conf)
sources.links          = $(sources.adoc:.adoc=.links)
sources.caslinks       = $(sources.adoc:.adoc=.caslinks)
sources.mapentry       = $(sources.adoc:.adoc=.mapentry)
articles.indexentry    = $(articles.adoc:.adoc=.indexentry)
articles.feedentry     = $(articles.adoc:.adoc=.feedentry)
articles.sortdata      = $(articles.adoc:.adoc=.sortdata)
articles.categorydata  = $(articles.adoc:.adoc=.categorydata)
listings.htmlheader    = $(listings.adoc:.adoc=.htmlheader)
listings.htmlfooter    = $(listings.adoc:.adoc=.htmlfooter)
listings.html          = $(listings.adoc:.adoc=.html)
indexes.htmllisting    = $(indexes.adoc:.adoc=.htmllisting)
categories.htmllisting = $(categories.adoc:.adoc=.htmllisting)
categories.txt         = $(categories.adoc:.adoc=.txt)
categories.xml         = $(categories.adoc:.adoc=.xml)
categories.xml.gz      = $(categories.adoc:.adoc=.xml.gz)
sources.media.torrent  = $(sources.media:=.torrent)
slides.ps              = $(slides.adoc:.adoc=.ps)
slides.pdf             = $(slides.adoc:.adoc=.pdf)

sources = \
	$(sources.adoc)                          \
	$(sources.extras)                        \
	$(images.svg)                            \
	src/content/favicon.ico                  \
	src/content/favicon.png                  \
	src/content/style.css                    \
	src/content/$(PUBURL)                    \

dynamic-contents = \
	$(sources.html)                          \
	$(slides.pdf)                            \
	$(feeds.xml)                             \
	src/content/sitemap.xml                  \

static-contents = \
	$(sources.extras)                        \
	$(images.svg)                            \
	src/content/favicon.ico                  \
	src/content/favicon.png                  \
	src/content/style.css                    \
	src/content/$(PUBURL)                    \
	src/content/.well-known/security.txt     \

dynamic-contents.gz = $(dynamic-contents:=.gz)

static-contents.gz = \
	$(images.svg:=.gz)                       \
	src/content/favicon.ico.gz               \
	src/content/style.css.gz                 \
	src/content/$(PUBURL).gz                 \
	src/content/.well-known/security.txt.gz  \

contents.gz = \
	$(dynamic-contents.gz)                   \
	$(static-contents.gz)                    \

contents = \
	$(dynamic-contents)                      \
	$(static-contents)                       \

all-filelists = \
	$(sources.snippets)                      \
	$(sources.snippets.gz)                   \
	$(categories.xml)                        \
	$(categories.xml.gz)                     \

all-contents = \
	$(contents)                              \
	$(contents.gz)                           \


derived-assets = \
	$(dynamic-contents)                      \
	$(contents.gz)                           \
	$(sources.html)                          \
	$(sources.htmlbody)                      \
	$(sources.snippets)                      \
	$(sources.snippets.gz)                   \
	$(sources.conf)                          \
	$(sources.links)                         \
	$(sources.caslinks)                      \
	$(sources.mapentry)                      \
	src/dyn.conf                             \
	src/base.conf                            \
	src/global.conf                          \
	$(articles.indexentry)                   \
	$(articles.feedentry)                    \
	$(articles.sortdata)                     \
	$(articles.categorydata)                 \
	$(listings.htmlheader)                   \
	$(listings.htmlfooter)                   \
	$(listings.html)                         \
	$(indexes.htmllisting)                   \
	$(categories.htmllisting)                \
	$(categories.txt)                        \
	$(categories.xml)                        \
	$(categories.xml.gz)                     \
	$(slides.ps)                             \
	$(slides.pdf)                            \
	email.txt                                \
	baseurl.txt                              \
	fingerprint.txt                          \
	expiry.txt                               \
	expiry-epoch.txt                         \
	now.txt                                  \
	src/content/.well-known/security.txt     \
	src/all-contents.txt                     \
	src/all-filelists.txt                    \
	src/all-symlinks.txt                     \
	src/install.txt                          \
	src/sort-expected.txt                    \
	src/sort-given.txt                       \
	src/sources.txt                          \
	install.txt                              \
	sources.txt                              \
	src/content/.gitignore                   \
	i18n.sentinel                            \

captured-assets = \
	src/content/$(PUBURL)                    \
	src/content/favicon.ico                  \
	src/content/favicon.png                  \
	$(sources.media.torrent)                 \

side-assets = \
	src/collections/*/*/*/*/*/*.html.*.txt   \
	src/collections/*/*/*/*/*/*.txt.gz       \
	src/collections/*/*/index.html.*.txt     \
	src/collections/*/*/sortdata.txt         \
	src/collections/*/*/feed.*.xml           \
	src/collections/*/*/feed.*.xml.gz        \
	src/collections/*/*/*.sortdata           \
	src/pages/*/*.html.*.txt                 \
	src/content/.well-known/                 \
	`cat src/all-symlinks.txt 2>/dev/null`   \
	`cat src/linkonly-dirs.txt 2>/dev/null`  \



## Default target.  Builds all artifacts required for testing
## and installation.
all: $(derived-assets)
all: $(captured-assets)


$(derived-assets): Makefile deps.mk
$(sources.conf): src/global.conf


src/content/.gitignore: src/symlinks.txt
	cd src/content/ && mkwb symlinks ../symlinks.txt > $(@F)

src/dyn.conf: email.txt baseurl.txt fingerprint.txt
	printf "export url_pre='%s'\n"   "`cat baseurl.txt`"      > $@
	printf "export email='%s'\n"     "`cat email.txt`"       >> $@
	printf "export publickey='%s'\n" "`cat fingerprint.txt`" >> $@
	printf "export publickey_url='$(PUBURL)'\n"              >> $@
	printf 'export sourcecode_url="$$url_pre/git/$(NAME)"\n' >> $@

src/base.conf: src/dyn.conf src/static.conf
	cat src/dyn.conf src/static.conf > $@

src/global.conf: src/base.conf
	mkwb conf -G src/base.conf > $@

$(listings.html):
	cat $*.htmlheader $*.htmlbody $*.htmllisting $*.htmlfooter > $@

$(indexes.htmllisting):
	mkwb indexbody      $*.conf > $@

$(categories.htmllisting):
	mkwb categoriesbody $*.conf > $@

$(categories.txt): src/global.conf
	mkwb categories src/global.conf $(@D) > $@

$(categories.xml):
	for f in `cat $*.txt`; do \
		c="`printf '%s\n' "$$f" | cut -d. -f2`"; \
		mkwb feed src/global.conf "$$f" > $(@D)/feed."$$c".xml; \
		printf '%s\n' $(@D)/feed."$$c".xml; \
	done > $@

$(feeds.xml):
	mkwb feed src/global.conf $(@D)/sortdata.txt > $@

$(contents.gz):
	gzip -9fk $*
	touch     $@

$(sources.snippets.gz) $(categories.xml.gz):
	if [ -s $* ]; then gzip -9fk `cat $*`; fi
	sed 's/$$/.gz/' $* > $@

src/content/$(PUBURL).gz: src/content/$(PUBURL)
src/content/$(PUBURL):
	gpg --export --armour "`jq -r '.email' < meta.json`" > $@

src/content/favicon.ico.gz: src/content/favicon.ico
src/content/favicon.ico: src/content/img/favicon.svg
	convert src/content/img/favicon.svg $@

src/content/favicon.png: src/content/img/favicon.svg
	convert src/content/img/favicon.svg $@

$(sources.media.torrent):
	F="`printf '%s\n' $* | cut -d/ -f3-`" && \
	mktorrent -xfd -n $(*F) -o $@ -w "https://$(NAME)$(BASEURL)$${F}" $*

src/content/sitemap.xml.gz: src/content/sitemap.xml
src/content/sitemap.xml: $(sources.mapentry)
	mkwb sitemap $(sources.mapentry) > $@

email.txt: meta.json
	jq -r '.email' < meta.json > $@

baseurl.txt: meta.json
	jq -r '.baseurl' < meta.json > $@

fingerprint.txt: src/content/$(PUBURL)
	gpg --always-trust --no-keyring --show-key --with-colons \
			src/content/$(PUBURL) | \
		awk -F: '/^pub:/ { print $$5 }' > $@

expiry.txt: src/content/$(PUBURL)
	gpg --always-trust --no-keyring --show-key --with-colons \
			src/content/$(PUBURL) | \
		awk -F: '/^pub:/ { print $$7 }' | \
		xargs -I% date -Is -d@% > $@

expiry-epoch.txt: expiry.txt
	date -d "`cat expiry.txt`" '+%s' > $@

now.txt:
	now > $@

src/content/.well-known/security.txt.gz: src/content/.well-known/security.txt
src/content/.well-known/security.txt: email.txt baseurl.txt expiry.txt
	mkdir -p $(@D)
	printf 'Contact: mailto:%s\n'        "`cat email.txt`"    > $@
	printf 'Expires: %s\n'               "`cat expiry.txt`"  >> $@
	printf 'Encryption: %s/$(PUBURL)\n'  "`cat baseurl.txt`" >> $@
	printf 'Preferred-Languages: en, pt, fr, eo, es, de\n'   >> $@

src/sources.txt:
	printf '%s\n' $(sources) > $@

src/all-contents.txt:
	printf '%s\n' $(all-contents) > $@

src/all-filelists.txt: src/all-symlinks.txt
	printf '%s\n' $(all-filelists) src/all-symlinks.txt > $@

src/all-symlinks.txt: src/content/.gitignore
	sed 's|^|src/content|' src/content/.gitignore > $@

src/install.txt: src/all-contents.txt src/all-filelists.txt $(all-filelists)
	cat src/all-contents.txt `cat src/all-filelists.txt` > $@

sources.txt: src/sources.txt
install.txt: src/install.txt
sources.txt install.txt:
	sed 's|^src/content/||' src/$(@F) > $@

i18n.sentinel: po/po4a.cfg po/note.txt $(sources.po) $(po4a.in)
	po4a po/po4a.cfg
	touch $@



src/sort-expected.txt:
	dirname $(articles.adoc) | env LANG=POSIX.UTF-8 sort | uniq -c | \
		awk '{ printf "%s\t%s\n", $$2, $$1 }' > $@

src/sort-given.txt: $(sources.conf) src/sort-expected.txt
	awk '{ \
		"grep \"^export sort=\" " $$1 "/*.conf | wc -l" | getline cnt; \
		printf "%s\t%s\n", $$1, cnt; \
	}' src/sort-expected.txt > $@

check-unit-sorting: src/sort-expected.txt src/sort-given.txt
	diff -U10 src/sort-expected.txt src/sort-given.txt


.SUFFIXES: .updatedat-check
sources.updatedat-check = $(sources.adoc:.adoc=.updatedat-check)
$(sources.updatedat-check):
	. ./$*.conf && if [ -n "$$updatedat_epoch" ] && \
		[ "$$updatedat_epoch" -le "$$date_epoch" ]; then exit 3; fi

check-unit-updatedat: $(sources.updatedat-check)


.SUFFIXES: .links-internal-check
sources.links-internal-check = $(sources.adoc:.adoc=.links-internal-check)
$(sources.links-internal-check): $(sources.html)
	grep -E '^(link|image):' $*.links | cut -d: -f2- | \
		xargs -I% test -e $(*D)/%

check-unit-links-internal: $(sources.links-internal-check)


check-unit-links-external:


symlink-deps = \
	$(sources.html)                          \
	$(feeds.xml)                             \
	$(categories.xml)                        \
	src/content/.well-known/security.txt     \

check-unit-symlinks: src/all-symlinks.txt $(symlink-deps)
	find `cat src/all-symlinks.txt` | xargs -n1 test -e


check-unit-links: check-unit-links-internal check-unit-links-external
check-unit-links: check-unit-symlinks


MAXSIZE = 52428800  # from spec: https://www.sitemaps.org/protocol.html
check-unit-sitemap-size: src/content/sitemap.xml
	test "`stat --printf='%s' src/content/sitemap.xml`" -le $(MAXSIZE)

check-unit-sitemap-count: src/content/sitemap.xml
	test "`grep -cF '</url>' src/content/sitemap.xml`" -le 50000

check-unit-sitemap: check-unit-sitemap-count check-unit-sitemap-size


check-unit-expiry: expiry-epoch.txt now.txt
	test "`cat expiry-epoch.txt`" -gt "`cat now.txt`"


check-unit: check-unit-sorting check-unit-updatedat check-unit-links
check-unit: check-unit-sitemap check-unit-expiry


integration-tests = \

.PRECIOUS: $(integration-tests)
$(integration-tests): ALWAYS
	sh $@

check-integration: $(integration-tests)


## Run all tests.  Each test suite is isolated, so that a parallel
## build can run tests at the same time.  The required artifacts
## are created if missing.
check: check-unit check-integration



## Remove *all* derived artifacts produced during the build.
## A dedicated test asserts that this is always true.
clean:
	rm -rf $(derived-assets) $(side-assets)


## Installs into $(DESTDIR)$(PREFIX).  Its dependency target
## ensures that all installable artifacts are crafted beforehand.
install: all
	rsync --mkpath -a --files-from=install.txt src/content/ \
		'$(DESTDIR)$(HTMLDIR)'
	rsync --mkpath -a --files-from=sources.txt src/content/ \
		'$(DESTDIR)$(SRCDIR)'

## Uninstalls from $(DESTDIR)$(PREFIX).  This is a perfect mirror
## of the "install" target, and removes *all* that was installed.
## A dedicated test asserts that this is always true.
uninstall:
	rm -rf \
		'$(DESTDIR)$(SRCDIR)'                 \
		'$(DESTDIR)$(HTMLDIR)'                \



PORT = 3333
## Run file server for local installed static files.
run:
	serve -n -p $(PORT) -d '$(DESTDIR)$(HTMLDIR)'


ALWAYS: