generate.sh - static-site-scripts - static site generator shellscripts
(HTM) git clone git://git.codemadness.org/static-site-scripts
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) 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-related things"
16 # site mail used for contact "mail link".
17 sitemail="hiltjo@AT@codemadness.DOT.org"
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 directory.
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@^-*@@g'
50 }
51
52 # initial values for page variables, use some site vars as global defaults.
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...\n' "${meta}" >&2
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> ${dateupdated}<br/>"
103 fi
104 }
105
106 pageheader() {
107 # prefix page title with site title, make sure its neatly formatted.
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" media="screen" />
119 <link rel="stylesheet" href="print.css" type="text/css" media="print" />
120 <link rel="alternate" type="application/rss+xml" title="${sitetitle} RSS Feed" href="rss.xml" />
121 <link rel="alternate" type="application/atom+xml" title="${sitetitle} Atom Feed" href="atom.xml" />
122 <link rel="icon" type="image/png" href="/favicon.png" />
123 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
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">Blog</a> |
135 <a href="http://git.codemadness.org/" title="Some of my projects">Git</a> |
136 <a href="https://github.com/hiltjo/" title="Some of my projects on github">Github</a>
137 </span>
138 <span id="links-contact">
139 <span class="hidden"> | </span>
140 <a href="rss.xml" title="RSS feed">RSS</a> |
141 <a href="atom.xml" title="Atom feed">Atom</a> |
142 <a href="mailto:${sitemail}" title="Mail me">Mail</a>
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}" >&2
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></td></tr>
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" "${timeupdated}")
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" "${timeupdated}")
225 contentatompublished=$(formatdate "%Y-%m-%dT%H:%M:%SZ" "${timecreated}")
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, because
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}/atom.xml" />
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__