9 Punkte von GN⁺ 2025-09-18 | 2 Kommentare | Auf WhatsApp teilen
  • Homebrew ist ein Paketmanager für macOS, mit dem sich CLI-Tools einfach installieren und verwalten lassen, sodass Entwickler ihre Systemumgebung mit häufig genutzten Werkzeugen effizient einrichten können
  • Dieser Leitfaden erklärt, wie man mit Homebrew persönliche CLI-Skripte verteilt, und zeigt, wie sich die Wartung durch GitHub-Integration und automatisierte Workflows vereinfachen lässt
  • Der Distributionsprozess verläuft über CLI erstellen → GitHub-Release → Tap anlegen → Formula schreiben und aktualisieren und ermöglicht am Ende die Installation allein mit den Befehlen brew tap und brew install
  • Wer das Begriffssystem und die Best Practices von Homebrew versteht, kann eine stabile Distribution mit besserer Reproduzierbarkeit und Supply-Chain-Sicherheit aufsetzen
  • Der Prozess lässt sich mit GitHub Actions automatisieren; ist er einmal eingerichtet, wird auch die spätere Distribution anderer CLIs sehr viel einfacher

Hintergrund und Motivation

  • Homebrew ist der bevorzugte Paketmanager für die Installation von CLI-Tools und wird von vielen Entwicklern genutzt
  • Eigene CLIs werden jedoch oft über npm oder RubyGems verteilt, weshalb sich der Distributionsweg über Homebrew zunächst ungewohnt anfühlen kann
  • Da das offizielle Core-Repository von Homebrew selbst entwickelte Tools nur ungern aufnimmt, verteilen normale Entwickler sie über einen separaten Tap und eine eigene Formula
  • Dieser Leitfaden basiert auf Erfahrungen mit der Distribution einer einfachen Ruby-basierten CLI

Begriffserklärung

  • Homebrew verwendet eigene Begriffe im Stil des Bierbrauens; wer sie versteht, kann die Systemstruktur leichter erfassen
    • Eine Formula ist eine Paketdefinitionsdatei, die Anweisungen zur Installation von Quellcode oder Binärdateien enthält
    • Ein Tap ist ein Git-Repository für Formulas, mit dem benutzer- oder organisationsspezifische Pakete verwaltet werden
    • Ein Cask ist ein Installationsmanifest für GUI-Apps oder große Binärdateien; ähnlich wie eine Formula, aber für vorgebaute Dateien
    • Eine Bottle ist ein vorgebautes Binärpaket, das statt eines Builds aus dem Quellcode einfach kopiert wird und so die Installation beschleunigt
    • Der Cellar ist das Verzeichnis, in dem installierte Formulas liegen, zum Beispiel unter /opt/homebrew/Cellar
    • Ein Keg ist das Installationsinstanz-Verzeichnis einer bestimmten Formula und liegt versionsweise innerhalb des Cellar

Überblick

  • Das Homebrew-Core-Repository nimmt nischige oder persönliche Einreichungen nicht an, daher müssen Nutzer ein separates Tap-Repository anlegen, um ihre CLI zu verteilen
    • 1. CLI erstellen, auf GitHub hochladen und ein Tag-Release veröffentlichen
    • 2. Mit brew tap-new ein Tap anlegen und zu GitHub pushen
    • 3. Mit brew create eine Formula erstellen (einschließlich Tarball-URL und SHA256)
    • 4. Bei jeder neuen Version die Formula aktualisieren, damit Nutzer die CLI einfach mit brew install installieren können
  • Nach Abschluss der Distribution können Nutzer die CLI mit zwei Befehlen installieren: brew tap your_github_handle/tap und brew install your_cool_cli
    • Dieser Leitfaden überspringt die CLI-Entwicklung und konzentriert sich auf das Anlegen des Tap, das Erstellen der Formula und deren Aktualisierung
    • Als Beispiel dient die CLI imsg, die aus einer iMessage-Datenbank ein interaktives Web-Archiv erstellt

Tap anlegen

  • Dazu folgt man dem Leitfaden zum Erstellen eines Tap von Homebrew und ersetzt dabei GitHub-Benutzernamen oder Organisationsnamen entsprechend
    • Um künftig alle CLI-Tools in einem Tap zu bündeln, wird der Name homebrew-tap empfohlen; das Präfix homebrew wird von der CLI speziell behandelt und das Präfix tap ist gängige Konvention
  • Befehl zum Anlegen des Tap: brew tap-new searlsco/homebrew-tap
    • Dadurch wird ein Scaffold unter /opt/homebrew/Library/Taps/searlsco/homebrew-tap erzeugt
    • Anschließend erstellt man das entsprechende Repository auf GitHub und pusht den generierten Inhalt: cd /opt/homebrew/Library/Taps/searlsco/homebrew-tap, git remote add origin git@github.com:searlsco/homebrew-tap.git, git push -u origin main
  • Sobald man Eigentümer des Tap ist, können andere Nutzer das Repository mit brew tap searlsco/tap klonen und unter /opt/homebrew/Library/Taps ablegen
    • Anfangs ist dort noch nichts Nützliches enthalten, aber das Grundverhalten lässt sich bereits überprüfen

