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.