Author’s Note: I’m currently in the process of migrating old blog posts to this new system. That may mean some links, syntax highlighting, and other details are broken or missing temporarily. Sorry for the inconvenience!

I did a dumb thing - I left this site alone for too long, and now I have no idea how it works. There’s some crazy bash scripting happening and it takes my markdown files and converts them into HTML and then injects them as part of a template and…ugh.

Who wrote this crap?!

Oh yeah.

Rule #1: Everything you did more than a few weeks ago is garbage

I don’t make the rules. I just define them here for your benefit. If you leave code alone long enough, you’ll decide it was awful. Nothing is documented; tests are missing or misleading; how you managed to skate by on this old tattered codebase is beyond imagining.

Welcome to life, this is just the programming equivalent of “Man, remember what I was like three years ago? Boy was I stupid”. Blame it on the telescopic nature of technological progress, or something like that.

Okay, so about this site then…

Let’s see. There’s no index page (or there wasn’t, there is now!), and all that I have is a weird tmux preset that spins up a text editor and also runs sync.sh. What the hell does that do? Let’s go code spelunking:

#!/bin/sh
clear
rsync -ru --del cheerskevin.com:/var/www/cheerskevin.com/ .
filewatcher -s '**/*' './deploy.sh'

Alright, so first it pulls down content from the site, and then it spins up filewatcher, which is a RubyGem that I kinda like, but want to stop using because I’m nervous about future breakages which I won’t get into here. The gist of the command though, is that it will ./deploy.sh on any file if it detects a change. Say, for example, me saving something with the text editor. Soooooo… on file save, it runs this deploy script. What the heck does that do?

Deploy.sh

#!/bin/bash
case "${FILENAME##*\.}" in
  md)
    if head -n 1 $FILENAME | grep -q '\-\-\-'; then
      VERSION=$(cat $FILENAME | sed -n '/^---/,/^---/p' | grep version: | sed 's/.*: //')
      ./templates/v$VERSION.sh $FILENAME > "${FILENAME%.*}.html"
    else
      # Contains no front matter, process as self-contained Markdown
      echo "<meta charset='utf-8'>" > "${FILENAME%.*}.html"
      kramdown -i GFM $FILENAME >> "${FILENAME%.*}.html"
    fi
  ;;
esac

./build-indexes.sh

rsync -ru --del . cheerskevin.com:/var/www/cheerskevin.com/

WHAT SORT OF IDIOT-

Ahem, sorry, I’m calm, I’m calm. Okay, let’s take this script back-to-front. At the end of things, it’s going to use rsync to push up any changes to the server. Fine. That makes sense. Before that, it runs ./build-indexes.sh, which I vaguely remember writing; it generates some ls files, so you can visit https://cheerskevin.com/ls to see all the files in a given directory. Also fine.

Prior to that though…there’s this obnoxious case statement. This checks the filetype, to decide if it should do something special. If the filetype is md (i.e. a markdown file), then it does some really stupid awful bash stuff to detect a version number (this blog post you’re reading is v0.4.0), then runs ./templates/v0.4.0.sh THEFILE.md > THEFILE.html

Ugh, okay. So basically, some files can automatically be converted from Markdown to HTML, using some template file as the way to do it. Which makes the template file NOT a template, but a converter script. So that’s a dumb name. Gross.

The smarter, wiser way

You know what would be reasonable? Let’s propose a rather modest change to our deploy script (which, by the way isn’t a deploy script, it’s an “on file change detection” script, so that’s also a crappy name). Let’s call it handleFileSave.sh, and let’s also have it take an argument, rather than assuming $FILENAME will be populated with the thing, because that’s just dumb. I wanna be able to run handleFileSave.sh my-cool-file.txt and have that work. Here’s what I want it to look like:

#!/bin/bash
FILENAME=$1
FILE_EXTENSION=${FILENAME##*\.}
[ -f ./processors/$FILE_EXTENSION ] && ./processors/$FILE_EXTENSION $FILENAME
./build-indexes.sh
rsync -ru --del . cheerskevin.com:/var/www/cheerskevin.com/

Let’s break that down. First, we name our variables so that the world makes sense. $1 is the first argument that gets passed to the script. So if we run ./handleFileSave.sh my-cool-file.txt, $1 will be “my-cool-file.txt”. BUT we’re being smart and assuming that one day we’ll be senile, so we’re giving it a useful variable name $FILENAME.

Next, we want the file extension. What’s a better way to talk about that? "${FILENAME##*\.}"? OR $FILE_EXTENSION?! Right. $FILE_EXTENSION it is.

Now we do a tiny bit of Bash weirdness. [ -f ./processors/$FILE_EXTENSION ] means “is there a file ./processors/$FILE_EXTENSION”? Or rather, “is there a file ./processors/md” or “is there a file ./processors/txt”, or whatever the danged file extension might happen to be. Then we use &&, which is “and and”, which is because programmers are weird, so AND AND run that processor on the $FILENAME.

In English: “assuming a processor for this filetype exists, run the danged processor”

All of which is to say: is there a processor for “md” files (or whatever file happened to have just been saved)? Cool. Run it. I don’t care what it does. Just do it, build the indexes, push all the changes, and go home.

Now, that means we have to extract this old template crap to a ./processors/md file, but it also means we can then leave it alone. If we decided we needed to do something fancy when we detect an image has been saved (like, say, automatically reducing it to a reasonable size), we could just add a ./processors/jpg file. The handleFileSave script doesn’t care what specifically is supposed to happen to particular file types. It cares about what’s in its name: what to do when files are saved.

Rule #2: JavaScript will find a way to take over everything

Now that that’s over, it’s time to make everything else worse by adding lots of JavaScript. Tune in to next week’s episode for that hot mess!

←Previous Post | Next Post→