Porting my blog to Hugo from inside Emacs
A few days ago I ported my blog to hugo. I did this mostly while staying inside Emacs and switching to the web browser every now and then.
Doing this required me to use Emacs to edit and manage multiple files at once and this post demonstrates a few of these techniques. The post is therefore mostly task agnostic and the techniques explained here should be usable for any such tasks.
This is in no way a comprehensive post for porting any blog to hugo and I've deliberately skipped steps that were either too straightforward to perform or used a technique that I've already covered in doing something else. For a more detailed understanding of the process, please refer to this blog post by someone else.
For the sake of brevity I’ll only cover these topics:
- Setting up the environment, i.e., setting up the directory structure, git repositories and tooling.
- Port my markdown files so that they work with hugo
Setting up the environment
Hugo is a static site generator that works by converting the "content" files written in many of the formats it supports, such as markdown or org into a set of html files.
It uses a simple layout system mainly comprising of single pages and list pages to save the developer any repetitive work by reusing components across multiple places.
Installing hugo
system-packages package makes it possible to install any package from
within emacs.
Pressing C-c P i bound to system-packages-install and
typing hugo in the minibuffer installs it using your preferred package
manager.
Setting up the directories and repositories
I planned on having two repositories for the blog. One would be the source repository having hugo files and the other would be for the generated html.
I usually do directory operations from inside dired but I feel
counsel-find-file is more intuitive when creating new files, in
different locations.
C-x C-fbound tocounsel-find-file- Type in
blog/blog-srcfollowed byC-M-o dto create a directory- Type in
blog-genandM-othendagain to create another directory and quit to ivy buffer
This is how it looks in practice:
Click here to download or view the video in a full browser window
Initializing repositories can be done via magit
C-x mbound tomagit-statusa directory will create a repository if one does not exist already and open magit-status bufferM afrom there adds a remote and fetches itb ccheckouts a new branch from another branch
After setting up the environment I can start porting my blog there.
Porting content files from old blog
Moving my files from octopress to hugo required a few minor transformations to happen.
2014-02-19-hello-blogging.markdownto be renamed tohello-blogging.md- Adding
aliasesto maintain the older links working - Fixing invalid markdown that was valid in the older spec
- Removing few unnecessary meta tags from the header files
These need to happen on every file.
Bulk renaming
dired-mode and wdired are great for such tasks. Wdired makes any
directory list editable like any other file.
- Opening the dired buffer and pressing
Wto switch to wdired C-x hto select all the lines followed byC-nto limit it to the only filesC-S-c C-S-cbound tomc/edit-linesto get a cursor on every line.- Edit the files names accordingly and
C-c C-cto save the changes to disk. This is how it looks in practice:Click here to download or view the video in a full browser window
Updating meta
aliases provide a way for hugo to create multiple links for one single
post. The path for posts in my older blog was in
year/month/day/blog-title format. There's a way to do this for all
posts in hugo, but I only wanted to retain this format for the older posts
and would be happy with /blog/blog-title format that hugo uses by default.
To do this I use the date field in the header of the octopress
markdown files. These can be manipulated to create the date
year/month/day/ part in the aliases field. The blog-title can be
derived from the file name, by writing some lisp code and running
eval-and-replace (custom function in my config). Macros can then be
used to do the same for all the files
Macros in emacs allow an edit to replicated any number of times after recording them once. If we open the first file from dired, make the necessary changes and switch back to the dired buffer, we can make emacs do the change for all the files sequentially with just a single keystroke.
A demonstration may give a better idea
Click here to download or view the video in a full browser window
This can be followed by running C-c p s bound to
projectile-save-project-buffers to save all the modified buffers
Fixing invalid spec
One of the few incompatibilities in the markdown spec was how markdown handled headings. Earlier
#H1#
##H2##
###H3###
####H4####
#H1
##H2
###H3
####H4were considered valid markdown headings which now had to be changed to
# H1
## H2
### H3
#### H4This again needs to be done across all the files.
Macros can be used here as well but macros can quickly get complex considering the keystrokes should be generic enough to work with all the files. I instead used a feature in emacs which allows me to search for terms from across multiple files and edit them in a single buffer, as if I'm editing a single file. Emacs can then cleverly apply those changes to the original files.
I did this by:
C-u C-c s sbound tocounsel-rgto search through the current directoryC-c C-obound toivy-occurto get the search results in a bufferwbound toivy-wgrep-change-to-wgrep-modemakes the buffer editable- Editing them and running
C-c C-cto save these changes
To keep this simple it is done twice once to remove the preceding # and once to remove the following #
This is how it looks:
Click here to download or view the video in a full browser window
Conclusion
These steps allowed me to have a working hugo blog with all the posts ported from the older blog system.
As I mentioned earlier, the purpose of this post was not to be a comprehensive guide of porting to hugo but instead a demonstration for how these tasks that might have required writing complex shell scripts or doing repetitive effort were done easily from within emacs.
Emacs provides other ways to manage multiple files together as well. Dired, LSP, Projectile can all be used to manage multiple files at once in ways not covered in this post and each demanding an article on it's own. I therefore, only covered the features that I used in this particular task.
My emacs configuration can be found on github for people who are interested in replicating some of the features described here.