Your Workstation Sucks
No, seriously, it does. Worse, it’s your fault. You can’t name half the apps that you have installed through
apt-get, homebrew, port, whatever.
If it was dropped in a vat of alien-larva-that-consume-electronics-and-also-souls right now, could you restore it tomorrow? In a week? Do you even know?
You preach repeatability and automation. You spend time configuring vagrant/docker for your projects. You don’t treat your workstations with the same care.
The usual suspects — Chef, Puppet, et. al. — are too complicated. They focus on managing thousands of servers, huge developer ecosystems, dozens of incompatible versions. Besides: they’re far too popular to be cool anymore.
This article will walk through configuring a workstation with Babushka. It will take about 20 minutes from start to finish.
Before starting anything, Babushka has to be installed.
Create a project.
Babushka projects define an acyclic dependency graph.
For example, I might require that the
zsh is installed, which would itself require
homebrew, gcc, and autoconf. When I ask Babushka to meet the zsh dependency, it would ensure that all of its dependencies are also met.
Dependencies are defined using a simple DSL, and are read from any ruby file.
The easiest dependencies to describe are all the apps under package management that are currently installed. If you’re on OSX and already using homebrew, you can see all of your installed apps by running brew list:
Babushka knows how to install apps using whatever package manager a platform provides, so the dependencies are simple. Create a file for all of these packaged apps and call it
apps.rb. Inside define a dependency for packaged apps. The app dependency name must end in
Now, ask Babushka to meet the
all-packaged-apps dependency, and view the output. If the dependency was met successfully, the dependency will be green, otherwise it will be red with an error message of some sort.
(Babushka looks for dependency definitions in several places, including in the directory
OS X Apps
Not all apps are packaged apps. Specifically Chromium, Firefox, Alfred, iTerm2, etc. are distributed as
.dmg files. Babushka knows how to install these too.
Create a file called
osx.rb where all of the dependencies specific to Mac OS X will go.
There’s some magic going on here.
First: The dependency must be named the same at the app that it provides. The iTerm.app dependency will only be met if an application called ‘iTerm.app’ exists in
Second: If ‘iTerm.app’ doesn’t exist, then the source URL must link to a zip file that contains an application bundle by that name, a
.dmg disk image that contains a bundle by that name, or a
.pkg installer that install a bundle by that name.
Make sure it’s working by running babushka.
OS X Settings
Aside from apps, there are system settings: Dock magnification, full disk encryption, keyboard shortcuts, etc.
osx.rb dependencies can be defined for these settings. On OS X these settings are stored in plists and can be read or written using the
Because Babushka doesn’t know how to “move the dock to the right”, it has to be manually implemented. Each dependency has two methods met? and meet.
met? is evaluated for truthiness (
truthy meaning “this dependency is already met” and
falsey meaning “this dependency is not yet met”). It is run every time a dependency is required.
meet is what performs the action to install a dependency if the dependency isn’t already
met?. Let’s look at the case of auto hiding the dock.
For example: If the dock is already set to hidden — i.e. the shell command
defaults read com.apple.dock autohide returns 0 and outputs the value “1” to stdout — then the dependency is already met. If it’s not already hidden, then write setting and restart the dock.
meet blocks should be idempotent by convention. Care should be taken so that running Babushka multiple times doesn’t have unintended side effects.
And of course, the results can be seen again by running the settings dependency.
(There’re a lot of OS X settings that can be set through the defaults command. A good resource for discovering them is secrets.blacktree.com)
Bringing it All Together
At this point the project has several different dependencies that describe various aspects of a workstation (settings, packaged apps, and GUI apps) that each can be run independently.
To ease configuration, create a root dependency for every machine that you want to manage with Babushka. A simple informal convention is to name this dependency the same as the hostname of the machine. For example, if a machine is named
cape-town, create a file called
cape_town.rb and add a single dependency.
Configuring the machine is now as simple as:
$ babushka cape-town
When there are multiple workstations, simple add another hostname dependency. Another machine might share many of the same dependencies, but look like:
Pretty neat! There’s now a repo that describes a set of common workstation dependencies, and it can be run on any current install to bring it up-to-date.
But… after re-installing OS X where will Babushka find the dependency project? And where will it get base dependencies like
gcc without manual effort to install them.
Babushka integrates with GitHub so configuring a machine after a fresh install is as easy as creating a repo on any GitHub account called
babushka-deps and pushing changes there.
For example, if the GitHub user samfoo has a
babushka-deps project, running
babushka samfoo:cape-town will clone samfoo’s project to
~/.babushka/sources/samfoo and try to meet the
cape-town dependency (which configures everything) therein.
Managing a workstation with Babushka is simple after understanding the conventions. Chef Solo and Puppet (and, of course others) can used for managing personal machine configurations, but are too unwieldy for simple tasks and require lots more configuration and domain knowledge.
Because Babushka is so simple, there’s no reason why a team couldn’t publish a
babushka-deps repo to their GitHub account that contains all the dependencies necessary for getting new devs up and running. For example, it could install vagrant and clone the project repo. Getting new developers setup is limited, then, only by download speed.