Add without_api specifier for CLI named args
This commit is contained in:
parent
1c081f379d
commit
68289f1165
@ -176,4 +176,20 @@ module Homebrew
|
||||
Tap.fetch(org, repo)
|
||||
end
|
||||
end
|
||||
|
||||
# @api private
|
||||
sig { params(block: T.proc.returns(T.untyped)).returns(T.untyped) }
|
||||
def self.with_no_api_env(&block)
|
||||
return yield if Homebrew::EnvConfig.no_install_from_api?
|
||||
|
||||
with_env(HOMEBREW_NO_INSTALL_FROM_API: "1", HOMEBREW_AUTOMATICALLY_SET_NO_INSTALL_FROM_API: "1", &block)
|
||||
end
|
||||
|
||||
# @api private
|
||||
sig { params(condition: T::Boolean, block: T.proc.returns(T.untyped)).returns(T.untyped) }
|
||||
def self.with_no_api_env_if_needed(condition, &block)
|
||||
return yield unless condition
|
||||
|
||||
with_no_api_env(&block)
|
||||
end
|
||||
end
|
||||
|
@ -32,7 +32,7 @@ module Homebrew
|
||||
self[:remaining] = remaining_args.freeze
|
||||
end
|
||||
|
||||
def freeze_named_args!(named_args, cask_options:)
|
||||
def freeze_named_args!(named_args, cask_options:, without_api:)
|
||||
options = {}
|
||||
options[:force_bottle] = true if self[:force_bottle?]
|
||||
options[:override_spec] = :head if self[:HEAD?]
|
||||
@ -41,6 +41,7 @@ module Homebrew
|
||||
*named_args.freeze,
|
||||
parent: self,
|
||||
cask_options: cask_options,
|
||||
without_api: without_api,
|
||||
**options,
|
||||
)
|
||||
end
|
||||
|
@ -19,6 +19,7 @@ module Homebrew
|
||||
force_bottle: T::Boolean,
|
||||
flags: T::Array[String],
|
||||
cask_options: T::Boolean,
|
||||
without_api: T::Boolean,
|
||||
).void
|
||||
}
|
||||
def initialize(
|
||||
@ -27,7 +28,8 @@ module Homebrew
|
||||
override_spec: T.unsafe(nil),
|
||||
force_bottle: T.unsafe(nil),
|
||||
flags: T.unsafe(nil),
|
||||
cask_options: false
|
||||
cask_options: false,
|
||||
without_api: false
|
||||
)
|
||||
require "cask/cask"
|
||||
require "cask/cask_loader"
|
||||
@ -40,6 +42,7 @@ module Homebrew
|
||||
@force_bottle = force_bottle
|
||||
@flags = flags
|
||||
@cask_options = cask_options
|
||||
@without_api = without_api
|
||||
@parent = parent
|
||||
|
||||
super(@args)
|
||||
@ -112,92 +115,94 @@ module Homebrew
|
||||
end
|
||||
|
||||
def load_formula_or_cask(name, only: nil, method: nil, warn: nil)
|
||||
unreadable_error = nil
|
||||
Homebrew.with_no_api_env_if_needed(@without_api) do
|
||||
unreadable_error = nil
|
||||
|
||||
if only != :cask
|
||||
begin
|
||||
formula = case method
|
||||
when nil, :factory
|
||||
options = { warn: warn, force_bottle: @force_bottle, flags: @flags }.compact
|
||||
Formulary.factory(name, *@override_spec, **options)
|
||||
when :resolve
|
||||
resolve_formula(name)
|
||||
when :latest_kegs
|
||||
resolve_latest_keg(name)
|
||||
when :default_kegs
|
||||
resolve_default_keg(name)
|
||||
when :kegs
|
||||
_, kegs = resolve_kegs(name)
|
||||
kegs
|
||||
else
|
||||
raise
|
||||
end
|
||||
|
||||
warn_if_cask_conflicts(name, "formula") if only != :formula
|
||||
return formula
|
||||
rescue FormulaUnreadableError, FormulaClassUnavailableError,
|
||||
TapFormulaUnreadableError, TapFormulaClassUnavailableError => e
|
||||
# Need to rescue before `FormulaUnavailableError` (superclass of this)
|
||||
# The formula was found, but there's a problem with its implementation
|
||||
unreadable_error ||= e
|
||||
rescue NoSuchKegError, FormulaUnavailableError => e
|
||||
raise e if only == :formula
|
||||
end
|
||||
end
|
||||
|
||||
if only != :formula
|
||||
want_keg_like_cask = [:latest_kegs, :default_kegs, :kegs].include?(method)
|
||||
|
||||
begin
|
||||
config = Cask::Config.from_args(@parent) if @cask_options
|
||||
options = { warn: warn }.compact
|
||||
cask = Cask::CaskLoader.load(name, config: config, **options)
|
||||
|
||||
if unreadable_error.present?
|
||||
onoe <<~EOS
|
||||
Failed to load formula: #{name}
|
||||
#{unreadable_error}
|
||||
EOS
|
||||
opoo "Treating #{name} as a cask."
|
||||
end
|
||||
|
||||
# If we're trying to get a keg-like Cask, do our best to use the same cask
|
||||
# file that was used for installation, if possible.
|
||||
if want_keg_like_cask && (installed_caskfile = cask.installed_caskfile) && installed_caskfile.exist?
|
||||
cask = Cask::CaskLoader.load(installed_caskfile)
|
||||
end
|
||||
|
||||
return cask
|
||||
rescue Cask::CaskUnreadableError, Cask::CaskInvalidError => e
|
||||
# If we're trying to get a keg-like Cask, do our best to handle it
|
||||
# not being readable and return something that can be used.
|
||||
if want_keg_like_cask
|
||||
cask_version = Cask::Cask.new(name, config: config).installed_version
|
||||
cask = Cask::Cask.new(name, config: config) do
|
||||
version cask_version if cask_version
|
||||
if only != :cask
|
||||
begin
|
||||
formula = case method
|
||||
when nil, :factory
|
||||
options = { warn: warn, force_bottle: @force_bottle, flags: @flags }.compact
|
||||
Formulary.factory(name, *@override_spec, **options)
|
||||
when :resolve
|
||||
resolve_formula(name)
|
||||
when :latest_kegs
|
||||
resolve_latest_keg(name)
|
||||
when :default_kegs
|
||||
resolve_default_keg(name)
|
||||
when :kegs
|
||||
_, kegs = resolve_kegs(name)
|
||||
kegs
|
||||
else
|
||||
raise
|
||||
end
|
||||
return cask
|
||||
|
||||
warn_if_cask_conflicts(name, "formula") if only != :formula
|
||||
return formula
|
||||
rescue FormulaUnreadableError, FormulaClassUnavailableError,
|
||||
TapFormulaUnreadableError, TapFormulaClassUnavailableError => e
|
||||
# Need to rescue before `FormulaUnavailableError` (superclass of this)
|
||||
# The formula was found, but there's a problem with its implementation
|
||||
unreadable_error ||= e
|
||||
rescue NoSuchKegError, FormulaUnavailableError => e
|
||||
raise e if only == :formula
|
||||
end
|
||||
|
||||
# Need to rescue before `CaskUnavailableError` (superclass of this)
|
||||
# The cask was found, but there's a problem with its implementation
|
||||
unreadable_error ||= e
|
||||
rescue Cask::CaskUnavailableError => e
|
||||
raise e if only == :cask
|
||||
end
|
||||
|
||||
if only != :formula
|
||||
want_keg_like_cask = [:latest_kegs, :default_kegs, :kegs].include?(method)
|
||||
|
||||
begin
|
||||
config = Cask::Config.from_args(@parent) if @cask_options
|
||||
options = { warn: warn }.compact
|
||||
cask = Cask::CaskLoader.load(name, config: config, **options)
|
||||
|
||||
if unreadable_error.present?
|
||||
onoe <<~EOS
|
||||
Failed to load formula: #{name}
|
||||
#{unreadable_error}
|
||||
EOS
|
||||
opoo "Treating #{name} as a cask."
|
||||
end
|
||||
|
||||
# If we're trying to get a keg-like Cask, do our best to use the same cask
|
||||
# file that was used for installation, if possible.
|
||||
if want_keg_like_cask && (installed_caskfile = cask.installed_caskfile) && installed_caskfile.exist?
|
||||
cask = Cask::CaskLoader.load(installed_caskfile)
|
||||
end
|
||||
|
||||
return cask
|
||||
rescue Cask::CaskUnreadableError, Cask::CaskInvalidError => e
|
||||
# If we're trying to get a keg-like Cask, do our best to handle it
|
||||
# not being readable and return something that can be used.
|
||||
if want_keg_like_cask
|
||||
cask_version = Cask::Cask.new(name, config: config).installed_version
|
||||
cask = Cask::Cask.new(name, config: config) do
|
||||
version cask_version if cask_version
|
||||
end
|
||||
return cask
|
||||
end
|
||||
|
||||
# Need to rescue before `CaskUnavailableError` (superclass of this)
|
||||
# The cask was found, but there's a problem with its implementation
|
||||
unreadable_error ||= e
|
||||
rescue Cask::CaskUnavailableError => e
|
||||
raise e if only == :cask
|
||||
end
|
||||
end
|
||||
|
||||
raise unreadable_error if unreadable_error.present?
|
||||
|
||||
user, repo, short_name = name.downcase.split("/", 3)
|
||||
if repo.present? && short_name.present?
|
||||
tap = Tap.fetch(user, repo)
|
||||
raise TapFormulaOrCaskUnavailableError.new(tap, short_name)
|
||||
end
|
||||
|
||||
raise NoSuchKegError, name if resolve_formula(name)
|
||||
|
||||
raise FormulaOrCaskUnavailableError, name
|
||||
end
|
||||
|
||||
raise unreadable_error if unreadable_error.present?
|
||||
|
||||
user, repo, short_name = name.downcase.split("/", 3)
|
||||
if repo.present? && short_name.present?
|
||||
tap = Tap.fetch(user, repo)
|
||||
raise TapFormulaOrCaskUnavailableError.new(tap, short_name)
|
||||
end
|
||||
|
||||
raise NoSuchKegError, name if resolve_formula(name)
|
||||
|
||||
raise FormulaOrCaskUnavailableError, name
|
||||
end
|
||||
private :load_formula_or_cask
|
||||
|
||||
|
@ -138,6 +138,7 @@ module Homebrew
|
||||
@named_args_type = nil
|
||||
@max_named_args = nil
|
||||
@min_named_args = nil
|
||||
@named_args_without_api = false
|
||||
@description = nil
|
||||
@usage_banner = nil
|
||||
@hide_from_man_page = false
|
||||
@ -346,7 +347,7 @@ module Homebrew
|
||||
check_named_args(named_args)
|
||||
end
|
||||
|
||||
@args.freeze_named_args!(named_args, cask_options: @cask_options)
|
||||
@args.freeze_named_args!(named_args, cask_options: @cask_options, without_api: @named_args_without_api)
|
||||
@args.freeze_remaining_args!(non_options.empty? ? remaining : [*remaining, "--", non_options])
|
||||
@args.freeze_processed_options!(@processed_options)
|
||||
@args.freeze
|
||||
@ -392,13 +393,14 @@ module Homebrew
|
||||
|
||||
sig {
|
||||
params(
|
||||
type: T.any(NilClass, Symbol, T::Array[String], T::Array[Symbol]),
|
||||
number: T.nilable(Integer),
|
||||
min: T.nilable(Integer),
|
||||
max: T.nilable(Integer),
|
||||
type: T.any(NilClass, Symbol, T::Array[String], T::Array[Symbol]),
|
||||
number: T.nilable(Integer),
|
||||
min: T.nilable(Integer),
|
||||
max: T.nilable(Integer),
|
||||
without_api: T::Boolean,
|
||||
).void
|
||||
}
|
||||
def named_args(type = nil, number: nil, min: nil, max: nil)
|
||||
def named_args(type = nil, number: nil, min: nil, max: nil, without_api: false)
|
||||
if number.present? && (min.present? || max.present?)
|
||||
raise ArgumentError, "Do not specify both `number` and `min` or `max`"
|
||||
end
|
||||
@ -417,6 +419,8 @@ module Homebrew
|
||||
@min_named_args = min
|
||||
@max_named_args = max
|
||||
end
|
||||
|
||||
@named_args_without_api = without_api
|
||||
end
|
||||
|
||||
sig { void }
|
||||
|
@ -123,7 +123,7 @@ module Homebrew
|
||||
ENV.activate_extensions!
|
||||
ENV.setup_build_environment
|
||||
|
||||
audit_formulae, audit_casks = without_api do # audit requires full Ruby source
|
||||
audit_formulae, audit_casks = with_no_api_env do # audit requires full Ruby source
|
||||
if args.tap
|
||||
Tap.fetch(args.tap).then do |tap|
|
||||
[
|
||||
@ -217,7 +217,7 @@ module Homebrew
|
||||
# Audit requires full Ruby source so disable API.
|
||||
# We shouldn't do this for taps however so that we don't unnecessarily require a full Homebrew/core clone.
|
||||
fa = if f.core_formula?
|
||||
without_api(&audit_proc)
|
||||
with_no_api_env(&audit_proc)
|
||||
else
|
||||
audit_proc.call
|
||||
end
|
||||
@ -347,10 +347,4 @@ module Homebrew
|
||||
"* #{location}#{message.chomp.gsub("\n", "\n ")}#{status}"
|
||||
end
|
||||
end
|
||||
|
||||
def self.without_api(&block)
|
||||
return yield if Homebrew::EnvConfig.no_install_from_api?
|
||||
|
||||
with_env(HOMEBREW_NO_INSTALL_FROM_API: "1", HOMEBREW_AUTOMATICALLY_SET_NO_INSTALL_FROM_API: "1", &block)
|
||||
end
|
||||
end
|
||||
|
@ -87,13 +87,19 @@ class FormulaOrCaskUnavailableError < RuntimeError
|
||||
super()
|
||||
|
||||
@name = name
|
||||
|
||||
# Store the state of these envs at the time the exception is thrown.
|
||||
# This is so we do the fuzzy search for "did you mean" etc under that same mode,
|
||||
# in case the list of formulae are different.
|
||||
@without_api = Homebrew::EnvConfig.no_install_from_api?
|
||||
@auto_without_api = Homebrew::EnvConfig.automatically_set_no_install_from_api?
|
||||
end
|
||||
|
||||
sig { returns(String) }
|
||||
def did_you_mean
|
||||
require "formula"
|
||||
|
||||
similar_formula_names = Formula.fuzzy_search(name)
|
||||
similar_formula_names = Homebrew.with_no_api_env_if_needed(@without_api) { Formula.fuzzy_search(name) }
|
||||
return "" if similar_formula_names.blank?
|
||||
|
||||
"Did you mean #{similar_formula_names.to_sentence two_words_connector: " or ", last_word_connector: " or "}?"
|
||||
@ -101,7 +107,11 @@ class FormulaOrCaskUnavailableError < RuntimeError
|
||||
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
"No available formula or cask with the name \"#{name}\". #{did_you_mean}".strip
|
||||
s = "No available formula or cask with the name \"#{name}\". #{did_you_mean}".strip
|
||||
if @auto_without_api && !CoreTap.instance.installed?
|
||||
s += "\nA full git tap clone is required to use this command on core packages."
|
||||
end
|
||||
s
|
||||
end
|
||||
end
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user