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