Code on a screen by Florian Olivo via Unsplash

Code on a screen by Florian Olivo via Unsplash

If you’re curious how I made the code samples in my earlier post on running old games in containers, read on!

You’ll note that this was a step-by-step tutorial, with a lot of trial-and-error, and I wanted to show the reader all the errors and issues I ran into, and what changes I had to make for each step, and I showed how the runner script and the Dockerfile changed along the way.

During the writing of the blog post, I had to update the code, clarify it add comments, and fix issues. It would have been quite tedious to manually update each of the step-by-step diffs in the blog post every time, so I wrote a script to automatically update all the diffs between each of the steps, and the blog post automatically included the diffs inline, and linked to the complete code.

Of course, if I wanted to make a change to the script in step 3, I would have to manually propagate it to the scripts in all the subsequent steps, but I would just update the shell script, and regenerate all the diffs automatically, which were sourced into the post with a Hugo shortcode.

Here’s the script that I used to create the diffs:

#!/bin/bash
#
# Copyright 2020 Misha Brukman
# SPDX-License-Identifier: Apache-2.0
# http://misha.brukman.net/blog/2020/04/running-decade-old-games-in-containers/

for dir in v*; do
  declare -i version_num="${dir:1}"
  if [ ${version_num} == 1 ]; then
    continue;
  fi
  for file in Dockerfile runner.sh; do
    # For consistency in Markdown rendering, convert all <Tab> characters,
    # mostly visible in the --- and +++ lines to two spaces, so they render
    # well.
    #
    # Hugo seems to render the first line with <Tab> longer than the second,
    # creating less-than-clean output due to lack of alignment.
    #
    # While we're at it, we can drop the first 3 lines of the output to make
    # it even cleaner.
    diff -u "${dir:0:1}$((version_num - 1))/${file}" "${dir}/${file}" \
        | sed "s/\t/  /g" \
        | tail -n +4 \
        > "${dir}/${file}.diff"
  done
done

As you can see, all the version subdirectories are named v{number}, e.g., v1, v2, up to v10. The script processes the files runner.sh and Dockerfile from one version to the next, ignoring the v1 directory since there is nothing before it.

The primary delta computation is really the following:

diff -u "${dir:0:1}$((version_num - 1))/${file}" "${dir}/${file}" \
    > "${dir}/${file}.diff"

which computes the delta from v{number - 1} to v{number} and outputs it into the target directory of v{number}, with a .diff suffix for the filename.

Then, I would include the file into the blog post as follows:

{{%
  code
  file="/blog/2020/04/running-decade-old-games-in-containers/v4/runner.sh.diff"
  lang="diff"
%}}

Here, code is a custom Hugo shortcode, which I discussed in an earlier post.

To improve the readability and succinctness of the diff output, I added the other two filter lines you see in the script:

    | sed "s/\t/  /g" \
    | tail -n +4 \

As the comments in the script say, the sed command replaces tabs with 2-spaces for consistency with my personal indentation style being 2 spaces for code, particularly those used in that post.

Then, the tail command drops the standard header that you see in the diff output, which is quote verbose and would be repetitive if you had to see it 10 times in a single post.

Let’s consider a simple example:

$ echo 1 > foo
$ echo 2 > bar
$ diff -u foo bar > foo-bar.diff

If we include the above diff output as-is, we would get the following:

--- foo	2020-12-15 23:16:58.486504105 -0500
+++ bar	2020-12-15 23:16:58.486504105 -0500
@@ -1 +1 @@
-1
+2

However, if we preprocess the diff output with tail -n +4, we will get a much cleaner and simpler version:

-1
+2

which is the style of diffs that you see in my post.

Hope this was interesting and/or helpful! Let me know if you end up using this approach in your own writing.