Or: What we blog about when we blog about blogs
🐙 ➡️ 🐍
This post is the story of how I switched the underlying framework for this blog from Octopress to Pelican.
And I added a side quest: Like many Octopress users, I grew fond of the default Octopress theme, and wanted to keep it after moving to Pelican.
Keeping the Octopress theme turned out to be easy; the pelican-octopress-theme github repo was what I needed:
And for other tips, Google revealed blog posts from other folks who made the Octopress-to-Pelican switch over the years. Trip reports I referred to were:
- https://jakevdp.github.io/blog/2013/05/07/migrating-from-octopress-to-pelican/
- http://themodernscientist.com/posts/2013/2013-06-02-my_octopelican_python_blog/
- http://jhshi.me/2015/10/11/migrating-from-octopress-to-pelican/
The plan
First off, after reading the docs, I wrote down the steps I assumed would be involved with the move; here they are:
- Create and activate a virtualenv, then use pip to install pelican
- Use the
pelican-quickstart
util to set up a barebones Pelican blog, as a starting point for the move - Get used to launching a dev server to preview changes
- Apply the pelican-octopress-theme to the barebones blog
- Bring my old blog's CSS and sidebar customizations into pelican-octopress-theme
- Create a public github repo containing the work so far
- Copy the old Markdown post files and images from my Octopress dir to my pelican repo
- Edit posts as needed to get them to display properly
- Back up the contents of my existing blog's s3 bucket (for easy rollback if the first deploy doesn't go smoothly)
- Publish the new files to s3!
The reality
Based on the outline above, here's what actually happened when I started carrying out the plan:
-
Installing pelican
For this step I set up a new virtualenv and installed the pelican and markdown packages:
mkdir blog.likewise.org cd blog.likewise.org/ virtualenv env . env/bin/activate pip install pelican markdown
For the record, I was using OS X, Python 2.7.12 from Macports, and Pelican 3.6.3.
-
Running
pelican-quickstart
This part of the process went smoothly. The quickstart util didn't bring up any surprises, and produced the files that became the blog you're reading now.
Here's a log of the input I gave
pelican-quickstart
to bring up a site with a dev server script, Makefile, and s3 publishing support:pelican-quickstart > Where do you want to create your new web site? [.] > What will be the title of this web site? Bill Agee's blog > Who will be the author of this web site? Bill Agee > What will be the default language of this web site? [en] > Do you want to specify a URL prefix? e.g., http://example.com (Y/n) n > Do you want to enable article pagination? (Y/n) n > What is your time zone? [Europe/Paris] America/Los_Angeles > Do you want to generate a Fabfile/Makefile to automate generation and publishing? (Y/n) Y > Do you want an auto-reload & simpleHTTP script to assist with theme and site development? (Y/n) > Do you want to upload your website using FTP? (y/N) > Do you want to upload your website using SSH? (y/N) > Do you want to upload your website using Dropbox? (y/N) > Do you want to upload your website using S3? (y/N) y > What is the name of your S3 bucket? [my_s3_bucket] blog.likewise.org > Do you want to upload your website using Rackspace Cloud Files? (y/N) > Do you want to upload your website using GitHub Pages? (y/N) Done. Your new project is available at /Users/bill/github/billagee/blog.likewise.org
-
Bringing up a dev server to preview changes
This was super easy. Assuming you answered yes to the auto-reload & simpleHTTP question in
pelican-quickstart
, just runmake devserver
.Then point your web browser at
localhost:8000
to browse your site.To stop your dev server, run
make stopserver
. -
Apply pelican-octopress-theme to the demo blog
At this point I paused to see what the docs had to say about how to use themes in Pelican.
To try out the stock pelican-octopress-theme, first clone its repo:
git clone https://github.com/duilio/pelican-octopress-theme.git \ ~/github/duilio/pelican-octopress-theme
Then install it in your site with the
pelican-themes
util:pelican-themes --install ~/github/duilio/pelican-octopress-theme
There's one more step - to make sure the dev server can find the theme, edit the
develop_server.sh
file in your pelican dir, and place the--theme-path
option and value in thePELICANOPTS
variable:# In develop_server.sh - replace the empty PELICANOPTS= var if it's present: PELICANOPTS="--theme-path ~/github/duilio/pelican-octopress-theme"
This is a good time to make the same change in the
Makefile
in the root of your site, since you'll be needing it there too (note that the double quotes around the value are left out):PELICANOPTS=--theme-path ~/github/billagee/pelican-octopress-theme
Restart your dev server after making those changes, and reload the site in your browser - you should then see the Octopress theme in place:
make stopserver && make devserver
-
Making a test post
At this point I added a new step to the original plan: Learning how to create a post.
To do that using Markdown (adapted from the content docs), you can cat out a post file to disk like so, if you're in your site's root dir:
# Again, this assumes your current working dir is your blog's root dir: cat > content/2016-08-20-my-test-post.md << EOL Title: My title Date: 2016-08-20 12:30 Category: Python Tags: pelican, publishing Slug: my-test-post Authors: Your Name Here Summary: Short version for index and feeds This is the content of my test post. EOL
-
Bring my old blog's color and sidebar customizations into pelican-octopress-theme
This is, of course, an optional step, but I wanted to change the header background color of the Octopress theme, and rearrange the sidebar.
This required a bit of tinkering, but it wasn't too bad.
To change the header background color in pelican-octopress-theme, I first made my own fork of the original repo.
Then, I cloned my fork, and changed the
$header-bg
value in the SASS file where it lives: sass/base/_theme.scss//$header-bg: #333 !default; // default octopress gray $header-bg: #35206f !default; // likewise purple
There's one more step required - recompiling the theme's SASS files using the
compass
util. To install sass and compass and update the theme with your changes,cd
to the root of your pelican-octopress-theme fork, and:# Run this in your pelican-octopress-theme root dir gem install sass compass compass compile
-
Create a public github repo containing the work so far
Not much to say here, except that you might be interested in the .gitignore file I created before pushing my repo:
*~ ._* *.lock *.DS_Store *.swp *.out *.py[cod] output env srv.pid pelican.pid
Omit the
output
dir from your .gitignore if you want to keep your generated site files under version control. -
Copy the old Markdown post files from my Octopress dir to my pelican repo
This is where things began to get real. I started by coping the post files from my
sources/_posts
Octopress dir tocontent/
. I then committed everything as-is before making edits.The first step was to convert the old Octopress post metadata, for example:
--- layout: post title: "Dockerized Ghostdriver Selenium Tests" date: 2016-02-14 00:23 comments: true categories: Docker Linux Selenium WebDriver Automation PhantomJS Python Testing ---
...to the corresponding Pelican Markdown:
Title: Dockerized Ghostdriver Selenium Tests Date: 2016-02-14 00:23 Tags: Docker, Linux, Selenium, WebDriver, Automation, PhantomJS, Python Slug: dockerized-ghostdriver-selenium-tests
Note the addition of the
Slug
field, and replacingcategories:
withTags
, since Pelican offers both categories AND tags. And Pelican tags seem akin to Octopress categories. -
Edit posts as needed to get them to display properly
I noticed a few indentation changes to existing code blocks in my posts were required to get them to display properly.
In the end, I switched over to using code blocks prefixed with
:::
, for syntax highlighting with CodeHilite. Here's an example: -
Converting Octopress image tags
There was another extra step required to get images in old posts to display - moving Octopress Markdown posts to Pelican means embedded images that use the Octopress
{% img %}
tag won't carry over directly without edits (or the liquid_tags Pelican plugin).I didn't have too many images in my old posts, so I just replaced my old Octopress image tags, such as:
{% img /images/fancybox.png 'fancybox screenshot' %}
...with the Pelican attach syntax:
![Fancybox Screenshot]({attach}images/fancybox.png)
This was also the point when I finished copying all the image files from my old Octopress dir (
source/images/
) into my Pelican blog'scontent/images/
dir. -
Back up the contents of my existing s3 bucket before copying any new files to the bucket
Not much to say here.
s3cmd sync
was my means of doing this. -
Publish the new files to s3!
With your AWS credentials in
~/.s3cfg
, just set your s3 bucket's name in your Pelican dir'sMakefile
, in theS3_BUCKET
variable.Then, to publish your changes to your s3 bucket:
make clean make s3_upload
-
Manually fixing the
Content-Type
value for main.cssI ran into a hiccup here - after publishing my files to s3, the MIME type guessing done during the upload apparently didn't work, so my main.css file was served by s3 as text/plain.
This resulted in the published copy of the blog in s3 displaying without CSS being applied; so, the appearance of the blog was totally broken in all browsers I tried. Oops.
Presumably this will only affect you if you're publishing to s3 like me; I didn't try deploying with Dropbox or the other options.
I worked around the problem by using the AWS console to manually change the Content-Type header value S3 serves up for my
main.css
file. (I still need to find a real fix for this, or at least a way of doing it withs3cmd
.)Steps for the fix were:
-
After
make s3_upload
completes, log in to the AWS s3 console. -
In the UI, navigate to: All Buckets > /YOUR_BUCKET/theme/css
-
Right-click
main.css
, and view its properties -
Under "Metadata", set the Content-Type key to
text/css
and save.
-
-
Using the pelican-alias plugin to create .html aliases to posts
I'd forgotten that my very oldest Octopress posts were actually raw HTML migrated from Blogger years ago - long ago I jammed that content into Markdown files, and each Markdown file contained one massive, single-line
<div>
exported from Blogger.Ugh! I couldn't let that stand, so I took the time to convert those old HTML posts to proper Markdown.
I then realized a few of those old Blogger-era HTML posts were still showing up in Google results, with their original .html extensions (which Pelican and Octopress don't create).
In the Octopress blog I'd resorted to creating s3 aliases for those old posts at publish time, in the bash script I used to upload everything with s3cmd.
That resulted in posts whose URLs ended in
2012-08-foo/
getting matching2012-08-foo.html
siblings, in case someone visited the old Blogger URL.In Pelican, you can use the pelican-alias plugin to create .html aliases for posts, which worked fine for me. See that plugin's docs for more info.
For more it boiled down to installing and activating the plugin, then adding an extra bit of metadata to the ancient posts that needed an .html alias:
Alias: /2011/07/selenium-2-net-test-drive.html
-
Google Analytics
To set up Google Analytics, I put my GA ID in the
pelicanconf.py
file in the site's root dir, in theGOOGLE_ANALYTICS
var. -
Modifying the order of items in the Octopress theme sidebar
My old blog had some custom tweaks to the sidebar; preserving those (and adding some new ones) was mainly a matter of editing this file in my pelican-octopress-theme fork:
pelican-octopress-theme/templates/_includes/sidebar.html
The commit history for my pelican-octopress-theme fork tells the full story of the sidebar.
-
Github sidebar fix
Either due to a bug in the theme, or as a result of my sidebar tweaks, the Github chunk of the sidebar was refusing to fetch the list of my github repos.
To get that working, I made this JS tweak in my fork's copy of
pelican-octopress-theme/templates/_includes/github.html
- namely pulling in jQuery.This seems rather...not great, but it works for now:
{% if GITHUB_SHOW_USER_LINK is defined %} <a href="https://github.com/{{ GITHUB_USER }}">@{{ GITHUB_USER }}</a> on GitHub {% endif %} + <script src="https://code.jquery.com/jquery-3.1.0.min.js" integrity="sha256-cCueBR6CsyA4/9szpPfrX3s49M9vUU5BgtiJj06wt/s=" crossorigin="anonymous"></script> <script type="text/javascript"> - $.domReady(function(){ + $(document).ready(function(){ if (!window.jXHR){ var jxhr = document.createElement('script'); jxhr.type = 'text/javascript';
Whew
That's all for now, I suppose! This concludes my first Pelican post.