비공개 GitHub 리포지토리를 위한 Homebrew Tap 생성

17448 단어
저는 2022년 7월에 새 직장을 시작했습니다. 개발자 경험은 훌륭하지만 새 직장에서 놓친 것 중 하나는 모든 것을 지배하는 CLI였습니다(예전 직장에서 그랬던 것처럼). go 및 cobra 을 사용하여 쉽게 확장 가능한 CLI 도구를 구축할 생각이었습니다. 엔지니어에게 배포를 처리하기 위해 go installhomebrew 을 모두 사용하기로 결정했습니다.

Homebrew는 macOS 및 Linux 사용자에게 매우 인기 있는 패키지 관리자입니다. 사용자는 brew install [PACKAGE]를 사용하여 새 패키지를 쉽게 설치할 수 있습니다. Homebrew는 적절한 디렉토리에 대한 패키지 다운로드 및 설치를 처리한 다음 (Intel 시스템에서) /usr/local에 대한 심볼릭 링크를 생성합니다.

Homebrew 패키지를 만들기 위해 Formulas라는 Ruby 클래스를 만듭니다. 수식은 다음과 같습니다.

class Wget < Formula
  homepage "https://www.gnu.org/software/wget/"
  url "https://ftp.gnu.org/gnu/wget/wget-1.15.tar.gz"
  sha256 "52126be8cf1bddd7536886e74c053ad7d0ed2aa89b4b630f76785bac21695fcd"

  def install
    system "./configure", "--prefix=#{prefix}"
    system "make", "install"
  end
end


오픈 소스 패키지를 추가하는 것은 매우 간단하지만 비공개 패키지를 사용하여 동일한 작업을 수행하려면 약간의 해킹이 필요합니다.

첫 번째 단계



가장 먼저 해야 할 일은 Github 릴리스를 만드는 것입니다. go를 사용하는 경우 goreleaser을 사용하는 것이 좋습니다. 그 방법에 대한 자습서를 작성했습니다here. 진정으로 릴리스를 쉽게 만듭니다. 다른 언어를 사용하는 경우 GitHubhere에서 릴리스를 관리하는 방법을 확인해야 합니다.

홈브류 탭 만들기



다음으로 할 일은 Homebrew tap 을 만드는 것입니다. Homebrew 탭은 공식을 보관하는 GitHub 저장소입니다. 비 Homebrew 코어 탭을 추가하려면 brew tap username/package 를 사용하여 homebrew에 로컬로 탭을 추가해야 합니다.brew tap의 단일 인수 형식을 사용하려면 GitHub 저장소가 homebrew-tap로 시작해야 하므로 naming convention을 따르고 GitHub 저장소의 이름을 homebrew-로 지정해야 합니다.

수식 만들기



Github에 이미 릴리스가 있는 경우 Formula 생성을 진행할 수 있습니다. homebrew-tap 리포지토리에서 Formula 라는 폴더를 만듭니다. Formula 디렉토리에서 mytool.rb라는 파일을 생성합니다.

이제 Formula 에서는 패키지가 개인 저장소에서 호스팅되기 때문에 패키지를 다운로드하는 표준 방법을 사용할 수 없습니다. 이를 위해 다음과 같은 새로운 다운로드 전략을 추가하기만 하면 됩니다.

require "formula"
require_relative "../custom_download_strategy.rb"

class Wget < Formula
  homepage "https://www.gnu.org/software/wget/"
  url "https://ftp.gnu.org/gnu/wget/wget-1.15.tar.gz", :using => GitHubPrivateRepositoryReleaseDownloadStrategy 
  sha256 "52126be8cf1bddd7536886e74c053ad7d0ed2aa89b4b630f76785bac21695fcd"

  def install
    system "./configure", "--prefix=#{prefix}"
    system "make", "install"
  end

  test do
      system "#{bin}/wget --help"
  end
end


클래스의 세 번째 줄에 추가된 , :using => GitHubPrivateRepositoryReleaseDownloadStrategy에 유의하십시오.
homebrew-tap 의 루트 폴더에 custom_download_strategy.rb 라는 새 파일을 만듭니다. 여기에서 다운로드 전략을 지원하기 위해 몇 가지 코드를 추가합니다.

require "download_strategy"

