Spread The Words: Distributing a Man Page With Goreleaser And Homebrew
In the previous Spotlight, I discussed a few options for writing or generating a man page for a CLI app. That's fine for having one locally, but how to distribute this man page to your app's users?
If you plan to distribute your CLI tool via go install
, you can have your binary install the man page on demand:
- Use a
//go:embed
directive to embed the man page in the binary - Add a flag to the tool that copies the man page to
/usr/local/share/man/man1/
and ensures that the file mode is0644
.
A nobler way of distributing an app is through package managers. There is a plethora of them, but luckily, there is also
goreleaser
, a tool that builds releases of your CLI app and manages various package managers for you.
I wrote an
introduction to goreleaser
on my blog, and a
second part where I add Homebrew to my goreleaser
config. In these articles, I used the tool
goman
that I
wrote to fake man pages by grabbing the command's README instead. Now I am going to make goman
obsolete by telling everyone how to package real man pages alongside their tools! đ
I won't go through all the steps of the two goreleaser
articles again; please read the articles if you're new to either of goreleaser
, Homebrew, or goreleaser
’s Homebrew integration.
In a nutshell, the goreleaser
config I built in the second article creates a new Homebrew tap called appliedgo/tools
, so that Homebrew users can install goman
as brew install appliedgo/tools/goman
.
Adding a man page to the Hombrew formula
The goal for today is to modify the goreleaser
config file to build the man page and have Homebrew install the man page along with the binary.
This turned out to be surprisingly easy.
Step 1: Build the man page
I decided to write the man page for goman
in Markdown and have pandoc
turn this into a man page.
goreleaser
has a pre-build hook that I utilized for running pandoc
. The original pre-build hook looked like this:
before:
hooks:
- go mod tidy
- go mod download
The before.hooks
property runs commands before the build, and I use this to tidy the dependency file and download missing ones.
For generating the man page, I only had to add this line to the list in order to invoke pandoc
:
- pandoc -s -t man goman.1.md -o goman.1
Step 2: Add the generated man page to the archive files
goreleaser
builds binaries for several OS/architecture combinations (based on what I told it). In the archives.files
property, I tell goreleaser
which files to zip up with the binary for getting released on GitHub:
archives:
files:
- README.md
- LICENSE*
Here, I added the generated man page:
- goman.1
Step 3: Ask Homebrew to install the man page
Finally, Homebrew must know that there is a man page to install. Homebrew makes installing man pages dead easy by providing a man1.install
directive that I added to goreleaser
’s brews.extra_install
property. (The extra_install
property lets me add installation steps without overriding the whole installation procedure.)
brews:
- repository:
owner: appliedgo
name: homebrew-tools
# ...omitted for brevity...
extra_install: |
man1.install "goman.1"
(Fun fact: Homebrew formulas are Ruby code, and if you don't put the man page file in quotes, Ruby thinks goman.1
is a floating-point number and complains loudly.)
Wrapping all up
Now I only had to create a new Git tag, push the changes to the remote repo, and run goreleaser release
.
The goman.1
file is now included in all .gz
files of the release, and the Homebrew formula will install it to the appropriate man1
directory.
Now goman
behaves a bit more like a well-mannered Linux/macOS CLI tool. What's your next tool to equip with a man page?