It's easier than you think to make a software package installable via Homebrew. If you depend on a very specific version of a software package (say, Postgres 9.5.3 with readline support), I highly recommend creating a Homebrew repository and publishing recipes to it. Then your team can install and update packages as easily as:
brew tap mycompany/packages brew install mycompany/packages/postgresql
You can use the existing formulas as a jumping off point, and modify as you see fit. (Obviously this won't work for Linux folks on your team, however in my experience people running Linux in a Mac software shop have more experience building dependencies on their own).
Anyway, I wanted to describe how to install Go binaries via Homebrew. One way to do this is to compile binaries, upload them to Github releases, and install from there. However, the Homebrew core team requires that packages are buildable from the source code. (This helps check that a binary wasn't tampered with, and avoids compatibility problems with e.g. 32 bit and 64 bit systems).
If you vendor dependencies, and check in the vendor
folder to Github,
installation is super easy.
# Classname should match the name of the installed package. class Hostsfile < Formula desc "CLI for manipulating /etc/hosts files" homepage "https://github.com/kevinburke/hostsfile" # Source code archive. Each tagged release will have one url "https://github.com/kevinburke/hostsfile/archive/1.2.tar.gz" sha256 "cc1f3c1cb505536044cbe01f44ad7da997e6a3928fac1f64590ef69d73da8acd" head "https://github.com/kevinburke/hostsfile" depends_on "go" => :build def install ENV["GOPATH"] = buildpath bin_path = buildpath/"src/github.com/kevinburke/hostsfile" # Copy all files from their current location (GOPATH root) # to $GOPATH/src/github.com/kevinburke/hostsfile bin_path.install Dir["*"] cd bin_path do # Install the compiled binary into Homebrew's `bin` - a pre-existing # global variable system "go", "build", "-o", bin/"hostsfile", "." end end # Homebrew requires tests. test do # "2>&1" redirects standard error to stdout. The "2" at the end means "the # exit code should be 2". assert_match "hostsfile version 1.2", shell_output("#{bin}/hostsfile version 2>&1", 2) end end
Basically, download some source code, move it to $GOPATH/src/path/to/binary
,
build it, and put the compiled binary in $(brew --prefix)/bin
.
If you don't vendor dependencies, the story gets a little more complicated
because you need to download a version of all of your dependencies. Say for
example I had one dependency in my project, I would add a go_resource
line for
each dependency, and then call stage_deps
to download/install all of them in
the correct places.
require "language/go" # Classname should match the name of the installed package. class Hostsfile < Formula desc "CLI for manipulating /etc/hosts files" homepage "https://github.com/kevinburke/hostsfile" # Source code archive. Each tagged release will have one url "https://github.com/kevinburke/hostsfile/archive/1.2.tar.gz" sha256 "cc1f3c1cb505536044cbe01f44ad7da997e6a3928fac1f64590ef69d73da8acd" head "https://github.com/kevinburke/hostsfile" go_resource "github.com/mattn/go-colorable" do url "https://github.com/mattn/go-colorable.git", :revision => "40e4aedc8fabf8c23e040057540867186712faa5" end depends_on "go" => :build def install ENV["GOPATH"] = buildpath bin_path = buildpath/"src/github.com/kevinburke/hostsfile" # Copy all files from their current location (GOPATH root) # to $GOPATH/src/github.com/kevinburke/hostsfile bin_path.install Dir["*"] # Stage dependencies. This requires the "require language/go" line above Language::Go.stage_deps resources, buildpath/"src" cd bin_path do # Install the compiled binary into Homebrew's `bin` - a pre-existing # global variable system "go", "build", "-o", bin/"hostsfile", "." end end # Homebrew requires tests. test do # "2>&1" redirects standard error to stdout. The "2" at the end means "the # exit code should be 2". assert_match "hostsfile version 1.2", shell_output("#{bin}/hostsfile version 2>&1", 2) end end
And that's it! You can test your new package by creating a symlink from
/usr/local/Homebrew/Library/Taps/homebrew
to wherever you keep your
homebrew-core
checkout:
ln -s ~/code/homebrew-core /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core
Then you can just use brew install
commands and they'll work just as you
expect.
Liked what you read? I am available for hire.
Just wanted to let you know I just used this to build my first homebrew formula. Thanks for the great guide, it made it a lot easier.