build(contrib): move packaging under contrib and track the tap as a submodule
This commit is contained in:
1 parent
499f99113f
commit
a2b5771922
7 files changed
+4
-252
No files matched your search
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "contrib/homebrew"]
|
||||||
|
path = contrib/homebrew
|
||||||
|
url = https://tildeforge.dev/beefcarver/homebrew
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
# AUR packaging for beefy-player
|
|
||||||
|
|
||||||
An AUR repository holds exactly two tracked files, `PKGBUILD` and `.SRCINFO`.
|
|
||||||
This directory is the staging area for both; the rest of the project is
|
|
||||||
irrelevant to the AUR.
|
|
||||||
|
|
||||||
## Build it locally
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd aur
|
|
||||||
makepkg -si # build, run the test suite, install
|
|
||||||
```
|
|
||||||
|
|
||||||
`makepkg -o && makepkg -e` skips the download/checksum phase, and
|
|
||||||
`extra-x86_64-build` (devtools) builds in a clean chroot. The package builds
|
|
||||||
with `base-devel` plus the `makedepends`/`checkdepends` listed in the
|
|
||||||
`PKGBUILD`; every dependency comes from the official repositories, none from
|
|
||||||
the AUR.
|
|
||||||
|
|
||||||
## Publish to the AUR
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone ssh://[email protected]/beefy-player.git /tmp/aur-beefy-player
|
|
||||||
cp PKGBUILD .SRCINFO /tmp/aur-beefy-player/
|
|
||||||
cd /tmp/aur-beefy-player
|
|
||||||
git add PKGBUILD .SRCINFO
|
|
||||||
git commit -m "Initial import: beefy-player 1.2.2-1"
|
|
||||||
git push
|
|
||||||
```
|
|
||||||
|
|
||||||
## Releasing a new version
|
|
||||||
|
|
||||||
1. Set `pkgver` in `PKGBUILD` and `pyproject.toml`, and reset `pkgrel=1`.
|
|
||||||
2. Point `_commit` at the commit carrying that version:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git rev-parse HEAD # or the tag, once one exists
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Refresh the checksum:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -fsSL "https://tildeforge.dev/beefcarver/beefy-player/archive/$_commit.tar.gz" | sha256sum
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Regenerate the metadata (on Arch, or inside a chroot):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
makepkg --printsrcinfo > .SRCINFO
|
|
||||||
```
|
|
||||||
|
|
||||||
5. Push to the AUR with the conventional commit message:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git commit -am "upgpkg: beefy-player <pkgver>-<pkgrel>"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Why the source is a commit archive
|
|
||||||
|
|
||||||
Upstream publishes no tags or releases, so the checksum in `sha256sums`
|
|
||||||
belongs to the archive of a specific commit rather than of a `v$pkgver` tag.
|
|
||||||
Forge archives of a commit are deterministic, so the checksum stays stable.
|
|
||||||
Once `v$pkgver` is tagged, replace the `source` line with
|
|
||||||
|
|
||||||
```bash
|
|
||||||
source=("$pkgname-$pkgver.tar.gz::$url/archive/v$pkgver.tar.gz")
|
|
||||||
```
|
|
||||||
|
|
||||||
## Packaging notes
|
|
||||||
|
|
||||||
- The wheel is built with `hatchling`; `theme.tcss` is force-included by
|
|
||||||
`pyproject.toml`, so it ends up in `site-packages/beefy_player/`.
|
|
||||||
- `check()` runs the real test suite. It is offline by design (station
|
|
||||||
catalogues are fixtures and `mpv`/`parec` are faked), which makes it safe in
|
|
||||||
a build chroot with no network.
|
|
||||||
- `mpv`, `ffmpeg`, `libpulse` (`parec`/`pactl`) and `tmux` are `optdepends`,
|
|
||||||
not `depends`: the player degrades gracefully without them and says so in
|
|
||||||
the UI. Users who want sound need `mpv` (or `ffmpeg` for `ffplay`) and, for
|
|
||||||
the output-synced spectrum, `libpulse`.
|
|
||||||
- `license=('WTFPL')` is an SPDX identifier shipped by Arch's `licenses`
|
|
||||||
package.
|
|
||||||
File renamed without changes.
File renamed without changes.
Submodule
+1
Submodule contrib/homebrew added at ad6fcc5732.
@@ -1,51 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
# 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