How to Distribute Your Program via Homebrew
I recently packaged a program I wrote called notes for distribution via Homebrew
, following this excellent tutorial.
To make your package installable via Homebrew, you put it in a GitHub repo and create a release. Then you create a tap, a repo containing at least one formula. The formula is a Ruby file pointing to a downloadable tarball of the package, with instructions on how to build and install it.
When a user downloads your package, the tarball is saved to /Library/Caches/Homebrew
. It gets unzipped and, depending on the formula, parts of the package are copied to /usr/local/Cellar/<pkg>/<version>
. This directory, in the user’s cellar, is called a keg.
To make writing formulae easier, you can use variables for directory locations. For example, bin.install foo
will create /usr/local/Cellar/<pkg>/<version>/bin/foo
, use chmod
to make sure foo is executable, and create a symlink from /usr/local/bin/foo
to foo in the cellar.
They say the right example is worth 1000 lines of documentation. Enough beating around the bush — here is notes’ directory tree, courtesy of tree:
.
├── LICENSE
├── README.md
├── _completions
│ ├── c.bash
│ ├── c.zsh
│ └── init.sh
├── _config
│ └── env.sh
├── _helpers
│ └── helpers.sh
└── bin
└── notes
And here’s the formula for installing notes, i.e. building the notes keg:
class Notes < Formula
desc "..."
homepage "https://github.com/kylebebak/notes"
url "https://github.com/kylebebak/notes/archive/1.0.0.tarball.gz"
version "1.0.0"
sha256 "e17405adc655824dec3ca6e2a9a4b199a715743ed5f0948df58f6bb369267aa3"
def install
bin.install "bin/notes"
prefix.install Dir["_completions"]
prefix.install Dir["_helpers"]
prefix.install Dir["_config"]
end
end
This install
method creates a keg with the same directory tree as the one in source code, while ignoring metadata like README.md
and LICENSE
, and tests or CI scripts, if I had any. The prefix.install
method copies the directories into the cellar without polluting the executable namespace under /usr/local/bin
. The only symlink created by this formula is /usr/local/bin/notes
.
Once you have your tarball release and your tap on GitHub, users can install your program with two shell commands:
brew tap kylebebak/notes
brew install notes
Tab completion is crucial to notes’ usability. Enabling it was the trickiest part of writing notes; I explain how in this post.