Homebrew를 통해 자신의 스크립트 배포하기
(justin.searls.co)- Homebrew는 macOS에서 CLI 도구를 쉽게 설치하고 관리할 수 있는 패키지 매니저로, 개발자들이 자주 사용하는 도구를 통해 시스템 환경을 효율적으로 구성할 수 있음
- 이 가이드는 Homebrew를 이용해 개인 CLI 스크립트를 배포하는 과정을 설명하며, GitHub 통합과 자동화 워크플로를 통해 유지보수를 간소화하는 방법을 제시
- 배포 과정은 CLI 제작 → GitHub 릴리스 → Tap 생성 → Formula 작성 및 업데이트로 이어지며, 최종적으로
brew tap
과brew install
명령어만으로 설치 가능함 - Homebrew의 용어 체계와 베스트 프랙티스를 이해하면, 재현성과 공급망 보안을 강화한 안정적인 배포가 가능
- GitHub Actions 워크플로우를 통해 자동화할 수 있으며, 한 번 설정하면 이후 다른 CLI 배포도 매우 간단해지는 장점이 있음
배경 및 동기
- Homebrew는 CLI 도구 설치 시 선호되는 패키지 관리자로, 많은 개발자들이 사용함
- 하지만 자신이 만든 CLI를 npm 또는 RubyGem으로 배포하는 경우가 많으며, Homebrew 배포 방식은 절차가 낯설게 느껴질 수 있음
- Homebrew의 공식 core 저장소에는 자작 툴 등록을 Homebrew 팀이 꺼리는 방침이 있어, 일반 개발자는 별도 tap과 formula로 배포함
- 본 가이드는 간단한 Ruby 기반 CLI 배포 경험을 기반으로 설명
용어 설명
- Homebrew는 맥주 양조 테마를 반영한 특유의 용어를 사용하므로, 이를 이해하면 시스템 구조를 파악하기 쉬움
- Formula는 패키지 정의 파일로, 소스 코드나 바이너리를 설치하는 지침을 포함
- Tap은 Formula들의 Git 저장소로, 사용자별 또는 조직별로 커스텀 패키지를 관리
- Cask는 GUI 앱이나 대형 바이너리 설치 매니페스트로, Formula와 유사하지만 미리 빌드된 파일을 처리
- Bottle은 소스에서 빌드하지 않고 미리 빌드된 바이너리 패키지를 복사하는 형태로, 설치 속도를 높임
- Cellar는 설치된 Formula들이 위치한 디렉토리로, 예를 들어
/opt/homebrew/Cellar
경로를 가짐 - Keg는 특정 Formula의 설치 인스턴스 디렉토리로, Cellar 내에 버전별로 배치됨
개요
- Homebrew 코어 저장소는 니치하거나 개인 제출한 콘텐츠를 받지 않으므로, 사용자들은 별도의 tap 저장소를 만들어 CLI를 배포해야 함
- 1. CLI 제작 후 GitHub에 올리고 태그 릴리스
- 2.
brew tap-new
로 Tap 생성 후 GitHub에 push - 3.
brew create
로 Formula 작성 (tarball URL과 SHA256 포함) - 4. 새 버전 릴리스마다 Formula 갱신하여 사용자들이
brew install
명령으로 쉽게 설치 가능
- 배포 완료 후 사용자는 두 명령어로 CLI를 설치할 수 있음:
brew tap your_github_handle/tap
과brew install your_cool_cli
- 이 가이드는 CLI 개발을 생략하고, tap 생성, Formula 생성, 업데이트 과정에 초점
- 예시로 iMessage 데이터베이스에서 인터랙티브 웹 아카이브를 만드는
imsg
CLI를 사용
tap 생성
- Homebrew의 tap 생성 가이드를 따르며, GitHub 사용자명이나 조직명을 대체하여 설정
- 앞으로 모든 CLI 도구를 하나의 tap에 모으기 위해
homebrew-tap
이름을 추천,homebrew
접두사는 CLI에서 특별 처리되고tap
접두사는 관례적
- 앞으로 모든 CLI 도구를 하나의 tap에 모으기 위해
- tap 생성 명령어 실행:
brew tap-new searlsco/homebrew-tap
- 이는
/opt/homebrew/Library/Taps/searlsco/homebrew-tap
에 스캐폴드를 생성 - GitHub에 대응하는 저장소를 만들고, 생성된 내용을 푸시:
cd /opt/homebrew/Library/Taps/searlsco/homebrew-tap
,git remote add origin git@github.com:searlsco/homebrew-tap.git
,git push -u origin main
- 이는
- tap 소유 완료 후 다른 사용자는
brew tap searlsco/tap
명령으로 저장소를 클론하여/opt/homebrew/Library/Taps
에 배치할 수 있음- 초기에는 유용한 내용이 없지만, 기본 동작은 확인 가능
Formula 생성
- Homebrew는 GitHub 저장소를 직접 참조할 수 있지만, 버전화된 tarball과 체크섬을 사용하는 것을 권장하여 재현성과 오픈소스 공급망 보안을 강화
- GitHub는 태그 푸시 시 예측 가능한 URL의 tarball을 호스팅, 예:
imsg
저장소에서git tag v0.0.5
,git push --tags
실행 후https://github.com/searlsco/imsg/archive/refs/tags/v0.0.5.tar.gz
생성
- GitHub는 태그 푸시 시 예측 가능한 URL의 tarball을 호스팅, 예:
- Formula 생성 명령어:
brew create https://github.com/searlsco/imsg/archive/refs/tags/v0.0.5.tar.gz --tap searlsco/homebrew-tap --set-name imsg --ruby
-
--tap
플래그는 커스텀 tap을 지정하고 Formula를/opt/homebrew/Library/Taps/searlsco/homebrew-tap/Formula
에 배치 -
--set-name imsg
는 Formula 이름을 명시적으로 설정, 중복 이름 피하기 위해 유니크하게 선택 (예: 기존 TLDR나 standard CLI와 충돌 주의) -
--ruby
는 Ruby CLI를 위한 템플릿 프리셋으로, 커스터마이징을 간소화하는 여러 옵션 중 하나
-
- 생성된 Formula는 초기에는 작동하지 않을 수 있으므로, LLM을 활용해 수정:
brew install --verbose imsg
실행 후 오류를 ChatGPT에 입력하고 Formula 업데이트 반복- 최종 Formula/imsg.rb 파일은 Ruby CLI 배포의 시작점으로 복사 가능
- Homebrew를 통해 언어 특정 패키지 매니저 대신 배포하면, 구현 언어를 변경해도 사용자 업그레이드가 원활
Formula 주요 하이라이트
- 모든 Formula는 Ruby로 작성되며, JavaScript나 AI 이전에 인기 있던 개발 도구가 Ruby 기반이었기 때문
-
head
메서드로 Git 저장소를 지정 가능하지만, 실제 효과는 불확실 -
livecheck
추가는 Formula 버전 업데이트를 쉽게 하여 가치 있음 - 바이너리 실행 테스트는 도움말 출력 확인으로 간단히 구현, 생성된 주석에 위축되지 말 것
-
brew style searlsco/tap
명령으로 스타일 오류 확인 -
--ruby
템플릿의 기본uses_from_macos "ruby"
는 2.6.10 버전 (COVID 이전 릴리스, 3년 전 EOL) 사용하므로,depends_on "ruby@3"
으로 최신 ruby Formula 의존 추천
-
- Formula가 만족스러우면
git push
로 라이브 배포, 사용자들은brew tap searlsco/tap
과brew install imsg
로 설치 가능
각 CLI 릴리스별 Formula 업데이트
- Formula 상단의
url
과sha256
해시는 매 릴리스마다 수동 업데이트가 번거로움, 태그 푸시나 GitHub 릴리스 생성조차 피로하다고 지적- Homebrew의
bump-formula-pr
명령이나 GitHub 액션으로 PR 생성 가능하지만, fork와 PR 프로세스가 불필요하게 복잡 - tap 소유자라면 main 브랜치에 직접 커밋하는 간단한 방법이 바람직
- Homebrew의
- 이를 피하기 위해 Formula 저장소에 GitHub 워크플로 추가 추천, 릴리스 시 자동으로 tap 업데이트
- 워크플로 예시를 복사하여 사용
- 설정 필요: GitHub 개인 액세스 토큰 (PAT) 생성 시
homebrew-tap
저장소에Content
→Write
권한 부여, Formula 저장소 Secrets에HOMEBREW_TAP_TOKEN
으로 저장 - 환경 변수로 tap과 Formula 지정 (예: 라인 13-15)
- GitHub 봇 계정 업데이트 추천:
GH_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com
,GH_NAME: github-actions[bot]
- 릴리스 생성 후
git push --tags
실행 시 몇 초 내 자동 업데이트, 사용자들은brew update
와brew upgrade imsg
로 업그레이드 가능
가장 좋은 점
- 이 과정은 복잡하지만, tap 설정과 하나의 Formula 예시 완료 후 추가 CLI 배포가 거의 사소해짐
- 몇 분 만에 새로운 Formula를 게시할 수 있어 편리
- Homebrew 공식 프로세스는 다소 복잡하지만, 자동화로 편해짐
- 각 도구 릴리스-배포 간의 번거로움을 줄이고, 다양한 언어 CLI까지 확장 지원 가능
- 실제로 또 다른 Formula를 게시할지는 미지수지만, 가능성이 열려 있어 만족스러움
Homebrew의 bump-formula-pr 명령이나 GitHub 액션으로 PR 생성 가능하지만, fork와 PR 프로세스가 불필요하게 복잡
--no-fork 옵션이 있어서 직접 브랜치 푸시하고 머지가 가능하며, 자동 업데이트 기능을 제공하고 있습니다.
Hacker News 의견
-
Homebrew의 네이밍 규칙이 가끔은 헷갈리게 느껴지기도 하지만, 전반적으로 정말 유용한 도구임을 계속 느끼고 있음
또한 자신의 tap을 만들어서 툴을 배포하는 과정이 이렇게 간단할 줄 몰랐음
언어별 패키지 매니저(예: uv)와 비교하면 어떤 점이 더 나은지 궁금함
특히 특정 생태계 안에 없는 사람에게 더 쉬운지, 즉 범용성 관점에서 우위가 있는지 알고 싶음-
고마움 전달하며, 패키지 레지스트리를 사용하는 다른 툴들은 대체로 계정 생성, 2단계 인증, 서명 과정 등이 필요함
Homebrew는 GitHub 약관(ToS)이 신뢰의 근거 역할을 하기에 전체적으로 훨씬 간소화됨
Homebrew 팀에서 이 방식 덕분에 많은 복잡함을 줄일 수 있음 -
Python 패키지 기준으로 이야기하면, uv같이 모든 걸 한 번에 패키징하려는 시도는 현실적으로 힘들음
그래서 일반적으로는 venv 환경에 고정된 의존성만 설치하는 방식을 사용함
구체적인 예시로는 이 포뮬라 참고 가능
uv에 관해서는, 공식 툴(brew update-python-resources, homebrew-pypi-poet)로 비공개 패키지를 지원해 보려 했지만 제대로 되지 않아서
직접 uvbrew를 만들어 리소스 생성을 돕도록 함
Homebrew에서 Python 포뮬라 작성 참고용 공식 문서 있음
-
-
Go 개발자라면 Goreleaser 툴을 추천함
개인 tap 내에서 바이너리 배포를 아주 쉽게 해줌(공식 core에는 금지된 방식임)- 최근에 알게 된 사실인데 Goreleaser가 이제 Go뿐 아니라 Rust, TypeScript, Python, Zig 등 여러 언어를 지원함
각 언어별 프로젝트 관리에서 활용도 높음
- 최근에 알게 된 사실인데 Goreleaser가 이제 Go뿐 아니라 Rust, TypeScript, Python, Zig 등 여러 언어를 지원함
-
개인적으로는, tap 쪽에서 직접 업데이트를 관리하는 게 좀 더 이상적이라고 생각함
일반적으로 upstream에서 업데이트하는 방식과 비슷함
이 워크플로우를 참고하면 소유하지 않은 포뮬라/캐스크도 쉽게 업데이트할 수 있음
brew bump
명령어로 모두 스캔하고, PR 만들어 올리면서brew test-bot
으로 테스트까지 자동화 가능함
실제 PR 예시는 여기 에 참고할 수 있음- 좋은 아이디어라고 생각함
평소엔 GitHub Actions 사용 시간이 아쉽다는 생각 때문에 엄두가 나지 않았는데, 오픈소스에서는 무료이니 이런 활용도 괜찮겠음
- 좋은 아이디어라고 생각함
-
나만의 Homebrew tap 버전 자동 bump 워크플로우로 homebrew-bump-revision을 직접 작성해 봄
여러 개인 프로젝트에서 이걸 잘 쓰고 있음- 멋져 보인다는 생각 전함
나는 귀찮아서 시도하지 않았지만 좋은 툴임
- 멋져 보인다는 생각 전함
-
Ruby Rogues 팟캐스트에서 Homebrew로 CLI 배포할 때의 각종 팁을 다룬 에피소드가 있었음
관련 에피소드 링크에서 더 많은 내용 들어볼 수 있음 -
Python 툴 패키징에 대해 흥미로운 점 발견함
일부 Python 패키지는 빌드 과정에서 의존성 루프가 발생해 Homebrew와 호환되지 않는 경우가 있음
pip는 바이너리 릴리스를 다운로드하므로 문제가 없지만, Homebrew는 모든 의존성까지 직접 빌드하므로 이 과정이 훨씬 오래 걸림
그래서 중간 크기 Python 프로젝트도 "bottle" 빌드에 한 시간이 넘게 걸릴 수 있음 -
나는 시스템 관리를 위해 nix를 사용하기 시작한 이후로 단 한 번도 후회하지 않았음
유일하게 아쉬운 점은 멀티플레이어 게임 때문에 windows에 의존해야 하는 부분 하나뿐임