304 lines
8.2 KiB
Bash
Executable File
304 lines
8.2 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
if ! [ -f "$PWD/config.cfg" ];then
|
|
cat << EOF > config.cfg
|
|
sitetitle=""
|
|
sitelang=""
|
|
sitedomain=""
|
|
siteurlrel=""
|
|
siteurlfull=""
|
|
sitekeywords=""
|
|
sitedescription=""
|
|
sitemail=""
|
|
siteauthor=""
|
|
siteupdated="$(date +%Y-%m-%d)"
|
|
siteprojects=""
|
|
EOF
|
|
else
|
|
source $PWD/config.cfg
|
|
fi
|
|
|
|
# directories containing content and metadata.
|
|
# NOTE: it's recommended to use absolute paths here, use "." for current directory.
|
|
pagesdir="pages"
|
|
# Output dir.
|
|
outputdir="output"
|
|
# Markdown processor: default: is "smu".
|
|
markdown="smu"
|
|
|
|
#gnudate(fmt,date)
|
|
gnudate() {
|
|
date "+$1" -d "$2" >/dev/null
|
|
}
|
|
|
|
#bsddate(fmt,date)
|
|
bsddate() {
|
|
date -j "+$1" "$(printf '%s' "$2" | tr -Cd '[:digit:]')" 2>/dev/null
|
|
}
|
|
|
|
# added for compatibility with GNU and BSD date.
|
|
alias formatdate='gnudate'
|
|
if ! gnudate '%Y' '2015-01-01 00:00' 2>/dev/null; then
|
|
alias formatdate='bsddate'
|
|
fi
|
|
|
|
#makeid(title), format "Some title" to "some-title".
|
|
makeid() {
|
|
printf '%s\n' "$1" | tr '[:upper:]' '[:lower:]' | \
|
|
sed -e 's@[^[:alnum:]]\{1,\}@-@g' -e 's@-*$@@g' -e 's@^-*@@g'
|
|
}
|
|
|
|
# initial values for page variables, use some site vars as global defaults.
|
|
pagereset() {
|
|
id=""
|
|
title=""
|
|
url=""
|
|
description="${sitedescription}"
|
|
keywords="${sitekeywords}"
|
|
author="${siteauthor}"
|
|
content=""
|
|
tags=""
|
|
categories=""
|
|
timecreated=""
|
|
datecreated=""
|
|
timeupdated=""
|
|
dateupdated=""
|
|
}
|
|
|
|
pageread() {
|
|
meta="$1"
|
|
. "${meta}" # source page metadata.
|
|
basename=$(basename "${meta}" ".sh")
|
|
datecreated=$(printf '%s' "${timecreated}" | cut -b 1-10)
|
|
dateupdated=$(printf '%s' "${timeupdated}" | cut -b 1-10)
|
|
|
|
# if ${id} is empty and title is set: create id based on title.
|
|
if test -z "${id}" && test -n "${title}"; then
|
|
id=$(makeid "${title}")
|
|
fi
|
|
if test -z "${id}"; then
|
|
printf 'Warning: $id or $title not set in "%s", skipping...\n' "${meta}" >&2
|
|
return 1
|
|
fi
|
|
if test -z "${url}"; then
|
|
url="${id}.html"
|
|
fi
|
|
outfile="${id}.html"
|
|
urlfull="${siteurlfull}/${outfile}"
|
|
filename=""
|
|
# ${content} not set; try data from filetypes.
|
|
if test -z "${content}"; then
|
|
if test -f "${pagesdir}/${basename}.html"; then
|
|
filename="${pagesdir}/${basename}.html"
|
|
content=$(cat "${filename}")
|
|
elif test -f "${pagesdir}/${basename}.md"; then
|
|
filename="${pagesdir}/${basename}.md"
|
|
content=$("${markdown}" "${filename}")
|
|
fi
|
|
fi
|
|
authors="<strong>Authors:</strong> ${author}<br/>"
|
|
created="<strong>Created on:</strong> ${datecreated}<br/>"
|
|
uuid="<strong>UUID:</strong> ${id}<br/>"
|
|
|
|
if test "${datecreated}" != "${dateupdated}"; then
|
|
created="${created}<strong>Last update on:</strong> ${dateupdated}<br/>"
|
|
fi
|
|
}
|
|
|
|
pageheader() {
|
|
# prefix page title with site title, make sure its neatly formatted.
|
|
if test -z "${title}"; then
|
|
pagetitle="${sitetitle}"
|
|
else
|
|
pagetitle="${title} - ${sitetitle}"
|
|
fi
|
|
cat <<!__EOF__
|
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.w3.org/MarkUp/SCHEMA/xhtml11.xsd" dir="ltr" xml:lang="${sitelang}" lang="${sitelang}">
|
|
<head>
|
|
<title>${pagetitle}</title>
|
|
<link rel="stylesheet" type="text/css" href="style.css" />
|
|
<link rel="alternate" type="application/rss+xml" title="${sitetitle} RSS Feed" href="rss.xml" />
|
|
<link rel="alternate" type="application/atom+xml" title="${sitetitle} Atom Feed" href="atom.xml" />
|
|
<link rel="icon" type="image/png" href="favicon.png" />
|
|
<meta http-equiv="Content-Type" content="application/xhtml+xml;charset=utf-8" />
|
|
<meta http-equiv="Content-Language" content="${sitelang}" />
|
|
<meta content="width=device-width" name="viewport" />
|
|
<meta content="${keywords}" name="keywords" />
|
|
<meta content="${description}" name="description" />
|
|
<meta content="${author}" name="author" />
|
|
</head>
|
|
<body>
|
|
<div id="menuwrap">
|
|
<div id="menu">
|
|
<span id="links">
|
|
<a href="index.html" title="Main page">Index</a> |
|
|
<a href="${siteprojects}" title="Some of my projects">Projects</a> |
|
|
<a href="http://validator.w3.org/check?uri=${siteurlfull}">Valid XHTML 1.1</a>
|
|
</span>
|
|
<span id="links-contact">
|
|
<span class="hidden"> | </span>
|
|
<a href="rss.xml" title="RSS feed">RSS</a> |
|
|
<a href="atom.xml" title="Atom feed">Atom</a> |
|
|
<a href="mailto:${sitemail}" title="Mail me">Mail</a>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<hr class="hidden" />
|
|
<div id="mainwrap">
|
|
<div id="main">
|
|
!__EOF__
|
|
}
|
|
|
|
pagecontent() {
|
|
pageheader
|
|
cat <<!__EOF__
|
|
<h1><a href="">${title}</a></h1>
|
|
<em>${authors}</em>
|
|
<em>${created}</em>
|
|
<em>${uuid}</em>
|
|
${content}
|
|
!__EOF__
|
|
pagefooter
|
|
}
|
|
|
|
pagefooter() {
|
|
cat <<!__EOF__
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|
|
!__EOF__
|
|
}
|
|
|
|
if ! test -d "${pagesdir}"; then
|
|
printf 'Error: pages directory "%s" not found.\n' "${pagesdir}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# process single page as argument (handy for testing a single page).
|
|
if test -n "$1"; then
|
|
pagereset
|
|
pageread "$1" || exit 1
|
|
pagecontent
|
|
exit 0
|
|
fi
|
|
|
|
# try to make output dir.
|
|
mkdir -p "${outputdir}"
|
|
|
|
# truncate urllist.txt (sitemap).
|
|
> "${outputdir}/urllist.txt"
|
|
# content for RSS, Atom sitemap and index, this is appended as a string.
|
|
contentindex=""
|
|
contentrss=""
|
|
contentatom=""
|
|
contentsitemap=""
|
|
while read -r meta; do
|
|
pagereset
|
|
pageread "${meta}" || continue
|
|
pagecontent > "${outputdir}/${outfile}"
|
|
|
|
# index / posts item: append.
|
|
contentindex="${contentindex}$(cat <<!__EOF__
|
|
<tr><td>${dateupdated}</td>
|
|
<td><a href="${url}" title="${description}">${title}</a></td></tr>
|
|
!__EOF__
|
|
)"
|
|
|
|
# RSS item: append.
|
|
# NOTE: GMT timezone is hard-coded because %z is not consistent,
|
|
# change accordingly.
|
|
contentrsspubdate=$(formatdate "%a, %d %b %Y %H:%M:%S GMT" "${timeupdated}")
|
|
contentrss="${contentrss}$(
|
|
cat <<!__EOF__
|
|
<item>
|
|
<title>${title}</title>
|
|
<link>${urlfull}</link>
|
|
<pubDate>${contentrsspubdate}</pubDate>
|
|
<author>${author}</author>
|
|
<guid isPermaLink="false">${urlfull}</guid>
|
|
<description><![CDATA[${description}]]></description>
|
|
</item>
|
|
!__EOF__
|
|
)"
|
|
|
|
# Atom item: append.
|
|
contentatomupdated=$(formatdate "%Y-%m-%dT%H:%M:%SZ" "${timeupdated}")
|
|
contentatompublished=$(formatdate "%Y-%m-%dT%H:%M:%SZ" "${timecreated}")
|
|
contentatom="${contentatom}$(
|
|
cat <<!__EOF__
|
|
<entry>
|
|
<title type="html"><![CDATA[${title}]]></title>
|
|
<link rel="alternate" type="text/html" href="${urlfull}" />
|
|
<id>${urlfull}</id>
|
|
<updated>${contentatomupdated}</updated>
|
|
<published>${contentatompublished}</published>
|
|
<author>
|
|
<name>${author}</name>
|
|
<uri>${siteurlfull}</uri>
|
|
</author>
|
|
<summary type="html"><![CDATA[${description}]]></summary>
|
|
</entry>
|
|
!__EOF__
|
|
)"
|
|
|
|
# sitemap: sitemap.xml, append item.
|
|
contentsitemap="${contentsitemap}<url><loc>${urlfull}</loc></url>"
|
|
|
|
# sitemap: urllist.txt, append item, write directly to file, because
|
|
# this is just a plain-text list.
|
|
printf '%s\n' "${urlfull}" >> "${outputdir}/urllist.txt"
|
|
done <<!FILELIST
|
|
$(find "${pagesdir}" -type f -name "*.sh" | sort -rn)
|
|
!FILELIST
|
|
# process pages (reverse numeric order).
|
|
# NOTE: above heredoc is used to make sure content* variables are known
|
|
# in the scope after the while loop (subshell / pipes prevents this in a
|
|
# standard manner).
|
|
|
|
# index HTML page (index.html).
|
|
pagereset
|
|
title="Posts"
|
|
(pageheader
|
|
cat <<!__EOF__
|
|
<h1>${title}</h1>
|
|
<table>
|
|
${contentindex}
|
|
</table>
|
|
!__EOF__
|
|
pagefooter) > "${outputdir}/index.html"
|
|
|
|
# RSS feed (rss.xml).
|
|
cat <<!__EOF__ > "${outputdir}/rss.xml"
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<rss version="2.0">
|
|
<channel>
|
|
<title>${sitetitle}</title>
|
|
<link>${siteurlfull}</link>
|
|
<description>${sitedescription}</description>
|
|
<language>${sitelang}</language>
|
|
${contentrss}
|
|
</channel>
|
|
</rss>
|
|
!__EOF__
|
|
|
|
# Atom feed (atom.xml).
|
|
cat <<!__EOF__ > "${outputdir}/atom.xml"
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="${sitelang}">
|
|
<title type="text">${sitetitle}</title>
|
|
<subtitle type="text">${sitedescription}</subtitle>
|
|
<updated>${siteupdated}</updated>
|
|
<link rel="alternate" type="text/html" href="${siteurlfull}" />
|
|
<id>${siteurlfull}/atom.xml</id>
|
|
<link rel="self" type="application/atom+xml" href="${siteurlfull}/atom.xml" />
|
|
${contentatom}
|
|
</feed>
|
|
!__EOF__
|
|
|
|
# sitemap (sitemap.xml).
|
|
cat <<!__EOF__ > "${outputdir}/sitemap.xml"
|
|
<?xml version="1.0" encoding="UTF-8"?><urlset>${contentsitemap}</urlset>
|
|
!__EOF__
|