It was not really an urgent need, but I thought it would be nice to get the git info for a given content .md
file, and put that into an HTML comment, inside the <head>
section. More or less for better troubleshooting. Here’s how to do it.
Rejected solution
There’s one method I tried, which I abandoned, because of dependency on OS environment variables. This is the bash script snippet for that, which creates a bunch of environment variables:
for f in /dev/path/to/content/post/.md; do export $(basename $f .md|tr - |tr -d 0-9|sed 's///')="$(git log --pretty="%h %s" -1 $f)"; done
It loops through the markdown files, gets the name, manipulates it, and puts that and the latest git info into an environment variable. I put the date in my filenames, because I want them to sort on that so I can find them. So this bash script needed to allow for my filename structure, and convert the filename into something that can be used as a variable. My intention was to use these in a template, using the getenv
function. It was a bit problematic to test, so, I decided to try a different tack.
Working Solution
Anyway, I gave up on the env vars, and switched to another method, the gist of which was to create a manifest in a yaml file in data, and use index against that to grab the latest info. It’s more portable anyway, assuming someone can do the below with some windows batch.
The following bash shell script needs to be run before hugo server is run, if you want the latest info. Therefore I imagine the best time to run it is right before you deploy.
This is the working script:
:\>| /dev/path/to/data/postgitinfo.yaml && for f in /dev/path/to/content/post/*.md; do echo "$(cat $f|grep slug|sed 's/slug: //'): $(git log --pretty="%h %s" -1 $f)" \>\> /dev/path/to/data/postgitinfo.yaml; done
Some points about it. It’s conveniently crammed all on one line.
- The
:\>|
is a relatively portable way (on *nix) to clear the content of a file, in this case the manifest yaml. Just pipe the:\>
to the file. - The next bit is a
for in do done
which loops through all your markdown files. It’s fiddly about placement of ;s. - The do clause uses
$()
because it’s safer to use than backticks (i.e.`somecmd`
). It just means execute what’s between the parentheses. - The do echoes a couple commands to the manifest with a colon between, so it is yaml format. Specifically, the echo has two sub commands: it cat’s the file to grep, grep looks for the line with slug in it, then sed removes the leading "slug: " from that. Then the git log command finds the latest sha (%h is the short form, %H is the long form) and subject of the commit message (i.e. the top line).
- All that is appended (each iteration of the loop) to the manifest.
The assumptions are:
- you’re using a system that speaks bash (this works on zsh as well)
- you’re using git, obviously
- your posts are files with
.md
extensions, which have yaml frontmatter. - yaml frontmatter has slug defined.
- slug is not defined twice (like in a code example or something)
When you run this it refreshes the yaml file. I’m going to put it in an alias.
Access the data from a template
Now that the manifest is created, you can access it from a template. I put mine in a partial I am calling from my head template.
{{ "<!-- ENTERING partial headend.html -->" | safeHTML }}
{{ $postgitinfo := (index $.Site.Data.postgitinfo .Slug ) }}
{{ (print "<!-- LATEST GIT UPDATE: " $postgitinfo " -->") | safeHTML }}
{{ "<!-- LEAVING partial headend.html -->" | safeHTML }}
A couple of points about this:
- the first and last lines are simply putting HTML comments at the beginning and the end of the partial. You don’t have to do this but I find it is helpful for troubleshooting, to see what content is coming from what template.
- Line two is using
index
to parse the yaml manifest (I just put it in the root of data). It’s using the same.Slug
that the batch script grabbed, so, it should match up. It sticks that in a variable. - Line three uses
print
to prepend and append the HTML comment start and end tags, around the variable created in the line before. Simple string concatenation.
Then when we look at the HTML source of the page, this information is in there, et voilà.
<!-- ENTERING partial headend.html -->
<!-- LATEST GIT UPDATE: de9911e Update post, correct typo, add images -->
<!-- LEAVING partial headend.html -->
It’s nifty, so I thought someone might like to try it. If you figure out how to do it on Windows or find any glitches, add that in the comments, by all means.