May 13, 2012
(Parts of this post, since I first wrote, may be dated. Please find an up-to-date version of readme on my repository at github. At the time of my contemplation, Tumblr was still on its own; In 2013, it was acquired by Yahoo! Two weeks after I first wrote this post, I switched to hosting on github using chisel to generate this site, and have been adding and updating my forked version to suit my humble needs. Please see the latter part of this post for mods, and updates.)
While I’m not leaving Tumblr, I am not averse to tinkering with a static site generator script either. Call it Plan B. This for an unlikely event if Tumblr decides to do something I am yet to imagine.1 So, I’ve been trying out chisel, which I forked from David Zhou’s original.
A few things that jumped at me about Chisel, in spite of the fact that there’s zero documentation, were the following:
- Written in Python, a scripting language I am familiar and comfortable with.
- Minimum number of dependencies.
- Code brevity. In less than 150 lines, I can actually read, understand, and modify Chisel.
- Minimalism, and lack of complexity in comparison to, say, the likes of framework based static generators.
I keep a backup of all my posts in Markdown.2 The advantage of this is that I can simply drop these files in a folder, and let Chisel regenerate my entire site in a matter of seconds.
Chisel needs a few packages for it to function. But before they can be installed, one needs
pip, a python package installer. On Debian, it can be installed thus:
$ sudo apt-get install python-pip
On the Mac, you can install pip this way:
$ sudo easy_install pip
Install python packages
pip, install these:
$ sudo pip install jinja2 markdown mdx_smartypants PyRSS2Gen
Create a site structure
~/site /posts /www
Write posts in Markdown and park them in the sub-folder
posts , e.g.,
All posts require a minimal pre-formatted information for the posts to be parsed into their HTML equivalents by Chisel. Following is the structure of a post:
Post title m/d/Y [blank line] Content here onward.
Date in the second line needs to be input as e.g.,
5/14/2012 by default. (Note: Chisel does not support taxonomy, and therefore, there are no fields for categories or tags in the above.)
Download chisel under
~/site folder, so its path would be
~/site/chisel as below:
$ git clone https://github.com/dz/chisel.git
My fork includes the following that didn’t exist in the original:
- Smartypants content parsing to emit typographically nicer quotes, proper em and en dashes, etc.
- A shorter (just year based) permalink structure.
- RSS feed generator script (Hat-tip: Ronan Jouchet).
- Support for Page titles in title tag for permalinks added in templates.
- Supports clean URLs.
- $\TeX$ rendering via MathJax.
Edit chisel.py to update settings
There are a few things to set in the single file,
chisel.py, which can be edited to suit. Once done, write a post, park the file with
.md extension under
~/site/posts folder, and then run the following command:
$ python ~/site/chisel/chisel.py
And the static site will be generated in the
www folder. This can then be synced to a web host, either manually, or via a cron job.
Once chisel churns out the posts into html files, the next obvious thing is to serve it. The beauty of generating a site with chisel is that you don’t need
mod_rewrite. And once you don’t need it, then running Apache or even nginx feels like an overkill on a home server. Instead here’s what I do. Run the following in a Terminal:
$ cd ~/site/www $ python -m SimpleHTTPServer
Then point my browser to
http://localhost:8000. The default port the webserve listens to is 8000. If you’re looking for serving without the port part of the URL (like
http://localhost) instead, then you’ll need to run it in sudo, like this:
$ sudo python -m SimpleHTTPServer 80
I wrote a tiny snippet in Gedit (under Markdown snippets) to automate the pre-formatted template, and assigned a trigger,
ct to this.
$(1:echo $GEDIT_CURRENT_DOCUMENT_NAME) $(2:date +%m/%d/%Y)
When I open a new
.md file in Gedit, type
ct and hit tab, line one above picks up the name of the file, and line 2, the date — as required.3
I am yet to tinker with its templating engine, Jinja2, but I like what I see. It looks straightforward, and I don’t expect it to vex my learning curve. Plan to work on this over next weekend.
Update [May 18]: I worked on my layout, and was surprised that it required less than half the markup I thought it would need. Awesome. Here’s a screenshot.
Update [May 27]: A week after fiddling with templates, working mostly offline and testing outcomes, I felt confident to take this site live. So yes, I’ve actually moved over from Tumblr. This site is now generated by chisel, version-controlled by git, and served by GitHub’s Pages.
Update [Jun 2]: The following script (
log.sh) automates generating posts using Chisel, followed by adding new and modified updates to git before committing and pushing to my site (now a repository on GitHub) when I run
sh log.sh in Terminal:
#!/usr/bin/env sh echo "" cd ~/Sites/chisel python chisel.py cd ~/Sites/ckunte.github.io echo "Updating log.." git add -A git commit -m 'Updating log.' git push -u origin master cd ~/ echo "" echo "All done."
Update [Jul 20]: See Rewrite for clean URLs.
Update [Dec 23]: Based entirely on Ned Batchelder’s script with subtle changes, the following is what I use to ping search engines via the Ping-o-matic service — to let them know that this chisel generated log has been updated:
# encoding: utf-8 #!/usr/bin/env python import xmlrpclib # Ping-o-matic the Pinging service: ps = "http://rpc.pingomatic.com/RPC2" # Your site's title and URL: title = "ckunte.net log" url = "http://ckunte.net/log/" rss = "http://ckunte.net/log/rss" remoteServer = xmlrpclib.Server(ps) ret = remoteServer.weblogUpdates.ping(title, url, rss) print title, ret['message']
Update [Dec 31]: Once you start maintaining all posts in plain-text Markdown, this makes it pretty easy to search for posts using Spotlight, or run some elementary unix commands to get interesting details about posts you have written. Here are just a few of examples:
Count lines, words, and bytes (in alphabetical file order):
Sort posts by number of decreasing words:
wc -w *.md | sort -nr
Print first two lines:
head -2 *.md
Prefer the bottom line instead? Then, try this following:
tail -1 *.md
Search for a certain text string (
-i: case insensitive):
grep -i "mac os x" *.md
Search for all instances of image links:
grep -i "\!\[" *.md; grep -i "<img" *.md
Look for updates in all posts:
grep -ai "update" *.md
Get a list of all words from all posts you’ve written so far — all sorted by number of times they’ve been used:
tr "A-Z" "a-z" < *.md | tr -sc "a-z" "\012" | \ sort | uniq -c | sort -nr
replace text within all markdown files (via) using perl:
perl -pi -w -e 's/this-word/that-word/g;' *.md
or using sed (simpler):
sed -i 's/this-word/that-word/g' *.md
Update [Feb 24]: Here’s how to setup to nginx server to run a local instance of the chisel generated site on your computer.
Update [Mar 16]: A method for generating atom feed.
Update [May 25]: $\TeX$ support via Mathjax. For multiple lines, remember to use
\newline instead of
Update [Jun 23]: The simplicity of chisel enables that you can have any number of themes. I now have two. This one is the second. Take a look at my templates repo.