jelford's blog

Building a static blog with Markdown, Make, and Python

Background

I wanted to build a simple way to publish blog posts. I'm happy without any server-side gubbins; all I want it a simple place to put some static content, so github-pages is fine.

The other must for me is to be able to use markdown to write in. I've tried just doing raw HTML in the past, and frankly it doesn't fill me with joy.

Github has a tool built in, which you can install locally and test out - Jekyll - but I wanted to use pandoc for compiling my markdown to HTML, and besides I don't have ruby installed.

Managing the build

All the build needs to do is:

Sounds like a job for make. Besides, that gives me a chance to brush up on Makefiles.

The rest of ths post goes through each of those steps, one by one. For reference, this whole site is checked in as a github page; you can easily check out the source for yourself here.

Gathering the markdown files

Make has built-in macros for grouping together a series of files from one place into a build target:

blog_sources := $(wildcard blog/*.md)
blog_outputs := $(patsubst %.md,%.html,$(blog_sources))

Those will translate to something like:

blog_sources := page_1.md this_blogpost.md that_blogpost.md
blog_outputs := page_1.html this_blogpost.html that_blogpost.html

Using these macros, we can define a set of make rules to compile the blog pages, and then generate a single front-page that combines them together for easy browsing:

blog.html : $(blog_outputs)
    combine_pages $(blog_outputs)

$(blog_outputs) : $(blog_sources)
    convert_to_html $< $@

So then we just have to implement the conversion and combining steps.

Converting to HTML

I'll be using pandoc to convert markdown files to HTML. This couldn't be eaiser:

blog/%.html : blog/%.md 
    pandoc --email-obfuscation=javascript $< -f markdown -t html5 -o $@

Notice this doesn't use $(blog_outputs) or $(blog_sources). I found make was desperate to do all the $(blog_outputs) at once in the case they were the make target (makes sense), so this is a pattern rule.

Combining

Here's the simplest implementation I can think of for creating an easy-to-browse front page from all the inputs:

blog.html : $(blog_objects)
    echo '<html><head><link rel="stylesheet" type="text/css" href="style.css" ></head><body>' > blog.html
    cat $(blog_objects) >> blog.html
    echo '</body></html>' >> blog.html

That'll just concatenate all the pages together (in any old order) into one long page with all the content. Pretty spartan, but it does the job. Just one more thing so we don't all hate ourselves every time we load the page: adding a style sheet:

blog.html : $(blog_outputs)
    echo '<html><head><link rel="stylesheet" type="text/css" href="style.css" ></head><body>' > blog.html
    cat $(blog_objects) >> blog.html
    echo '</body></html>' >> blog.html

Over the course of the next few blog posts, I'll about adding nicities on top of this starting point: