From c0df920660f60d89f7bdae1bbe2c60e56af453fb Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Tue, 19 Aug 2025 00:12:20 -0400 Subject: [PATCH] Parse named args from formula stubs --- Library/Homebrew/cli/named_args.rb | 72 ++++++++++++++++++++++-------- Library/Homebrew/cli/parser.rb | 2 +- 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/Library/Homebrew/cli/named_args.rb b/Library/Homebrew/cli/named_args.rb index 58153426e6..d5b07aabd2 100644 --- a/Library/Homebrew/cli/named_args.rb +++ b/Library/Homebrew/cli/named_args.rb @@ -80,17 +80,28 @@ module Homebrew @to_formulae_and_casks ||= T.let( {}, T.nilable(T::Hash[T.nilable(Symbol), T::Array[T.any(Formula, Keg, Cask::Cask)]]) ) - @to_formulae_and_casks[only] ||= downcased_unique_named.flat_map do |name| - options = { warn: }.compact - load_formula_or_cask(name, only:, method:, **options) - rescue FormulaUnreadableError, FormulaClassUnavailableError, - TapFormulaUnreadableError, TapFormulaClassUnavailableError, - Cask::CaskUnreadableError - # Need to rescue before `*UnavailableError` (superclass of this) - # The formula/cask was found, but there's a problem with its implementation - raise - rescue NoSuchKegError, FormulaUnavailableError, Cask::CaskUnavailableError, FormulaOrCaskUnavailableError - ignore_unavailable ? [] : raise + @to_formulae_and_casks[only] ||= begin + download_queue = Homebrew::DownloadQueue.new if Homebrew::EnvConfig.download_concurrency > 1 + + formulae_and_casks = downcased_unique_named.flat_map do |name| + load_and_fetch_full_formula_or_cask(name, only:, method:, warn:, download_queue:) + rescue FormulaUnreadableError, FormulaClassUnavailableError, + TapFormulaUnreadableError, TapFormulaClassUnavailableError, + Cask::CaskUnreadableError + # Need to rescue before `*UnavailableError` (superclass of this) + # The formula/cask was found, but there's a problem with its implementation + raise + rescue NoSuchKegError, FormulaUnavailableError, Cask::CaskUnavailableError, FormulaOrCaskUnavailableError + ignore_unavailable ? [] : raise + end + + download_queue&.fetch + + formulae_and_casks.map do |formula_or_cask| + next formula_or_cask unless formula_or_cask.is_a?(Formula) + + formula_or_cask.fully_loaded_formula + end end.freeze if uniq @@ -152,11 +163,23 @@ module Homebrew T::Array[T.any(Formula, Keg, Cask::Cask, T::Array[Keg], FormulaOrCaskUnavailableError)], ]), ) - @to_formulae_casks_unknowns[method] = downcased_unique_named.map do |name| - load_formula_or_cask(name, only:, method:) - rescue FormulaOrCaskUnavailableError => e - e - end.uniq.freeze + @to_formulae_casks_unknowns[method] = begin + download_queue = Homebrew::DownloadQueue.new if Homebrew::EnvConfig.download_concurrency > 1 + + formulae_and_casks = downcased_unique_named.map do |name| + load_and_fetch_full_formula_or_cask(name, only:, method:, download_queue:) + rescue FormulaOrCaskUnavailableError => e + e + end.uniq + + download_queue&.fetch + + formulae_and_casks.map do |formula_or_cask| + next formula_or_cask unless formula_or_cask.is_a?(Formula) + + formula_or_cask.fully_loaded_formula + end + end.freeze end sig { params(uniq: T::Boolean).returns(T::Array[Formula]) } @@ -314,6 +337,17 @@ module Homebrew end.uniq end + sig { + params(name: String, only: T.nilable(Symbol), method: T.nilable(Symbol), warn: T.nilable(T::Boolean), + download_queue: T.nilable(Homebrew::DownloadQueue)) + .returns(T.any(Formula, Keg, Cask::Cask, T::Array[Keg])) + } + def load_and_fetch_full_formula_or_cask(name, only: nil, method: nil, warn: nil, download_queue: nil) + formula_or_cask = load_formula_or_cask(name, only:, method:, warn:) + formula_or_cask.fetch_fully_loaded_formula!(download_queue:) if formula_or_cask.is_a?(Formula) + formula_or_cask + end + sig { params(name: String, only: T.nilable(Symbol), method: T.nilable(Symbol), warn: T.nilable(T::Boolean)) .returns(T.any(Formula, Keg, Cask::Cask, T::Array[Keg])) @@ -326,8 +360,8 @@ module Homebrew begin case method when nil, :factory - options = { warn:, force_bottle: @force_bottle, flags: @flags }.compact - Formulary.factory(name, *@override_spec, **options) + Formulary.factory(name, *@override_spec, + warn:, force_bottle: @force_bottle, flags: @flags, prefer_stub: true) when :resolve resolve_formula(name) when :latest_kegs @@ -447,7 +481,7 @@ module Homebrew sig { params(name: String).returns(Formula) } def resolve_formula(name) - Formulary.resolve(name, **{ spec: @override_spec, force_bottle: @force_bottle, flags: @flags }.compact) + Formulary.resolve(name, spec: @override_spec, force_bottle: @force_bottle, flags: @flags, prefer_stub: true) end sig { params(name: String).returns([Pathname, T::Array[Keg]]) } diff --git a/Library/Homebrew/cli/parser.rb b/Library/Homebrew/cli/parser.rb index 54e791c080..327727e4fb 100644 --- a/Library/Homebrew/cli/parser.rb +++ b/Library/Homebrew/cli/parser.rb @@ -733,7 +733,7 @@ module Homebrew next if arg.match?(HOMEBREW_CASK_TAP_CASK_REGEX) begin - Formulary.factory(arg, spec, flags: argv.select { |a| a.start_with?("--") }) + Formulary.factory(arg, spec, flags: argv.select { |a| a.start_with?("--") }, prefer_stub: true) rescue FormulaUnavailableError, FormulaSpecificationError nil end