Endless Tinkering

9 Jan 2025 on chupson's Blog

This is going to be a pretty simple post, I just want to show off something cool I made.

I have a little bit of a problem. I am constantly, and I mean constantly tinkering with my computer configuration. I’m always looking for a new plugin to add to my ever-growing collection, always changing some keymapping, and don’t even get me started on themes and wallpapers. Almost of all the tools I regularly use are highly configurable, and in text form too. So there really isn’t anything stopping me from constantly making little changes here and there. And don’t get me wrong, I’m all for getting your computer setup just right, having everything where you want it and how you want it, but there’s a balance to be found. When you change things too often, it can be difficult to get comfortable with your current setup, essentially defeating the purpose of getting things perfectly customized - you also have to learn how to operate within those customization and that requires time. Not to mention the sheer amount of time that that whole ordeal takes. I can remember times when I would spend more time customizing my computer than actually using it.

I believe that while there is value in tweaking your tools to suit you perfectly, there is also value in getting comfortable using them, and it’s important to remember that new is not necessarily better. That one change might not be as absolutely critical as I might think, and maybe the font I’m using now is just fine and doesn’t need to be changed for that other, slightly different one. I also think this idea might apply to things other than computers. Food for thought.


Something cool I made

Okay that previous section turned out much longer than I expected, so let’s keep it short from now on. I store my configuration files, or dotfiles, in a Git repository. One time when I was git pushing some new changes I had made, I realized that (unsurprisingly) I didn’t have any automated job that would run on push. I love automation, so most of my repositories have jobs which run tests, check formatting, etc., but in the case of my dotfiles there wasn’t a need for any of that.

So, what I came up with to both make fun of how often I change my configs and to have a cool automated job, was this fun little page, obviously inspired by those memes that say 0 days since blank. What the page does is show how many days have passed since the last time I made a commit in my dotfiles repository, along with a summary of the latest commit. It’s very simple, so here’s how I did it.

The page itself

Really not much to be said about the actual HTML page. It’s some very simple HTML, part of my Hugo website. The only thing that makes it the slightest bit special, is that all the tags which are supposed to contain information about the commit and how many days have passed, are marked with an ID that makes it very clear where information should be placed. Here it is if you want to take a look1.

Updating on push

When commits are pushed to the remote of my dotfiles repository, a builds.sr.ht job kicks off. All it does is extract some information about the latest commit in that repository, stores it in a file, and copies said file over to the server where my website lives. That information is the commit’s timestamp, title (or message, I’m not sure what it’s called), number of lines added and removed, as well as the link to the corresponding commit page on git.sr.ht. Here’s a simplified version of the build manifest which does all that:

image: alpine/latest
...
tasks:
  - update_last_commit: |
      cd .dotfiles
      touch last_update
      git show --format=raw | sed -n 's/author.*> \([0-9]\+\) .*/\1/p' | tee -a last_update
      git show --format="%s" | head -n 1 | tee -a last_update
      git diff --numstat HEAD~ HEAD | awk '{printf "%s ", $1} {printf "%s\n", $2}' | tee -a last_update
      git show --format="%H" |  head -n 1 | awk '{printf "https:\/\/git.sr.ht/~chupson/.dotfiles/commit/%s", $1}' | tee -a last_update
      rsync -e "ssh -o StrictHostKeyChecking=no" ./last_update deploy@chupson.dev:/usr/local/share/days_since_config/last_update
      ssh -o StrictHostKeyChecking=no -t deploy@chupson.dev \
      '/bin/bash /usr/local/bin/update_days_since_last_config.sh /usr/local/share/days_since_config/last_update /var/www/chupson.dev/days_since_config/index.html' || true      

Updating the actual page

As you might have noticed, the build manifest presented above calls a script called update_days_since_last_config.sh, which looks at the HTML file of my page, uses pattern-matching to find the tags which are supposed to have their contents replaced, and puts information about the latest commit and days passed, as derived from the file we made in the last step. Well, I say derived, but actually the only thing that isn’t copied from the file verbatim is the commit’s timestamp, which has to be processed so that we can find out how many days have passed since then. Here’s the script:

last_update_path=$(realpath "$1")
html_path=$(realpath "$2")

last_commit_timestamp=$(awk 'NR==1' "$last_update_path")
days_since=$((($(date +%s)-$(date +%s -d "@$last_commit_timestamp"))/(60*60*24)))
if [ "$days_since" -le 0 ]; then
    days_since=0
fi
last_commit_date=$(date +"%d %b %Y" -d "@$last_commit_timestamp")

last_commit_message=$(awk 'NR==2' "$last_update_path")

changes=$(awk 'NR==3' "$last_update_path")
added=$(echo "$changes" | awk '{print $1}')
removed=$(echo "$changes" | awk '{print $2}')

url=$(awk 'NR>=4' "$last_update_path")
url=$(echo "$url" | sed 's/[&/\]/\\&/g')

# Days since
sed -i -E "s/(<h1[^>]*id=\"days_since_config_days\"[^>]*>)[^<]*(<\/h1>)/\1$days_since\2/" "$html_path"
# Last commit date
sed -i -E "s/(<span[^>]*id=\"days_since_config_date\"[^>]*>)[^<]*(<\/span>)/\1$last_commit_date\2/" "$html_path"
# Last commit message
sed -i -E "s/(<span[^>]*id=\"days_since_config_message\"[^>]*>)[^<]*(<\/span>)/\1$last_commit_message\2/" "$html_path"
# Last commit added
sed -i -E "s/(<span[^>]*id=\"days_since_config_added\"[^>]*>)[^<]*(<\/span>)/\1\+$added\2/" "$html_path"
# Last commit removed
sed -i -E "s/(<span[^>]*id=\"days_since_config_removed\"[^>]*>)[^<]*(<\/span>)/\1\-$removed\2/" "$html_path"
# Last commit URL
sed -i -E "s/(<a[^>]*id=\"days_since_config_url\" href=\")[^\"]*(.*<\/p>)/\1$url\2/" "$html_path"

This script is also periodically by a cronjob, ensuring the number of days displayed on the page is accurate.

And yeah, that’s pretty much it. I think the page is pretty cool, and I certainly had some fun making it.


  1. This page, as mentioned, is part of a website built in Hugo, so it contains some directives which Hugo will replace with appropriate code. None of that is relevant, though. ↩︎