How-tos  Scripts  Pricing  Testimonials  Support  Newsletter

Tested on OpenBSD 6.3 and 6.4

Make a static site with find(1), grep(1), and lowdown(1)

ssg is a static site generator written in shell. Optionally it converts Markdown files to HTML with lowdown(1).

Unless a page has <HTML> tag ssg4 extracts its title from <H1> tag, wraps the page with _header.html, _footer.html.

Then copies everything (excluding .*, CVS, and _*) from src to dst directory.

ssg4 180 LoC. Enlarge, enhance, zoom!

Install

Download and chmod it:

$ mkdir -p bin
$ ftp -Vo bin/ssg4 https://www.romanzolotarev.com/bin/ssg4
ssg4       100% |*********************|    4916      00:00
$ chmod +x bin/ssg4
$ doas pkg_add lowdown
quirks-2.414 signed on 2018-03-28T14:24:37Z
lowdown-0.3.1: ok
$

lowdown(1) is optional. It’s required only if there are any *.md files.

Usage

$ mkdir src dst
$ echo '# Hello, World!' > src/index.md
$ ftp -Vo src/_header.html https://www.romanzolotarev.com/raw/_header.html
_header.html 100% |**************************|  3362       00:00
$ ftp -Vo src/_footer.html https://www.romanzolotarev.com/raw/_footer.html
_header.html 100% |**************************|   727       00:00
$ ftp -Vo src/favicon.png https://www.romanzolotarev.com/raw/favicon.png
favicon.png  100% |**************************|   408       00:00
$ bin/ssg4 src dst 'Test' 'http://www'
./index.md
./favicon.png
[ssg] 2 files, 1 url
$ find dst
dst
dst/.files
dst/index.html
dst/favicon.png
dst/sitemap.xml
$ open dst/index.html

Markdown and HTML files

HTML files from src have greater priority than Markdown ones. ssg4 converts Markdown files from src to HTML in dst and then copies HTML files from src to dst. In the following example src/a.html wins:

src/a.md   -> dst/a.html
src/a.html -> dst/a.html

Favicon

Make sure you have /favicon.png in place.

Some browsers fetch /favicon.ico despite what you specified in the <LINK> tag, so you can use an empty one (180 bytes) as a placeholder.

Sitemap

ssg4 generates sitemap.xml with the list of all page. Don’t forget to add absolute URL of the sitemap to your robot.txt.
For example:

user-agent: *
sitemap: https://www.romanzolotarev.com/sitemap.xml

RSS

To generate RSS feeds use rssg, then add their URLs to _header.html.
For example:

<link rel="alternate" type="application/atom+xml" href="/rss.xml">

Incremental updates

On every run ssg4 saves a list of files in dst/.files and updates only newer files. If no files were modified after that, ssg4 does nothing.

$ bin/ssg4 src dst 'Test' 'https://www'
[ssg] no files, 1 url
$

To force the update delete dst/.files and re-run ssg4.

$ rm dst/.files
$ bin/ssg4 src dst 'Test' 'https://www'
index.md
[ssg] 1 file, 1 url
$

Watch

Save this helper to ~/bin/sssg. It re-runs ssg4 with entr(1) on every file change.

$ cat $HOME/bin/sssg
#!/bin/sh
while :
do
    find . -type f ! -path '*/.*' |
    entr -d "$HOME/bin/ssg4" . "$1" "$(date)" '//www'
done
$

Install entr(1):

$ doas pkg_add entr
quirks-2.414 signed on 2018-03-28T14:24:37Z
entr-4.0: ok
$

Start the helper and keep it running:

$ ~/bin/s /var/www/htdocs/www
[ssg] 1 file, 1 url

Upgrade

Previous version of ssg has been retired.

Add <!DOCTYPE html>, <STYLE>...</STYLE> with your styles and an empty <TITLE></TITLE> tags to _header.html.

ssg4 captures page’s title from the first <H1> tag of the page and inject it into <TITLE>, if it’s present and empty.

Move _rss.html to _header.html, _styles.css to <STYLE> tag in _header.html, and _scripts.js to <SCRIPT> tag.

ssg3 ssg4
Builds 1,730 files in 8.54s in 5.43s
 
Contains basic HTML tags. Contains no HTML tags.
wc(1) is required. Doesn’t use wc(1).
 
List of feeds read from _rss.html, _rss.html,
styles from _styles.css, and _styles.css, and
scripts from _scripts.js. _scripts.js have been removed.

Dependencies

ssg4 depends on few programs from OpenBSD base:

$ for f in $(which cat cpio date sh awk find grep printf readlink sort tee)
do ldd "$f"
done | awk '/\//{print$7}' | grep '.' | sort -u
/bin/cat
/bin/cpio
/bin/date
/bin/sh
/usr/bin/awk
/usr/bin/find
/usr/bin/grep
/usr/bin/printf
/usr/bin/readlink
/usr/bin/sort
/usr/bin/tee
/usr/lib/libc.so.92.5
/usr/lib/libm.so.10.1
/usr/lib/libutil.so.13.0
/usr/lib/libz.so.5.0
/usr/libexec/ld.so

Users

blog.solobsd.org
bloguslibrus.fr
bsdjobs.com
cryogenix.net
dethronedemperor.com
grosu.nl
h3artbl33d.nl
high5.nl
matthewgraybosch.com
mvidal.net
openbsd.amsterdam
openbsd.space
romanzolotarev.com — obviously ;)
runbsd.info
stockersolutions.com


Thanks to Devin Teske for helping with awk(1), Kristaps Dzonsons for lowdown(1), and Eric Radman for entr(1).


© 2008–2019 Roman Zolotarev  User Agreement  Privacy Policy