diff --git a/homebrew/Formula/b/beefy-player.rb b/homebrew/Formula/b/beefy-player.rb new file mode 100644 index 0000000..c74d86c --- /dev/null +++ b/homebrew/Formula/b/beefy-player.rb @@ -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 "python@3.14" + + # 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 diff --git a/homebrew/README.md b/homebrew/README.md new file mode 100644 index 0000000..ffac788 --- /dev/null +++ b/homebrew/README.md @@ -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//`): + +```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.