Formula erstellen

  • Homebrew kann GitHub-Repositories direkt referenzieren, empfiehlt aber die Verwendung von versionierten Tarballs und Checksummen, um Reproduzierbarkeit und Open-Source-Supply-Chain-Sicherheit zu stärken
  • Befehl zum Erstellen der Formula: brew create https://github.com/searlsco/imsg/archive/refs/tags/v0.0.5.tar.gz --tap searlsco/homebrew-tap --set-name imsg --ruby
    • Das Flag --tap gibt das benutzerdefinierte Tap an und legt die Formula unter /opt/homebrew/Library/Taps/searlsco/homebrew-tap/Formula ab
    • --set-name imsg setzt den Namen der Formula explizit; dieser sollte eindeutig gewählt werden, um Namenskonflikte zu vermeiden (zum Beispiel mit vorhandenem TLDR oder der Standard-CLI)
    • --ruby ist ein Template-Preset für Ruby-CLIs und eines von mehreren Optionen, die die Anpassung vereinfachen
  • Die erzeugte Formula funktioniert anfangs möglicherweise noch nicht, daher kann man sie mit Hilfe eines LLM überarbeiten: brew install --verbose imsg ausführen, den Fehler in ChatGPT eingeben und die Formula wiederholt anpassen
    • Die finale Datei Formula/imsg.rb kann als Ausgangspunkt für die Distribution einer Ruby-CLI kopiert werden
    • Wer statt eines sprachspezifischen Paketmanagers über Homebrew verteilt, ermöglicht Nutzern reibungslose Upgrades auch dann, wenn sich die Implementierungssprache ändert

Wichtige Highlights der Formula

  • Alle Formulas werden in Ruby geschrieben, da viele beliebte Entwicklerwerkzeuge vor JavaScript oder AI auf Ruby basierten
    • Mit der Methode head lässt sich ein Git-Repository angeben, auch wenn der tatsächliche Effekt unklar ist
    • Das Hinzufügen von livecheck lohnt sich, weil es Versionsupdates der Formula erleichtert
    • Ein Test für die Ausführung der Binärdatei lässt sich einfach über die Prüfung der Hilfsausgabe implementieren; man sollte sich von den generierten Kommentaren nicht einschüchtern lassen
    • Mit brew style searlsco/tap lassen sich Stilfehler prüfen
    • Das Standard-uses_from_macos "ruby" des --ruby-Templates verwendet Version 2.6.10 (ein Release von vor COVID, seit 3 Jahren EOL), daher wird stattdessen depends_on "ruby@3" als Abhängigkeit von der aktuellen Ruby-Formula empfohlen
  • Wenn die Formula zufriedenstellend ist, wird sie mit git push live verteilt; Nutzer können sie dann mit brew tap searlsco/tap und brew install imsg installieren

Formula bei jedem CLI-Release aktualisieren

  • Die url und der sha256-Hash am Anfang der Formula müssen bei jedem Release manuell aktualisiert werden, was mühsam ist; selbst das Pushen eines Tags oder das Erstellen eines GitHub-Releases kann auf Dauer lästig werden
    • Mit dem Homebrew-Befehl bump-formula-pr oder per GitHub Action lässt sich zwar ein PR erzeugen, aber der Prozess mit Fork und PR ist unnötig komplex
    • Wenn man Eigentümer des Tap ist, ist ein einfacher Weg mit direkten Commits auf den Main-Branch wünschenswerter
  • Um das zu vermeiden, wird empfohlen, dem Formula-Repository einen GitHub-Workflow hinzuzufügen, der das Tap beim Release automatisch aktualisiert
    • Das Workflow-Beispiel kann direkt kopiert und verwendet werden
    • Erforderliche Einrichtung: Beim Erstellen eines GitHub Personal Access Token (PAT) dem Repository homebrew-tap die Berechtigung ContentWrite geben und das Token in den Secrets des Formula-Repositories unter HOMEBREW_TAP_TOKEN speichern
    • Tap und Formula werden über Umgebungsvariablen festgelegt (zum Beispiel in Zeile 13–15)
    • Für Updates wird das GitHub-Bot-Konto empfohlen: GH_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com, GH_NAME: github-actions[bot]
  • Nach dem Erstellen eines Releases genügt git push --tags, und innerhalb weniger Sekunden erfolgt die automatische Aktualisierung; Nutzer können dann mit brew update und brew upgrade imsg upgraden

Das Beste daran

  • Der Prozess ist zwar komplex, aber sobald das Tap eingerichtet und ein Formula-Beispiel fertig ist, wird die Verteilung zusätzlicher CLIs fast trivial
    • Neue Formulas lassen sich bequem in wenigen Minuten veröffentlichen
  • Der offizielle Homebrew-Prozess ist etwas kompliziert, wird durch Automatisierung aber deutlich angenehmer
    • So lässt sich der Aufwand zwischen Tool-Release und Distribution verringern und auch auf CLIs in verschiedenen Sprachen ausweiten
  • Ob tatsächlich noch eine weitere Formula veröffentlicht wird, ist offen, aber allein die Möglichkeit fühlt sich lohnend an

