feat: install via homebrew (#9)
Add a release job that regenerates Formula/soulseek-rs.rb in michel/homebrew-tap from the archives the binaries matrix uploads, and lead with `brew install michel/tap/soulseek-rs` in the READMEs and on the website.
This commit is contained in:
@@ -185,3 +185,79 @@ jobs:
|
|||||||
checksum: sha256
|
checksum: sha256
|
||||||
ref: refs/tags/${{ needs.release.outputs.tag }}
|
ref: refs/tags/${{ needs.release.outputs.tag }}
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
# Rewrites Formula/soulseek-rs.rb in the tap to point at the archives the
|
||||||
|
# matrix just uploaded. The formula is generated whole rather than patched, so
|
||||||
|
# the workflow is the only place its contents live.
|
||||||
|
homebrew:
|
||||||
|
name: Homebrew tap
|
||||||
|
needs: [release, binaries]
|
||||||
|
if: needs.release.outputs.created == 'true' || inputs.tag != ''
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: michel/homebrew-tap
|
||||||
|
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
|
||||||
|
|
||||||
|
- name: Write formula
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
TAG: ${{ needs.release.outputs.tag }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
base="https://github.com/${GITHUB_REPOSITORY}/releases/download/${TAG}"
|
||||||
|
sha() {
|
||||||
|
gh release download "$TAG" --repo "$GITHUB_REPOSITORY" \
|
||||||
|
--pattern "soulseek-rs-$TAG-$1.sha256" --output - | cut -d' ' -f1
|
||||||
|
}
|
||||||
|
mkdir -p Formula
|
||||||
|
cat > Formula/soulseek-rs.rb <<EOF
|
||||||
|
# Generated by the soulseek-rs release workflow. Do not edit by hand.
|
||||||
|
class SoulseekRs < Formula
|
||||||
|
desc "Soulseek client in Rust"
|
||||||
|
homepage "https://re-invention.nl/soulseek-rs/"
|
||||||
|
version "${TAG#v}"
|
||||||
|
license "MIT"
|
||||||
|
|
||||||
|
on_macos do
|
||||||
|
on_arm do
|
||||||
|
url "$base/soulseek-rs-$TAG-aarch64-apple-darwin.tar.gz"
|
||||||
|
sha256 "$(sha aarch64-apple-darwin)"
|
||||||
|
end
|
||||||
|
on_intel do
|
||||||
|
url "$base/soulseek-rs-$TAG-x86_64-apple-darwin.tar.gz"
|
||||||
|
sha256 "$(sha x86_64-apple-darwin)"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
on_linux do
|
||||||
|
on_arm do
|
||||||
|
url "$base/soulseek-rs-$TAG-aarch64-unknown-linux-musl.tar.gz"
|
||||||
|
sha256 "$(sha aarch64-unknown-linux-musl)"
|
||||||
|
end
|
||||||
|
on_intel do
|
||||||
|
url "$base/soulseek-rs-$TAG-x86_64-unknown-linux-musl.tar.gz"
|
||||||
|
sha256 "$(sha x86_64-unknown-linux-musl)"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def install
|
||||||
|
bin.install "soulseek-rs"
|
||||||
|
end
|
||||||
|
|
||||||
|
test do
|
||||||
|
assert_match version.to_s, shell_output("#{bin}/soulseek-rs --version")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
EOF
|
||||||
|
|
||||||
|
- name: Commit
|
||||||
|
env:
|
||||||
|
TAG: ${{ needs.release.outputs.tag }}
|
||||||
|
run: |
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||||
|
git add Formula/soulseek-rs.rb
|
||||||
|
git diff --staged --quiet || git commit -m "soulseek-rs $TAG"
|
||||||
|
git push
|
||||||
|
|||||||
@@ -78,6 +78,14 @@ This structure allows:
|
|||||||
|
|
||||||
### For Users
|
### For Users
|
||||||
|
|
||||||
|
Homebrew, on macOS or Linux — a prebuilt binary, no Rust toolchain:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install michel/tap/soulseek-rs
|
||||||
|
```
|
||||||
|
|
||||||
|
Or with cargo:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo install soulseek-rs
|
cargo install soulseek-rs
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ Releases are automated by [release-plz](https://release-plz.dev). You do not run
|
|||||||
| `soulseek-rs-vX.Y.Z-x86_64-pc-windows-msvc.zip` | |
|
| `soulseek-rs-vX.Y.Z-x86_64-pc-windows-msvc.zip` | |
|
||||||
| `soulseek-rs-vX.Y.Z-aarch64-pc-windows-msvc.zip` | |
|
| `soulseek-rs-vX.Y.Z-aarch64-pc-windows-msvc.zip` | |
|
||||||
|
|
||||||
|
- rewrites `Formula/soulseek-rs.rb` in the `michel/homebrew-tap` repository so
|
||||||
|
`brew install michel/tap/soulseek-rs` picks up the new macOS and Linux archives.
|
||||||
|
|
||||||
Both crates always share one version, one tag, and one changelog — see `release-plz.toml`.
|
Both crates always share one version, one tag, and one changelog — see `release-plz.toml`.
|
||||||
|
|
||||||
## One-time repository setup
|
## One-time repository setup
|
||||||
@@ -38,6 +41,10 @@ Both crates always share one version, one tag, and one changelog — see `releas
|
|||||||
[crates.io token](https://crates.io/settings/tokens) scoped to `publish-new` and
|
[crates.io token](https://crates.io/settings/tokens) scoped to `publish-new` and
|
||||||
`publish-update`. Without it the tag and GitHub release still happen, but the crates.io
|
`publish-update`. Without it the tag and GitHub release still happen, but the crates.io
|
||||||
publish fails.
|
publish fails.
|
||||||
|
- **Homebrew tap**: create a public `michel/homebrew-tap` repository, then add a
|
||||||
|
`HOMEBREW_TAP_TOKEN` secret — a fine-grained PAT with *Contents: read and write* on that
|
||||||
|
repository only. `GITHUB_TOKEN` cannot reach another repository. The formula itself is
|
||||||
|
generated by the workflow; nothing in the tap needs editing by hand.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ Website: <https://re-invention.nl/soulseek-rs/>
|
|||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo install soulseek-rs
|
brew install michel/tap/soulseek-rs # macOS and Linux, prebuilt
|
||||||
|
cargo install soulseek-rs # anywhere with a Rust toolchain
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|||||||
@@ -84,13 +84,13 @@ export const Docs = () => {
|
|||||||
|
|
||||||
<Section>
|
<Section>
|
||||||
<SectionHead eyebrow="1 · first run" title="Two commands to a running client.">
|
<SectionHead eyebrow="1 · first run" title="Two commands to a running client.">
|
||||||
You need a Rust toolchain. After <Code>cargo install</Code>, the binary is on your
|
Homebrew puts the binary on your PATH. With a Rust toolchain,{' '}
|
||||||
PATH.
|
<Code>cargo install soulseek-rs</Code> does the same.
|
||||||
</SectionHead>
|
</SectionHead>
|
||||||
<Cols start>
|
<Cols start>
|
||||||
<Terminal
|
<Terminal
|
||||||
lines={[
|
lines={[
|
||||||
{ t: 'cmd', text: 'cargo install soulseek-rs' },
|
{ t: 'cmd', text: 'brew install michel/tap/soulseek-rs' },
|
||||||
{ t: 'cmd', text: 'soulseek-rs' },
|
{ t: 'cmd', text: 'soulseek-rs' },
|
||||||
{ t: 'cm', text: '# the TUI opens; log in or register on first run' },
|
{ t: 'cm', text: '# the TUI opens; log in or register on first run' },
|
||||||
]}
|
]}
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ export const Home = () => {
|
|||||||
<Button href="/docs">Read the docs</Button>
|
<Button href="/docs">Read the docs</Button>
|
||||||
<Button href={LINKS.gh}>GitHub</Button>
|
<Button href={LINKS.gh}>GitHub</Button>
|
||||||
</div>
|
</div>
|
||||||
<CommandPill text="cargo install soulseek-rs" />
|
<CommandPill text="brew install michel/tap/soulseek-rs" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -312,7 +312,7 @@ export const Home = () => {
|
|||||||
Install it, then press <span className="text-accent-text">s</span> to search.
|
Install it, then press <span className="text-accent-text">s</span> to search.
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-secondary">
|
<p className="text-secondary">
|
||||||
Needs a Rust toolchain. From there it’s one command, then the TUI opens.
|
One command on macOS or Linux, then the TUI opens. No Rust toolchain needed.
|
||||||
</p>
|
</p>
|
||||||
<div className="mt-1.5 flex flex-wrap gap-2 sm:gap-3">
|
<div className="mt-1.5 flex flex-wrap gap-2 sm:gap-3">
|
||||||
<Button href="/docs" variant="accent">
|
<Button href="/docs" variant="accent">
|
||||||
@@ -324,7 +324,7 @@ export const Home = () => {
|
|||||||
<Terminal
|
<Terminal
|
||||||
label="quick start"
|
label="quick start"
|
||||||
lines={[
|
lines={[
|
||||||
{ t: 'cmd', text: 'cargo install soulseek-rs' },
|
{ t: 'cmd', text: 'brew install michel/tap/soulseek-rs' },
|
||||||
{ t: 'cmd', text: 'soulseek-rs' },
|
{ t: 'cmd', text: 'soulseek-rs' },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -183,15 +183,24 @@ export const Install = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageHead eyebrow="install" title="Three ways in.">
|
<PageHead eyebrow="install" title="Three ways in.">
|
||||||
One command if you have Rust. Build from source if you’d rather. Or depend on
|
One command with Homebrew or cargo. Build from source if you’d rather. Or
|
||||||
the library and write your own client.
|
depend on the library and write your own client.
|
||||||
</PageHead>
|
</PageHead>
|
||||||
|
|
||||||
<Section>
|
<Section>
|
||||||
<div className="flex flex-col gap-9">
|
<div className="flex flex-col gap-9">
|
||||||
<Step n={1} title="Install the client">
|
<Step n={1} title="Install the client">
|
||||||
<p className="text-secondary">
|
<p className="text-secondary">
|
||||||
Needs a Rust toolchain, available from{' '}
|
Homebrew, on macOS or Linux. A prebuilt binary, so no Rust toolchain:
|
||||||
|
</p>
|
||||||
|
<Terminal
|
||||||
|
lines={[
|
||||||
|
{ t: 'cmd', text: 'brew install michel/tap/soulseek-rs' },
|
||||||
|
{ t: 'cmd', text: 'soulseek-rs' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<p className="text-secondary">
|
||||||
|
With a Rust toolchain from{' '}
|
||||||
<a
|
<a
|
||||||
href={LINKS.rustup}
|
href={LINKS.rustup}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -200,17 +209,13 @@ export const Install = () => {
|
|||||||
>
|
>
|
||||||
rustup.rs
|
rustup.rs
|
||||||
</a>
|
</a>
|
||||||
. Then:
|
, cargo works everywhere else:
|
||||||
</p>
|
</p>
|
||||||
<Terminal
|
<Terminal lines={[{ t: 'cmd', text: 'cargo install soulseek-rs' }]} />
|
||||||
lines={[
|
|
||||||
{ t: 'cmd', text: 'cargo install soulseek-rs' },
|
|
||||||
{ t: 'cmd', text: 'soulseek-rs' },
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<p className="text-[13px] text-muted">
|
<p className="text-[13px] text-muted">
|
||||||
Cargo puts the binary on your PATH. Run <Code>soulseek-rs</Code> in a terminal
|
Either way the binary lands on your PATH. Run <Code>soulseek-rs</Code> in a
|
||||||
and the TUI opens, in a script or a pipe it wants a subcommand instead.
|
terminal and the TUI opens, in a script or a pipe it wants a subcommand
|
||||||
|
instead.
|
||||||
</p>
|
</p>
|
||||||
<div className="flex flex-wrap gap-2 sm:gap-3">
|
<div className="flex flex-wrap gap-2 sm:gap-3">
|
||||||
<Button href={LINKS.releases}>Prebuilt binaries</Button>
|
<Button href={LINKS.releases}>Prebuilt binaries</Button>
|
||||||
|
|||||||
Reference in New Issue
Block a user