generate.sh - static-site-scripts - static site generator shellscripts | |
git clone git://git.codemadness.org/static-site-scripts | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
generate.sh (8477B) | |
--- | |
1 #!/bin/sh | |
2 # site title (part of ${pagetitle} probably). | |
3 sitetitle="Codemadness" | |
4 # site language. | |
5 sitelang="en" | |
6 # main site domain. | |
7 sitedomain="http://www.codemadness.nl" | |
8 # relative site url, can be "/blog" or something. | |
9 siteurlrel="" | |
10 # full site url. | |
11 siteurlfull="${sitedomain}${siteurlrel}" | |
12 # site keywords (global default), don't use too many. | |
13 sitekeywords="blog, suckless, dwm-hiltjo" | |
14 # site description (global default). | |
15 sitedescription="blog with various projects and articles about computer-… | |
16 # site mail used for contact "mail link". | |
17 sitemail="hiltjo@[email protected]" | |
18 # site author (global). | |
19 siteauthor="hiltjo" | |
20 # site last updated (default use date when script was run). | |
21 siteupdated=$(date "+%Y-%m-%dT%H:%M:%SZ") | |
22 # directories containing content and metadata. | |
23 # NOTE: it's recommended to use absolute paths here, use "." for current… | |
24 pagesdir="pages" | |
25 # Output dir. | |
26 outputdir="output" | |
27 # Markdown processor: default: is "smu". | |
28 markdown="smu" | |
29 | |
30 #gnudate(fmt,date) | |
31 gnudate() { | |
32 date "+$1" -d "$2" | |
33 } | |
34 | |
35 #bsddate(fmt,date) | |
36 bsddate() { | |
37 date -j "+$1" "$(printf '%s' "$2" | tr -Cd '[:digit:]')" | |
38 } | |
39 | |
40 # added for compatibility with GNU and BSD date. | |
41 alias formatdate='gnudate' | |
42 if ! gnudate '%Y' '2015-01-01 00:00' 2>/dev/null; then | |
43 alias formatdate='bsddate' | |
44 fi | |
45 | |
46 #makeid(title), format "Some title" to "some-title". | |
47 makeid() { | |
48 printf '%s\n' "$1" | tr '[:upper:]' '[:lower:]' | \ | |
49 sed -e 's@[^[:alnum:]]\{1,\}@-@g' -e 's@-*$@@g' -e 's@^-… | |
50 } | |
51 | |
52 # initial values for page variables, use some site vars as global defaul… | |
53 pagereset() { | |
54 id="" | |
55 title="" | |
56 url="" | |
57 description="${sitedescription}" | |
58 keywords="${sitekeywords}" | |
59 author="${siteauthor}" | |
60 content="" | |
61 tags="" | |
62 categories="" | |
63 timecreated="" | |
64 datecreated="" | |
65 timeupdated="" | |
66 dateupdated="" | |
67 } | |
68 | |
69 pageread() { | |
70 meta="$1" | |
71 . "${meta}" # source page metadata. | |
72 basename=$(basename "${meta}" ".sh") | |
73 datecreated=$(printf '%s' "${timecreated}" | cut -b 1-10) | |
74 dateupdated=$(printf '%s' "${timeupdated}" | cut -b 1-10) | |
75 | |
76 # if ${id} is empty and title is set: create id based on title. | |
77 if test -z "${id}" && test -n "${title}"; then | |
78 id=$(makeid "${title}") | |
79 fi | |
80 if test -z "${id}"; then | |
81 printf 'Warning: $id or $title not set in "%s", skipping… | |
82 return 1 | |
83 fi | |
84 if test -z "${url}"; then | |
85 url="${id}.html" | |
86 fi | |
87 outfile="${id}.html" | |
88 urlfull="${siteurlfull}/${outfile}" | |
89 filename="" | |
90 # ${content} not set; try data from filetypes. | |
91 if test -z "${content}"; then | |
92 if test -f "${pagesdir}/${basename}.html"; then | |
93 filename="${pagesdir}/${basename}.html" | |
94 content=$(cat "${filename}") | |
95 elif test -f "${pagesdir}/${basename}.md"; then | |
96 filename="${pagesdir}/${basename}.md" | |
97 content=$("${markdown}" "${filename}") | |
98 fi | |
99 fi | |
100 created="<strong>Created on:</strong> ${datecreated}<br/>" | |
101 if test "${datecreated}" != "${dateupdated}"; then | |
102 created="${created}<strong>Last update on:</strong> ${da… | |
103 fi | |
104 } | |
105 | |
106 pageheader() { | |
107 # prefix page title with site title, make sure its neatly format… | |
108 if test -z "${title}"; then | |
109 pagetitle="${sitetitle}" | |
110 else | |
111 pagetitle="${title} - ${sitetitle}" | |
112 fi | |
113 cat <<!__EOF__ | |
114 <!DOCTYPE html> | |
115 <html dir="ltr" lang="${sitelang}"> | |
116 <head> | |
117 <title>${pagetitle}</title> | |
118 <link rel="stylesheet" href="style.css" type="text/css" … | |
119 <link rel="stylesheet" href="print.css" type="text/css" … | |
120 <link rel="alternate" type="application/rss+xml" title="… | |
121 <link rel="alternate" type="application/atom+xml" title=… | |
122 <link rel="icon" type="image/png" href="/favicon.png" /> | |
123 <meta http-equiv="Content-Type" content="text/html; char… | |
124 <meta http-equiv="Content-Language" content="${sitelang}… | |
125 <meta content="width=device-width" name="viewport" /> | |
126 <meta content="${keywords}" name="keywords" /> | |
127 <meta content="${description}" name="description" /> | |
128 <meta content="${author}" name="author" /> | |
129 </head> | |
130 <body> | |
131 <div id="menuwrap"> | |
132 <div id="menu"> | |
133 <span id="links"> | |
134 <a href="index.html" title="Blog… | |
135 <a href="http://git.codemadness.… | |
136 <a href="https://github.com/hilt… | |
137 </span> | |
138 <span id="links-contact"> | |
139 <span class="hidden"> | </span> | |
140 <a href="rss.xml" title="RSS fee… | |
141 <a href="atom.xml" title="Atom f… | |
142 <a href="mailto:${sitemail}" tit… | |
143 </span> | |
144 </div> | |
145 </div> | |
146 <hr class="hidden" /> | |
147 <div id="mainwrap"> | |
148 <div id="main"> | |
149 !__EOF__ | |
150 } | |
151 | |
152 pagecontent() { | |
153 pageheader | |
154 cat <<!__EOF__ | |
155 <h1><a href="">${title}</a></h1> | |
156 <em>${created}</em> | |
157 ${content} | |
158 !__EOF__ | |
159 pagefooter | |
160 } | |
161 | |
162 pagefooter() { | |
163 cat <<!__EOF__ | |
164 </div> | |
165 </div> | |
166 </body> | |
167 </html> | |
168 !__EOF__ | |
169 } | |
170 | |
171 if ! test -d "${pagesdir}"; then | |
172 printf 'Error: pages directory "%s" not found.\n' "${pagesdir}" … | |
173 exit 1 | |
174 fi | |
175 | |
176 # process single page as argument (handy for testing a single page). | |
177 if test -n "$1"; then | |
178 pagereset | |
179 pageread "$1" || exit 1 | |
180 pagecontent | |
181 exit 0 | |
182 fi | |
183 | |
184 # try to make output dir. | |
185 mkdir -p "${outputdir}" | |
186 | |
187 # truncate urllist.txt (sitemap). | |
188 > "${outputdir}/urllist.txt" | |
189 # content for RSS, Atom sitemap and index, this is appended as a string. | |
190 contentindex="" | |
191 contentrss="" | |
192 contentatom="" | |
193 contentsitemap="" | |
194 while read -r meta; do | |
195 pagereset | |
196 pageread "${meta}" || continue | |
197 pagecontent > "${outputdir}/${outfile}" | |
198 | |
199 # index / posts item: append. | |
200 contentindex="${contentindex}$(cat <<!__EOF__ | |
201 <tr><td>${dateupdated}</td> | |
202 <td><a href="${url}" title="${description}">${title}</a>… | |
203 !__EOF__ | |
204 )" | |
205 | |
206 # RSS item: append. | |
207 # NOTE: GMT timezone is hard-coded because %z is not consistent, | |
208 # change accordingly. | |
209 contentrsspubdate=$(formatdate "%a, %d %b %Y %H:%M:%S GMT" "${ti… | |
210 contentrss="${contentrss}$( | |
211 cat <<!__EOF__ | |
212 <item> | |
213 <title>${title}</title> | |
214 <link>${urlfull}</link> | |
215 <pubDate>${contentrsspubdate}</pubDate> | |
216 <author>${author}</author> | |
217 <guid isPermaLink="false">${urlfull}</guid> | |
218 <description><![CDATA[${description}]]></description> | |
219 </item> | |
220 !__EOF__ | |
221 )" | |
222 | |
223 # Atom item: append. | |
224 contentatomupdated=$(formatdate "%Y-%m-%dT%H:%M:%SZ" "${timeupda… | |
225 contentatompublished=$(formatdate "%Y-%m-%dT%H:%M:%SZ" "${timecr… | |
226 contentatom="${contentatom}$( | |
227 cat <<!__EOF__ | |
228 <entry> | |
229 <title type="html"><![CDATA[${title}]]></title> | |
230 <link rel="alternate" type="text/html" href="${urlfull}"… | |
231 <id>${urlfull}</id> | |
232 <updated>${contentatomupdated}</updated> | |
233 <published>${contentatompublished}</published> | |
234 <author> | |
235 <name>${author}</name> | |
236 <uri>${siteurlfull}</uri> | |
237 </author> | |
238 <summary type="html"><![CDATA[${description}]]></summary> | |
239 </entry> | |
240 !__EOF__ | |
241 )" | |
242 | |
243 # sitemap: sitemap.xml, append item. | |
244 contentsitemap="${contentsitemap}<url><loc>${urlfull}</loc></url… | |
245 | |
246 # sitemap: urllist.txt, append item, write directly to file, bec… | |
247 # this is just a plain-text list. | |
248 printf '%s\n' "${urlfull}" >> "${outputdir}/urllist.txt" | |
249 done <<!FILELIST | |
250 $(find "${pagesdir}" -type f -name "*.sh" | sort -rn) | |
251 !FILELIST | |
252 # process pages (reverse numeric order). | |
253 # NOTE: above heredoc is used to make sure content* variables are known | |
254 # in the scope after the while loop (subshell / pipes prevents this in a | |
255 # standard manner). | |
256 | |
257 # index HTML page (index.html). | |
258 pagereset | |
259 title="Posts" | |
260 (pageheader | |
261 cat <<!__EOF__ | |
262 <h1>${title}</h1> | |
263 <table> | |
264 ${contentindex} | |
265 </table> | |
266 !__EOF__ | |
267 pagefooter) > "${outputdir}/index.html" | |
268 | |
269 # RSS feed (rss.xml). | |
270 cat <<!__EOF__ > "${outputdir}/rss.xml" | |
271 <?xml version="1.0" encoding="UTF-8"?> | |
272 <rss version="2.0"> | |
273 <channel> | |
274 <title>${sitetitle}</title> | |
275 <link>${siteurlfull}</link> | |
276 <description>${sitedescription}</description> | |
277 <language>${sitelang}</language> | |
278 ${contentrss} | |
279 </channel> | |
280 </rss> | |
281 !__EOF__ | |
282 | |
283 # Atom feed (atom.xml). | |
284 cat <<!__EOF__ > "${outputdir}/atom.xml" | |
285 <?xml version="1.0" encoding="UTF-8"?> | |
286 <feed xmlns="http://www.w3.org/2005/Atom" xml:lang="${sitelang}"> | |
287 <title type="text">${sitetitle}</title> | |
288 <subtitle type="text">${sitedescription}</subtitle> | |
289 <updated>${siteupdated}</updated> | |
290 <link rel="alternate" type="text/html" href="${siteurlfull}" /> | |
291 <id>${siteurlfull}/atom.xml</id> | |
292 <link rel="self" type="application/atom+xml" href="${siteurlfull… | |
293 ${contentatom} | |
294 </feed> | |
295 !__EOF__ | |
296 | |
297 # sitemap (sitemap.xml). | |
298 cat <<!__EOF__ > "${outputdir}/sitemap.xml" | |
299 <?xml version="1.0" encoding="UTF-8"?><urlset>${contentsitemap}</urlset> | |
300 !__EOF__ |