2 Kommentare

 
lamanus 2025-09-18

Mit dem bump-formula-pr-Befehl von Homebrew oder per GitHub Actions lassen sich zwar PRs erstellen, aber der Fork- und PR-Prozess ist unnötig komplex.

Es gibt eine --no-fork-Option, mit der man direkt auf den Branch pushen und mergen kann; außerdem bietet sie eine automatische Update-Funktion.

 
GN⁺ 2025-09-18
Hacker-News-Kommentare
  • Die Namenskonventionen von Homebrew wirken manchmal etwas verwirrend, aber insgesamt merke ich immer wieder, wie nützlich das Tool wirklich ist
    Außerdem hatte ich nicht erwartet, dass es so einfach ist, mit einem eigenen Tap seine Tools zu verteilen
    Im Vergleich zu sprachspezifischen Paketmanagern wie z. B. uv würde mich interessieren, was daran besser ist
    Vor allem würde ich gern wissen, ob es für Leute außerhalb eines bestimmten Ökosystems einfacher ist, also ob es unter dem Gesichtspunkt der Allgemeingültigkeit einen Vorteil hat

    • Danke dafür. Andere Tools, die Paket-Registries verwenden, erfordern in der Regel die Erstellung eines Kontos, Zwei-Faktor-Authentifizierung, Signaturprozesse usw.
      Bei Homebrew dienen die GitHub-Nutzungsbedingungen (ToS) als Vertrauensgrundlage, wodurch insgesamt vieles deutlich einfacher wird
      Das Homebrew-Team kann dank dieses Ansatzes viel Komplexität vermeiden

    • Wenn man von Python-Paketen ausgeht, ist der Versuch, wie bei uv alles in einem Schritt zu paketieren, in der Praxis schwierig
      Deshalb verwendet man normalerweise den Ansatz, nur festgelegte Abhängigkeiten in einer venv-Umgebung zu installieren
      Als konkretes Beispiel kann man sich diese Formula ansehen
      Was uv betrifft: Ich hatte versucht, mit offiziellen Tools (brew update-python-resources, homebrew-pypi-poet) private Pakete zu unterstützen, aber das hat nicht richtig funktioniert
      Deshalb habe ich selbst uvbrew erstellt, um die Ressourcenerzeugung zu unterstützen
      Es gibt auch eine offizielle Dokumentation als Referenz zum Schreiben von Python-Formulas in Homebrew

  • Für Go-Entwickler würde ich das Tool Goreleaser empfehlen
    Damit lässt sich die Verteilung von Binärdateien im eigenen Tap sehr einfach umsetzen (im offiziellen Core ist diese Vorgehensweise verboten)

    • Ich habe erst vor Kurzem erfahren, dass Goreleaser inzwischen nicht nur Go, sondern auch Rust, TypeScript, Python, Zig und weitere Sprachen unterstützt
      Es ist für das Projektmanagement in den jeweiligen Sprachen sehr nützlich
  • Persönlich finde ich es idealer, Updates direkt auf der Tap-Seite zu verwalten
    Das ähnelt dem üblichen Vorgehen, bei dem im Upstream aktualisiert wird
    Wenn man sich diesen Workflow ansieht, kann man auch Formulas/Casks, die man nicht besitzt, leicht aktualisieren
    Mit dem Befehl brew bump kann man alles scannen, automatisch PRs erstellen und mit brew test-bot sogar die Tests automatisieren
    Ein echtes Beispiel für einen PR findet sich hier

    • Finde ich eine gute Idee
      Normalerweise habe ich wegen der verfügbaren GitHub-Actions-Zeit gezögert, aber da es für Open Source kostenlos ist, scheint das eine gute Nutzung zu sein
  • Ich habe auch selbst einen automatischen Workflow zum Bumpen von Versionen für meinen eigenen Homebrew-Tap geschrieben: homebrew-bump-revision
    Ich nutze das erfolgreich in mehreren privaten Projekten

    • Sieht großartig aus
      Ich war zu faul, es selbst auszuprobieren, aber es ist ein gutes Tool
  • Im Ruby-Rogues-Podcast gab es eine Episode mit verschiedenen Tipps zur Verteilung von CLI-Tools über Homebrew
    Unter diesem Episodenlink kann man noch mehr dazu hören

  • Ich habe etwas Interessantes beim Paketieren von Python-Tools festgestellt
    Bei einigen Python-Paketen entstehen während des Build-Prozesses Abhängigkeitszyklen, sodass sie mit Homebrew nicht kompatibel sind
    Bei pip gibt es dieses Problem nicht, weil es Binär-Releases herunterlädt, Homebrew baut jedoch alle Abhängigkeiten selbst, weshalb der Vorgang viel länger dauert
    Deshalb kann selbst der Build einer "bottle" für ein mittelgroßes Python-Projekt mehr als eine Stunde dauern

  • Seit ich für die Systemverwaltung angefangen habe, nix zu verwenden, habe ich es kein einziges Mal bereut
    Der einzige Wermutstropfen ist, dass ich wegen Multiplayer-Spielen in einem Punkt immer noch auf Windows angewiesen bin