|
| 1 | +require "download_strategy" |
| 2 | +require "shellwords" |
| 3 | +require "utils/curl" |
| 4 | + |
| 5 | +class GitHubPrivateRepositoryReleaseDownloadStrategy < AbstractFileDownloadStrategy |
| 6 | + def initialize(url, name, version, **meta) |
| 7 | + super |
| 8 | + @github_token = ENV["HOMEBREW_GITHUB_API_TOKEN"] |
| 9 | + parse_url_pattern |
| 10 | + end |
| 11 | + |
| 12 | + def resolved_basename |
| 13 | + super.gsub(' ', '+') |
| 14 | + end |
| 15 | + |
| 16 | + def parse_url_pattern |
| 17 | + url_pattern = |
| 18 | + %r{https://github.com/([^/]+)/([^/]+)/releases/download/([^/]+)/(\S+)} |
| 19 | + unless @url =~ url_pattern |
| 20 | + raise CurlDownloadStrategyError, "Invalid url pattern for GitHub Release." |
| 21 | + end |
| 22 | + |
| 23 | + _, @owner, @repo, @tag, @filename = *@url.match(url_pattern) |
| 24 | + end |
| 25 | + |
| 26 | + def fetch(timeout: nil) |
| 27 | + if cached_location.exist? |
| 28 | + ohai "Already downloaded: #{cached_location}" |
| 29 | + else |
| 30 | + if @github_token != nil |
| 31 | + ohai "PAT found... using it" |
| 32 | + asset_url = |
| 33 | + "https://api.github.com/repos/#{@owner}/#{@repo}/releases/assets/#{asset_id}" |
| 34 | + |
| 35 | + ::Utils::Curl.curl_download asset_url, |
| 36 | + "--header", |
| 37 | + "Authorization: Bearer #{@github_token}", |
| 38 | + "--header", |
| 39 | + "X-GitHub-Api-Version: 2022-11-28", |
| 40 | + "--header", |
| 41 | + "Accept: application/octet-stream", |
| 42 | + to: temporary_path |
| 43 | + else |
| 44 | + ohai "Downloading to: #{Shellwords.escape(temporary_path.to_s)}" |
| 45 | + cmd = |
| 46 | + "gh --repo=#{@owner}/#{@repo} release download #{@tag} --pattern=#{@filename} --output=#{Shellwords.escape(temporary_path.to_s)} --clobber" |
| 47 | + puts `export PATH=$PATH:/opt/homebrew/bin:/usr/local/bin:~/.local/bin && #{cmd}` |
| 48 | + if not $?.success? |
| 49 | + raise CurlDownloadStrategyError, "You may need to run 'gh auth login' or 'gh auth refresh' to login to GitHub." |
| 50 | + end |
| 51 | + end |
| 52 | + |
| 53 | + ignore_interrupts { temporary_path.rename(cached_location) } |
| 54 | + end |
| 55 | + end |
| 56 | + |
| 57 | + def clear_cache |
| 58 | + super |
| 59 | + rm_rf(temporary_path) |
| 60 | + end |
| 61 | + |
| 62 | + private |
| 63 | + |
| 64 | + def asset_id |
| 65 | + @asset_id ||= resolve_asset_id |
| 66 | + end |
| 67 | + |
| 68 | + def resolve_asset_id |
| 69 | + release_metadata = fetch_release_metadata |
| 70 | + assets = release_metadata["assets"].select { |a| a["name"] == @filename } |
| 71 | + raise CurlDownloadStrategyError, "Asset file not found." if assets.empty? |
| 72 | + |
| 73 | + assets.first["id"] |
| 74 | + end |
| 75 | + |
| 76 | + def fetch_release_metadata |
| 77 | + release_url = |
| 78 | + "https://api.github.com/repos/#{@owner}/#{@repo}/releases/tags/#{@tag}" |
| 79 | + GitHub::API.open_rest(release_url) |
| 80 | + end |
| 81 | +end |
0 commit comments