January 28, 2025

Past Sunday

This past Sunday I played music for the brunch at the Coach Grill in Wayland (joined by my friend Dave who played cajon). It was an early enough start (with the drive) that I didn't have time to do an update. I'll be looking to capture more music information over time particularly in a way that it can be readily extracted from the other content on this site (and allow for things like communicating upcoming shows rather than those that have already passed.

Build Extraction

The build logic from the 25th now needs to be adjusted to incorporate the filter from yesterday. I'll therefore pull that logic into generate.mk.

Directory Creation

One of the additional challenges is that the deeper directory source structure will require a mirrored structure in the destination - this will be supported by (potentially unnecessarily) making directories in the recipe bodies.

Filter Use

The filter has been added as an option - at the moment it will need to be moved into the desired place, but this will be cleaned up as part of orchestrating tangling.

File Definitions

The files to generate must also be captured in this file now, so that has been added.

Update the Flow

In the current form the generation (but not tangling) can be automated through make, and so a next step would be looking to get this working within the CI workflow (should be straightforward given a suitable base image is available).

I'll start with making sure everything is working end-to-end locally which will involve pulling in some of the logic previously defined in site.mk to orchestrate tarball creation and hut invocation (and connecting some edges in the build DAG). For now I'll add that to generate.mk though I'll likely split up that file a bit down the road (or just rename it to Makefile).

Updating the CI build should be straightforward which I'll circle back to tomorrow.

Next Steps

In additon to wiring the CI and removing generated files from the repository, now that some of the basics are in place I'll be starting to clean up some of the existing content. I'll also look at orchestrating tangling and probably also digging into babel a bit more given that there were some gaps I recently stumbled into in my current knowledge (some details I think I used to have approaches for but have since forgotten).

I will also look at adding some style to this site which I've been neglecting for several years now.

Noodling with AsyncAPI JavaScript Generation

I've been spending a bit of time working with the AsyncAPI generator - and have worked through a couple hurdles that seem worth recording.

Operation Messages

One quick note that I'll look to file as an issue somewhere, is that the AsyncAPI spec clearly states that messages for operations should be those that are defined for the channel and not those from the shared components, but the vast majority of the examples seem to reference those from components that cause issues. The one workable example I found (which references the messages under the channel) came from the Adding Messages page.

CommonJS and ESM for Hooks

While I've spent a fair amount of time writing JavaScript I've never brought myself to care enough to get a firm handle on some of the quirks around CommonJS modules and ESM (and was not in the space at the time when that switch was happening). When working with AsyncAPI this is significant given that the hooks seem to rely on CommonJS (presumably to be closer to NodeJS) whereas the rest of the code prefers ESM. In my case I was looking to share code across the two and also had some issues when trying to use an ESM style import, but just using require in both cases worked out.

Poor Feedback

A fairly common experience I have with JavaScript projects is starting to feel pleased with how smoothly things are going only to have that thoroughly derail by some arcane behavior or error. I mostly need to remember that this happens and have my go-to approach ready which in the case of NodeJS is to make sure I have the relevant code downloaded into a node_modules directory where I can modify it a bit in place to get better feedback. In this particular an error was getting rethrown as a GeneratorError but only the message and not the stack trace was forwarded which led to an error I was fairly sure I understood but no idea where it was happening. In this case it was related to some of the automatic hook loading behavior and a rogue file that shouldn't have been there.

This type of issue is certainly not unique to JavaScript though it feels more common than in some other languages - maybe due some combination of the proliferation of libraries, the expressiveness of the language, and some cultural aspects (all of which may grease wheels in ways that may slip more than in other places).

Updated CI Flow

Given that I have a small pocket of time, I'll see if I can quickly get the CI for this site working with the new logic. Optimistically the job definition lists packages, so I could see about just adding pandoc to that list and make use of the new build file.

image: alpine/edge
oauth: pages.sr.ht/PAGES:RW
packages:
- cabal
- hut
environment:
  site: mwhipple.srht.site
tasks:
- pandoc_install: cabal update && cabal install pandoc
- publish: make --file=generate.mk --directory=$site publish

Missing Bibliography File

I somewhat foolishly neglected to include my bibilography, so I'll pull that in using an updated make directive which will be expected to be run locally (I'll attach it to another task at some point).

Missing runhaskell

Thankfully pandoc worked after adding it to the package list, but the haskell filter also requires the runhaskell script so I'll try adding the haskell package (which hopefully exists in a usable form and provides that utility).

Replace with ghc

"Haskell" would theoretically be some kind of meta-package where the reference implmenetation is the Glasgow Haskell Compiler (ghc), so I'll try that instead.

