home Anil Madhavapeddy, Professor of Planetary Computing  

How to publish custom Homebrew taps for OCaml / Jan 2025

Now that I've switched to a new website, I'm working on open-sourcing its components. I've got a lot of small OCaml scripts that are all work-in-progress, and so not quite suitable to be published to the central opam-repository but I still need be able to run them conveniently on my own self-hosted infrastructure.

I mainly use a variety of macOS and Linux hosts[1] and I want a workflow as simple as "brew install avsm/ocaml/srcsetter" and have it install a working binary version of my CLI utility. In this case, it's srcsetter, a simple tool I knocked up to generate the responsive images on this website. Luckily, Homebrew has made this really easy for us! They have a BrewTestBot that integrates with GitHub Actions to automate the compilation of binary packages for us, all from a convenient PR-like workflow.

First, we need to set up a GitHub Homebrew "tap" repository. Mine is avsm/homebrew-ocaml which allows for the tap to be referred to as avsm/ocaml (Homebrew special-cases these to expand to the full GitHub repository). We then add in a couple of GitHub Actions to activate the testbot:

Secondly, we need to create a Homebrew package for the opam package. For this, I just added a very simple script to the srcsetter repository called .opambuild.sh which builds a local binary using a temporary opam installation. In the future, we should be able to use dune package management to remove the need for this script, but I'm blocked on some teething issues there in the short-term.

export OPAMROOT=`pwd`/_opamroot
export OPAMYES=1
export OPAMCONFIRMLEVEL=unsafe-yes
opam init -ny --disable-sandboxing
opam switch create . 
opam exec -- dune build --profile=release

Once this is present in the repository we're building, I just need to open a pull request with the Homebrew formula for my CLI tool.

class Srcsetter < Formula
  desc "Webp image generator for responsive HTML sites"
  homepage "https://github.com/avsm/srcsetter/"
  url "https://github.com/avsm/srcsetter.git", branch: "main"
  version "0.0.1"
  license "ISC"

  depends_on "gpatch"
  depends_on "opam"

  def install
    system "bash", "./.opambuild.sh"
    bin.install "_opam/bin/srcsetter"
  end
end

The formula is fairly self-explanatory: I just point Homebrew at the source repository, give it some descriptive metadata, and tell it to invoke the binary build script and make the sole resulting binary available as the contents of the package. At this point, the BrewBot will run against the PR and report any build failures on both macOS and Ubuntu. Most of these were swiftly fixed by running brew style (as instructed in the build failures) to take of fairly minor issues.

When the PR went green, all I then had to do was to add the pr-pull label, and the bot takes care of uploading the binary artefacts to my homebrew tap repo and merging the PR. It also takes care of adding checksums to the merged Formula, so what actually got merged is:

class Srcsetter < Formula
  desc "Webp image generator for responsive HTML sites"
  homepage "https://github.com/avsm/srcsetter/"
  url "https://github.com/avsm/srcsetter.git", branch: "main"
  version "0.0.1"
  license "ISC"

  bottle do
    root_url "https://github.com/avsm/homebrew-ocaml/releases/download/srcsetter-0.0.1"
    sha256 cellar: :any_skip_relocation, arm64_sequoia: "b3e1289965d8bcf086db06b18e6c2865f9949a9e1202b8fafa640f3e363b6bd4"
    sha256 cellar: :any_skip_relocation, ventura:       "9b61e8e4be5f777e3ef98672f275909a80c3cc3f82d6886ca1a90b66ea7bb9f8"
    sha256 cellar: :any_skip_relocation, x86_64_linux:  "d8279f11f30edf865368a3c6f63d811d31c1a9ca019ef86e93afeb6624232850"
  end

  depends_on "gpatch"
  depends_on "opam"

  def install
    system "bash", "./.opambuild.sh"
    bin.install "_opam/bin/srcsetter"
  end
end

The end result is that brew install avsm/ocaml/srcsetter now works, without me having to cut a release of the tool more centrally. I'd love to incorporate some aspects of this workflow into the OCaml opam-repository, as users are currently responsible for the checksumming generation themselves via dune-release or opam-publish. It's an interesting twist to automate this part of the process and let the humans focus on the core package metadata instead. Thanks for all the help, Brewbot!

  1. Let's leave OpenBSD support to another day!

    ↩︎︎
# 31st Jan 2025   iconnotes bushel homebrew ocaml packaging testing til

Related News