2021-08-06 02:30:44 -04:00
|
|
|
# typed: false
|
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
require "api/analytics"
|
|
|
|
require "api/cask"
|
|
|
|
require "api/formula"
|
2021-08-09 10:29:55 -04:00
|
|
|
require "extend/cachable"
|
2021-08-06 02:30:44 -04:00
|
|
|
|
|
|
|
module Homebrew
|
|
|
|
# Helper functions for using Homebrew's formulae.brew.sh API.
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
module API
|
|
|
|
extend T::Sig
|
|
|
|
|
2021-08-09 10:29:55 -04:00
|
|
|
extend Cachable
|
|
|
|
|
2021-08-06 02:30:44 -04:00
|
|
|
module_function
|
|
|
|
|
2021-12-07 00:13:56 +00:00
|
|
|
HOMEBREW_CACHE_API = (HOMEBREW_CACHE/"api").freeze
|
2023-02-03 10:22:50 +00:00
|
|
|
|
2023-01-26 17:36:40 +00:00
|
|
|
sig { params(endpoint: String).returns(Hash) }
|
|
|
|
def fetch(endpoint)
|
2021-08-09 10:29:55 -04:00
|
|
|
return cache[endpoint] if cache.present? && cache.key?(endpoint)
|
2021-08-06 02:30:44 -04:00
|
|
|
|
2023-02-03 14:10:40 +00:00
|
|
|
api_url = "#{Homebrew::EnvConfig.api_domain}/#{endpoint}"
|
2023-02-03 10:22:50 +00:00
|
|
|
output = Utils::Curl.curl_output("--fail", api_url)
|
2023-02-03 14:10:40 +00:00
|
|
|
if !output.success? && Homebrew::EnvConfig.api_domain != HOMEBREW_API_DEFAULT_DOMAIN
|
|
|
|
# Fall back to the default API domain and try again
|
|
|
|
api_url = "#{HOMEBREW_API_DEFAULT_DOMAIN}/#{endpoint}"
|
|
|
|
output = Utils::Curl.curl_output("--fail", api_url)
|
|
|
|
end
|
2021-08-06 02:30:44 -04:00
|
|
|
raise ArgumentError, "No file found at #{Tty.underline}#{api_url}#{Tty.reset}" unless output.success?
|
|
|
|
|
2023-01-26 17:36:40 +00:00
|
|
|
cache[endpoint] = JSON.parse(output.stdout)
|
2021-08-06 02:30:44 -04:00
|
|
|
rescue JSON::ParserError
|
|
|
|
raise ArgumentError, "Invalid JSON file: #{Tty.underline}#{api_url}#{Tty.reset}"
|
|
|
|
end
|
2022-12-30 01:01:52 -05:00
|
|
|
|
2023-01-26 17:36:40 +00:00
|
|
|
sig { params(endpoint: String, target: Pathname).returns(Hash) }
|
2022-12-30 01:01:52 -05:00
|
|
|
def fetch_json_api_file(endpoint, target:)
|
|
|
|
retry_count = 0
|
2023-02-03 14:10:40 +00:00
|
|
|
url = "#{Homebrew::EnvConfig.api_domain}/#{endpoint}"
|
|
|
|
default_url = "#{HOMEBREW_API_DEFAULT_DOMAIN}/#{endpoint}"
|
2023-02-10 19:15:31 +00:00
|
|
|
|
|
|
|
# TODO: consider using more of Utils::Curl
|
2023-02-10 17:27:10 +00:00
|
|
|
curl_args = %W[
|
|
|
|
--compressed
|
|
|
|
--speed-limit #{ENV.fetch("HOMEBREW_CURL_SPEED_LIMIT")}
|
|
|
|
--speed-time #{ENV.fetch("HOMEBREW_CURL_SPEED_TIME")}
|
|
|
|
]
|
2023-02-10 19:15:31 +00:00
|
|
|
curl_args << "--progress-bar" unless Context.current.verbose?
|
|
|
|
curl_args << "--verbose" if Homebrew::EnvConfig.curl_verbose?
|
|
|
|
curl_args << "--silent" unless $stdout.tty?
|
|
|
|
|
|
|
|
skip_download = target.exist? &&
|
|
|
|
!target.empty? &&
|
|
|
|
(Homebrew::EnvConfig.no_auto_update? ||
|
|
|
|
((Time.now - Homebrew::EnvConfig.api_auto_update_secs.to_i) < target.mtime))
|
2023-02-03 10:22:50 +00:00
|
|
|
|
2022-12-30 01:01:52 -05:00
|
|
|
begin
|
2023-02-04 13:22:15 +01:00
|
|
|
begin
|
2023-02-09 18:26:37 +00:00
|
|
|
args = curl_args.dup
|
|
|
|
args.prepend("--time-cond", target) if target.exist? && !target.empty?
|
2023-02-10 19:15:31 +00:00
|
|
|
unless skip_download
|
|
|
|
ohai "Downloading #{url}" if $stdout.tty?
|
|
|
|
# Disable retries here, we handle them ourselves below.
|
|
|
|
Utils::Curl.curl_download(*args, url, to: target, retries: 0, show_error: false)
|
|
|
|
end
|
2023-02-04 13:22:15 +01:00
|
|
|
rescue ErrorDuringExecution
|
2023-02-03 14:10:40 +00:00
|
|
|
if url == default_url
|
|
|
|
raise unless target.exist?
|
|
|
|
raise if target.empty?
|
|
|
|
elsif retry_count.zero? || !target.exist? || target.empty?
|
|
|
|
# Fall back to the default API domain and try again
|
|
|
|
# This block will be executed only once, because we set `url` to `default_url`
|
|
|
|
url = default_url
|
|
|
|
target.unlink if target.exist? && target.empty?
|
2023-02-10 19:15:31 +00:00
|
|
|
skip_download = false
|
2023-02-03 14:10:40 +00:00
|
|
|
|
|
|
|
retry
|
|
|
|
end
|
2022-12-30 01:01:52 -05:00
|
|
|
|
2023-02-04 13:22:15 +01:00
|
|
|
opoo "#{target.basename}: update failed, falling back to cached version."
|
|
|
|
end
|
2023-02-03 10:22:50 +00:00
|
|
|
|
2023-02-10 19:15:31 +00:00
|
|
|
FileUtils.touch target
|
2023-02-04 01:46:50 +01:00
|
|
|
JSON.parse(target.read)
|
2022-12-30 01:01:52 -05:00
|
|
|
rescue JSON::ParserError
|
|
|
|
target.unlink
|
|
|
|
retry_count += 1
|
2023-02-10 19:15:31 +00:00
|
|
|
skip_download = false
|
2023-02-03 10:22:50 +00:00
|
|
|
odie "Cannot download non-corrupt #{url}!" if retry_count > Homebrew::EnvConfig.curl_retries.to_i
|
2022-12-30 01:01:52 -05:00
|
|
|
|
|
|
|
retry
|
|
|
|
end
|
|
|
|
end
|
2023-01-26 17:36:40 +00:00
|
|
|
|
2023-01-28 02:16:09 -06:00
|
|
|
sig { params(filepath: String, repo: String, git_head: T.nilable(String)).returns(String) }
|
2023-01-28 02:15:00 -06:00
|
|
|
def fetch_file_source(filepath, repo:, git_head: nil)
|
2023-01-26 17:36:40 +00:00
|
|
|
git_head ||= "master"
|
2023-01-28 02:15:00 -06:00
|
|
|
endpoint = "#{git_head}/#{filepath}"
|
2023-01-26 17:36:40 +00:00
|
|
|
return cache[endpoint] if cache.present? && cache.key?(endpoint)
|
|
|
|
|
2023-01-28 02:15:00 -06:00
|
|
|
raw_url = "https://raw.githubusercontent.com/#{repo}/#{endpoint}"
|
2023-02-03 10:22:50 +00:00
|
|
|
output = Utils::Curl.curl_output("--fail", raw_url)
|
2023-01-26 17:36:40 +00:00
|
|
|
raise ArgumentError, "No file found at #{Tty.underline}#{raw_url}#{Tty.reset}" unless output.success?
|
|
|
|
|
|
|
|
cache[endpoint] = output.stdout
|
|
|
|
end
|
2023-02-10 12:07:36 -05:00
|
|
|
|
|
|
|
sig { params(json: Hash).returns(Hash) }
|
|
|
|
def merge_variations(json)
|
|
|
|
if (bottle_tag = ::Utils::Bottles.tag.to_s.presence) &&
|
|
|
|
(variations = json["variations"].presence) &&
|
|
|
|
(variation = variations[bottle_tag].presence)
|
|
|
|
json = json.merge(variation)
|
|
|
|
end
|
|
|
|
|
|
|
|
json.except("variations")
|
|
|
|
end
|
2021-08-06 02:30:44 -04:00
|
|
|
end
|
|
|
|
end
|