-
-
Save ZPascal/b21c652b811872b3f56db9d54d61d6c6 to your computer and use it in GitHub Desktop.
| require "formula" | |
| require_relative "lib/private_strategy" | |
| class Hoge < Formula | |
| homepage "https://github.com/yourcompany/hoge" | |
| url "https://github.com/yourcompany/hoge/releases/download/v0.1.0/hoge_v0.1.0_darwin_amd64.tar.gz", :using => GitHubPrivateRepositoryReleaseDownloadStrategy | |
| sha256 "6de411ff3e4b1658a413dd6181fcXXXXXXXXXXXXXXXXXXXX" | |
| head "https://github.com/yourcompany/hoge.git" | |
| version "0.1.0" | |
| def install | |
| bin.install "hoge" | |
| end | |
| end |
| brew tap yourcompany/tap [email protected]:yourcompany/homebrew-tap.git | |
| export HOMEBREW_GITHUB_API_TOKEN=xxx | |
| brew install hoge |
| # Save this file as `lib/private_strategy.rb` | |
| # Add `require_relative "lib/private_strategy"` to your formula. | |
| # | |
| # This is based on the following, with minor fixes. | |
| # https://github.com/Homebrew/brew/blob/193af1442f6b9a19fa71325160d0ee2889a1b6c9/Library/Homebrew/compat/download_strategy.rb#L48-L157 | |
| # BSD 2-Clause License | |
| # | |
| # Copyright (c) 2009-present, Homebrew contributors | |
| # All rights reserved. | |
| # | |
| # Redistribution and use in source and binary forms, with or without | |
| # modification, are permitted provided that the following conditions are met: | |
| # | |
| # * Redistributions of source code must retain the above copyright notice, this | |
| # list of conditions and the following disclaimer. | |
| # | |
| # * Redistributions in binary form must reproduce the above copyright notice, | |
| # this list of conditions and the following disclaimer in the documentation | |
| # and/or other materials provided with the distribution. | |
| # | |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | |
| # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
| # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
| # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| # GitHubPrivateRepositoryDownloadStrategy downloads contents from GitHub | |
| # Private Repository. To use it, add | |
| # `:using => GitHubPrivateRepositoryDownloadStrategy` 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. This | |
| # strategy is suitable for corporate use just like S3DownloadStrategy, because | |
| # it lets you use a private GitHub repository for internal distribution. It | |
| # works with public one, but in that case simply use CurlDownloadStrategy. | |
| 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 | |
| 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::API::HTTPNotFoundError | |
| # We switched to GitHub::API::HTTPNotFoundError, | |
| # because we can now handle bad credentials messages | |
| 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 | |
| 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 | |
| #release_url = "https://api.github.com/repos/#{@owner}/#{@repo}/releases/tags/#{@tag}" | |
| #GitHub::API.open_rest(release_url) | |
| GitHub.get_release(@owner, @repo, @tag) | |
| end | |
| end |
I am not sure this is the exact place for it but has anyone using this seen an error Error: can't modify frozen class while using these scripts? I am running a brew install for a private github repo when I get this error. My google-fu is weak so taking a shot in the dark in case it is more widespread.
Hi @mtintes, could you please post the output of the --debug flag of the installation command?
One of coworkers ended up finding an answer (sort of). This was the original error. konductor is a cli written in go in this case.
➜ brew install konductor --debug --verbose
/opt/homebrew/Library/Homebrew/brew.rb (Formulary::FormulaLoader): loading /opt/homebrew/Library/Taps/<org>/homebrew-konductor/formula/konductor.rb
/opt/homebrew/Library/Homebrew/shims/shared/curl --disable --cookie /dev/null --globoff --show-error --user-agent Homebrew/3.6.4\ \(Macintosh\;\ arm64\ Mac\ OS\ X\ 12.5.1\)\ curl/7.79.1 --header Accept-Language:\ en --retry 3 --location https://api.github.com/repos/<org>/konductor --header Accept:\ application/vnd.github\+json --write-out '
'\%\{http_code\} --header Authorization:\ token\ ****** --dump-header /private/tmp/github_api_headers20221005-47324-1n0405m
/opt/homebrew/Library/Homebrew/shims/shared/curl --disable --cookie /dev/null --globoff --show-error --user-agent Homebrew/3.6.4\ \(Macintosh\;\ arm64\ Mac\ OS\ X\ 12.5.1\)\ curl/7.79.1 --header Accept-Language:\ en --retry 3 --location --silent --head --request GET https://github.com/<org>/konductor/releases/download/v1.17.9/konductor-osx-amd64.tar.gz
==> Downloading https://github.com/<org>/konductor/releases/download/v1.17.9/konductor-osx-amd64.tar.gz
/opt/homebrew/Library/Homebrew/shims/shared/curl --disable --cookie /dev/null --globoff --show-error --user-agent Homebrew/3.6.4\ \(Macintosh\;\ arm64\ Mac\ OS\ X\ 12.5.1\)\ curl/7.79.1 --header Accept-Language:\ en --retry 3 --location https://api.github.com/repos/<org>/konductor/releases/tags/v1.17.9 --header Accept:\ application/vnd.github\+json --write-out '
'\%\{http_code\} --header Authorization:\ token\ ****** --dump-header /private/tmp/github_api_headers20221005-47324-f7o4v1
/opt/homebrew/Library/Homebrew/shims/shared/curl --disable --cookie /dev/null --globoff --show-error --user-agent Homebrew/3.6.4\ \(Macintosh\;\ arm64\ Mac\ OS\ X\ 12.5.1\)\ curl/7.79.1 --header Accept-Language:\ en --fail --retry 3 --location --remote-time --output /Users/miketintes/Library/Caches/Homebrew/downloads/e21e5b9112fcd59c4caec2c40316e0fe0c08cab973ba491d5ccd1460569812b8--konductor-osx-amd64.tar.gz.incomplete https://******@api.github.com/repos/<org>/konductor/releases/assets/79035814 --header Accept:\ application/octet-stream
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
100 30.6M 100 30.6M 0 0 13.2M 0 0:00:02 0:00:02 --:--:-- 16.4M
==> Verifying checksum for 'e21e5b9112fcd59c4caec2c40316e0fe0c08cab973ba491d5ccd1460569812b8--konductor-osx-amd64.tar.gz'
==> Installing konductor from <org>/konductor
/opt/homebrew/Library/Homebrew/brew.rb (Formulary::TapLoader): loading /opt/homebrew/Library/Taps/<org>/homebrew-konductor/Formula/konductor.rb
Error: can't modify frozen class
/opt/homebrew/Library/Taps/<org>/homebrew-konductor/Formula/lib/private_strategy.rb:98:in `<class:GitHubPrivateRepositoryReleaseDownloadStrategy>'
/opt/homebrew/Library/Taps/<org>/homebrew-konductor/Formula/lib/private_strategy.rb:97:in `<top (required)>'
/opt/homebrew/Library/Taps/<org>/homebrew-konductor/Formula/konductor.rb:2:in `require_relative'
/opt/homebrew/Library/Taps/<org>/homebrew-konductor/Formula/konductor.rb:2:in `block in load_formula'
/opt/homebrew/Library/Homebrew/formulary.rb:90:in `module_eval'
/opt/homebrew/Library/Homebrew/formulary.rb:90:in `block in load_formula'
/opt/homebrew/Library/Homebrew/formulary.rb:102:in `load_formula'
/opt/homebrew/Library/Homebrew/formulary.rb:122:in `load_formula_from_path'
/opt/homebrew/Library/Homebrew/formulary.rb:321:in `load_file'
/opt/homebrew/Library/Homebrew/formulary.rb:478:in `load_file'
/opt/homebrew/Library/Homebrew/formulary.rb:311:in `klass'
/opt/homebrew/Library/Homebrew/formulary.rb:306:in `get_formula'
/opt/homebrew/Library/Homebrew/formulary.rb:468:in `get_formula'
/opt/homebrew/Library/Homebrew/formulary.rb:560:in `factory'
/opt/homebrew/Library/Homebrew/formula_installer.rb:374:in `install'
/opt/homebrew/Library/Homebrew/upgrade.rb:212:in `install_formula'
/opt/homebrew/Library/Homebrew/install.rb:333:in `install_formula'
/opt/homebrew/Library/Homebrew/install.rb:323:in `block in install_formulae'
/opt/homebrew/Library/Homebrew/install.rb:322:in `each'
/opt/homebrew/Library/Homebrew/install.rb:322:in `install_formulae'
/opt/homebrew/Library/Homebrew/cmd/install.rb:226:in `install'
/opt/homebrew/Library/Homebrew/brew.rb:95:in `<main>'
We had to copy a bunch of old code from homebrew that looks like it got deprecated and put that in the private strategy. This is a copy of that. No idea if that is the best path since neither of us does anything with ruby.
For anyone recently having issues with this, see Homebrew/brew#15169. CurlDownloadStrategy changed a bit.
This fix worked for me.
For anyone recently having issues with this, see Homebrew/brew#15169.
CurlDownloadStrategychanged a bit.This fix worked for me.
It worked for me too. Thanks for sharing.
I'm not sure when Homebrew added it, but it looks like they now have a GitHub::API.credentials helper, documented here:https://rubydoc.brew.sh/GitHub/API.html#credentials-class_method. Admittedly this says it's a private API, so YMMV.
This helper looked for a token in 3 separate sources:
- An env var named
HOMEBREW_GITHUB_API_TOKEN - The token managed by the
ghutility (i.e. what you get when you dogh auth login) - A GitHub username/password combo kept in the MacOS keystore
I already use the gh utility, which makes it a lot more seamless than having to provide a PAT every time I wanted to update. I used the above strategy, but with one tweak:
def set_github_token
# See https://rubydoc.brew.sh/GitHub/API.html#credentials-class_method
@github_token = GitHub::API.credentials
raise CurlDownloadStrategyError, "A GitHub token is required. Either set HOMEBREW_GITHUB_API_TOKEN or login with: gh auth login" if @github_token.nil? || @github_token.empty?
validate_github_repository_access!
end
Hi @alejakun, great to hear that now everything works as aspected.