It’s written in shell-script.
In the end I managed to make it work so all-in-all this was a success! I didn’t need many features and wanted easy templating and extensibility.
I’m still saying it’s a bad idea because shell-script is terrible but
I really like calling executables, processing lines of text and escaping
strings with sed. Also it runs everywhere.
No Hugo?
I want to self-host and use a tool that generates a static website that I can push somewhere. That excludes WordPress and the likes, and Medium and co. A friend of mine tried Hugo and seemed happy with it so I had a look.
And it’s bigger and more complicated than I need or want. I just wanted a few markdown files that I can easily edit and build as a static website that I can push to my host (who incidentally is myself). And simple templates.
So what is it that I’m doing
I’m using pandoc, but sometimes in a twisted way. Also
sed, grep, and a little rsync.
The script is written in shell-script, for dash. It can run
on busybox! I just like good old dash. Well I
hate some of its drawbacks but bash is too big and
dash is everywhere.
pandoc is big, yeah. But I like its versatility.
File hierarchy
Everything is pretty straightforward. During the build process, static files get copied as-is, posts are converted to HTML using the provided template. A list of posts is generated as an HTML page and as a RSS feed. An index template is there to add some introductory text, link to other pages and stuff on the website, and contains links to the latest blog posts.
my-blog
| blog.sh
| blog.vars
| static
| | style.css
| \ (images, media…)
| templates
| | index.tpl.html
| | posts.tpl.html
| | post.tpl.html
| \ feed.tpl.rss
| posts
| | 00001 the-post-s-title
| | | post.md
| | \ (images, media…)
| | 00002 the-other-post-s-title
| | | post.md
| | \ (images, media…)
| \ (more posts…)
\ out
| index.html
| static
| | style.css
| \ …
\ posts
| index.html
| feed.rss
| the-posts-s-title.1
| | index.html
| \ …
\ the-other-posts-s-title.2
| index.html
\ …
The command
Things happen when one calls blog.sh. It is the only
file needed to bootstrap a blog as it will create the file hierarchy,
provide a basic stylesheet and sample templates.
blog.sh newwill create a new blog post.blog.sh editwill let you edit an existing blog post.blog.sh delwill let you delete blog posts.blog.sh buildwill apply templates to all pages and put the result inout. Add-uto make it build unpublished pages for a preview!blog.sh deploywill build the website and usersyncto deploy the website somewhere remote or not. No unpublished pages will be built.
Blog posts have some additional metadata that let the script know if
the post is published or not. Here is the header in the
post.md for this blog post:
---
title: I wrote my blog engine
date: 2024-10-16 21:55
author: Hiro Lynx
# Document number: 00003
created: 2024-10-16 21:55
comment: Obviously this was not a good idea but I got afraid when I tried hugo.
published: false #TODO: Change to true whenever the article is ready
---
The templates
There is the post.tpl.html template, which does things
the normal way.
And then, there are the other templates. They do not use the
$body$ of their source documents.
For those, blog.sh creates “mardown” files with metadata
only written in YAML blocks. It uses pandoc to generate the
index and list of blog posts this way.
It also uses pandoc to extract metadata from mardown
files using a template that only puts some metadata besides variable
names that I then extract using sed in the script. The
template looks like this:
post_title:$title/nowrap$
post_comment:$comment/nowrap$
post_published:$published/nowrap$
post_author:$author/nowrap$
post_created:$created/nowrap$
post_date:$date/nowrap$
You might notice that the names between the dollars are the same as in the metadata of the post header above.
pandoc will also be used to generate the RSS feed! XML
and HTML aren’t that different, so I made a template for a generated
source markdown file that only contains metadata. The template looks
like this:
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>$title$</title>
<description>$desc$</description>
<link>$url$</link>
$if(blog-items)$
$for(blog-items)$
<item>
<title>$blog-items.title$</title>
<description>$blog-items.comment$</description>
<link>$url$posts/$blog-items.link$/</link>
<pubDate>$blog-items.date$</pubDate>
</item>
$endfor$
$endif$
</channel>
</rss>
It works similarly for the index and the list of all blog posts.
All in all
I’m happy with blog.sh for now. I plan on adding pages
in addition to blog posts so I can build the rest of my website with it.
I may have to rename it…
I also want it to generate gemtext for my future presence on the
Gemini Space. I made a new pandoc writer for that, because
the ones I found weren’t to my taste. But it’s a story for another blog
post!