mirror of
https://github.com/Homebrew/brew.git
synced 2025-07-14 16:09:03 +08:00
Support offline usage under HOMEBREW_INSTALL_FROM_API
This commit is contained in:
parent
b49949dc01
commit
1d36c42fb7
@ -21,6 +21,7 @@ module Homebrew
|
|||||||
module_function
|
module_function
|
||||||
|
|
||||||
API_DOMAIN = "https://formulae.brew.sh/api"
|
API_DOMAIN = "https://formulae.brew.sh/api"
|
||||||
|
HOMEBREW_CACHE_API = (HOMEBREW_CACHE/"api").freeze
|
||||||
|
|
||||||
sig { params(endpoint: String, json: T::Boolean).returns(T.any(String, Hash)) }
|
sig { params(endpoint: String, json: T::Boolean).returns(T.any(String, Hash)) }
|
||||||
def fetch(endpoint, json: true)
|
def fetch(endpoint, json: true)
|
||||||
|
@ -20,6 +20,17 @@ module Homebrew
|
|||||||
def fetch(name)
|
def fetch(name)
|
||||||
Homebrew::API.fetch "#{formula_api_path}/#{name}.json"
|
Homebrew::API.fetch "#{formula_api_path}/#{name}.json"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { returns(Array) }
|
||||||
|
def all_formulae
|
||||||
|
@all_formulae ||= begin
|
||||||
|
json_formulae = JSON.parse((HOMEBREW_CACHE_API/"#{formula_api_path}.json").read)
|
||||||
|
|
||||||
|
json_formulae.to_h do |json_formula|
|
||||||
|
[json_formula["name"], json_formula.except("name")]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -764,7 +764,7 @@ then
|
|||||||
export HOMEBREW_DEVELOPER_MODE="1"
|
export HOMEBREW_DEVELOPER_MODE="1"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "${HOMEBREW_INSTALL_FROM_API}" && -n "${HOMEBREW_DEVELOPER_COMMAND}" ]]
|
if [[ -n "${HOMEBREW_INSTALL_FROM_API}" && -n "${HOMEBREW_DEVELOPER_COMMAND}" && "${HOMEBREW_COMMAND}" != "irb" ]]
|
||||||
then
|
then
|
||||||
odie "Developer commands cannot be run while HOMEBREW_INSTALL_FROM_API is set!"
|
odie "Developer commands cannot be run while HOMEBREW_INSTALL_FROM_API is set!"
|
||||||
elif [[ -n "${HOMEBREW_INSTALL_FROM_API}" && -n "${HOMEBREW_DEVELOPER_MODE}" ]]
|
elif [[ -n "${HOMEBREW_INSTALL_FROM_API}" && -n "${HOMEBREW_DEVELOPER_MODE}" ]]
|
||||||
|
@ -94,11 +94,6 @@ module Homebrew
|
|||||||
unreadable_error = nil
|
unreadable_error = nil
|
||||||
|
|
||||||
if only != :cask
|
if only != :cask
|
||||||
if prefer_loading_from_api && Homebrew::EnvConfig.install_from_api? &&
|
|
||||||
Homebrew::API::Bottle.available?(name)
|
|
||||||
Homebrew::API::Bottle.fetch_bottles(name)
|
|
||||||
end
|
|
||||||
|
|
||||||
begin
|
begin
|
||||||
formula = case method
|
formula = case method
|
||||||
when nil, :factory
|
when nil, :factory
|
||||||
|
@ -252,16 +252,7 @@ module Homebrew
|
|||||||
def info_formula(f, args:)
|
def info_formula(f, args:)
|
||||||
specs = []
|
specs = []
|
||||||
|
|
||||||
if Homebrew::EnvConfig.install_from_api? && Homebrew::API::Bottle.available?(f.name)
|
if (stable = f.stable)
|
||||||
info = Homebrew::API::Bottle.fetch(f.name)
|
|
||||||
|
|
||||||
latest_version = info["pkg_version"].split("_").first
|
|
||||||
bottle_exists = info["bottles"].key?(Utils::Bottles.tag.to_s) || info["bottles"].key?("all")
|
|
||||||
|
|
||||||
s = "stable #{latest_version}"
|
|
||||||
s += " (bottled)" if bottle_exists
|
|
||||||
specs << s
|
|
||||||
elsif (stable = f.stable)
|
|
||||||
s = "stable #{stable.version}"
|
s = "stable #{stable.version}"
|
||||||
s += " (bottled)" if stable.bottled? && f.pour_bottle?
|
s += " (bottled)" if stable.bottled? && f.pour_bottle?
|
||||||
specs << s
|
specs << s
|
||||||
|
@ -745,6 +745,20 @@ EOS
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
if [[ -n "${HOMEBREW_INSTALL_FROM_API}" ]]
|
||||||
|
then
|
||||||
|
mkdir -p "${HOMEBREW_CACHE}/api"
|
||||||
|
# TODO: etags?
|
||||||
|
curl \
|
||||||
|
"${CURL_DISABLE_CURLRC_ARGS[@]}" \
|
||||||
|
--fail --compressed --silent --max-time 5 \
|
||||||
|
--location --output "${HOMEBREW_CACHE}/api/formula.json" \
|
||||||
|
--user-agent "${HOMEBREW_USER_AGENT_CURL}" \
|
||||||
|
"https://formulae.brew.sh/api/formula.json"
|
||||||
|
# TODO: we probably want to print an error if this fails.
|
||||||
|
# TODO: set HOMEBREW_UPDATED or HOMEBREW_UPDATE_FAILED
|
||||||
|
fi
|
||||||
|
|
||||||
safe_cd "${HOMEBREW_REPOSITORY}"
|
safe_cd "${HOMEBREW_REPOSITORY}"
|
||||||
|
|
||||||
# HOMEBREW_UPDATE_AUTO wasn't modified in subshell.
|
# HOMEBREW_UPDATE_AUTO wasn't modified in subshell.
|
||||||
|
@ -161,19 +161,6 @@ module Homebrew
|
|||||||
puts pinned.map { |f| "#{f.full_specified_name} #{f.pkg_version}" } * ", "
|
puts pinned.map { |f| "#{f.full_specified_name} #{f.pkg_version}" } * ", "
|
||||||
end
|
end
|
||||||
|
|
||||||
if Homebrew::EnvConfig.install_from_api?
|
|
||||||
formulae_to_install.map! do |formula|
|
|
||||||
next formula if formula.head?
|
|
||||||
next formula if formula.tap.present? && !formula.core_formula?
|
|
||||||
next formula unless Homebrew::API::Bottle.available?(formula.name)
|
|
||||||
|
|
||||||
Homebrew::API::Bottle.fetch_bottles(formula.name)
|
|
||||||
Formulary.factory(formula.name)
|
|
||||||
rescue FormulaUnavailableError
|
|
||||||
formula
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if formulae_to_install.empty?
|
if formulae_to_install.empty?
|
||||||
oh1 "No packages to upgrade"
|
oh1 "No packages to upgrade"
|
||||||
else
|
else
|
||||||
|
@ -6,6 +6,8 @@ require "extend/cachable"
|
|||||||
require "tab"
|
require "tab"
|
||||||
require "utils/bottles"
|
require "utils/bottles"
|
||||||
|
|
||||||
|
require "active_support/core_ext/hash/deep_transform_values"
|
||||||
|
|
||||||
# The {Formulary} is responsible for creating instances of {Formula}.
|
# The {Formulary} is responsible for creating instances of {Formula}.
|
||||||
# It is not meant to be used directly from formulae.
|
# It is not meant to be used directly from formulae.
|
||||||
#
|
#
|
||||||
@ -44,6 +46,8 @@ module Formulary
|
|||||||
remove_const(namespace.demodulize)
|
remove_const(namespace.demodulize)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
remove_const("FormulaNamespaceAPI")
|
||||||
|
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -392,6 +396,102 @@ module Formulary
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Load formulae from the API.
|
||||||
|
class FormulaAPILoader < FormulaLoader
|
||||||
|
def initialize(name)
|
||||||
|
super name, Formulary.core_path(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def klass(flags:, ignore_errors:)
|
||||||
|
namespace = "FormulaNamespaceAPI"
|
||||||
|
mod = if Formulary.const_defined?(namespace)
|
||||||
|
Formulary.const_get(namespace)
|
||||||
|
else
|
||||||
|
Formulary.const_set(namespace, Module.new)
|
||||||
|
end
|
||||||
|
|
||||||
|
mod.send(:remove_const, :BUILD_FLAGS) if mod.const_defined?(:BUILD_FLAGS)
|
||||||
|
mod.const_set(:BUILD_FLAGS, flags)
|
||||||
|
|
||||||
|
class_s = Formulary.class_s(name)
|
||||||
|
if mod.const_defined?(class_s)
|
||||||
|
mod.const_get(class_s)
|
||||||
|
else
|
||||||
|
json_formula = Homebrew::API::Formula.all_formulae[name]
|
||||||
|
klass = Class.new(::Formula) do
|
||||||
|
desc json_formula["desc"]
|
||||||
|
homepage json_formula["homepage"]
|
||||||
|
license json_formula["license"]
|
||||||
|
revision json_formula["revision"]
|
||||||
|
version_scheme json_formula["version_scheme"]
|
||||||
|
|
||||||
|
if (urls_stable = json_formula["urls"]["stable"]).present?
|
||||||
|
stable do
|
||||||
|
url urls_stable["url"]
|
||||||
|
version json_formula["versions"]["stable"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (bottles_stable = json_formula["bottle"]["stable"]).present?
|
||||||
|
bottle do
|
||||||
|
root_url bottles_stable["root_url"]
|
||||||
|
bottles_stable["files"].each do |tag, bottle_spec|
|
||||||
|
cellar = bottle_spec["cellar"]
|
||||||
|
cellar = cellar[1..].to_sym if cellar.start_with?(":")
|
||||||
|
sha256 cellar: cellar, tag.to_sym => bottle_spec["sha256"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (keg_only_reason = json_formula["keg_only_reason"]).present?
|
||||||
|
reason = keg_only_reason["reason"]
|
||||||
|
reason = reason[1..].to_sym if reason.start_with?(":")
|
||||||
|
keg_only reason, keg_only_reason["explanation"]
|
||||||
|
end
|
||||||
|
|
||||||
|
if (deprecation_date = json_formula["deprecation_date"]).present?
|
||||||
|
deprecate! date: deprecation_date, because: json_formula["deprecation_reason"]
|
||||||
|
end
|
||||||
|
|
||||||
|
if (disable_date = json_formula["disable_date"]).present?
|
||||||
|
disable! date: disable_date, because: json_formula["disable_reason"]
|
||||||
|
end
|
||||||
|
|
||||||
|
json_formula["build_dependencies"].each do |dep|
|
||||||
|
depends_on dep => :build
|
||||||
|
end
|
||||||
|
|
||||||
|
json_formula["dependencies"].each do |dep|
|
||||||
|
depends_on dep
|
||||||
|
end
|
||||||
|
|
||||||
|
json_formula["recommended_dependencies"].each do |dep|
|
||||||
|
depends_on dep => :recommended
|
||||||
|
end
|
||||||
|
|
||||||
|
json_formula["optional_dependencies"].each do |dep|
|
||||||
|
depends_on dep => :optional
|
||||||
|
end
|
||||||
|
|
||||||
|
json_formula["uses_from_macos"].each do |dep|
|
||||||
|
dep = dep.deep_transform_values(&:to_sym) if dep.is_a?(Hash)
|
||||||
|
uses_from_macos dep
|
||||||
|
end
|
||||||
|
|
||||||
|
def install
|
||||||
|
raise "Cannot build from source from abstract formula."
|
||||||
|
end
|
||||||
|
|
||||||
|
@caveats_string = json_formula["caveats"]
|
||||||
|
def caveats
|
||||||
|
@caveats_string
|
||||||
|
end
|
||||||
|
end
|
||||||
|
mod.const_set(class_s, klass)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Return a {Formula} instance for the given reference.
|
# Return a {Formula} instance for the given reference.
|
||||||
# `ref` is a string containing:
|
# `ref` is a string containing:
|
||||||
#
|
#
|
||||||
@ -539,11 +639,9 @@ module Formulary
|
|||||||
when URL_START_REGEX
|
when URL_START_REGEX
|
||||||
return FromUrlLoader.new(ref)
|
return FromUrlLoader.new(ref)
|
||||||
when HOMEBREW_TAP_FORMULA_REGEX
|
when HOMEBREW_TAP_FORMULA_REGEX
|
||||||
# If `homebrew/core` is specified and not installed, check whether the formula is already installed.
|
|
||||||
if ref.start_with?("homebrew/core/") && !CoreTap.instance.installed? && Homebrew::EnvConfig.install_from_api?
|
if ref.start_with?("homebrew/core/") && !CoreTap.instance.installed? && Homebrew::EnvConfig.install_from_api?
|
||||||
name = ref.split("/", 3).last
|
name = ref.split("/", 3).last
|
||||||
possible_keg_formula = Pathname.new("#{HOMEBREW_PREFIX}/opt/#{name}/.brew/#{name}.rb")
|
return FormulaAPILoader.new(name) if Homebrew::API::Formula.all_formulae.key?(name)
|
||||||
return FormulaLoader.new(name, possible_keg_formula) if possible_keg_formula.file?
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return TapLoader.new(ref, from: from)
|
return TapLoader.new(ref, from: from)
|
||||||
@ -557,6 +655,12 @@ module Formulary
|
|||||||
possible_alias = CoreTap.instance.alias_dir/ref
|
possible_alias = CoreTap.instance.alias_dir/ref
|
||||||
return AliasLoader.new(possible_alias) if possible_alias.file?
|
return AliasLoader.new(possible_alias) if possible_alias.file?
|
||||||
|
|
||||||
|
if !CoreTap.instance.installed? &&
|
||||||
|
Homebrew::EnvConfig.install_from_api? &&
|
||||||
|
Homebrew::API::Formula.all_formulae.key?(ref)
|
||||||
|
return FormulaAPILoader.new(ref)
|
||||||
|
end
|
||||||
|
|
||||||
possible_tap_formulae = tap_paths(ref)
|
possible_tap_formulae = tap_paths(ref)
|
||||||
raise TapFormulaAmbiguityError.new(ref, possible_tap_formulae) if possible_tap_formulae.size > 1
|
raise TapFormulaAmbiguityError.new(ref, possible_tap_formulae) if possible_tap_formulae.size > 1
|
||||||
|
|
||||||
|
@ -142,8 +142,6 @@ class Tap
|
|||||||
# The remote repository name of this {Tap}.
|
# The remote repository name of this {Tap}.
|
||||||
# e.g. `user/homebrew-repo`
|
# e.g. `user/homebrew-repo`
|
||||||
def remote_repo
|
def remote_repo
|
||||||
raise TapUnavailableError, name unless installed?
|
|
||||||
|
|
||||||
return unless remote
|
return unless remote
|
||||||
|
|
||||||
@remote_repo ||= remote.delete_prefix("https://github.com/")
|
@remote_repo ||= remote.delete_prefix("https://github.com/")
|
||||||
@ -795,6 +793,12 @@ class CoreTap < Tap
|
|||||||
safe_system HOMEBREW_BREW_FILE, "tap", instance.name
|
safe_system HOMEBREW_BREW_FILE, "tap", instance.name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def remote
|
||||||
|
super if installed? || !Homebrew::EnvConfig.install_from_api?
|
||||||
|
|
||||||
|
Homebrew::EnvConfig.core_git_remote
|
||||||
|
end
|
||||||
|
|
||||||
# CoreTap never allows shallow clones (on request from GitHub).
|
# CoreTap never allows shallow clones (on request from GitHub).
|
||||||
def install(quiet: false, clone_target: nil, force_auto_update: nil, custom_remote: false)
|
def install(quiet: false, clone_target: nil, force_auto_update: nil, custom_remote: false)
|
||||||
remote = Homebrew::EnvConfig.core_git_remote # set by HOMEBREW_CORE_GIT_REMOTE
|
remote = Homebrew::EnvConfig.core_git_remote # set by HOMEBREW_CORE_GIT_REMOTE
|
||||||
|
Loading…
x
Reference in New Issue
Block a user