build(homebrew): add Homebrew tap formula and publishing notes
This commit is contained in:
1 parent
cbcdfae8bf
commit
1f686ce7ba
2 files changed
+171
No files matched your search
@@ -0,0 +1,51 @@
|
||||
class BeefyPlayer < Formula
|
||||
include Language::Python::Virtualenv
|
||||
|
||||
desc "Terminal player for internet radio with a live spectrum analyser"
|
||||
homepage "https://tildeforge.dev/beefcarver/beefy-player"
|
||||
url "https://tildeforge.dev/beefcarver/beefy-player/releases/download/v1.2.2/beefy-player-1.2.2.tar.gz"
|
||||
sha256 "0000000000000000000000000000000000000000000000000000000000000000" # TODO: release asset
|
||||
license "WTFPL"
|
||||
head "https://tildeforge.dev/beefcarver/beefy-player.git", branch: "main"
|
||||
|
||||
depends_on "[email protected]"
|
||||
|
||||
# numpy and pillow are large native builds. Depending on Homebrew's own
|
||||
# formulae (which have bottles) keeps them out of the app's virtualenv build;
|
||||
# the venv sees them through system site-packages.
|
||||
depends_on "numpy"
|
||||
depends_on "pillow"
|
||||
|
||||
# Runtime tools the app shells out to: mpv for audio, ffmpeg for the stream
|
||||
# decode fallback of the spectrum analyser. Both are optional at runtime --
|
||||
# the UI degrades gracefully -- but a radio player without them is not much fun.
|
||||
depends_on "ffmpeg"
|
||||
depends_on "mpv"
|
||||
|
||||
# Tells `brew update-python-resources` what to resolve: numpy/pillow come from
|
||||
# the formulae above, and dbus-next is marker-gated to Linux upstream so it
|
||||
# has to be requested explicitly for the Linux side of the tap.
|
||||
pypi_packages exclude_packages: "numpy,pillow", extra_packages: "dbus-next"
|
||||
|
||||
def install
|
||||
# system_site_packages is the default, so the excluded numpy/pillow from the
|
||||
# formulae are importable from the virtualenv.
|
||||
virtualenv_install_with_resources
|
||||
end
|
||||
|
||||
def caveats
|
||||
<<~EOS
|
||||
The spectrum analyser follows what you hear. On macOS 14.2+ grant your
|
||||
terminal permission under System Settings > Privacy & Security > System
|
||||
Audio Recording, otherwise it falls back to decoding the stream.
|
||||
|
||||
Inside tmux, install `tmux` for image passthrough.
|
||||
EOS
|
||||
end
|
||||
|
||||
test do
|
||||
assert_match version.to_s, shell_output("#{bin}/beefy-player --version")
|
||||
# --offline keeps the test hermetic: cached or bundled stations only.
|
||||
assert_match(/^# /, shell_output("#{bin}/beefy-player --offline --list"))
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,120 @@
|
||||
# Homebrew packaging for beefy-player
|
||||
|
||||
A Homebrew **tap** is just a second git repository that Homebrew clones next to
|
||||
homebrew/core. There is no central submission, no review and no binary host:
|
||||
`brew` reads the Ruby formula from the tap, downloads the pinned source tarball
|
||||
and installs it on the user's machine.
|
||||
|
||||
This directory is the staging area for the tap repository, which lives at
|
||||
**https://tildeforge.dev/beefcarver/homebrew-tap** (repo name `homebrew-tap`, so
|
||||
the tap name is `beefcarver/tap`).
|
||||
|
||||
Because Homebrew's one-argument `brew tap` assumes GitHub, a Forgejo tap has to
|
||||
be tapped with its URL, and Homebrew 6+ also wants an explicit trust.
|
||||
|
||||
## Install (user side)
|
||||
|
||||
```bash
|
||||
brew tap beefcarver/tap https://tildeforge.dev/beefcarver/homebrew-tap
|
||||
brew trust --formula beefcarver/tap/beefy-player
|
||||
brew install beefcarver/tap/beefy-player
|
||||
```
|
||||
|
||||
`brew update` refreshes the tap from then on; `brew upgrade` picks up new
|
||||
versions like any core formula. If the tap is mirrored to GitHub later,
|
||||
`brew install beefcarver/tap/beefy-player` becomes a one-liner, because that
|
||||
form auto-taps from GitHub and trusts only the formula it installs.
|
||||
|
||||
## Publishing the tap (maintainer side)
|
||||
|
||||
### 1. One tag per release, with a release asset
|
||||
|
||||
The formula pins a stable URL plus a SHA-256, so it needs an immutable tarball.
|
||||
Do **not** point it at Forgejo's `/archive/v$VERSION.tar.gz` URL: those archives
|
||||
are generated on demand and are not guaranteed byte-stable. Attach a tarball to
|
||||
the release instead (Forgejo serves it at `/releases/download/<tag>/<file>`):
|
||||
|
||||
```bash
|
||||
VERSION=$(uv run python -c 'import beefy_player; print(beefy_player.__version__)')
|
||||
git archive --format=tar.gz --prefix="beefy-player-$VERSION/" \
|
||||
-o "beefy-player-$VERSION.tar.gz" "v$VERSION"
|
||||
sha256sum "beefy-player-$VERSION.tar.gz"
|
||||
```
|
||||
|
||||
Create the tag on the mirror (`git push tildeforge "v$VERSION"`), upload the
|
||||
tarball to the `v$VERSION` release, then paste the URL and checksum into
|
||||
`Formula/b/beefy-player.rb`.
|
||||
|
||||
### 2. Resolve the Python resources
|
||||
|
||||
Every Python dependency (and its recursive dependencies) that is not provided by
|
||||
another formula must be declared as a `resource` so Homebrew installs with
|
||||
dependency resolution disabled. Never write these by hand:
|
||||
|
||||
```bash
|
||||
brew tap beefcarver/tap /path/to/homebrew-tap # local clone, or the URL
|
||||
brew update-python-resources --print-only beefcarver/tap/beefy-player
|
||||
brew update-python-resources beefcarver/tap/beefy-player
|
||||
```
|
||||
|
||||
`pypi_packages exclude_packages: "numpy,pillow"` keeps the two native builds out
|
||||
of the resource list — they come from the `numpy`/`pillow` formulae, which ship
|
||||
bottles, and the virtualenv picks them up through system site-packages.
|
||||
`extra_packages: "dbus-next"` makes sure the Linux-only dependency is recorded
|
||||
even though the resolver runs on macOS.
|
||||
|
||||
In a third-party tap, `--ignore-errors` records anything that cannot be resolved
|
||||
and leaves a `RESOURCE-ERROR` comment; the official taps do not allow that, a
|
||||
personal one does.
|
||||
|
||||
### 3. Build, test and audit locally
|
||||
|
||||
```bash
|
||||
brew install --build-from-source beefcarver/tap/beefy-player
|
||||
brew test beefcarver/tap/beefy-player
|
||||
brew audit --strict beefcarver/tap/beefy-player
|
||||
brew style beefcarver/tap/beefy-player
|
||||
```
|
||||
|
||||
The formula's `test do` block runs `--version` and `--offline --list`, so it
|
||||
needs no network and no audio device.
|
||||
|
||||
### 4. Push
|
||||
|
||||
```bash
|
||||
git add Formula/b/beefy-player.rb && git commit -m 'beefy-player 1.2.2' && git push
|
||||
```
|
||||
|
||||
## Version bumps
|
||||
|
||||
For each release: tag, upload the tarball, update `url`/`sha256`, rerun
|
||||
`brew update-python-resources` (only needed when the dependency set or pins
|
||||
changed), install from source, test, push. `brew bump-formula-pr` only works
|
||||
against GitHub-hosted taps, so on Forgejo the bump is a `sed` plus a re-test.
|
||||
|
||||
Optional `livecheck` support, so `brew livecheck --tap beefcarver/tap` can spot
|
||||
new tags:
|
||||
|
||||
```ruby
|
||||
livecheck do
|
||||
url "https://tildeforge.dev/beefcarver/beefy-player/tags"
|
||||
regex(/^v?(\d+(?:\.\d+)+)$/i)
|
||||
end
|
||||
```
|
||||
|
||||
## Bottles (optional)
|
||||
|
||||
Without a `bottle do` block users build from source — for this app that means
|
||||
filling a virtualenv with pure-Python resources while `numpy`, `pillow`, `mpv`
|
||||
and `ffmpeg` arrive as bottles, so it is quick. Prebuilt bottles need Homebrew's
|
||||
GitHub Actions workflows, which cannot run on Forgejo; skip them unless the tap
|
||||
is also mirrored to GitHub.
|
||||
|
||||
## Why a tap and not homebrew-core
|
||||
|
||||
homebrew-core requires a tagged, immutable source URL and enough notability to
|
||||
be accepted at all (roughly 75+ stars / 30+ forks, or coverage that makes a
|
||||
project notable). A tap has none of those constraints, which is why upstream
|
||||
taps are the normal route for a project this size. The formula here follows
|
||||
core's conventions, so it could be submitted there later unchanged if the
|
||||
project qualifies.
|
||||
Reference in new issue
Block a user