class GitHubPrivateRepositoryDownloadStrategy < CurlDownloadStrategy
  require "utils/formatter"
  require "utils/github"

  def initialize(url, name, version, **meta)
    super
    parse_url_pattern
    set_github_token
  end

  def parse_url_pattern
    unless match = url.match(%r{https://github.com/([^/]+)/([^/]+)/(\S+)})
      raise CurlDownloadStrategyError, "Invalid url pattern for GitHub Repository."
    end

    _, @owner, @repo, @filepath = *match
  end

  def download_url
    "https://#{@github_token}@github.com/#{@owner}/#{@repo}/#{@filepath}"
  end

  private

  def _fetch(url:, resolved_url:, timeout:)
    curl_download download_url, to: temporary_path, timeout: timeout
  end

  def set_github_token
    @github_token = ENV["HOMEBREW_GITHUB_API_TOKEN"]
    unless @github_token
      raise CurlDownloadStrategyError, "Environmental variable HOMEBREW_GITHUB_API_TOKEN is required."
    end

    validate_github_repository_access!
  end

  def validate_github_repository_access!
    # Test access to the repository
    GitHub.repository(@owner, @repo)
  rescue GitHub::HTTPNotFoundError
    # We only handle HTTPNotFoundError here,
    # becase AuthenticationFailedError is handled within util/github.
    message = <<~EOS
      HOMEBREW_GITHUB_API_TOKEN can not access the repository: #{@owner}/#{@repo}
      This token may not have permission to access the repository or the url of formula may be incorrect.
    EOS
    raise CurlDownloadStrategyError, message
  end
end

# GitHubPrivateRepositoryReleaseDownloadStrategy downloads tarballs from GitHub
# Release assets. To use it, add
# `:using => GitHubPrivateRepositoryReleaseDownloadStrategy` to the URL section of
# your formula. This download strategy uses GitHub access tokens (in the
# environment variables HOMEBREW_GITHUB_API_TOKEN) to sign the request.
class GitHubPrivateRepositoryReleaseDownloadStrategy < GitHubPrivateRepositoryDownloadStrategy
  def initialize(url, name, version, **meta)
    super
  end

  def parse_url_pattern
    url_pattern = %r{https://github.com/([^/]+)/([^/]+)/releases/download/([^/]+)/(\S+)}
    unless @url =~ url_pattern
      raise CurlDownloadStrategyError, "Invalid url pattern for GitHub Release."
    end

    _, @owner, @repo, @tag, @filename = *@url.match(url_pattern)
  end

  def download_url
    "https://#{@github_token}@api.github.com/repos/#{@owner}/#{@repo}/releases/assets/#{asset_id}"
  end

  private

  def _fetch(url:, resolved_url:, timeout:)
    # HTTP request header `Accept: application/octet-stream` is required.
    # Without this, the GitHub API will respond with metadata, not binary.
    curl_download download_url, "--header", "Accept: application/octet-stream", to: temporary_path, timeout: timeout
  end

  def asset_id
    @asset_id ||= resolve_asset_id
  end

  def resolve_asset_id
    release_metadata = fetch_release_metadata
    assets = release_metadata["assets"].select { |a| a["name"] == @filename }
    raise CurlDownloadStrategyError, "Asset file not found." if assets.empty?

    assets.first["id"]
  end

  def fetch_release_metadata
    GitHub.get_release(@owner, @repo, @tag)
  end
end



다음과 같은 폴더 구조가 있어야 합니다.

├── homebrew-tap
│   ├── Formula
│   │   ├── mytool.rb
└── custom_download_strategy.rb


용법



거의 끝났습니다. Homebrew를 통해 도구를 설치하려면 개인 리포지토리에 대한 액세스를 제공하는 Github 토큰을 내보내야 합니다. 새 토큰을 생성할 수 있습니다here. 토큰에는 repo 권한이 있어야 합니다. 토큰을 HOMEBREW_GITHUB_API_TOKEN로 내보내야 합니다. 토큰을 내보내려면 다음을 실행합니다.

export HOMEBREW_GITHUB_API_TOKEN=<GITHUB_TOKEN>
# if you're using fish shell like me, run `set -x HOMEBREW_GITHUB_API_TOKEN <GITHUB_TOKEN>`


그런 다음 다음 명령을 실행할 수 있습니다.

brew install username/homebrew-tap/mytool


이렇게 하면 홈브류 탭이 자동으로 추가되고 도구가 설치됩니다.

요약


  • 바이너리로 GitHub 릴리스를 만듭니다. 이것은 go의 경우 goreleaser를 사용하여 매우 쉽게 수행할 수 있습니다.
  • homebrew-tap라는 GitHub 저장소를 만듭니다. 예는 here 입니다.
  • Formula 폴더를 만듭니다.
  • repo의 루트에서 custom_download_strategy.rb라는 파일을 만듭니다. 내용은 위에 나와 있습니다
  • Formula 폴더에서 도구 이름이 mytool.rb인 ruby ​​파일을 만듭니다.

  • GitHub 토큰here을 생성하고 토큰에 대한 권한repo을 부여합니다.
  • export HOMEBREW_GITHUB_API_TOKEN=<GITHUB_TOKEN>로 토큰 내보내기
  • brew install username/homebrew-tap/mytool를 사용하여 추출과 함께 도구를 설치합니다.
  • 좋은 웹페이지 즐겨찾기