diff --git a/Library/Homebrew/cli/args.rb b/Library/Homebrew/cli/args.rb index 5a313b5249..709a84e77f 100644 --- a/Library/Homebrew/cli/args.rb +++ b/Library/Homebrew/cli/args.rb @@ -1,4 +1,4 @@ -# typed: true # rubocop:disable Sorbet/StrictSigil +# typed: strict # frozen_string_literal: true require "ostruct" @@ -6,6 +6,17 @@ require "ostruct" module Homebrew module CLI class Args < OpenStruct + # FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed. + # rubocop:disable Style/MutableConstant + # Represents a processed option. The array elements are: + # 0: short option name (e.g. "-d") + # 1: long option name (e.g. "--debug") + # 2: option description (e.g. "Print debugging information") + # 3: whether the option is hidden + OptionsType = T.type_alias { T::Array[[String, T.nilable(String), String, T::Boolean]] } + # rubocop:enable Style/MutableConstant + + sig { returns(T::Array[String]) } attr_reader :options_only, :flags_only # undefine tap to allow --tap argument @@ -17,10 +28,12 @@ module Homebrew super - @processed_options = [] - @options_only = [] - @flags_only = [] - @cask_options = false + @cli_args = T.let(nil, T.nilable(T::Array[String])) + @processed_options = T.let([], OptionsType) + @options_only = T.let([], T::Array[String]) + @flags_only = T.let([], T::Array[String]) + @cask_options = T.let(false, T::Boolean) + @table = T.let({}, T::Hash[Symbol, T.untyped]) # Can set these because they will be overwritten by freeze_named_args! # (whereas other values below will only be overwritten if passed). @@ -28,10 +41,12 @@ module Homebrew self[:remaining] = [] end + sig { params(remaining_args: T::Array[T.any(T::Array[String], String)]).void } def freeze_remaining_args!(remaining_args) self[:remaining] = remaining_args.freeze end + sig { params(named_args: T::Array[String], cask_options: T::Boolean, without_api: T::Boolean).void } def freeze_named_args!(named_args, cask_options:, without_api:) options = {} options[:force_bottle] = true if self[:force_bottle?] @@ -46,6 +61,7 @@ module Homebrew ) end + sig { params(processed_options: OptionsType).void } def freeze_processed_options!(processed_options) # Reset cache values reliant on processed_options @cli_args = nil @@ -53,8 +69,8 @@ module Homebrew @processed_options += processed_options @processed_options.freeze - @options_only = cli_args.select { |a| a.start_with?("-") }.freeze - @flags_only = cli_args.select { |a| a.start_with?("--") }.freeze + @options_only = cli_args.select { _1.start_with?("-") }.freeze + @flags_only = cli_args.select { _1.start_with?("--") }.freeze end sig { returns(NamedArgs) } @@ -63,10 +79,10 @@ module Homebrew self[:named] end - def no_named? - named.blank? - end + sig { returns(T::Boolean) } + def no_named? = named.blank? + sig { returns(T::Array[String]) } def build_from_source_formulae if build_from_source? || self[:HEAD?] || self[:build_bottle?] named.to_formulae.map(&:full_name) @@ -75,6 +91,7 @@ module Homebrew end end + sig { returns(T::Array[String]) } def include_test_formulae if include_test? named.to_formulae.map(&:full_name) @@ -83,6 +100,7 @@ module Homebrew end end + sig { params(name: String).returns(T.nilable(String)) } def value(name) arg_prefix = "--#{name}=" flag_with_value = flags_only.find { |arg| arg.start_with?(arg_prefix) } @@ -96,6 +114,7 @@ module Homebrew Context::ContextStruct.new(debug: debug?, quiet: quiet?, verbose: verbose?) end + sig { returns(T.nilable(Symbol)) } def only_formula_or_cask if formula? && !cask? :formula @@ -141,11 +160,13 @@ module Homebrew private + sig { params(option: String).returns(String) } def option_to_name(option) option.sub(/\A--?/, "") .tr("-", "_") end + sig { returns(T::Array[String]) } def cli_args return @cli_args if @cli_args @@ -165,10 +186,12 @@ module Homebrew @cli_args.freeze end - def respond_to_missing?(method_name, *) + sig { params(method_name: Symbol, _include_private: T::Boolean).returns(T::Boolean) } + def respond_to_missing?(method_name, _include_private = false) @table.key?(method_name) end + sig { params(method_name: Symbol, args: T.untyped).returns(T.untyped) } def method_missing(method_name, *args) return_value = super diff --git a/Library/Homebrew/cli/parser.rb b/Library/Homebrew/cli/parser.rb index 4ac4625171..79db0ede47 100644 --- a/Library/Homebrew/cli/parser.rb +++ b/Library/Homebrew/cli/parser.rb @@ -16,7 +16,6 @@ module Homebrew # FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed. # rubocop:disable Style/MutableConstant ArgType = T.type_alias { T.any(NilClass, Symbol, T::Array[String], T::Array[Symbol]) } - OptionsType = T.type_alias { T::Array[[String, T.nilable(String), T.nilable(String), String, T::Boolean]] } # rubocop:enable Style/MutableConstant HIDDEN_DESC_PLACEHOLDER = "@@HIDDEN@@" SYMBOL_TO_USAGE_MAPPING = T.let({ @@ -25,7 +24,7 @@ module Homebrew }.freeze, T::Hash[Symbol, String]) private_constant :ArgType, :HIDDEN_DESC_PLACEHOLDER, :SYMBOL_TO_USAGE_MAPPING - sig { returns(OptionsType) } + sig { returns(Args::OptionsType) } attr_reader :processed_options sig { returns(T::Boolean) } @@ -177,7 +176,7 @@ module Homebrew @constraints = T.let([], T::Array[[String, String]]) @conflicts = T.let([], T::Array[T::Array[String]]) @switch_sources = T.let({}, T::Hash[String, Symbol]) - @processed_options = T.let([], OptionsType) + @processed_options = T.let([], Args::OptionsType) @non_global_processed_options = T.let([], T::Array[[String, ArgType]]) @named_args_type = T.let(nil, T.nilable(ArgType)) @max_named_args = T.let(nil, T.nilable(Integer)) @@ -671,7 +670,7 @@ module Homebrew def process_option(*args, type:, hidden: false) option, = @parser.make_switch(args) @processed_options.reject! { |existing| existing.second == option.long.first } if option.long.first.present? - @processed_options << [option.short.first, option.long.first, option.arg, option.desc.first, hidden] + @processed_options << [option.short.first, option.long.first, option.desc.first, hidden] args.pop # last argument is the description if type == :switch diff --git a/Library/Homebrew/commands.rb b/Library/Homebrew/commands.rb index bd15e09d2b..bff04823ef 100644 --- a/Library/Homebrew/commands.rb +++ b/Library/Homebrew/commands.rb @@ -199,7 +199,7 @@ module Commands return if path.blank? if (cmd_parser = Homebrew::CLI::Parser.from_cmd_path(path)) - cmd_parser.processed_options.filter_map do |short, long, _, desc, hidden| + cmd_parser.processed_options.filter_map do |short, long, desc, hidden| next if hidden [long || short, desc] diff --git a/Library/Homebrew/manpages.rb b/Library/Homebrew/manpages.rb index f49184cf12..3b3048017f 100644 --- a/Library/Homebrew/manpages.rb +++ b/Library/Homebrew/manpages.rb @@ -96,9 +96,10 @@ module Homebrew man_page_lines.compact.join("\n") end + sig { params(cmd_parser: CLI::Parser).returns(T::Array[String]) } def self.cmd_parser_manpage_lines(cmd_parser) lines = [format_usage_banner(cmd_parser.usage_banner_text)] - lines += cmd_parser.processed_options.filter_map do |short, long, _, desc, hidden| + lines += cmd_parser.processed_options.filter_map do |short, long, desc, hidden| next if hidden if long.present?