Try Installing Pandoc

ghc exposes runhaskell - but since pandoc is installed a cli utility it doesn't include the library files needed to support my filter. At this point lua would certainly have been easier…but I'll install cabal and use that to install pandoc rather than using the package.

Updated the command to update cabal's repositories first.

Swapping Base Image

I should likely use a different image that includes the files. This would be a good idea for reasons of reproducibility and efficiency, and so far the cabal installation also seems to take a fair amount of time. The above route offers a good way to get it working quickly, but this should be cleaned up soon.

Like Now

I'll try just using a pandoc base image using a docker hub friendly path.

image: pandoc/core
oauth: pages.sr.ht/PAGES:RW
packages:
- hut
environment:
  site: mwhipple.srht.site
tasks:
- publish: make --file=generate.mk --directory=$site publish

Unfortunately that did not find an image, and I've now navigated my way over to the relevant builds.sr.ht docs. I'll try out NixOS since that project appeals to me.

image: nixos/24.11
oauth: pages.sr.ht/PAGES:RW
packages:
- hut
- pandoc
environment:
  site: mwhipple.srht.site
tasks:
- publish: make --file=generate.mk --directory=$site publish

With that file, the hut package could not be found.

image: nixos/24.11
oauth: pages.sr.ht/PAGES:RW
packages:
- nixos.haskellPackages.pandoc-cli
- nixos.haskellPackages.pandoc-types
- nixos.hut
- nixos.ghc
- nixos.gnumake
environment:
  site: mwhipple.srht.site
tasks:
- publish: make --file=generate.mk --directory=$site publish

I have no practical experience with NixOS (and virtually none with nix) but combining the docs from SourceHut and the NixOS search leads me to try to qualify the packages.

As would be expected with nix, I also need to explicitly declare make (gnumake) per NixOS search.

Look kids, Big Ben, Parliament: ghc is also added again And…back to pandoc missing as a library. I'll now add the haskellPackages.pandoc package. I somewhat expected this but figured it would at least be a fun experiment to work through with NixOS. I also tend to find the options in alpine a bit limited when looking for finer grained control over things like library packages and alternatives seemed more promising in this regard.

There is a pandoc-types package which seems particularly promising.

Ultimately one of the main reasons I'd want to use nix is to avoid these types of issues by being able to configure a controlled local environment that is readily reproducible elsewhere…I guess this is a signal I should be doing that now.

Starting with Nix.

I tried to start with a nix a few months ago but got sidetracked - I think due to low disk space which I've since resolved.

I've tried installing it again using the multir-use instructions from the Web site, but without further help the expected commands aren't found.

The installer has added some content to /etc/bashrc - where that content is duplicated in my file likely residue from the previous attempt.

if [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then
  . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'
fi

It's likely I don't have that file sourced while my shell is loading, but after sourcing it I seem to have nix-daemon found on my PATH.

nix-daemon is indicating the socket is unavailable, but nix-shell isn't working - so I'll try just removing the socket file for now.

Given that I'm not using systemd I'll need to configure the daemon. For now launching it as root in a background process seems to work.

Nix Motivation

For many years I've been a proponent of self-contained projects. There is a common unfortunate pattern of having project configurations defined in terms of some kind of presumed configuration of the host environment. This amounts to the project prerequisites being split across what is defined in the source code and some expected host settings. In the best case this often leads to difficult to parse errors when something isn't done quite right which often translates to tribal feedback around some wrong version being in play and a missing incantation.

Such issues tend to cause more severe issues over time as different projects may have different such expectations, or preferred host provided tools may shift over time, or just gradual shifts in how hosts are configured have introduced conflicts with some subset of expectations. Often these seem to reflect a snapshot of assumptions that become invalidated such that they may offer net negative impact in the long term as information needs to reconstructed and expertise resurrected.

This could fairly easily be reduced to poor contract enforcement and lack of appropriate defensive practices - though more likely neglected given that it sits outside of the tools you may normally use to pursue such robustness.

To be clear: it may not be worthwhile to always satisfy all such conditions, but verification and better feedback can typically be provided by basic tools (such as make) and can quickly deliver value.

The nix model (and shared with some other tools) enables all such requirements to be defined within the source code and therefore avoids such issues.

Working Through CI Issues

Right in-line with some of the proposed value of nix, I'm encountering the same issue as the CI build for my site in terms of resolving pandoc types - though that is when I've entered a shell with pandoc. I likely need to find an invocation that also ignores any other host provided dependencies.

A command of the form:

nix-shell --packages haskellPackages.pandoc-types --run 'make --file generate.mk publish' --pure

seems likely to provide an appropriate level of reproducibility to work through my issue.