1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
# Homebrew
`slosh.rb` is a **formula**, which is the right kind of thing. The distinction,
since it is the first question anyone asks:
| | what it is for | what it does |
|---|---|---|
| **formula** | command-line software | brew builds it (or fetches a prebuilt "bottle") into `Cellar/` and symlinks `bin/` |
| **cask** | prebuilt macOS apps: `.app`, `.dmg`, `.pkg` | brew unpacks the drop into `/Applications`, builds nothing |
slosh is a binary you run in a terminal and it builds from source in under a
minute, so: formula. A cask would be the answer only if we shipped the signed,
notarized zip that `Makefile.macos` produces and wanted brew to just drop it in
place.
## The tap
A formula has to live in a *tap* — a git repo named `homebrew-<tapname>` full
of `Formula/*.rb`. Ours is `homebrew-slosh`, so users say:
```bash
brew tap sl0p-foo/slosh
brew install slosh
```
The tap lives at `github.com/sl0p-foo/homebrew-slosh`, which brew resolves
from the short name on its own. `brew install --HEAD slosh` builds the tip of
master instead of the pinned release.
(Getting into `homebrew-core` — plain `brew install slosh`, no tap — has a
higher bar: a stable tagged release, a LICENSE, notable usage, and no
network access during the build. See "known rough edges" below.)
## Why source and not the signed binary
The obvious thought, once there is a mac builder producing a signed, notarized
zip, is to point brew at that zip instead. Three reasons not to:
- **Notarization buys nothing here.** Gatekeeper only checks binaries carrying
the `com.apple.quarantine` attribute, and the curl that fetches a formula's
tarball does not set it. (Casks are different: they manage quarantine
deliberately.) Every bottle in homebrew-core is unsigned-but-for-ad-hoc and
runs fine. The notarized zip matters for the *web* download, where the
browser does set the attribute — not for `brew install`.
- **The build is a minute and needs one thing.** zig. Formulae that take ten
minutes and drag in twenty dependencies are the ones that need binaries.
- **Source is the only path that covers Linux**, which brew also runs on.
If the build time ever does become the complaint, the answer is **bottles**,
not a cask and not a hand-rolled binary url. A bottle is Homebrew's own binary
format: a tarball of the installed keg, listed in a `bottle do` block with a
`root_url` pointing at wherever we host them. It is *additive* — the formula
keeps its source path, and anyone whose macOS version we have not bottled
falls back to building. The cost is a matrix: bottles are tagged per macOS
version *and* arch (`arm64_sequoia`, `arm64_sonoma`, ...), each one built on
that version. With one builder mac that means one tag covered and everyone
else compiling — which is most of the work for a fraction of the benefit,
until there are more builders.
## Releasing
`slosh.rb` here is the source of truth; the tap repo gets a copy.
**This needs no mac and no brew.** `brew-release` resolves a ref, downloads the
snapshot and hashes it, so cutting a release works from the Linux box — which
is the point, because that is where releases are cut. Signed macOS binaries are
a separate pipeline (`make macos-dist`) that brew is not involved in.
```bash
git fetch origin && git push origin v0.2.0 # brew-release pins what
# the server can serve
contrib/brew-release --tap ../homebrew-slosh # pin origin/master
contrib/brew-release --tap ../homebrew-slosh v0.2.0 # pin a pushed tag
```
Then, on a machine that has brew (either OS), prove it before pushing the tap:
```bash
brew install --build-from-source contrib/homebrew/slosh.rb
brew test slosh
```
The script resolves the ref to a full commit id, downloads the cgit snapshot,
hashes it, and rewrites `url` / `version` / `sha256`. Untagged pins are
versioned `0.1.0-<commits>-<short>` so brew can tell which build is newer;
a tag is used verbatim.
Before pushing a formula change:
```bash
brew style sl0p/slosh
brew audit --strict --tap=sl0p/slosh
```
## Known rough edges
- **The build fetches.** `zig build` downloads the pinned libghostty-vt
dependencies from `deps.files.ghostty.org` during `make vendor`. Homebrew's
sandbox allows this (verified), but homebrew-core forbids it — that would
need the zig packages vendored into the tarball or declared as `resource`s.
- **No LICENSE.** The formula therefore has no `license` stanza. Taps do not
care; homebrew-core would refuse.
- **Snapshot tarballs.** GitHub generates `/archive/<sha>.tar.gz` on demand;
the bytes are stable per ref (and after the Jan 2023 compression incident
GitHub committed to keeping them so), which is what the `sha256` relies on.
If that ever changes, switch the formula to
`url "https://github.com/sl0p-foo/slosh.git", using: :git, revision: "<sha>"`,
which is content-addressed and needs no hash.
|