bork
I originally created bork in 2012 out of, well, despair. I was going through some rough times at work and was frustrated with setting up a new personal computer, and people were asking me why don’t you try out chef or puppet to automate setting up your laptop , and upon looking into it, it seemed overly complex, required computational resources outside of the computer, and was vendor-specific. I wondered, why can’t I just use bash for this? It’s already everywhere I thought of the infamous Sweedish Chef puppet and so began a journey.
What would a declarative domain-specific language for config management meant to sit atop bash? Let’s say I wanted to ensure a few things existed:
ok brew # presence and updatedness of Homebrew
ok brew git # presence and updatedness of Homebrew git package
ok directory $HOME/code # presence of the ~/code directory
ok github $HOME/code/dotfiles mattly/dotfiles # presence, drift of git repository in ~/code/dotfiles
cd $HOME
for file in $HOME/code/dotfiles/configs/.[!.]*
do # for each file in ~/code/dotfiles/configs,
ok symlink "$(basename $file)" $file # presense of a symlink to file in ~ with a leading dot
done
Like a lot of things I create these days, it started with the shape of what I wanted. I needed a command to assert something and landed on ok. Then I needed nouns about which to make assertions:
-
brewis the presence of homebrew and things installed via it -
directoryis just that -
githubis shorthand forgitwith the domain name pre-filled -
symlinkasserts that a link exists and points to a different file
Ideally, I’d be able to run commands to validate or enforce these assertions:
$ bork status mysetup.sh
outdated: brew
ok: brew git
missing: brew fish
ok: directory ~/code/mattly
conflict (upgradable): github mattly/dotfiles
- local git repository has uncommitted changes
ok: symlink ~/.gitignore ~/code/mattly/dotfiles/configs/gitignore
conflict (clobber required): symlink ~/.lein ~/code/mattly/dotfiles/configs/lein
- not a symlink: ~/.lein
$ bork satisfy mysetup.sh
The weird thing was, I got it working. It wasn’t painful. I had to think about some things like status codes and what they would mean semantically:
$STATUS_OK) echo "ok" ;;
$STATUS_FAILED) echo "failed" ;;
$STATUS_MISSING) echo "missing" ;;
$STATUS_OUTDATED) echo "outdated" ;;
$STATUS_PARTIAL) echo "partial" ;;
$STATUS_MISMATCH_UPGRADE) echo "mismatch (upgradable)" ;;
$STATUS_MISMATCH_CLOBBER) echo "mismatch (clobber required)" ;;
$STATUS_CONFLICT_UPGRADE) echo "conflict (upgradable)" ;;
$STATUS_CONFLICT_CLOBBER) echo "conflict (clobber required)" ;;
$STATUS_CONFLICT_HALT) echo "conflict (unresolvable)" ;;
$STATUS_BAD_ARGUMENT) echo "error (bad arguments)" ;;
$STATUS_FAILED_ARGUMENTS) echo "error (failed arguments)" ;;
$STATUS_FAILED_ARGUMENT_PRECONDITION) echo "error (failed argument precondition)" ;;
$STATUS_FAILED_PRECONDITION) echo "error (failed precondition)" ;;
$STATUS_UNSUPPORTED_PLATFORM) echo "error (unsupported platform)" ;;
*) echo "unknown status: $1" ;;
And I added a feature which would compile your specific configuration script to a standalone bash script, so you could run it without bork already installed:
$ bork compile mysetup.sh > mysetup_standalone.sh
But the biggest challenge was getting people to understand what it was and why they might want it. A colleague at the time told me I should try making a business out of it, but I was struggling to simply get people to get it, the sheer simplicity of it, and how it didn’t require a truckload of infrastructure to make work.
When terraform came around a few years later, I figured that simplicity was the problem; I could have tried to add stuff to manage networked resources, but by that time I was enamored with other things and was happy to keep bork as my personal side project, meant to work with the local machine only.
Eventually I burnt out on the project – I’ve struggled with depression for most of my life, I was in yet another difficult spot at work, and my partner and I had just become parents. I couldn’t bring myself to care anymore, so I archived the project. A few years alter, Skylar MacDonald reached out to ask if she could take over the homebrew formulae for her fork and I agreed. She’s been adding new things, a code of conduct and even created a website, and I’m happy that the project still has life beyond me.
The biggest thing I learned from this project, and why I moved on, is that I think there’s a fundamental disconnect between declarative setups – I want it to look like this – and the imperative setups we use to actually work with computers – To get it to look like this, first I have to do that and then I have to do this other thing, and that abstraction mismatch, like most abstraction mismatches, shows the seams over time. Experience at employers with other declarative tools like terraform simply reiterated this for me, and, well, thankfully I don’t have to manage networked resources anymore. But it put me off of declarative setups entirely because that mismatch makes them hard.
These days, I get people asking me why I’m not using nix and I don’t really know how to reply to that. I sigh and wave my hands, point to its reputation, and state I have better things to do. I don’t need my computer’s setup to become a hobby again.