Goodbye WordPress, hi rstblog!

Since having switched from the PHP world to the Python world about 2 years ago, I thought about
relaunching my Blog using Python instead of PHP. At first, I thought about creating an application
with Django and PostgreSQL, but never really had the time and motivation to finally implement it.
But today I stumbled over rstblog by Armin Ronacher.

Meet rstblog

It is basically a static reStructuredText to HTML converter. You create a
year/month/day folder structure, create .rst files in there, add metadata
to them in YAML format and run the generator-script.

Because it’s static, you don’t need any dynamic webserver or interpreter, it’s just plain HTML files
that you can serve practically everywhere. You can even track them using a source control system.
And last but not least – you’ll never have to update your WordPress installation again, yay!

rstblog supports everything a blog needs: detail pages, archive pages, tags,
atom feeds and comments (using Disqus). You can create
custom stylesheets and templates.

You can also embed syntax highlighted code using pygments:

class Bar(object):
    def foo(bar):
        print 'I don't like spam!'

And LaTeX formulas:

$$f(x) = a_0 + sum_{n=1}^{infty}left(a_n cos frac{n pi x}{L} + b_n sin frac{n pi x}{L}right)$$

There’s even more to like. If you want to know more, take a look at the
repository and the sourcecode. That’s
also one of the downsides – there’s no official documentation and the project
seems pretty inactive, pull requests aren’t being merged.

To get started, here are some related blogposts:

Publishing Content

To easily publish content, I use Fabric and rsync. Some easy fab tasks simplify the workflow:

import time
from fabric.api import local, env
from fabric.contrib.project import rsync_project

env.hosts = ['dbrgn.ch']
env.path = '/var/www/dbrgn/blog/'

def push():
    local('git push')

def serve():
    local('run-rstblog serve')

def build():
    # Build HTML
    local('rm -rf _build/ && run-rstblog build')

    # Generate sitemaps
    local('python gensitemap.py > _build/sitemap.xml')

    # Minify CSS
    local('cssmin < _build/static/style.css > _build/static/style.min.css')
    local('mv _build/static/style.min.css _build/static/style.css')
    local('cssmin < _build/static/_pygments.css > _build/static/_pygments.min.css')
    local('mv _build/static/_pygments.min.css _build/static/_pygments.css')

    # Add timestamp to css files
    local('find _build -type f -exec sed -i "s/(link.*)' + 
          'style.css/1style.css?%s/g" {} ;' % int(time.time()))
    local('find _build -type f -exec sed -i "s/(link.*)' + 
          '_pygments.css/1_pygments.css?%s/g" {} ;' % int(time.time()))

def sync():
    rsync_project(remote_dir=env.path,
                  local_dir='_build/',
                  delete=True,
                  exclude=['*.py', '*.pyc', 'requirements.txt'])

def deploy():
    build()
    sync()

def publish():
    deploy()
    push()

You can see the entire fabfile on Github. The sitemaps are
generated by gensitemap.py.

By issueing a simple fab publish in the root directory, the following steps
are taken:

  • The _build directory is (re)built
  • Sitemaps are generated for each .html file
  • CSS files are minified in-place
  • A timestamp is appended to all CSS file names to make browsers reload cached
    content
  • The _build directory is deployed to the server
  • The git repository is pushed to Github

This Blog

Besides the blog-related technical details, this blog will from now on focus
mostly on technical content, usually written in English, mostly about Python /
Django / Linux / Programming related things.

The blog repository is published on Github. Content is under a CC by-sa 3.0 license.