Of course I don't catch this when proofreading
[web-old.git] / blogit
CommitLineData
0324a0cf
JM
1#!/usr/bin/make -f
2# Source: https://pedantic.software/git/blogit/
3BLOG := $(MAKE) -f $(lastword $(MAKEFILE_LIST)) --no-print-directory
4ifneq ($(filter-out help,$(MAKECMDGOALS)),)
5include config
6endif
7
8# The following can be configured in config
f4fc716c
JM
9BLOG_DATE_FORMAT_INDEX ?= %d/%m/%Y
10BLOG_DATE_FORMAT ?= %d/%m/%Y %X
0324a0cf
JM
11BLOG_TITLE ?= blog
12BLOG_DESCRIPTION ?= blog
8dd9db16 13BLOG_AUTHOR ?= John Doe
0324a0cf
JM
14BLOG_URL_ROOT ?= http://localhost/blog
15BLOG_FEED_MAX ?= 20
16BLOG_FEEDS ?= rss atom
17BLOG_SRC ?= articles
18
19
20.PHONY: help init build deploy clean
21
22ARTICLES = $(shell git ls-tree HEAD --name-only -- $(BLOG_SRC)/ 2>/dev/null)
23TAGFILES = $(patsubst $(BLOG_SRC)/%.md,tags/%,$(ARTICLES))
24
25help:
26 $(info blogit init|build|deploy|clean)
27
28init:
29 mkdir -p $(BLOG_SRC) data templates
30 printf '<!DOCTYPE html><html><head><title>$$TITLE</title></head><body>' > templates/header.html
31 printf '</body></html>' > templates/footer.html
32 printf '' > templates/index_header.html
33 printf '<p>Tags:' > templates/tag_list_header.html
34 printf '<a href="$$URL">$$NAME</a>' > templates/tag_entry.html
35 printf ', ' > templates/tag_separator.html
36 printf '</p>' > templates/tag_list_footer.html
37 printf '<h2>Articles</h2><ul>' > templates/article_list_header.html
38 printf '<li><a href="$$URL">$$DATE $$TITLE</a></li>' > templates/article_entry.html
39 printf '' > templates/article_separator.html
40 printf '</ul>' > templates/article_list_footer.html
41 printf '' > templates/index_footer.html
42 printf '' > templates/tag_index_header.html
43 printf '' > templates/tag_index_footer.html
44 printf '<h1>$$TITLE</h1>' > templates/article_header.html
45 printf '' > templates/article_footer.html
46 printf 'blog\n' > .git/info/exclude
47
48build: blog/index.html tagpages $(patsubst $(BLOG_SRC)/%.md,blog/%.html,$(ARTICLES)) $(patsubst %,blog/%.xml,$(BLOG_FEEDS))
49
50deploy: build
51 rsync -rLtvz $(BLOG_RSYNC_OPTS) blog/ data/ $(BLOG_REMOTE)
52
53clean:
54 rm -rf blog tags
55
56config:
57 printf 'BLOG_REMOTE:=%s\n' \
58 '$(shell printf "Blog remote (eg: host:/var/www/html): ">/dev/tty; head -n1)' \
59 > $@
60
61tags/%: $(BLOG_SRC)/%.md
62 mkdir -p tags
63 grep -i '^; *tags:' "$<" | cut -d: -f2- | sed 's/ */\n/g' | sed '/^$$/d' | sort -u > $@
64
65blog/index.html: $(ARTICLES) $(TAGFILES) $(addprefix templates/,$(addsuffix .html,header index_header tag_list_header tag_entry tag_separator tag_list_footer article_list_header article_entry article_separator article_list_footer index_footer footer))
66 mkdir -p blog
67 TITLE="$(BLOG_TITLE)"; \
68 export TITLE; \
adfee06d
JM
69 DESCRIPTION="$(BLOG_DESCRIPTION)"; \
70 export DESCRIPTION; \
8dd9db16
JM
71 AUTHOR="$(BLOG_AUTHOR)"; \
72 export AUTHOR; \
0324a0cf
JM
73 envsubst < templates/header.html > $@; \
74 envsubst < templates/index_header.html >> $@; \
75 envsubst < templates/tag_list_header.html >> $@; \
76 first=true; \
77 for t in $(shell cat $(TAGFILES) | sort -u); do \
78 "$$first" || envsubst < templates/tag_separator.html; \
79 NAME="$$t" \
80 URL="@$$t.html" \
81 envsubst < templates/tag_entry.html; \
82 first=false; \
83 done >> $@; \
84 envsubst < templates/tag_list_footer.html >> $@; \
85 envsubst < templates/article_list_header.html >> $@; \
86 first=true; \
87 for f in $(ARTICLES); do \
88 printf '%s ' "$$f"; \
89 git log --diff-filter=A --date="format:%s $(BLOG_DATE_FORMAT_INDEX)" --pretty=format:'%ad%n' -- "$$f"; \
90 done | sort -k2nr | cut -d" " -f1,3- | while IFS=" " read -r FILE DATE; do \
91 "$$first" || envsubst < templates/article_separator.html; \
92 URL="`printf '%s' "\$$FILE" | sed 's,^$(BLOG_SRC)/\(.*\).md,\1,'`.html" \
93 DATE="$$DATE" \
94 TITLE="`head -n1 "\$$FILE" | sed -e 's/^# //g'`" \
95 envsubst < templates/article_entry.html; \
96 first=false; \
97 done >> $@; \
98 envsubst < templates/article_list_footer.html >> $@; \
99 envsubst < templates/index_footer.html >> $@; \
100 envsubst < templates/footer.html >> $@; \
101
102
103blog/tag/%.html: $(ARTICLES) $(addprefix templates/,$(addsuffix .html,header tag_header index_entry tag_footer footer))
104
105.PHONY: tagpages
106tagpages: $(TAGFILES)
107 +$(BLOG) $(patsubst %,blog/@%.html,$(shell cat $(TAGFILES) | sort -u))
108
109blog/@%.html: $(TAGFILES) $(addprefix templates/,$(addsuffix .html,header tag_index_header tag_list_header tag_entry tag_separator tag_list_footer article_list_header article_entry article_separator article_list_footer tag_index_footer footer))
110 mkdir -p blog
adfee06d 111 TITLE="$(BLOG_TITLE) - Articles tagged $*"; \
0324a0cf 112 TAGS="$*"; \
8dd9db16
JM
113 AUTHOR=""; \
114 export AUTHOR; \
0324a0cf
JM
115 export TITLE; \
116 export TAGS; \
117 envsubst < templates/header.html > $@; \
118 envsubst < templates/tag_index_header.html >> $@; \
119 envsubst < templates/article_list_header.html >> $@; \
120 first=true; \
121 for f in $(shell grep -FH '$*' $(TAGFILES) | sed 's,^tags/\([^:]*\):.*,$(BLOG_SRC)/\1.md,'); do \
122 printf '%s ' "$$f"; \
123 git log --diff-filter=A --date="format:%s $(BLOG_DATE_FORMAT_INDEX)" --pretty=format:'%ad%n' -- "$$f"; \
124 done | sort -k2nr | cut -d" " -f1,3- | while IFS=" " read -r FILE DATE; do \
125 "$$first" || envsubst < templates/article_separator.html; \
126 URL="`printf '%s' "\$$FILE" | sed 's,^$(BLOG_SRC)/\(.*\).md,\1,'`.html" \
127 DATE="$$DATE" \
128 TITLE="`head -n1 "\$$FILE" | sed -e 's/^# //g'`" \
129 envsubst < templates/article_entry.html; \
130 first=false; \
131 done >> $@; \
132 envsubst < templates/article_list_footer.html >> $@; \
133 envsubst < templates/tag_index_footer.html >> $@; \
134 envsubst < templates/footer.html >> $@; \
135
136
137blog/%.html: $(BLOG_SRC)/%.md $(addprefix templates/,$(addsuffix .html,header article_header article_footer footer))
138 mkdir -p blog
adfee06d 139 TITLE=" $(BLOG_TITLE) - $(shell head -n1 $<)"; \
0324a0cf 140 export TITLE; \
8dd9db16 141 AUTHOR="$(shell git log -n 1 --reverse --format="%an" -- "$<")"; \
0324a0cf
JM
142 export AUTHOR; \
143 DATE_POSTED="$(shell git log --diff-filter=A --date="format:$(BLOG_DATE_FORMAT)" --pretty=format:'%ad' -- "$<")"; \
144 export DATE_POSTED; \
145 DATE_EDITED="$(shell git log -n 1 --date="format:$(BLOG_DATE_FORMAT)" --pretty=format:'%ad' -- "$<")"; \
146 export DATE_EDITED; \
147 TAGS="$(shell grep -i '^; *tags:' "$<" | cut -d: -f2- | paste -sd ',')"; \
148 export TAGS; \
8c9e33cd
JM
149 DESCRIPTION="$(shell grep -i '^; *description:' "$<" | cut -d: -f2-)"; \
150 export DESCRIPTION; \
78738995
JM
151 OG_IMAGE="$(shell grep -i '^; *og_image:' "$<" | cut -d: -f2-)"; \
152 export OG_IMAGE; \
0324a0cf
JM
153 envsubst < templates/header.html > $@; \
154 envsubst < templates/article_header.html >> $@; \
155 sed -e 1d \
156 -e '/^;/d' \
157 -e 's/&/\&amp;/g' \
158 -e 's/</\&lt;/g' \
159 -e 's/>/\&gt;/g' \
160 -e '/^```$$/{s,.*,,;x;p;/^<\/code>/d;s,.*,<pre><code>,;bT}' \
161 -e 'x;/<\/code>/{x;s,\$$,\&#36;,g;$$G;p;d};x' \
162 -e 's,\\\$$,\&#36;,g' \
163 -e '/^####/{s,^####,<h4>,;s,$$,</h4>,;H;s,.*,,;x;p;d}' \
164 -e '/^###/{s,^###,<h3>,;s,$$,</h3>,;H;s,.*,,;x;p;d}' \
165 -e '/^##/{s,^##,<h2>,;s,$$,</h2>,;H;s,.*,,;x;p;d}' \
166 -e '/^#/{s,^#,<h1>,;s,$$,</h1>,;H;s,.*,,;x;p;d}' \
167 -e 's,`\([^`]*\)`,<code>\1</code>,g' \
168 -e 's,\*\*\(\([^*<>][^*<>]*\*\?\)*\)\*\*,<b>\1</b>,g' \
169 -e 's,\*\([^*<>][^*<>]*\)\*,<i>\1</i>,g' \
170 -e 's,!\[\([^]]*\)\](\([^)]*\)),<img src="\2" alt="\1"/>,g' \
171 -e 's,\[\([^]]*\)\](\([^)]*\)),<a href="\2">\1</a>,g' \
172 -e '/^- /{s,^- ,<li>,;s,$$,</li>,;x;/^<\/ul>/{x;bL};p;s,.*,<ul>,;bT}' \
173 -e '/^[1-9][0-9]*\. /{s,^[0-9]*\. ,<li>,;s,$$,</li>,;x;/^<\/ol>/{x;bL};p;s,.*,<ol>,;bT}' \
174 -e '/^$$/{x;/^$$/d;p;d}' \
175 -e 'x;/^$$/{s,.*,<p>,;bT};x' \
176 -e ':L;$$G;p;d' \
177 -e ':T;p;:t;s,<\([^/>][^>]*\)>\(\(<[^/>][^>]*>\)*\),\2</\1>,;/<[^\/>]/bt;x;/^$$/{$${x;p};d};bL' \
178 "$<" | envsubst >> $@; \
179 envsubst < templates/article_footer.html >> $@; \
180 envsubst < templates/footer.html >> $@; \
181
182blog/rss.xml: $(ARTICLES)
183 printf '<?xml version="1.0" encoding="UTF-8"?>\n<rss version="2.0">\n<channel>\n<title>%s</title>\n<link>%s</link>\n<description>%s</description>\n' \
184 "$(BLOG_TITLE)" "$(BLOG_URL_ROOT)" "$(BLOG_DESCRIPTION)" > $@
185 for f in $(ARTICLES); do \
186 printf '%s ' "$$f"; \
187 git log --diff-filter=A --date="format:%s %a, %d %b %Y %H:%M:%S %z" --pretty=format:'%ad%n' -- "$$f"; \
188 done | sort -k2nr | head -n $(BLOG_FEED_MAX) | cut -d" " -f1,3- | while IFS=" " read -r FILE DATE; do \
189 printf '<item>\n<title>%s</title>\n<link>%s</link>\n<guid>%s</guid>\n<pubDate>%s</pubDate>\n<description>%s</description>\n</item>\n' \
a9f6852b 190 "`head -n 1 $$FILE | sed 's/&/&amp;/'`" \
0324a0cf
JM
191 "$(BLOG_URL_ROOT)/`basename $$FILE .md`.html" \
192 "$(BLOG_URL_ROOT)/`basename $$FILE .md`.html" \
193 "$$DATE" \
7f10ed74 194 "`cat "$$FILE" | grep ";description:" | cut -d: -f2-`"; \
0324a0cf
JM
195 done >> $@
196 printf '</channel>\n</rss>\n' >> $@
197
198blog/atom.xml: $(ARTICLES)
199 printf '<?xml version="1.0" encoding="UTF-8"?>\n<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">\n<title type="text">%s</title>\n<subtitle type="text">%s</subtitle>\n<updated>%s</updated>\n<link rel="alternate" type="text/html" href="%s"/>\n<id>%s</id>\n<link rel="self" type="application/atom+xml" href="%s"/>\n' \
200 "$(BLOG_TITLE)" "$(BLOG_DESCRIPTION)" "$(shell date +%Y-%m-%dT%H:%M:%SZ)" "$(BLOG_URL_ROOT)" "$(BLOG_URL_ROOT)/atom.xml" "$(BLOG_URL_ROOT)/atom.xml" > $@
201 for f in $(ARTICLES); do \
202 printf '%s ' "$$f"; \
203 git log --diff-filter=A --date="format:%s %Y-%m-%dT%H:%M:%SZ" --pretty=format:'%ad %aN%n' -- "$$f"; \
204 done | sort -k2nr | head -n $(BLOG_FEED_MAX) | cut -d" " -f1,3- | while IFS=" " read -r FILE DATE AUTHOR; do \
205 printf '<entry>\n<title type="text">%s</title>\n<link rel="alternate" type="text/html" href="%s"/>\n<id>%s</id>\n<published>%s</published>\n<updated>%s</updated>\n<author><name>%s</name></author>\n<summary type="text">%s</summary>\n</entry>\n' \
a9f6852b 206 "`head -n 1 $$FILE | sed 's/&/&amp;/'`" \
0324a0cf
JM
207 "$(BLOG_URL_ROOT)/`basename $$FILE .md`.html" \
208 "$(BLOG_URL_ROOT)/`basename $$FILE .md`.html" \
209 "$$DATE" \
210 "`git log -n 1 --date="format:%Y-%m-%dT%H:%M:%SZ" --pretty=format:'%ad' -- "$$FILE"`" \
211 "$$AUTHOR" \
7f10ed74 212 "`cat "$$FILE" | grep ";description:" | cut -d: -f2-`"; \
0324a0cf
JM
213 done >> $@
214 printf '</feed>\n' >> $@