Brioche Project Update - October 2024
Published on
By Kyle Lacy
Well, it’s been a busy couple of months! Since the last update in August, there have been two releases, some big changes in std
, and more!
Blog posts
If you hadn’t seen it yet, I published a post a couple of weeks ago called “Portable, dynamically linked packages on Linux”
It’s a pretty in-depth behind the scenes look at how packed executables work in Brioche. I wanted to make it general enough that folks interested in packaging or distributing software more generally for Linux get some value out of it— which is also why it’s pretty technical and long
Brioche releases
Brioche v0.1.2 was released last week, with Brioche v0.1.3 close behind. v0.1.3 was pretty small release with a few bugfixes (most notably a fix for an LSP regression from v0.1.2), but the real meat and potatoes were in v0.1.2.
The release notes cover everything that changed, and there’s a lot of exciting stuff! Especially the CLI changes that allow for running across multiple projects at once and the fix for the Brioche auto-updater (finally!) which will make future updates go more smoothly.
My favorite new features though are locked downloads and locked git refs.
Locked downloads
Up to this point, if you were adding a package in Brioche, you’d get something that looks like this package (dust). In the middle, you’d see something like this:
To download the source code to build a project, we need its hash. So, how do we even get the hash for a URL? Well, before v0.1.2, there were two ways:
- Copy the URL and paste it into a shell one-liner using
curl | sha256sum
, then copy the hash into the source code - Add an invalid hash, run the build, then copy the hash from the error message into the source code
In either case, manually copy/pasting hashes is busywork, which is the kind of thing we want to automate away. Which brings us to Brioche.download
! Here’s a snippet that’s roughly the same as before:
The “trick” is that, when you call brioche build
on this project, Brioche scans for all occurrences of Brioche.download
in the code, downloads each one, then saves each hash in the lockfile. This has all the same benefits as having the hash directly in the source code, except you don’t need to manually figure out the hash yourself (plus Brioche only downloads the URL once, instead of making Brioche download it a second time after you manually hashed it)
Since Brioche needs to scan the script to find all URLs, there are some limitations on how you can construct the URL. Namely, the URL needs to be hard-coded as a string literal, or as a template that uses the project metadata (like project.version
above). In the future, it should be possible to make this support a little more general, but the important thing is that Brioche needs to be able to figure out the URL statically.
Locked git refs
In the same vein, packages that clone from git used to need to reference the git hash directly in the source code.
If you squint, this is the exact same problem as with URL download hashes! So, Brioche can also apply the same trick: instead of referencing the git hash directly, you can call Brioche.gitRef({ repository, ref })
, and Brioche will record the commit hash the currently corresponds with that git ref in the lockfile, such as in this snippet:
Package updates
Since the last update, the only new package is terraform
(thanks @asheliahut!), but quite a few packages were also updated across the board (kudos to @jaudiger and @asheliahut!)
The rust
package was updated from v1.79 to v1.81, which did see a few packages break along the way. go
was also updated to support more complex module layouts, namely to unblock the terraform
package (under the hood, the go
package now properly grabs all the go.mod
and go.sum
files before trying to download dependencies).
std updates
A lot of work went into std
updates. The changelog has a full breakdown.
The std.glob()
, Brioche.download()
, and Brioche.gitRef()
functions were added to support new features from Brioche v0.1.2. The std.setEnv()
function had a breaking change that also enables support for more ways to set env vars (which also requires Brioche v0.1.2). Also, the new std.semverMatches()
function allows for testing semver constraints, which is used by std
itself to ensure you can’t accidentally use new features on older versions of Brioche
std.toolchain()
now sets a bunch of env vars that autotools use, so autotools builds should now work without needing to configure lots of env vars manually!
Also, both std.toolchain()
and std.tools()
are now “rewrapped”, which ensures the final built version of glibc is used internally by all the different binaries. Previously, if you saved std.toolchain()
as an output, you’d see that there were multiple different copies of glibc present in the output, due to different binaries being built at different stages and ending up with different versions of glibc! Rewrapping ensures everything is using a single copy of glibc for consistency (which also has the nice benefit that the output is now smaller too!)
Brioche core updates
Shortly after the v0.1.3 update, I fixed another LSP issue (#134). This one is certainly annoying as well, but I didn’t feel that it was critical enough to cut another release immediately.
I also added a new --locked
flag for the quartet of brioche build
, brioche run
, brioche check
and brioche install
(#133). Basically, it just ensures that the brioche.lock
lockfile is up-to-date. This is useful for CI/CD (and was also sorely needed for the brioche-packages
repo, especially now that downloads and git refs are being recorded in the lockfile)
Infrastructure updates
I’ve been doing my best running Brioche on a shoestring budget, and so far things have been going really well! Besides an outage due to an expired TLS cert, all of the infrastructure behind Brioche has been ticking along smoothly.
…well, with one exception. Builds are obviously super important for Brioche, and making it so updates to the brioche-packages
repo get built and published in a timely manner is a core part of the project!
That entire pipeline is handled with a pretty boring GitHub Actions workflow, which first validates all the packages, builds and syncs the recipes to the registry, then publishes the project files to the recipe. We use GitHub Action’s generous free runners where possible. But, for the actual slow, CPU-intensive builds, those get run on my and @asheliahut’s homelab.
In early September, I decided to upgrade the Linux kernel on the hypervisor, plus all of the OS packages. The upgrade appeared to go fine. It was not fine.
To cut a long story short, the server would crash after about 24 hours of uptime (and, very annoyingly, would bring down our entire home network as well). We fought for weeks to triage the issue, from using older kernel releases, to trying out different kernel flags, to swapping the NIC in the server (which at least made it so the server crashes wouldn’t bring down the network), to updating the BIOS. The last thing we did was disabling CPU C-states in the BIOS, and so far that seems to be holding strong
Coming soon
As with last time, here’s a short wishlist of things I hope to make progress on soon
- CMake and Python are still work in progress and haven’t been touched since the last update. These will be pretty high priority!
- There’s still some work to do before merging brioche-dev/brioche-packages#80, but that should unlock more NPM packages as well
Brioche.download()
andBrioche.gitRef()
make it so many package updates are as simple as bumping a version number inproject.bri
. The next logical step would be to support package auto-updates, where bumping the version number itself is automated- Still no forward progress on cross-platform support. The immediate next step is to set up Asahi Linux on our homelab Mac Mini, which will make it possible to start tinkering with ARM64 Linux builds