jekyll plugin: upload site after build

After using jekyll for years, I’m finally starting to leverage its plugin system to make life easier. The first one I did was to strip footnotes from the post excerpt only when displayed on the main index. No official plugin gem existed, but I found one by Sumit Khanna. It worked perfectly, but I didn’t make or modify it at all. However, recently I discovered that my upload scripts were failing, which prompted me to look for a new solution involving a plugin.

The old set up was thus:

  • jekyll serve runs inside of a docker container on our NAS. This continually rebuilds a local instance of the site when it detects changes.
  • Syncthing is used to synchronize changes from my phone and my laptops between each other and to the NAS. I use this to make quick microblogs, update the now page, or author entire new posts like this one. 1
  • My cronfile on the NAS contained a few hand written bash scripts that would upload to my webhost when inotify detected changes to the _site output folder.

It worked for a long time, but when it didn’t work, it didn’t work, and troubleshooting inotify is a pain in the ass2. The only reason I started with it for this problem was because I knew it. I hadn’t yet learned how to hook into jekyll’s build process, but today that’s what I realized I had to do and a quick web search revealed to me exactly how to do so! The hook I wanted was specifically :site, :post_write which gets triggered “After writing all of the rendered files to disk.” Perfect!

Jekyll’s plugins are written in ruby, just like jekyll itself. I have very minor experience in ruby but that’s not really a problem. Picking up a language for simple things like this is incredibly easy. It was a trivial process of determining which OS I’m on so I could call the appropriate upload script. Currently I only run the build process automatically on one Linux machine (the NAS) and manually on two different Windows machines (old x86_64 Surface Pro 7 and new arm64 Surface Laptop 7). I will have to modify this at some point if I move the Surface Pro 7 to Linux; perhaps checking for the hostname of the device instead of the OS? But manually running the build process on my laptops is rare and only used for testing, which will be true no matter the OS, so this is not a problem to be solved right now.

So the plugin currently checks for the OS and if it finds anything that contains “linux” it runs the upload script, but if it finds “mingw32” it gives a nudge to run the script manually if that’s your goal. I did run into a couple minor issues:

  1. Because the upload script is now running inside of the docker container instead of on the NAS itself, pathing needs to be updated: no problem!
  2. rclone did not exist inside of the jekyll container. Not a big problem either! All it took was one little apk add rclone and a copy of my working config. Yes this will break if I pull a new jekyll docker image. I’m sure there’s some docker-compose magic I could pull to reinstall it on rebuild though. I’ll burn that bridge that when I get there.

Now it works perfectly any time I author, update, or delete any post, page, or microblog from my phone or from my laptop!

This is a much easier and far more robust solution than inotify ever was.

Here’s the full script3:

@os = RbConfig::CONFIG['host_os']
linux_upload_script = "/srv/jekyll/scripts/web_push.sh"

Jekyll::Hooks.register :site, :post_write do 
  puts "  Upload Script: found OS: " + @os
  case 
  when @os.downcase.include?('linux')
    puts "  Upload Script: execing : " + linux_upload_script
    system "sh " + linux_upload_script
  when @os.downcase.include?('mingw32')
    puts "  Upload Script: !! running on windows, so probably building for test reasons, run upload script manually!"
  end
end

Maybe this can help someone else out there too :)

I’m realizing this is the first technical post I’ve made in a long while. It feels kinda good. I can definitely feel how rusty my writing skills are though. I’d like to flex that muscle again

  1. On both mobile and desktop I use Obsidian. Because jekyll and obsidian both work in Markdown files, it is very easy to turn a jekyll website into an obsidian vault and edit it directly within obsidian. 

  2. I’ve used inotify in the past for something on my old old old desktops and laptops. We’re talking like, well over a decade ago. It was janky then and it’s janky now. 

  3. I realize this post is a lot like those recipe posts that include the author’s life story before you get to the ingredient list. Deal with it? I like explaining things and talking about where I came from and how I got somewhere. If that’s not enough of a reason: this is my blog and I’ll type what I want toÂ