I've had this sort of ongoing project to update my Middleman installation for this blog, and in the process of doing so, decided to re-evaluate and switch to a different production technology called Pelican.
Middleman is servicable software for generating static websites, and is written in Ruby. The officially approved and supported modules work. The unapproved ones, however, are corroded and do not work (for me) out of the box in a FreeBSD jail. As far as I can tell, people don't maintain them. As any Ruby user knows, if a Gemfile has like a million dependencies in it - it will go out-of-sync very quickly and become impossible for other people to use out of the box. In fact, none of the unsupported Middleman modules I tested worked under a FreeBSD jail RVM install of the latest stable Ruby.
So this is partly a Ruby thing, partly an RVM thing, and partly a Middleman unofficial modules thing. FreeBSD jails are non-negotiable for me. The software must work in a jail. Plus I want cool features, and an unbroken ecosystem. All the baggage is just a bit too much to maintain and retain when months may go by between blog posts. And I'm bored. not enough interesting features (like Pelican's Themes) and a broken ecosystem.
So with this situation, it's time for a new platform.
Some big pluses for Pelican:
It's elegant. Not an Elephant. I don't have to mess with frameworks to get it running.
INSTALLATION
## PELICAN INSTALLATION STEPS
# install python3
sudo pkg install python3
# install pip package manager for python
fetch https://bootstrap.pypa.io/get-pip.py
sudo python3 ./get-pip.py
# make shell Unicode
vi .login_conf
me:\
:charset=UTF-8:\
:lang=en_US.UTF-8:\
:setenv=LC_COLLATE=C:
# check Unicodeness
locale
# install pelican and some needed packages
sudo pip install pelican
sudo pip install Markdown
sudo pip install typogrify
sudo pkg install gmake
That's all. No RVM muckity-muck or much in the way of shell-dotfile-trickery. `Python3
is installed via the FreeBSD package system.
Configuration
To create a project, all I have to do is run pelican quickstart
and some questions get asked, and a project directory tree gets built.
There is only one config file: pelicanconf.py
#!/usr/bin/env python
# -*- coding: utf-8 -*- #
from __future__ import unicode_literals
AUTHOR = 'Allan'
SITENAME = 'SyntaxFX'
SITEURL = 'http://abowhill.github.io'
PATH = 'content'
STATIC_PATHS = ['images','javascripts','examples']
# skips processing of all .html
READERS = {'html': None}
TIMEZONE = 'America/Vancouver'
DEFAULT_LANG = 'en'
# Feed generation is usually not desired when developing
FEED_ALL_ATOM = None
CATEGORY_FEED_ATOM = None
TRANSLATION_FEED_ATOM = None
AUTHOR_FEED_ATOM = None
AUTHOR_FEED_RSS = None
SITESUBTITLE="Tech Blog"
# Blogroll
LINKS = (('Pelican', 'http://getpelican.com/'),
('Python.org', 'http://python.org/'),)
# Social widget
SOCIAL = (('Facebook', 'https://www.facebook.com/allan.bowhill.1/'),)
DEFAULT_PAGINATION = 10
# Uncomment following line if you want document-relative URLs when developing
#$RELATIVE_URLS = True
Project layout is very simple. There are just content
and output
directories that your should care about. The content
directory is where you put your markdown for blog articles. The output
directory is where your html gets compiled.
Beneath content
you may create other directories to include in the site. Photos and javascript directories are easily handled by Pelican's STATIC_PATHS
config file setting. Files in these directories (as long as they are not markdown or html) will be included in the built output tree unmodified.
One niggle about configuration: the READERS =
line in the above pelicanconf.py has to be there if you want to be able to insert and publish raw HTML verbatim, not to be processed by the framework. I had to supress compilation of html because I needed a place to store html files verbatim, without exposing them to the compile process. Some Javascripts for example will not play well with certain complex Javascript layout frameworks like Gumby and need to be isolated in their own space. If you don't use this READERS
setting, Pelican will aggressively try to embed any html it finds into the layout framework's wrapper, or in some cases, simply not include it in the files to be uploaded to your site.
Development
The development process can be done several ways, most of which can be controlled from the Pelican Makefile
. You just enter: gmake
for a help screen:
[devblog]$gmake
Makefile for a pelican Web site
Usage:
make html (re)generate the web site
make clean remove the generated files
make regenerate regenerate files upon modification
make publish generate using production settings
make serve [PORT=8000] serve site at http://localhost:8000
make devserver [PORT=8000] start/restart develop_server.sh
make stopserver stop local server
make ssh_upload upload the web site via SSH
make rsync_upload upload the web site via rsync+ssh
make dropbox_upload upload the web site via Dropbox
make ftp_upload upload the web site via FTP
make s3_upload upload the web site via S3
make cf_upload upload the web site via Cloud Files
make github upload the web site via gh-pages
Set the DEBUG variable to 1 to enable debugging, e.g. make DEBUG=1 html
[devblog]$
gmake devserver
displays the website on local port 8000 while you edit markdown. gmake stopserver
shuts down the dev server. I haven't tried the upload commands yet.
Conversion of Articles
Writing articles in markdown is almost identical to doing it in Middleman, so the articles translate reasonably well. Headers are not the same between the two platforms. Pelican uses more optional information:
Title: My super title
Date: 2010-12-03 10:20
Modified: 2010-12-05 19:30
Category: Python
Tags: pelican, publishing
Slug: my-super-post
Authors: Alexis Metaireau, Conan Doyle
Summary: Short version for index and feeds
Middleman uses less, in my config:
layout: single
title: 'Using Opal to Generate JavaScript'
tags: ruby, opal, www
Converting headers between then required a crude script (beware: it's hackish) and an ERB template:
require 'erb'
require 'date'
class Convert
attr_accessor :title, :date_a, :date_b, :slug, :mainfile, :tags, :template
def initialize template
@title = nil
@date_a = nil
@date_b = nil
@slug = nil
@mainfile = ""
@tags = nil
@template = template
end
def post_init
cvt names
end
def names
# writes copies of all *.html.markdown files in current directory to *.md!
rbfiles = File.join("**", "*.markdown")
Dir.glob(rbfiles)
end
def cvt(file_ary)
file_ary.each do |file|
basename = File.basename(file,".html.markdown")
part = basename.partition(/\d+-\d+-\d+-/)
@slug = part[2]
@date_a = part[1].chop
@date_b = DateTime.now.strftime ("%m-%d-%Y %I:%M:%S")
@mainfile = read_header file
header = render
fh = File.new("#{basename}.md","w")
fh.write(header + @mainfile)
fh.close
end
end
def read_header(fn)
fh = File.open fn
mfile = ""
fh.each_line do |line|
mfile += line
line.chomp!
@title = clean line,"title:" if line =~ /title:/i
@tags = clean line,"tags:" if line =~ /tags:/i
end
mfile
end
def clean(line,type)
part = line.partition type
item = part[2]
item = item.delete "'"
item = item.delete "\""
item.strip
end
def render
@resolved = ERB.new(@template).result(binding).to_s
@resolved
end
end
template = File.read "convert.erb"
c = Convert.new template
c.post_init
Title: <%= @title %>
Date: <%= @date_a %>
Modified: <%= @date_b %>
Category: <%= @tags %>
Tags: <%= @tags %>
Slug: <%= @slug %>
Authors: Allan Bowhill
Summary: <%= @title %>
Also, Pelican is less tolerant of certain things like uneven open and close code gating symbols, which I had to correct with in a Perl/sed editing pipelines and manual edits.
Selecting a Theme
This is one of Pelican's Big Strengths as a blogging platform. It has many themes (around 90) and they're all easy to test. Just run pelican-themes --list
to list currently installed or linked themes. To get the entire themes collection you'll need git. Here's how to get all the themes, link to one called blue-penguin
and serve it up on port 8000
# don't forget --recursive switch since many themes will be empty due to project linking
git clone https://github.com/getpelican/pelican-themes.git --recursive
# link your blog to the theme
sudo pelican-themes --symlink <path to pelican-themes>/blue-penguin
# Verify the themes registered
pelican-themes -l -v
# build and serve the new theme
gmake clean && pelican ./content -o ./output -t blue-penguin && gmake serve
Just repeat the last three commands from the above code for each new theme you want to test. It's an eye opener and a great blogging platform overall!
Compiling with a Theme
gmake clean && pelican ./content -o ./output -t <theme-name> && gmake serve