From 34caeb7ea8981ca841e9901ea89af5508ccf7451 Mon Sep 17 00:00:00 2001 From: Issy Long Date: Sun, 30 Jun 2024 17:49:27 +0100 Subject: [PATCH 01/24] dev-cmd/unbottled: Bump to Sorbet `typed: strict` --- Library/Homebrew/dev-cmd/unbottled.rb | 33 +++++++++++++++------------ 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/Library/Homebrew/dev-cmd/unbottled.rb b/Library/Homebrew/dev-cmd/unbottled.rb index 359724dfbb..b64c1fbb43 100644 --- a/Library/Homebrew/dev-cmd/unbottled.rb +++ b/Library/Homebrew/dev-cmd/unbottled.rb @@ -1,4 +1,4 @@ -# typed: true +# typed: strict # frozen_string_literal: true require "abstract_command" @@ -34,11 +34,11 @@ module Homebrew def run Formulary.enable_factory_cache! - @bottle_tag = if (tag = args.tag) + @bottle_tag = T.let(if (tag = args.tag) Utils::Bottles::Tag.from_symbol(tag.to_sym) else Utils::Bottles.tag - end + end, T.nilable(Utils::Bottles::Tag)) if args.lost? if args.named.present? @@ -51,13 +51,13 @@ module Homebrew end end - os = @bottle_tag.system - arch = if Hardware::CPU::INTEL_ARCHS.include?(@bottle_tag.arch) + os = T.must(@bottle_tag).system + arch = if Hardware::CPU::INTEL_ARCHS.include?(T.must(@bottle_tag).arch) :intel - elsif Hardware::CPU::ARM_ARCHS.include?(@bottle_tag.arch) + elsif Hardware::CPU::ARM_ARCHS.include?(T.must(@bottle_tag).arch) :arm else - raise "Unknown arch #{@bottle_tag.arch}." + raise "Unknown arch #{T.must(@bottle_tag).arch}." end Homebrew::SimulateSystem.with(os:, arch:) do @@ -98,12 +98,13 @@ module Homebrew ["installs", formula_installs] end - output_unbottled(formulae, deps_hash, noun, hash, args.named.present?) + output_unbottled(formulae, deps_hash, noun, T.must(hash), args.named.present?) end end private + sig { params(all: T::Boolean).returns([T::Array[Formula], T::Array[Formula], T.nilable(T::Hash[Symbol, Integer])]) } def formulae_all_installs_from_args(all) if args.named.present? formulae = all_formulae = args.named.to_formulae @@ -115,7 +116,7 @@ module Homebrew formulae = all_formulae = Formula.all(eval_all: args.eval_all?) - @sort = " (sorted by number of dependents)" + @sort = T.let(" (sorted by number of dependents)", T.nilable(String)) elsif all formulae = all_formulae = Formula.all(eval_all: args.eval_all?) else @@ -142,7 +143,7 @@ module Homebrew nil end end - @sort = " (sorted by installs in the last 90 days; top 10,000 only)" + @sort = T.let(" (sorted by installs in the last 90 days; top 10,000 only)", T.nilable(String)) all_formulae = Formula.all(eval_all: args.eval_all?) end @@ -151,9 +152,10 @@ module Homebrew formulae = Array(formulae).reject(&:deprecated?) if formulae.present? all_formulae = Array(all_formulae).reject(&:deprecated?) if all_formulae.present? - [formulae, all_formulae, formula_installs] + [T.let(formulae, T::Array[Formula]), T.let(all_formulae, T::Array[Formula]), T.let(T.must(formula_installs), T.nilable(T::Hash[Symbol, Integer]))] end + sig { params(all_formulae: T.untyped).returns([T::Hash[String, T.untyped], T::Hash[String, T.untyped]]) } def deps_uses_from_formulae(all_formulae) ohai "Populating dependency tree..." @@ -175,6 +177,7 @@ module Homebrew [deps_hash, uses_hash] end + sig { params(formulae: T::Array[Formula]).returns(NilClass) } def output_total(formulae) ohai "Unbottled :#{@bottle_tag} formulae" unbottled_formulae = 0 @@ -188,6 +191,7 @@ module Homebrew puts "#{unbottled_formulae}/#{formulae.length} remaining." end + sig { params(formulae: T::Array[Formula], deps_hash: T::Hash[T.any(Symbol, String), T.untyped], noun: T.nilable(String), hash: T::Hash[T.any(Symbol, String), T.untyped], any_named_args: T::Boolean).returns(NilClass) } def output_unbottled(formulae, deps_hash, noun, hash, any_named_args) ohai ":#{@bottle_tag} bottle status#{@sort}" any_found = T.let(false, T::Boolean) @@ -201,7 +205,7 @@ module Homebrew end requirements = f.recursive_requirements - if @bottle_tag.linux? + if T.must(@bottle_tag).linux? if requirements.any? { |r| r.is_a?(MacOSRequirement) && !r.version } puts "#{Tty.bold}#{Tty.red}#{name}#{Tty.reset}: requires macOS" if any_named_args next @@ -210,7 +214,7 @@ module Homebrew puts "#{Tty.bold}#{Tty.red}#{name}#{Tty.reset}: requires Linux" if any_named_args next else - macos_version = @bottle_tag.to_macos_version + macos_version = T.must(@bottle_tag).to_macos_version macos_satisfied = requirements.all? do |r| case r when MacOSRequirement @@ -222,7 +226,7 @@ module Homebrew Version.new(MacOS::Xcode.latest_version(macos: macos_version)) >= r.version when ArchRequirement - r.arch == @bottle_tag.arch + r.arch == T.must(@bottle_tag).arch else true end @@ -258,6 +262,7 @@ module Homebrew puts "No unbottled dependencies found!" end + sig { returns(NilClass) } def output_lost_bottles ohai ":#{@bottle_tag} lost bottles" From c57cd4bf98c702e4ec042bc465092b2a23aca11a Mon Sep 17 00:00:00 2001 From: Issy Long Date: Sun, 30 Jun 2024 18:42:16 +0100 Subject: [PATCH 02/24] dev-cmd/contributions: Bump to Sorbet `typed: strict` --- Library/Homebrew/dev-cmd/contributions.rb | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Library/Homebrew/dev-cmd/contributions.rb b/Library/Homebrew/dev-cmd/contributions.rb index 2e6452937b..1fbf958318 100644 --- a/Library/Homebrew/dev-cmd/contributions.rb +++ b/Library/Homebrew/dev-cmd/contributions.rb @@ -1,4 +1,4 @@ -# typed: true +# typed: strict # frozen_string_literal: true require "abstract_command" @@ -11,11 +11,11 @@ module Homebrew module DevCmd class Contributions < AbstractCommand PRIMARY_REPOS = %w[brew core cask].freeze - SUPPORTED_REPOS = [ + SUPPORTED_REPOS = T.let([ PRIMARY_REPOS, OFFICIAL_CMD_TAPS.keys.map { |t| t.delete_prefix("homebrew/") }, OFFICIAL_CASK_TAPS.reject { |t| t == "cask" }, - ].flatten.freeze + ].flatten.freeze, T::Array[String]) MAX_REPO_COMMITS = 1000 cmd_args do @@ -55,7 +55,7 @@ module Homebrew elsif T.must(args.repositories).include?("all") SUPPORTED_REPOS else - args.repositories + T.must(args.repositories) end from = args.from.presence || Date.today.prev_year.iso8601 @@ -116,7 +116,7 @@ module Homebrew end end - sig { params(totals: Hash).returns(String) } + sig { params(totals: T::Hash[T.untyped, T.untyped]).returns(String) } def generate_csv(totals) CSV.generate do |csv| csv << %w[user repo author committer coauthor review total] @@ -127,7 +127,7 @@ module Homebrew end end - sig { params(user: String, grand_total: Hash).returns(Array) } + sig { params(user: String, grand_total: T::Hash[Symbol, T.untyped]).returns(T::Array[T.any(String, Integer)]) } def grand_total_row(user, grand_total) [ user, @@ -140,6 +140,7 @@ module Homebrew ] end + sig { params(repos: T::Array[String], person: String, from: String).void } def scan_repositories(repos, person, from:) data = {} @@ -168,7 +169,7 @@ module Homebrew data[repo] = { author: author_commits, committer: committer_commits, - coauthor: git_log_trailers_cmd(T.must(repo_path), person, "Co-authored-by", from:, to: args.to), + coauthor: git_log_trailers_cmd(repo_path, person, "Co-authored-by", from:, to: args.to), review: count_reviews(repo_full_name, person, from:, to: args.to), } end @@ -176,7 +177,7 @@ module Homebrew data end - sig { params(results: Hash).returns(Hash) } + sig { params(results: T::Hash[Symbol, T.untyped]).returns(T::Hash[Symbol, Integer]) } def total(results) totals = { author: 0, committer: 0, coauthor: 0, review: 0 } From 1b517a9d49c7fbac16c831539693a789523764d5 Mon Sep 17 00:00:00 2001 From: Issy Long Date: Sun, 30 Jun 2024 19:07:38 +0100 Subject: [PATCH 03/24] dev-cmd/irb: Bump to Sorbet `typed: strict` --- Library/Homebrew/dev-cmd/irb.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Library/Homebrew/dev-cmd/irb.rb b/Library/Homebrew/dev-cmd/irb.rb index 9caafbed5a..6599b73b22 100644 --- a/Library/Homebrew/dev-cmd/irb.rb +++ b/Library/Homebrew/dev-cmd/irb.rb @@ -1,4 +1,4 @@ -# typed: true +# typed: strict # frozen_string_literal: true require "abstract_command" @@ -7,12 +7,14 @@ require "cask/cask_loader" class String # @!visibility private + sig { params(args: Integer).returns(Formula) } def f(*args) require "formula" Formulary.factory(self, *args) end # @!visibility private + sig { params(config: T.nilable(T::Hash[Symbol, T.untyped])).returns(Cask::Cask) } def c(config: nil) Cask::CaskLoader.load(self, config:) end @@ -20,11 +22,13 @@ end class Symbol # @!visibility private + sig { params(args: Integer).returns(Formula) } def f(*args) to_s.f(*args) end # @!visibility private + sig { params(config: T.nilable(T::Hash[Symbol, T.untyped])).returns(Cask::Cask) } def c(config: nil) to_s.c(config:) end @@ -94,6 +98,7 @@ module Homebrew # Remove the `--debug`, `--verbose` and `--quiet` options which cause problems # for IRB and have already been parsed by the CLI::Parser. + sig { returns(T.nilable(T::Array[Symbol])) } def clean_argv global_options = Homebrew::CLI::Parser .global_options From 57ba22053faf63a93964eb88b6cdf028e9855fa1 Mon Sep 17 00:00:00 2001 From: Issy Long Date: Sun, 30 Jun 2024 19:10:26 +0100 Subject: [PATCH 04/24] dev-cmd/update-sponsors: Bump to Sorbet `typed: strict` --- Library/Homebrew/dev-cmd/update-sponsors.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Library/Homebrew/dev-cmd/update-sponsors.rb b/Library/Homebrew/dev-cmd/update-sponsors.rb index 248a290413..26a2202418 100644 --- a/Library/Homebrew/dev-cmd/update-sponsors.rb +++ b/Library/Homebrew/dev-cmd/update-sponsors.rb @@ -1,4 +1,4 @@ -# typed: true +# typed: strict # frozen_string_literal: true require "abstract_command" @@ -62,14 +62,17 @@ module Homebrew private + sig { params(sponsor: T::Hash[Symbol, T.untyped]).returns(T.nilable(String)) } def sponsor_name(sponsor) sponsor[:name] || sponsor[:login] end + sig { params(sponsor: T::Hash[Symbol, T.untyped]).returns(String) } def sponsor_logo(sponsor) "https://github.com/#{sponsor[:login]}.png?size=64" end + sig { params(sponsor: T::Hash[Symbol, T.untyped]).returns(String) } def sponsor_url(sponsor) "https://github.com/#{sponsor[:login]}" end From 69cf1df56fdf02d2bee8120a8a8446c94e91d2cd Mon Sep 17 00:00:00 2001 From: Issy Long Date: Sun, 30 Jun 2024 19:23:26 +0100 Subject: [PATCH 05/24] dev-cmd/livecheck: Bump to Sorbet `typed: strict` --- Library/Homebrew/dev-cmd/livecheck.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Library/Homebrew/dev-cmd/livecheck.rb b/Library/Homebrew/dev-cmd/livecheck.rb index 017f1a9d29..b2ffcbdb16 100644 --- a/Library/Homebrew/dev-cmd/livecheck.rb +++ b/Library/Homebrew/dev-cmd/livecheck.rb @@ -1,4 +1,4 @@ -# typed: true +# typed: strict # frozen_string_literal: true require "abstract_command" @@ -113,8 +113,9 @@ module Homebrew private + sig { returns(String) } def watchlist_path - @watchlist_path ||= File.expand_path(Homebrew::EnvConfig.livecheck_watchlist) + @watchlist_path ||= T.let(File.expand_path(Homebrew::EnvConfig.livecheck_watchlist), T.nilable(String)) end end end From 3b28e90556b9262f845d65fc28f83e803456b7a6 Mon Sep 17 00:00:00 2001 From: Issy Long Date: Sun, 30 Jun 2024 19:25:19 +0100 Subject: [PATCH 06/24] dev-cmd/tap-new: Bump to Sorbet `typed: strict` --- Library/Homebrew/dev-cmd/tap-new.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Library/Homebrew/dev-cmd/tap-new.rb b/Library/Homebrew/dev-cmd/tap-new.rb index 1471b16f58..aeda5d721c 100644 --- a/Library/Homebrew/dev-cmd/tap-new.rb +++ b/Library/Homebrew/dev-cmd/tap-new.rb @@ -1,4 +1,4 @@ -# typed: true +# typed: strict # frozen_string_literal: true require "abstract_command" @@ -197,6 +197,7 @@ module Homebrew private + sig { params(tap: Tap, filename: T.any(String, Pathname), content: String).void } def write_path(tap, filename, content) path = tap.path/filename tap.path.mkpath From 944790acfe3274a2bb35158a570152a9a508446d Mon Sep 17 00:00:00 2001 From: Issy Long Date: Sun, 30 Jun 2024 19:27:35 +0100 Subject: [PATCH 07/24] dev-cmd/generate-cask-api: Bump to Sorbet `typed: strict` --- Library/Homebrew/dev-cmd/generate-cask-api.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Library/Homebrew/dev-cmd/generate-cask-api.rb b/Library/Homebrew/dev-cmd/generate-cask-api.rb index d72b20118e..4e6d424f26 100644 --- a/Library/Homebrew/dev-cmd/generate-cask-api.rb +++ b/Library/Homebrew/dev-cmd/generate-cask-api.rb @@ -1,4 +1,4 @@ -# typed: true +# typed: strict # frozen_string_literal: true require "abstract_command" @@ -71,6 +71,7 @@ module Homebrew private + sig { params(title: String).returns(String) } def html_template(title) <<~EOS --- From 3bf6a01516f68eb29931553d885da7b83c837de0 Mon Sep 17 00:00:00 2001 From: Issy Long Date: Sun, 30 Jun 2024 19:29:22 +0100 Subject: [PATCH 08/24] dev-cmd/generate-formula-api: Bump to Sorbet `typed: strict` --- Library/Homebrew/dev-cmd/generate-formula-api.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Library/Homebrew/dev-cmd/generate-formula-api.rb b/Library/Homebrew/dev-cmd/generate-formula-api.rb index 563fceb2b6..a3fe69de0d 100644 --- a/Library/Homebrew/dev-cmd/generate-formula-api.rb +++ b/Library/Homebrew/dev-cmd/generate-formula-api.rb @@ -1,4 +1,4 @@ -# typed: true +# typed: strict # frozen_string_literal: true require "abstract_command" @@ -69,6 +69,7 @@ module Homebrew private + sig { params(title: String).returns(String) } def html_template(title) <<~EOS --- From 0837f7c23c4d2a0aeecfb8a1e24812ca1d58e0d2 Mon Sep 17 00:00:00 2001 From: Issy Long Date: Sun, 30 Jun 2024 19:30:35 +0100 Subject: [PATCH 09/24] dev-cmd/test: Bump to Sorbet `typed: strict` --- Library/Homebrew/dev-cmd/test.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Library/Homebrew/dev-cmd/test.rb b/Library/Homebrew/dev-cmd/test.rb index 38e0796300..b2a9c47194 100644 --- a/Library/Homebrew/dev-cmd/test.rb +++ b/Library/Homebrew/dev-cmd/test.rb @@ -1,4 +1,4 @@ -# typed: true +# typed: strict # frozen_string_literal: true require "abstract_command" @@ -110,8 +110,9 @@ module Homebrew private + sig { params(formula: Formula).returns(T::Boolean) } def retry_test?(formula) - @test_failed ||= Set.new + @test_failed ||= T.let(Set.new, T.nilable(T::Set[T.untyped])) if args.retry? && @test_failed.add?(formula) oh1 "Testing #{formula.full_name} (again)" formula.clear_cache From d5af469e85c573288f5388e1f9629bf2b216ee2c Mon Sep 17 00:00:00 2001 From: Issy Long Date: Sun, 30 Jun 2024 20:41:02 +0100 Subject: [PATCH 10/24] dev-cmd/tests: Bump to Sorbet `typed: strict` --- Library/Homebrew/dev-cmd/tests.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Library/Homebrew/dev-cmd/tests.rb b/Library/Homebrew/dev-cmd/tests.rb index 60845d6cc2..1ac6edfe2c 100644 --- a/Library/Homebrew/dev-cmd/tests.rb +++ b/Library/Homebrew/dev-cmd/tests.rb @@ -1,4 +1,4 @@ -# typed: true +# typed: strict # frozen_string_literal: true require "abstract_command" @@ -168,15 +168,17 @@ module Homebrew private + sig { returns(T.nilable(T::Boolean)) } def use_buildpulse? return @use_buildpulse if defined?(@use_buildpulse) - @use_buildpulse = ENV["HOMEBREW_BUILDPULSE_ACCESS_KEY_ID"].present? && + @use_buildpulse = T.let(ENV["HOMEBREW_BUILDPULSE_ACCESS_KEY_ID"].present? && ENV["HOMEBREW_BUILDPULSE_SECRET_ACCESS_KEY"].present? && ENV["HOMEBREW_BUILDPULSE_ACCOUNT_ID"].present? && - ENV["HOMEBREW_BUILDPULSE_REPOSITORY_ID"].present? + ENV["HOMEBREW_BUILDPULSE_REPOSITORY_ID"].present?, T.nilable(T::Boolean)) end + sig { void } def run_buildpulse require "formula" @@ -198,6 +200,7 @@ module Homebrew ] end + sig { returns(T::Array[String]) } def changed_test_files changed_files = Utils.popen_read("git", "diff", "--name-only", "master") @@ -215,6 +218,7 @@ module Homebrew end.select(&:exist?) end + sig { returns(T::Array[String]) } def setup_environment! # Cleanup any unwanted user configuration. allowed_test_env = %w[ From 6b995ad111c6dcc808de054c07666ac0bd32e9ee Mon Sep 17 00:00:00 2001 From: Issy Long Date: Sun, 30 Jun 2024 20:58:10 +0100 Subject: [PATCH 11/24] dev-cmd/pr-upload: Bump to Sorbet `typed: strict` --- Library/Homebrew/dev-cmd/pr-upload.rb | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Library/Homebrew/dev-cmd/pr-upload.rb b/Library/Homebrew/dev-cmd/pr-upload.rb index 672086f3ef..4217f27e08 100644 --- a/Library/Homebrew/dev-cmd/pr-upload.rb +++ b/Library/Homebrew/dev-cmd/pr-upload.rb @@ -1,4 +1,4 @@ -# typed: true +# typed: strict # frozen_string_literal: true require "abstract_command" @@ -120,6 +120,7 @@ module Homebrew private + sig { params(bottles_hash: T::Hash[String, T.untyped]).void } def check_bottled_formulae!(bottles_hash) bottles_hash.each do |name, bottle_hash| formula_path = HOMEBREW_REPOSITORY/bottle_hash["formula"]["path"] @@ -131,22 +132,25 @@ module Homebrew end end + sig { params(bottles_hash: T::Hash[String, T.untyped]).returns(T::Boolean) } def github_releases?(bottles_hash) - @github_releases ||= bottles_hash.values.all? do |bottle_hash| + @github_releases ||= T.let(bottles_hash.values.all? do |bottle_hash| root_url = bottle_hash["bottle"]["root_url"] url_match = root_url.match GitHubReleases::URL_REGEX _, _, _, tag = *url_match tag - end + end, T.nilable(T::Boolean)) end + sig { params(bottles_hash: T::Hash[String, T.untyped]).returns(T::Boolean) } def github_packages?(bottles_hash) - @github_packages ||= bottles_hash.values.all? do |bottle_hash| + @github_packages ||= T.let(bottles_hash.values.all? do |bottle_hash| bottle_hash["bottle"]["root_url"].match? GitHubPackages::URL_REGEX - end + end, T.nilable(T::Boolean)) end + sig { params(json_files: T::Array[String], args: T.untyped).returns(T::Hash[String, T.untyped]) } def bottles_hash_from_json_files(json_files, args) puts "Reading JSON files: #{json_files.join(", ")}" if args.verbose? From 8587f4ba11bc7be30ece7a5ceae10e3395fdf131 Mon Sep 17 00:00:00 2001 From: Issy Long Date: Mon, 1 Jul 2024 13:14:47 +0100 Subject: [PATCH 12/24] dev-cmd/bump-formula-pr: Bump to Sorbet `typed: strict` --- Library/Homebrew/dev-cmd/bump-formula-pr.rb | 36 +++++++++++++-------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/Library/Homebrew/dev-cmd/bump-formula-pr.rb b/Library/Homebrew/dev-cmd/bump-formula-pr.rb index 1bbbc6b9d8..78fbb1ea17 100644 --- a/Library/Homebrew/dev-cmd/bump-formula-pr.rb +++ b/Library/Homebrew/dev-cmd/bump-formula-pr.rb @@ -1,4 +1,4 @@ -# typed: true +# typed: strict # frozen_string_literal: true require "abstract_command" @@ -145,10 +145,10 @@ module Homebrew old_mirrors = formula_spec.mirrors new_mirrors ||= args.mirror - new_mirror ||= determine_mirror(new_url) + new_mirror ||= determine_mirror(T.must(new_url)) new_mirrors ||= [new_mirror] if new_mirror.present? - check_for_mirrors(formula, old_mirrors, new_mirrors) if new_url.present? + check_for_mirrors(formula, old_mirrors, T.must(new_mirrors)) if new_url.present? old_hash = formula_spec.checksum&.hexdigest new_hash = args.sha256 @@ -179,7 +179,7 @@ module Homebrew EOS end check_new_version(formula, tap_remote_repo, url: old_url, tag: new_tag) if new_version.blank? - resource_path, forced_version = fetch_resource_and_forced_version(formula, new_version, old_url, + resource_path, forced_version = fetch_resource_and_forced_version(formula, T.must(new_version), old_url, tag: new_tag) new_revision = Utils.popen_read("git", "-C", resource_path.to_s, "rev-parse", "-q", "--verify", "HEAD") new_revision = new_revision.strip @@ -207,7 +207,7 @@ module Homebrew EOS end check_new_version(formula, tap_remote_repo, url: new_url) if new_version.blank? - resource_path, forced_version = fetch_resource_and_forced_version(formula, new_version, new_url) + resource_path, forced_version = fetch_resource_and_forced_version(formula, T.must(new_version), new_url) Utils::Tar.validate_file(resource_path) new_hash = resource_path.sha256 end @@ -395,6 +395,7 @@ module Homebrew private + sig { params(url: String).returns(T.nilable(String)) } def determine_mirror(url) case url when %r{.*ftp\.gnu\.org/gnu.*} @@ -408,6 +409,7 @@ module Homebrew end end + sig { params(formula: String, old_mirrors: T::Array[String], new_mirrors: T::Array[String]).void } def check_for_mirrors(formula, old_mirrors, new_mirrors) return if new_mirrors.present? || old_mirrors.empty? @@ -432,6 +434,7 @@ module Homebrew new_url.gsub(%r{/(v?)#{Regexp.escape(partial_old_version)}/}, "/\\1#{partial_new_version}/") end + sig { params(formula: Formula, new_version: T.nilable(String), url: String, specs: Float).returns(T::Array[T.untyped]) } def fetch_resource_and_forced_version(formula, new_version, url, **specs) resource = Resource.new resource.url(url, **specs) @@ -442,6 +445,7 @@ module Homebrew [resource.fetch, forced_version] end + sig { params(formula: Formula, contents: T.nilable(String)).returns(String) } def formula_version(formula, contents = nil) spec = :stable name = formula.name @@ -453,18 +457,20 @@ module Homebrew end end + sig { params(formula: Formula, tap_remote_repo: String).returns(T.nilable(T::Array[String])) } def check_open_pull_requests(formula, tap_remote_repo) GitHub.check_for_duplicate_pull_requests(formula.name, tap_remote_repo, state: "open", - file: formula.path.relative_path_from(formula.tap.path).to_s, + file: formula.path.relative_path_from(T.must(formula.tap).path).to_s, quiet: args.quiet?) end + sig { params(formula: Formula, tap_remote_repo: String, version: T.nilable(String), url: T.nilable(String), tag: T.nilable(String)).void } def check_new_version(formula, tap_remote_repo, version: nil, url: nil, tag: nil) if version.nil? specs = {} specs[:tag] = tag if tag.present? - version = Version.detect(url, **specs).to_s + version = Version.detect(T.must(url), **specs).to_s return if version.blank? end @@ -472,9 +478,10 @@ module Homebrew check_closed_pull_requests(formula, tap_remote_repo, version:) end + sig { params(formula: Formula, new_version: String).returns(NilClass) } def check_throttle(formula, new_version) throttled_rate = formula.livecheck.throttle - throttled_rate ||= if (rate = formula.tap.audit_exceptions.dig(:throttled_formulae, formula.name)) + throttled_rate ||= if (rate = T.must(formula.tap).audit_exceptions.dig(:throttled_formulae, formula.name)) odisabled "throttled_formulae.json", "Livecheck#throttle" rate end @@ -486,27 +493,30 @@ module Homebrew odie "#{formula} should only be updated every #{throttled_rate} releases on multiples of #{throttled_rate}" end + sig { params(formula: Formula, tap_remote_repo: String, version: T.nilable(String)).returns(T.nilable(T::Array[String])) } def check_closed_pull_requests(formula, tap_remote_repo, version:) # if we haven't already found open requests, try for an exact match across closed requests GitHub.check_for_duplicate_pull_requests(formula.name, tap_remote_repo, version:, state: "closed", - file: formula.path.relative_path_from(formula.tap.path).to_s, + file: formula.path.relative_path_from(T.must(formula.tap).path).to_s, quiet: args.quiet?) end + sig { params(formula: Formula, new_formula_version: String).returns(T.nilable(T::Array[String])) } def alias_update_pair(formula, new_formula_version) versioned_alias = formula.aliases.grep(/^.*@\d+(\.\d+)?$/).first return if versioned_alias.nil? name, old_alias_version = versioned_alias.split("@") - new_alias_regex = (old_alias_version.split(".").length == 1) ? /^\d+/ : /^\d+\.\d+/ + new_alias_regex = (T.must(old_alias_version).split(".").length == 1) ? /^\d+/ : /^\d+\.\d+/ new_alias_version, = *new_formula_version.to_s.match(new_alias_regex) - return if Version.new(new_alias_version) <= Version.new(old_alias_version) + return if Version.new(T.must(new_alias_version)) <= Version.new(T.must(old_alias_version)) [versioned_alias, "#{name}@#{new_alias_version}"] end + sig { params(formula: Formula, alias_rename: T.nilable(T::Array[String]), old_contents: String).void } def run_audit(formula, alias_rename, old_contents) audit_args = ["--formula"] audit_args << "--strict" if args.strict? @@ -521,7 +531,7 @@ module Homebrew end return end - FileUtils.mv alias_rename.first, alias_rename.last if alias_rename.present? + FileUtils.mv T.must(alias_rename.first), T.must(alias_rename.last) if alias_rename.present? failed_audit = false if args.no_audit? ohai "Skipping `brew audit`" @@ -535,7 +545,7 @@ module Homebrew return unless failed_audit formula.path.atomic_write(old_contents) - FileUtils.mv alias_rename.last, alias_rename.first if alias_rename.present? + FileUtils.mv T.must(alias_rename.last), T.must(alias_rename.first) if alias_rename.present? odie "`brew audit` failed!" end end From b1817391a805a72b574bdf3590e87430b534cd23 Mon Sep 17 00:00:00 2001 From: Issy Long Date: Mon, 1 Jul 2024 18:07:47 +0100 Subject: [PATCH 13/24] dev-cmd/pr-pull: Bump to Sorbet `typed: strict` --- Library/Homebrew/dev-cmd/pr-pull.rb | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/Library/Homebrew/dev-cmd/pr-pull.rb b/Library/Homebrew/dev-cmd/pr-pull.rb index c880c43630..ca5f01bdad 100644 --- a/Library/Homebrew/dev-cmd/pr-pull.rb +++ b/Library/Homebrew/dev-cmd/pr-pull.rb @@ -1,4 +1,4 @@ -# typed: true +# typed: strict # frozen_string_literal: true require "abstract_command" @@ -126,7 +126,7 @@ module Homebrew cherry_pick_pr!(user, repo, pr, path: tap.path) unless args.no_cherry_pick? if args.autosquash? && !args.dry_run? autosquash!(original_commit, tap:, cherry_picked: !args.no_cherry_pick?, - verbose: args.verbose?, resolve: args.resolve?, reason: args.message) + verbose: args.verbose?, resolve: args.resolve?, reason: T.must(args.message)) end signoff!(git_repo, pull_request: pr, dry_run: args.dry_run?) unless args.clean? end @@ -183,8 +183,9 @@ module Homebrew end # Separates a commit message into subject, body and trailers. + sig { params(message: String).returns([String, String, String]) } def separate_commit_message(message) - subject = message.lines.first.strip + subject = T.must(message.lines.first).strip # Skip the subject and separate lines that look like trailers (e.g. "Co-authored-by") # from lines that look like regular body text. @@ -196,8 +197,9 @@ module Homebrew [subject, body, trailers] end + sig { params(git_repo: GitRepository, pull_request: T.nilable(String), dry_run: T::Boolean).void } def signoff!(git_repo, pull_request: nil, dry_run: false) - subject, body, trailers = separate_commit_message(git_repo.commit_message) + subject, body, trailers = separate_commit_message(T.must(git_repo.commit_message)) if pull_request # This is a tap pull request and approving reviewers should also sign-off. @@ -210,7 +212,7 @@ module Homebrew # Append the close message as well, unless the commit body already includes it. close_message = "Closes ##{pull_request}." - body += "\n\n#{close_message}" unless body.include? close_message + body.concat("\n\n#{close_message}") unless body.include?(close_message) end git_args = Utils::Git.git, "-C", git_repo.pathname, "commit", "--amend", "--signoff", "--allow-empty", @@ -223,6 +225,7 @@ module Homebrew end end + sig { params(tap: Tap, subject_name: String, subject_path: Pathname, content: String).returns(T.untyped) } def get_package(tap, subject_name, subject_path, content) if subject_path.to_s.start_with?("#{tap.cask_dir}/") cask = begin @@ -240,6 +243,7 @@ module Homebrew end end + sig { params(old_contents: String, new_contents: String, subject_path: T.any(String, Pathname), reason: T.nilable(String)).returns(String) } def determine_bump_subject(old_contents, new_contents, subject_path, reason: nil) subject_path = Pathname(subject_path) tap = Tap.from_path(subject_path) @@ -268,6 +272,7 @@ module Homebrew # Cherry picks a single commit that modifies a single file. # Potentially rewords this commit using {determine_bump_subject}. + sig { params(commit: String, file: String, git_repo: GitRepository, reason: T.nilable(String), verbose: T::Boolean, resolve: T::Boolean).void } def reword_package_commit(commit, file, git_repo:, reason: "", verbose: false, resolve: false) package_file = git_repo.pathname / file package_name = package_file.basename.to_s.chomp(".rb") @@ -279,7 +284,7 @@ module Homebrew new_package = Utils::Git.file_at_commit(git_repo.to_s, file, "HEAD") bump_subject = determine_bump_subject(old_package, new_package, package_file, reason:).strip - subject, body, trailers = separate_commit_message(git_repo.commit_message) + subject, body, trailers = separate_commit_message(T.must(git_repo.commit_message)) if subject != bump_subject && !subject.start_with?("#{package_name}:") safe_system("git", "-C", git_repo.pathname, "commit", "--amend", "-q", @@ -293,6 +298,7 @@ module Homebrew # Cherry picks multiple commits that each modify a single file. # Words the commit according to {determine_bump_subject} with the body # corresponding to all the original commit messages combined. + sig { params(commits: T::Array[String], file: String, git_repo: GitRepository, reason: T.nilable(String), verbose: T::Boolean, resolve: T::Boolean).void } def squash_package_commits(commits, file, git_repo:, reason: "", verbose: false, resolve: false) odebug "Squashing #{file}: #{commits.join " "}" @@ -304,7 +310,7 @@ module Homebrew messages = [] trailers = [] commits.each do |commit| - subject, body, trailer = separate_commit_message(git_repo.commit_message(commit)) + subject, body, trailer = separate_commit_message(T.must(git_repo.commit_message(commit))) body = body.lines.map { |line| " #{line.strip}" }.join("\n") messages << "* #{subject}\n#{body}".strip trailers << trailer @@ -340,6 +346,7 @@ module Homebrew end # TODO: fix test in `test/dev-cmd/pr-pull_spec.rb` and assume `cherry_picked: false`. + sig { params(original_commit: String, tap: Tap, reason: String, verbose: T::Boolean, resolve: T::Boolean, cherry_picked: T::Boolean).void } def autosquash!(original_commit, tap:, reason: "", verbose: false, resolve: false, cherry_picked: true) git_repo = tap.git_repository original_head = git_repo.head_ref @@ -403,13 +410,14 @@ module Homebrew end rescue opoo "Autosquash encountered an error; resetting to original state at #{original_head}" - system "git", "-C", tap.path, "reset", "--hard", original_head - system "git", "-C", tap.path, "cherry-pick", "--abort" if cherry_picked + system "git", "-C", tap.path.to_s, "reset", "--hard", T.must(original_head) + system "git", "-C", tap.path.to_s, "cherry-pick", "--abort" if cherry_picked raise end private + sig { params(user: String, repo: String, pull_request: String, path: T.any(String, Pathname)).void } def cherry_pick_pr!(user, repo, pull_request, path: ".") if args.dry_run? puts <<~EOS @@ -427,6 +435,7 @@ module Homebrew resolve: args.resolve?) end + sig { params(tap: Tap, original_commit: String, labels: T::Array[String]).returns(T::Boolean) } def formulae_need_bottles?(tap, original_commit, labels) return false if args.dry_run? @@ -437,6 +446,7 @@ module Homebrew end end + sig { params(tap: Tap, original_commit: String).returns(T::Array[String]) } def changed_packages(tap, original_commit) formulae = Utils.popen_read("git", "-C", tap.path, "diff-tree", "-r", "--name-only", "--diff-filter=AM", @@ -473,6 +483,7 @@ module Homebrew formulae + casks end + sig { params(repo: String, pull_request: String).void } def pr_check_conflicts(repo, pull_request) long_build_pr_files = GitHub.issues( repo:, state: "open", labels: "no long build conflict", From 9e0a74923150d560fbdb47986eaafc552f465c46 Mon Sep 17 00:00:00 2001 From: Issy Long Date: Mon, 1 Jul 2024 18:11:11 +0100 Subject: [PATCH 14/24] dev-cmd/extract: Can't be `typed: strict` because of `undef` usage --- Library/Homebrew/dev-cmd/extract.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Library/Homebrew/dev-cmd/extract.rb b/Library/Homebrew/dev-cmd/extract.rb index af8e3b6375..5ffaac41ab 100644 --- a/Library/Homebrew/dev-cmd/extract.rb +++ b/Library/Homebrew/dev-cmd/extract.rb @@ -1,4 +1,4 @@ -# typed: true +# typed: true # This cannot be `# typed: strict` due to the use of `undef`. # frozen_string_literal: true require "abstract_command" From f854a9f3fcf08b226070fa0dd86ceb34d29617e3 Mon Sep 17 00:00:00 2001 From: Issy Long Date: Mon, 1 Jul 2024 19:11:17 +0100 Subject: [PATCH 15/24] dev-cmd/audit: Bump to Sorbet `typed: strict` --- Library/Homebrew/dev-cmd/audit.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Library/Homebrew/dev-cmd/audit.rb b/Library/Homebrew/dev-cmd/audit.rb index 7451f2124f..21682ae9ed 100644 --- a/Library/Homebrew/dev-cmd/audit.rb +++ b/Library/Homebrew/dev-cmd/audit.rb @@ -1,4 +1,4 @@ -# typed: true +# typed: strict # frozen_string_literal: true require "abstract_command" @@ -329,6 +329,7 @@ module Homebrew private + sig { params(results: T::Hash[[Symbol, Pathname], T::Array[T::Hash[Symbol, T.untyped]]]).void } def print_problems(results) results.each do |(name, path), problems| problem_lines = format_problem_lines(problems) @@ -343,6 +344,7 @@ module Homebrew end end + sig { params(problems: T::Array[T::Hash[Symbol, T.untyped]]).returns(T::Array[String]) } def format_problem_lines(problems) problems.map do |problem| status = " #{Formatter.success("[corrected]")}" if problem.fetch(:corrected) From 8360218a3e8812f95432badca1c0949f0deec9da Mon Sep 17 00:00:00 2001 From: Issy Long Date: Mon, 1 Jul 2024 19:13:38 +0100 Subject: [PATCH 16/24] Run `brew style` on all the new Sorbet sigs --- Library/Homebrew/dev-cmd/bump-formula-pr.rb | 37 ++++++++++++++------- Library/Homebrew/dev-cmd/pr-pull.rb | 20 ++++++++--- Library/Homebrew/dev-cmd/unbottled.rb | 26 ++++++++++----- 3 files changed, 59 insertions(+), 24 deletions(-) diff --git a/Library/Homebrew/dev-cmd/bump-formula-pr.rb b/Library/Homebrew/dev-cmd/bump-formula-pr.rb index 78fbb1ea17..b0e2f8e076 100644 --- a/Library/Homebrew/dev-cmd/bump-formula-pr.rb +++ b/Library/Homebrew/dev-cmd/bump-formula-pr.rb @@ -434,7 +434,10 @@ module Homebrew new_url.gsub(%r{/(v?)#{Regexp.escape(partial_old_version)}/}, "/\\1#{partial_new_version}/") end - sig { params(formula: Formula, new_version: T.nilable(String), url: String, specs: Float).returns(T::Array[T.untyped]) } + sig { + params(formula: Formula, new_version: T.nilable(String), url: String, + specs: Float).returns(T::Array[T.untyped]) + } def fetch_resource_and_forced_version(formula, new_version, url, **specs) resource = Resource.new resource.url(url, **specs) @@ -459,13 +462,18 @@ module Homebrew sig { params(formula: Formula, tap_remote_repo: String).returns(T.nilable(T::Array[String])) } def check_open_pull_requests(formula, tap_remote_repo) - GitHub.check_for_duplicate_pull_requests(formula.name, tap_remote_repo, - state: "open", - file: formula.path.relative_path_from(T.must(formula.tap).path).to_s, - quiet: args.quiet?) + GitHub.check_for_duplicate_pull_requests( + formula.name, tap_remote_repo, + state: "open", + file: formula.path.relative_path_from(T.must(formula.tap).path).to_s, + quiet: args.quiet? + ) end - sig { params(formula: Formula, tap_remote_repo: String, version: T.nilable(String), url: T.nilable(String), tag: T.nilable(String)).void } + sig { + params(formula: Formula, tap_remote_repo: String, version: T.nilable(String), url: T.nilable(String), + tag: T.nilable(String)).void + } def check_new_version(formula, tap_remote_repo, version: nil, url: nil, tag: nil) if version.nil? specs = {} @@ -493,14 +501,19 @@ module Homebrew odie "#{formula} should only be updated every #{throttled_rate} releases on multiples of #{throttled_rate}" end - sig { params(formula: Formula, tap_remote_repo: String, version: T.nilable(String)).returns(T.nilable(T::Array[String])) } + sig { + params(formula: Formula, tap_remote_repo: String, + version: T.nilable(String)).returns(T.nilable(T::Array[String])) + } def check_closed_pull_requests(formula, tap_remote_repo, version:) # if we haven't already found open requests, try for an exact match across closed requests - GitHub.check_for_duplicate_pull_requests(formula.name, tap_remote_repo, - version:, - state: "closed", - file: formula.path.relative_path_from(T.must(formula.tap).path).to_s, - quiet: args.quiet?) + GitHub.check_for_duplicate_pull_requests( + formula.name, tap_remote_repo, + version:, + state: "closed", + file: formula.path.relative_path_from(T.must(formula.tap).path).to_s, + quiet: args.quiet? + ) end sig { params(formula: Formula, new_formula_version: String).returns(T.nilable(T::Array[String])) } diff --git a/Library/Homebrew/dev-cmd/pr-pull.rb b/Library/Homebrew/dev-cmd/pr-pull.rb index ca5f01bdad..2799830f44 100644 --- a/Library/Homebrew/dev-cmd/pr-pull.rb +++ b/Library/Homebrew/dev-cmd/pr-pull.rb @@ -243,7 +243,10 @@ module Homebrew end end - sig { params(old_contents: String, new_contents: String, subject_path: T.any(String, Pathname), reason: T.nilable(String)).returns(String) } + sig { + params(old_contents: String, new_contents: String, subject_path: T.any(String, Pathname), + reason: T.nilable(String)).returns(String) + } def determine_bump_subject(old_contents, new_contents, subject_path, reason: nil) subject_path = Pathname(subject_path) tap = Tap.from_path(subject_path) @@ -272,7 +275,10 @@ module Homebrew # Cherry picks a single commit that modifies a single file. # Potentially rewords this commit using {determine_bump_subject}. - sig { params(commit: String, file: String, git_repo: GitRepository, reason: T.nilable(String), verbose: T::Boolean, resolve: T::Boolean).void } + sig { + params(commit: String, file: String, git_repo: GitRepository, reason: T.nilable(String), verbose: T::Boolean, + resolve: T::Boolean).void + } def reword_package_commit(commit, file, git_repo:, reason: "", verbose: false, resolve: false) package_file = git_repo.pathname / file package_name = package_file.basename.to_s.chomp(".rb") @@ -298,7 +304,10 @@ module Homebrew # Cherry picks multiple commits that each modify a single file. # Words the commit according to {determine_bump_subject} with the body # corresponding to all the original commit messages combined. - sig { params(commits: T::Array[String], file: String, git_repo: GitRepository, reason: T.nilable(String), verbose: T::Boolean, resolve: T::Boolean).void } + sig { + params(commits: T::Array[String], file: String, git_repo: GitRepository, reason: T.nilable(String), + verbose: T::Boolean, resolve: T::Boolean).void + } def squash_package_commits(commits, file, git_repo:, reason: "", verbose: false, resolve: false) odebug "Squashing #{file}: #{commits.join " "}" @@ -346,7 +355,10 @@ module Homebrew end # TODO: fix test in `test/dev-cmd/pr-pull_spec.rb` and assume `cherry_picked: false`. - sig { params(original_commit: String, tap: Tap, reason: String, verbose: T::Boolean, resolve: T::Boolean, cherry_picked: T::Boolean).void } + sig { + params(original_commit: String, tap: Tap, reason: String, verbose: T::Boolean, resolve: T::Boolean, + cherry_picked: T::Boolean).void + } def autosquash!(original_commit, tap:, reason: "", verbose: false, resolve: false, cherry_picked: true) git_repo = tap.git_repository original_head = git_repo.head_ref diff --git a/Library/Homebrew/dev-cmd/unbottled.rb b/Library/Homebrew/dev-cmd/unbottled.rb index b64c1fbb43..b85e0da356 100644 --- a/Library/Homebrew/dev-cmd/unbottled.rb +++ b/Library/Homebrew/dev-cmd/unbottled.rb @@ -34,11 +34,14 @@ module Homebrew def run Formulary.enable_factory_cache! - @bottle_tag = T.let(if (tag = args.tag) - Utils::Bottles::Tag.from_symbol(tag.to_sym) - else - Utils::Bottles.tag - end, T.nilable(Utils::Bottles::Tag)) + @bottle_tag = T.let( + if (tag = args.tag) + Utils::Bottles::Tag.from_symbol(tag.to_sym) + else + Utils::Bottles.tag + end, + T.nilable(Utils::Bottles::Tag), + ) if args.lost? if args.named.present? @@ -104,7 +107,9 @@ module Homebrew private - sig { params(all: T::Boolean).returns([T::Array[Formula], T::Array[Formula], T.nilable(T::Hash[Symbol, Integer])]) } + sig { + params(all: T::Boolean).returns([T::Array[Formula], T::Array[Formula], T.nilable(T::Hash[Symbol, Integer])]) + } def formulae_all_installs_from_args(all) if args.named.present? formulae = all_formulae = args.named.to_formulae @@ -152,7 +157,8 @@ module Homebrew formulae = Array(formulae).reject(&:deprecated?) if formulae.present? all_formulae = Array(all_formulae).reject(&:deprecated?) if all_formulae.present? - [T.let(formulae, T::Array[Formula]), T.let(all_formulae, T::Array[Formula]), T.let(T.must(formula_installs), T.nilable(T::Hash[Symbol, Integer]))] + [T.let(formulae, T::Array[Formula]), T.let(all_formulae, T::Array[Formula]), + T.let(T.must(formula_installs), T.nilable(T::Hash[Symbol, Integer]))] end sig { params(all_formulae: T.untyped).returns([T::Hash[String, T.untyped], T::Hash[String, T.untyped]]) } @@ -191,7 +197,11 @@ module Homebrew puts "#{unbottled_formulae}/#{formulae.length} remaining." end - sig { params(formulae: T::Array[Formula], deps_hash: T::Hash[T.any(Symbol, String), T.untyped], noun: T.nilable(String), hash: T::Hash[T.any(Symbol, String), T.untyped], any_named_args: T::Boolean).returns(NilClass) } + sig { + params(formulae: T::Array[Formula], deps_hash: T::Hash[T.any(Symbol, String), T.untyped], + noun: T.nilable(String), hash: T::Hash[T.any(Symbol, String), T.untyped], + any_named_args: T::Boolean).returns(NilClass) + } def output_unbottled(formulae, deps_hash, noun, hash, any_named_args) ohai ":#{@bottle_tag} bottle status#{@sort}" any_found = T.let(false, T::Boolean) From 3b695c6aa2961b1ef187a6802bb9d80fb82794ca Mon Sep 17 00:00:00 2001 From: Issy Long Date: Mon, 1 Jul 2024 23:36:18 +0100 Subject: [PATCH 17/24] dev-cmd/bottle: Bump to Sorbet `typed: strict` --- Library/Homebrew/dev-cmd/bottle.rb | 57 ++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/Library/Homebrew/dev-cmd/bottle.rb b/Library/Homebrew/dev-cmd/bottle.rb index 32c04a66ed..f1b4e4f355 100644 --- a/Library/Homebrew/dev-cmd/bottle.rb +++ b/Library/Homebrew/dev-cmd/bottle.rb @@ -1,4 +1,4 @@ -# typed: true +# typed: strict # frozen_string_literal: true require "abstract_command" @@ -20,7 +20,7 @@ module Homebrew class Bottle < AbstractCommand include FileUtils - BOTTLE_ERB = <<-EOS.freeze + BOTTLE_ERB = T.let(<<-EOS.freeze, String) bottle do <% if [HOMEBREW_BOTTLE_DEFAULT_DOMAIN.to_s, "#{HOMEBREW_BOTTLE_DEFAULT_DOMAIN}/bottles"].exclude?(root_url) %> @@ -39,9 +39,9 @@ module Homebrew MAXIMUM_STRING_MATCHES = 100 - ALLOWABLE_HOMEBREW_REPOSITORY_LINKS = [ + ALLOWABLE_HOMEBREW_REPOSITORY_LINKS = T.let([ %r{#{Regexp.escape(HOMEBREW_LIBRARY)}/Homebrew/os/(mac|linux)/pkgconfig}, - ].freeze + ].freeze, T::Array[Regexp]) cmd_args do description <<~EOS @@ -110,6 +110,10 @@ module Homebrew end end + sig { + params(tag: String, digest: String, cellar: T.any(Symbol, String), tag_column: Integer, + digest_column: Integer).returns(String) + } def generate_sha256_line(tag, digest, cellar, tag_column, digest_column) line = "sha256 " tag_column += line.length @@ -125,6 +129,7 @@ module Homebrew %Q(#{line}"#{digest}") end + sig { params(bottle: BottleSpecification, root_url_using: T.nilable(String)).returns(String) } def bottle_output(bottle, root_url_using) cellars = bottle.checksums.filter_map do |checksum| cellar = checksum["cellar"] @@ -153,12 +158,14 @@ module Homebrew erb.result(erb_binding).gsub(/^\s*$\n/, "") end + sig { params(filenames: T::Array[String]).returns(T::Array[T::Hash[String, T.untyped]]) } def parse_json_files(filenames) filenames.map do |filename| JSON.parse(File.read(filename)) end end + sig { params(json_files: T::Array[T::Hash[String, T.untyped]]).returns(T::Hash[String, T.untyped]) } def merge_json_files(json_files) json_files.reduce({}) do |hash, json_file| json_file.each_value do |json_hash| @@ -172,6 +179,10 @@ module Homebrew end end + sig { + params(old_keys: T::Array[String], old_bottle_spec: BottleSpecification, + new_bottle_hash: T::Hash[String, T.untyped]).returns(T::Array[T::Array[String]]) + } def merge_bottle_spec(old_keys, old_bottle_spec, new_bottle_hash) mismatches = [] checksums = [] @@ -214,16 +225,20 @@ module Homebrew private + sig { + params(string: String, keg: Keg, ignores: T::Array[String], + formula_and_runtime_deps_names: T.nilable(T::Array[String])).returns(T::Boolean) + } def keg_contain?(string, keg, ignores, formula_and_runtime_deps_names = nil) @put_string_exists_header, @put_filenames = nil print_filename = lambda do |str, filename| unless @put_string_exists_header opoo "String '#{str}' still exists in these files:" - @put_string_exists_header = true + @put_string_exists_header = T.let(true, T.nilable(T::Boolean)) end - @put_filenames ||= [] + @put_filenames ||= T.let([], T.nilable(T::Array[T.any(String, Pathname)])) return false if @put_filenames.include?(filename) @@ -265,6 +280,7 @@ module Homebrew keg_contain_absolute_symlink_starting_with?(string, keg) || result end + sig { params(string: String, keg: Keg).returns(T::Boolean) } def keg_contain_absolute_symlink_starting_with?(string, keg) absolute_symlinks_start_with_string = [] keg.find do |pn| @@ -283,6 +299,7 @@ module Homebrew !absolute_symlinks_start_with_string.empty? end + sig { params(cellar: String).returns(T.nilable(T::Boolean)) } def cellar_parameter_needed?(cellar) default_cellars = [ Homebrew::DEFAULT_MACOS_CELLAR, @@ -292,6 +309,7 @@ module Homebrew cellar.present? && default_cellars.exclude?(cellar) end + sig { returns(T.nilable(T::Boolean)) } def sudo_purge return unless ENV["HOMEBREW_BOTTLE_SUDO_PURGE"] @@ -354,6 +372,7 @@ module Homebrew [gnu_tar(gnu_tar_formula), reproducible_gnutar_args(mtime)].freeze end + sig { params(formula: T.untyped).returns(T::Array[T.untyped]) } def formula_ignores(formula) ignores = [] cellar_regex = Regexp.escape(HOMEBREW_CELLAR) @@ -384,6 +403,7 @@ module Homebrew ignores.compact end + sig { params(formula: Formula).void } def bottle_formula(formula) local_bottle_json = args.json? && formula.local_bottle_path.present? @@ -453,7 +473,7 @@ module Homebrew if local_bottle_json bottle_path = formula.local_bottle_path - local_filename = bottle_path.basename.to_s + local_filename = bottle_path&.basename&.to_s tab_path = Utils::Bottles.receipt_path(bottle_path) raise "This bottle does not contain the file INSTALL_RECEIPT.json: #{bottle_path}" unless tab_path @@ -529,11 +549,13 @@ module Homebrew Utils::Gzip.compress_with_options(relocatable_tar_path, mtime: tab.source_modified_time, orig_name: relocatable_tar_path, - output: bottle_path) + output: T.must(bottle_path)) sudo_purge end - ohai "Detecting if #{local_filename} is relocatable..." if bottle_path.size > 1 * 1024 * 1024 + if bottle_path && bottle_path.size > 1 * 1024 * 1024 + ohai "Detecting if #{local_filename} is relocatable..." + end prefix_check = if Homebrew.default_prefix?(prefix) File.join(prefix, "opt") @@ -574,7 +596,7 @@ module Homebrew end puts if !relocatable && args.verbose? rescue Interrupt - ignore_interrupts { bottle_path.unlink if bottle_path.exist? } + ignore_interrupts { bottle_path.unlink if bottle_path&.exist? } raise ensure ignore_interrupts do @@ -597,7 +619,7 @@ module Homebrew cellar end bottle.rebuild rebuild - sha256 = bottle_path.sha256 + sha256 = bottle_path&.sha256 bottle.sha256 cellar: bottle_cellar, bottle_tag.to_sym => sha256 old_spec = formula.bottle_specification @@ -606,7 +628,7 @@ module Homebrew old_spec.send(key) == bottle.send(key) end unless mismatches.empty? - bottle_path.unlink if bottle_path.exist? + bottle_path.unlink if bottle_path&.exist? mismatches.map! do |key| old_value = old_spec.send(key).inspect @@ -681,6 +703,7 @@ module Homebrew json_path.write(JSON.pretty_generate(json)) end + sig { returns(T::Hash[String, T.untyped]) } def merge bottles_hash = merge_json_files(parse_json_files(args.named)) @@ -750,7 +773,7 @@ module Homebrew end end - all_bottle_hash = T.let(nil, T.nilable(Hash)) + all_bottle_hash = T.let(nil, T.nilable(T::Hash[String, T.untyped])) bottle_hash["bottle"]["tags"].each do |tag, tag_hash| filename = ::Bottle::Filename.new( formula_name, @@ -801,7 +824,7 @@ module Homebrew checksums = old_checksums(formula, formula_ast, bottle_hash) update_or_add = checksums.nil? ? "add" : "update" - checksums&.each(&bottle.method(:sha256)) + checksums&.each { |checksum| bottle.sha256(checksum) } output = bottle_output(bottle, args.root_url_using) puts output @@ -835,8 +858,12 @@ module Homebrew end end + sig { + params(formula: Formula, formula_ast: Utils::AST::FormulaAST, + bottle_hash: T::Hash[String, T.untyped]).returns(T.nilable(T::Array[String])) + } def old_checksums(formula, formula_ast, bottle_hash) - bottle_node = formula_ast.bottle_block + bottle_node = T.cast(formula_ast.bottle_block, T.nilable(RuboCop::AST::BlockNode)) return if bottle_node.nil? return [] unless args.keep_old? From 9130dd12101d6cae5b00e82c13acc5984ac9e2e4 Mon Sep 17 00:00:00 2001 From: Issy Long Date: Mon, 1 Jul 2024 23:46:25 +0100 Subject: [PATCH 18/24] dev-cmd/contributions: Tighten up type sigs --- Library/Homebrew/dev-cmd/contributions.rb | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Library/Homebrew/dev-cmd/contributions.rb b/Library/Homebrew/dev-cmd/contributions.rb index 1fbf958318..a1fe4b80cd 100644 --- a/Library/Homebrew/dev-cmd/contributions.rb +++ b/Library/Homebrew/dev-cmd/contributions.rb @@ -116,7 +116,7 @@ module Homebrew end end - sig { params(totals: T::Hash[T.untyped, T.untyped]).returns(String) } + sig { params(totals: T::Hash[String, T::Hash[Symbol, Integer]]).returns(String) } def generate_csv(totals) CSV.generate do |csv| csv << %w[user repo author committer coauthor review total] @@ -127,7 +127,14 @@ module Homebrew end end - sig { params(user: String, grand_total: T::Hash[Symbol, T.untyped]).returns(T::Array[T.any(String, Integer)]) } + sig { + params( + user: String, + grand_total: T::Hash[Symbol, Integer], + ).returns( + [String, String, T.nilable(Integer), T.nilable(Integer), T.nilable(Integer), T.nilable(Integer), Integer], + ) + } def grand_total_row(user, grand_total) [ user, From b9b065a54ed56e8328e0dcd64f44e7d56987a439 Mon Sep 17 00:00:00 2001 From: Issy Long Date: Tue, 2 Jul 2024 00:03:28 +0100 Subject: [PATCH 19/24] dev-cmd/bottle: Fix type errors (strings, symbols, either, none) thanks to the tests --- Library/Homebrew/dev-cmd/bottle.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Library/Homebrew/dev-cmd/bottle.rb b/Library/Homebrew/dev-cmd/bottle.rb index f1b4e4f355..7e9c37c776 100644 --- a/Library/Homebrew/dev-cmd/bottle.rb +++ b/Library/Homebrew/dev-cmd/bottle.rb @@ -111,8 +111,8 @@ module Homebrew end sig { - params(tag: String, digest: String, cellar: T.any(Symbol, String), tag_column: Integer, - digest_column: Integer).returns(String) + params(tag: Symbol, digest: T.any(Checksum, String), cellar: T.nilable(T.any(String, Symbol)), + tag_column: Integer, digest_column: Integer).returns(String) } def generate_sha256_line(tag, digest, cellar, tag_column, digest_column) line = "sha256 " @@ -299,7 +299,7 @@ module Homebrew !absolute_symlinks_start_with_string.empty? end - sig { params(cellar: String).returns(T.nilable(T::Boolean)) } + sig { params(cellar: T.nilable(T.any(String, Symbol))).returns(T.nilable(T::Boolean)) } def cellar_parameter_needed?(cellar) default_cellars = [ Homebrew::DEFAULT_MACOS_CELLAR, From 1db0834a91d9c68d3d4b7a186c1b0a7447b4066d Mon Sep 17 00:00:00 2001 From: Issy Long Date: Tue, 2 Jul 2024 11:21:29 +0100 Subject: [PATCH 20/24] dev-cmd/bottle: The `cellar_parameter_needed?` method returns always boolean --- Library/Homebrew/dev-cmd/bottle.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Library/Homebrew/dev-cmd/bottle.rb b/Library/Homebrew/dev-cmd/bottle.rb index 7e9c37c776..b46b335414 100644 --- a/Library/Homebrew/dev-cmd/bottle.rb +++ b/Library/Homebrew/dev-cmd/bottle.rb @@ -299,7 +299,7 @@ module Homebrew !absolute_symlinks_start_with_string.empty? end - sig { params(cellar: T.nilable(T.any(String, Symbol))).returns(T.nilable(T::Boolean)) } + sig { params(cellar: T.nilable(T.any(String, Symbol))).returns(T::Boolean) } def cellar_parameter_needed?(cellar) default_cellars = [ Homebrew::DEFAULT_MACOS_CELLAR, From 3d09094df0b67cd3848e0bd60cb9cb7b0ea5de5d Mon Sep 17 00:00:00 2001 From: Issy Long Date: Tue, 2 Jul 2024 15:24:01 +0100 Subject: [PATCH 21/24] Fewer `T.must`s --- Library/Homebrew/dev-cmd/bottle.rb | 17 +++++------ Library/Homebrew/dev-cmd/bump-formula-pr.rb | 28 +++++++++++++----- Library/Homebrew/dev-cmd/contributions.rb | 12 ++++---- Library/Homebrew/dev-cmd/pr-pull.rb | 32 ++++++++++++++------- Library/Homebrew/dev-cmd/unbottled.rb | 25 ++++++++++------ 5 files changed, 75 insertions(+), 39 deletions(-) diff --git a/Library/Homebrew/dev-cmd/bottle.rb b/Library/Homebrew/dev-cmd/bottle.rb index b46b335414..6f96a13ee8 100644 --- a/Library/Homebrew/dev-cmd/bottle.rb +++ b/Library/Homebrew/dev-cmd/bottle.rb @@ -473,7 +473,9 @@ module Homebrew if local_bottle_json bottle_path = formula.local_bottle_path - local_filename = bottle_path&.basename&.to_s + return if bottle_path.blank? + + local_filename = bottle_path.basename.to_s tab_path = Utils::Bottles.receipt_path(bottle_path) raise "This bottle does not contain the file INSTALL_RECEIPT.json: #{bottle_path}" unless tab_path @@ -491,6 +493,7 @@ module Homebrew else tar_filename = filename.to_s.sub(/.gz$/, "") tar_path = Pathname.pwd/tar_filename + return if tar_path.blank? keg = Keg.new(formula.prefix) end @@ -549,13 +552,11 @@ module Homebrew Utils::Gzip.compress_with_options(relocatable_tar_path, mtime: tab.source_modified_time, orig_name: relocatable_tar_path, - output: T.must(bottle_path)) + output: bottle_path) sudo_purge end - if bottle_path && bottle_path.size > 1 * 1024 * 1024 - ohai "Detecting if #{local_filename} is relocatable..." - end + ohai "Detecting if #{local_filename} is relocatable..." if bottle_path.size > 1 * 1024 * 1024 prefix_check = if Homebrew.default_prefix?(prefix) File.join(prefix, "opt") @@ -596,7 +597,7 @@ module Homebrew end puts if !relocatable && args.verbose? rescue Interrupt - ignore_interrupts { bottle_path.unlink if bottle_path&.exist? } + ignore_interrupts { bottle_path.unlink if bottle_path.exist? } raise ensure ignore_interrupts do @@ -619,7 +620,7 @@ module Homebrew cellar end bottle.rebuild rebuild - sha256 = bottle_path&.sha256 + sha256 = bottle_path.sha256 bottle.sha256 cellar: bottle_cellar, bottle_tag.to_sym => sha256 old_spec = formula.bottle_specification @@ -628,7 +629,7 @@ module Homebrew old_spec.send(key) == bottle.send(key) end unless mismatches.empty? - bottle_path.unlink if bottle_path&.exist? + bottle_path.unlink if bottle_path.exist? mismatches.map! do |key| old_value = old_spec.send(key).inspect diff --git a/Library/Homebrew/dev-cmd/bump-formula-pr.rb b/Library/Homebrew/dev-cmd/bump-formula-pr.rb index b0e2f8e076..2e3f10b25f 100644 --- a/Library/Homebrew/dev-cmd/bump-formula-pr.rb +++ b/Library/Homebrew/dev-cmd/bump-formula-pr.rb @@ -429,8 +429,10 @@ module Homebrew return new_url if (old_version_parts = old_version.split(".")).length < 2 return new_url if (new_version_parts = new_version.split(".")).length != old_version_parts.length - partial_old_version = T.must(old_version_parts[0..-2]).join(".") - partial_new_version = T.must(new_version_parts[0..-2]).join(".") + partial_old_version = old_version_parts[0..-2]&.join(".") + partial_new_version = new_version_parts[0..-2]&.join(".") + return new_url if partial_old_version.blank? || partial_new_version.blank? + new_url.gsub(%r{/(v?)#{Regexp.escape(partial_old_version)}/}, "/\\1#{partial_new_version}/") end @@ -462,10 +464,13 @@ module Homebrew sig { params(formula: Formula, tap_remote_repo: String).returns(T.nilable(T::Array[String])) } def check_open_pull_requests(formula, tap_remote_repo) + tap = formula.tap + return if tap.nil? + GitHub.check_for_duplicate_pull_requests( formula.name, tap_remote_repo, state: "open", - file: formula.path.relative_path_from(T.must(formula.tap).path).to_s, + file: formula.path.relative_path_from(tap.path).to_s, quiet: args.quiet? ) end @@ -488,8 +493,11 @@ module Homebrew sig { params(formula: Formula, new_version: String).returns(NilClass) } def check_throttle(formula, new_version) + tap = formula.tap + return if tap.nil? + throttled_rate = formula.livecheck.throttle - throttled_rate ||= if (rate = T.must(formula.tap).audit_exceptions.dig(:throttled_formulae, formula.name)) + throttled_rate ||= if (rate = tap.audit_exceptions.dig(:throttled_formulae, formula.name)) odisabled "throttled_formulae.json", "Livecheck#throttle" rate end @@ -506,12 +514,15 @@ module Homebrew version: T.nilable(String)).returns(T.nilable(T::Array[String])) } def check_closed_pull_requests(formula, tap_remote_repo, version:) + tap = formula.tap + return if tap.nil? + # if we haven't already found open requests, try for an exact match across closed requests GitHub.check_for_duplicate_pull_requests( formula.name, tap_remote_repo, version:, state: "closed", - file: formula.path.relative_path_from(T.must(formula.tap).path).to_s, + file: formula.path.relative_path_from(tap.path).to_s, quiet: args.quiet? ) end @@ -522,9 +533,12 @@ module Homebrew return if versioned_alias.nil? name, old_alias_version = versioned_alias.split("@") - new_alias_regex = (T.must(old_alias_version).split(".").length == 1) ? /^\d+/ : /^\d+\.\d+/ + return if old_alias_version.blank? + + new_alias_regex = (old_alias_version.split(".").length == 1) ? /^\d+/ : /^\d+\.\d+/ new_alias_version, = *new_formula_version.to_s.match(new_alias_regex) - return if Version.new(T.must(new_alias_version)) <= Version.new(T.must(old_alias_version)) + return if new_alias_version.blank? + return if Version.new(new_alias_version) <= Version.new(old_alias_version) [versioned_alias, "#{name}@#{new_alias_version}"] end diff --git a/Library/Homebrew/dev-cmd/contributions.rb b/Library/Homebrew/dev-cmd/contributions.rb index a1fe4b80cd..96159227fa 100644 --- a/Library/Homebrew/dev-cmd/contributions.rb +++ b/Library/Homebrew/dev-cmd/contributions.rb @@ -10,7 +10,7 @@ end module Homebrew module DevCmd class Contributions < AbstractCommand - PRIMARY_REPOS = %w[brew core cask].freeze + PRIMARY_REPOS = T.let(%w[brew core cask].freeze, T::Array[String]) SUPPORTED_REPOS = T.let([ PRIMARY_REPOS, OFFICIAL_CMD_TAPS.keys.map { |t| t.delete_prefix("homebrew/") }, @@ -50,12 +50,12 @@ module Homebrew results = {} grand_totals = {} - repos = if args.repositories.blank? || T.must(args.repositories).include?("primary") + repos = if args.repositories.blank? || args.repositories&.include?("primary") PRIMARY_REPOS - elsif T.must(args.repositories).include?("all") + elsif args.repositories&.include?("all") SUPPORTED_REPOS else - T.must(args.repositories) + args.repositories end from = args.from.presence || Date.today.prev_year.iso8601 @@ -147,8 +147,10 @@ module Homebrew ] end - sig { params(repos: T::Array[String], person: String, from: String).void } + sig { params(repos: T.nilable(T::Array[String]), person: String, from: String).void } def scan_repositories(repos, person, from:) + return if repos.blank? + data = {} repos.each do |repo| diff --git a/Library/Homebrew/dev-cmd/pr-pull.rb b/Library/Homebrew/dev-cmd/pr-pull.rb index 2799830f44..d3f8225109 100644 --- a/Library/Homebrew/dev-cmd/pr-pull.rb +++ b/Library/Homebrew/dev-cmd/pr-pull.rb @@ -126,7 +126,7 @@ module Homebrew cherry_pick_pr!(user, repo, pr, path: tap.path) unless args.no_cherry_pick? if args.autosquash? && !args.dry_run? autosquash!(original_commit, tap:, cherry_picked: !args.no_cherry_pick?, - verbose: args.verbose?, resolve: args.resolve?, reason: T.must(args.message)) + verbose: args.verbose?, resolve: args.resolve?, reason: args.message) end signoff!(git_repo, pull_request: pr, dry_run: args.dry_run?) unless args.clean? end @@ -141,7 +141,7 @@ module Homebrew user, repo, pr, workflow_id: workflow, artifact_pattern: ) if args.ignore_missing_artifacts.present? && - T.must(args.ignore_missing_artifacts).include?(workflow) && + args.ignore_missing_artifacts&.include?(workflow) && workflow_run.first.blank? # Ignore that workflow as it was not executed and we specified # that we could skip it. @@ -185,7 +185,8 @@ module Homebrew # Separates a commit message into subject, body and trailers. sig { params(message: String).returns([String, String, String]) } def separate_commit_message(message) - subject = T.must(message.lines.first).strip + first_line = message.lines.first + return ["", "", ""] unless first_line # Skip the subject and separate lines that look like trailers (e.g. "Co-authored-by") # from lines that look like regular body text. @@ -194,12 +195,15 @@ module Homebrew trailers = trailers.uniq.join.strip body = body.join.strip.gsub(/\n{3,}/, "\n\n") - [subject, body, trailers] + [first_line.strip, body, trailers] end sig { params(git_repo: GitRepository, pull_request: T.nilable(String), dry_run: T::Boolean).void } def signoff!(git_repo, pull_request: nil, dry_run: false) - subject, body, trailers = separate_commit_message(T.must(git_repo.commit_message)) + msg = git_repo.commit_message + return if msg.blank? + + subject, body, trailers = separate_commit_message(msg) if pull_request # This is a tap pull request and approving reviewers should also sign-off. @@ -290,7 +294,10 @@ module Homebrew new_package = Utils::Git.file_at_commit(git_repo.to_s, file, "HEAD") bump_subject = determine_bump_subject(old_package, new_package, package_file, reason:).strip - subject, body, trailers = separate_commit_message(T.must(git_repo.commit_message)) + msg = git_repo.commit_message + return if msg.blank? + + subject, body, trailers = separate_commit_message(msg) if subject != bump_subject && !subject.start_with?("#{package_name}:") safe_system("git", "-C", git_repo.pathname, "commit", "--amend", "-q", @@ -319,7 +326,10 @@ module Homebrew messages = [] trailers = [] commits.each do |commit| - subject, body, trailer = separate_commit_message(T.must(git_repo.commit_message(commit))) + msg = git_repo.commit_message(commit) + next if msg.blank? + + subject, body, trailer = separate_commit_message(msg) body = body.lines.map { |line| " #{line.strip}" }.join("\n") messages << "* #{subject}\n#{body}".strip trailers << trailer @@ -356,12 +366,11 @@ module Homebrew # TODO: fix test in `test/dev-cmd/pr-pull_spec.rb` and assume `cherry_picked: false`. sig { - params(original_commit: String, tap: Tap, reason: String, verbose: T::Boolean, resolve: T::Boolean, + params(original_commit: String, tap: Tap, reason: T.nilable(String), verbose: T::Boolean, resolve: T::Boolean, cherry_picked: T::Boolean).void } def autosquash!(original_commit, tap:, reason: "", verbose: false, resolve: false, cherry_picked: true) git_repo = tap.git_repository - original_head = git_repo.head_ref commits = Utils.safe_popen_read("git", "-C", tap.path, "rev-list", "--reverse", "#{original_commit}..HEAD").lines.map(&:strip) @@ -421,8 +430,11 @@ module Homebrew end end rescue + original_head = git_repo&.head_ref + return if original_head.nil? + opoo "Autosquash encountered an error; resetting to original state at #{original_head}" - system "git", "-C", tap.path.to_s, "reset", "--hard", T.must(original_head) + system "git", "-C", tap.path.to_s, "reset", "--hard", original_head system "git", "-C", tap.path.to_s, "cherry-pick", "--abort" if cherry_picked raise end diff --git a/Library/Homebrew/dev-cmd/unbottled.rb b/Library/Homebrew/dev-cmd/unbottled.rb index b85e0da356..7a73caf4a1 100644 --- a/Library/Homebrew/dev-cmd/unbottled.rb +++ b/Library/Homebrew/dev-cmd/unbottled.rb @@ -42,6 +42,7 @@ module Homebrew end, T.nilable(Utils::Bottles::Tag), ) + return unless @bottle_tag if args.lost? if args.named.present? @@ -54,13 +55,13 @@ module Homebrew end end - os = T.must(@bottle_tag).system - arch = if Hardware::CPU::INTEL_ARCHS.include?(T.must(@bottle_tag).arch) + os = @bottle_tag.system + arch = if Hardware::CPU::INTEL_ARCHS.include?(@bottle_tag.arch) :intel - elsif Hardware::CPU::ARM_ARCHS.include?(T.must(@bottle_tag).arch) + elsif Hardware::CPU::ARM_ARCHS.include?(@bottle_tag.arch) :arm else - raise "Unknown arch #{T.must(@bottle_tag).arch}." + raise "Unknown arch #{@bottle_tag.arch}." end Homebrew::SimulateSystem.with(os:, arch:) do @@ -101,7 +102,9 @@ module Homebrew ["installs", formula_installs] end - output_unbottled(formulae, deps_hash, noun, T.must(hash), args.named.present?) + return if hash.nil? + + output_unbottled(formulae, deps_hash, noun, hash, args.named.present?) end end @@ -158,7 +161,7 @@ module Homebrew all_formulae = Array(all_formulae).reject(&:deprecated?) if all_formulae.present? [T.let(formulae, T::Array[Formula]), T.let(all_formulae, T::Array[Formula]), - T.let(T.must(formula_installs), T.nilable(T::Hash[Symbol, Integer]))] + T.let(formula_installs, T.nilable(T::Hash[Symbol, Integer]))] end sig { params(all_formulae: T.untyped).returns([T::Hash[String, T.untyped], T::Hash[String, T.untyped]]) } @@ -185,6 +188,8 @@ module Homebrew sig { params(formulae: T::Array[Formula]).returns(NilClass) } def output_total(formulae) + return unless @bottle_tag + ohai "Unbottled :#{@bottle_tag} formulae" unbottled_formulae = 0 @@ -203,6 +208,8 @@ module Homebrew any_named_args: T::Boolean).returns(NilClass) } def output_unbottled(formulae, deps_hash, noun, hash, any_named_args) + return unless @bottle_tag + ohai ":#{@bottle_tag} bottle status#{@sort}" any_found = T.let(false, T::Boolean) @@ -215,7 +222,7 @@ module Homebrew end requirements = f.recursive_requirements - if T.must(@bottle_tag).linux? + if @bottle_tag.linux? if requirements.any? { |r| r.is_a?(MacOSRequirement) && !r.version } puts "#{Tty.bold}#{Tty.red}#{name}#{Tty.reset}: requires macOS" if any_named_args next @@ -224,7 +231,7 @@ module Homebrew puts "#{Tty.bold}#{Tty.red}#{name}#{Tty.reset}: requires Linux" if any_named_args next else - macos_version = T.must(@bottle_tag).to_macos_version + macos_version = @bottle_tag.to_macos_version macos_satisfied = requirements.all? do |r| case r when MacOSRequirement @@ -236,7 +243,7 @@ module Homebrew Version.new(MacOS::Xcode.latest_version(macos: macos_version)) >= r.version when ArchRequirement - r.arch == T.must(@bottle_tag).arch + r.arch == @bottle_tag.arch else true end From 9baf50af291b3536c9c119363e8afe6d93f55aef Mon Sep 17 00:00:00 2001 From: Issy Long Date: Wed, 3 Jul 2024 14:09:11 +0100 Subject: [PATCH 22/24] Get rid of even more `T.must`s Co-authored-by: Mike McQuaid --- Library/Homebrew/dev-cmd/bump-formula-pr.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Library/Homebrew/dev-cmd/bump-formula-pr.rb b/Library/Homebrew/dev-cmd/bump-formula-pr.rb index 2e3f10b25f..8b20ea8c2a 100644 --- a/Library/Homebrew/dev-cmd/bump-formula-pr.rb +++ b/Library/Homebrew/dev-cmd/bump-formula-pr.rb @@ -558,7 +558,9 @@ module Homebrew end return end - FileUtils.mv T.must(alias_rename.first), T.must(alias_rename.last) if alias_rename.present? + if alias_rename && (source = alias_rename.first) && (destination = alias_rename.last) + FileUtils.mv source, destination + end failed_audit = false if args.no_audit? ohai "Skipping `brew audit`" @@ -572,7 +574,9 @@ module Homebrew return unless failed_audit formula.path.atomic_write(old_contents) - FileUtils.mv T.must(alias_rename.last), T.must(alias_rename.first) if alias_rename.present? + if alias_rename && (source = alias_rename.first) && (destination = alias_rename.last) + FileUtils.mv source, destination + end odie "`brew audit` failed!" end end From b6f142f7a96186e4b2e6b4a37d1d4fdab29e8b60 Mon Sep 17 00:00:00 2001 From: Issy Long Date: Wed, 3 Jul 2024 16:20:36 +0100 Subject: [PATCH 23/24] Fewer `T.must`s --- Library/Homebrew/dev-cmd/bump-formula-pr.rb | 28 ++++++++++++--------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/Library/Homebrew/dev-cmd/bump-formula-pr.rb b/Library/Homebrew/dev-cmd/bump-formula-pr.rb index 8b20ea8c2a..74dea4cf15 100644 --- a/Library/Homebrew/dev-cmd/bump-formula-pr.rb +++ b/Library/Homebrew/dev-cmd/bump-formula-pr.rb @@ -145,10 +145,10 @@ module Homebrew old_mirrors = formula_spec.mirrors new_mirrors ||= args.mirror - new_mirror ||= determine_mirror(T.must(new_url)) - new_mirrors ||= [new_mirror] if new_mirror.present? - - check_for_mirrors(formula, old_mirrors, T.must(new_mirrors)) if new_url.present? + if new_url.present? && (new_mirror = determine_mirror(new_url)) + new_mirrors ||= [new_mirror] + check_for_mirrors(formula, old_mirrors, new_mirrors) + end old_hash = formula_spec.checksum&.hexdigest new_hash = args.sha256 @@ -179,7 +179,7 @@ module Homebrew EOS end check_new_version(formula, tap_remote_repo, url: old_url, tag: new_tag) if new_version.blank? - resource_path, forced_version = fetch_resource_and_forced_version(formula, T.must(new_version), old_url, + resource_path, forced_version = fetch_resource_and_forced_version(formula, new_version, old_url, tag: new_tag) new_revision = Utils.popen_read("git", "-C", resource_path.to_s, "rev-parse", "-q", "--verify", "HEAD") new_revision = new_revision.strip @@ -190,12 +190,14 @@ module Homebrew elsif new_url.blank? && new_version.blank? raise UsageError, "#{formula}: no `--url` or `--version` argument specified!" else - new_url ||= PyPI.update_pypi_url(old_url, T.must(new_version)) + return unless new_version.present? + + new_url ||= PyPI.update_pypi_url(old_url, new_version) if new_url.blank? - new_url = update_url(old_url, old_version, T.must(new_version)) + new_url = update_url(old_url, old_version, new_version) if new_mirrors.blank? && old_mirrors.present? new_mirrors = old_mirrors.map do |old_mirror| - update_url(old_mirror, old_version, T.must(new_version)) + update_url(old_mirror, old_version, new_version) end end end @@ -207,7 +209,7 @@ module Homebrew EOS end check_new_version(formula, tap_remote_repo, url: new_url) if new_version.blank? - resource_path, forced_version = fetch_resource_and_forced_version(formula, T.must(new_version), new_url) + resource_path, forced_version = fetch_resource_and_forced_version(formula, new_version, new_url) Utils::Tar.validate_file(resource_path) new_hash = resource_path.sha256 end @@ -271,9 +273,9 @@ module Homebrew old_contents = formula.path.read - if new_mirrors.present? + if new_mirrors.present? && new_url.present? replacement_pairs << [ - /^( +)(url "#{Regexp.escape(T.must(new_url))}"[^\n]*?\n)/m, + /^( +)(url "#{Regexp.escape(new_url)}"[^\n]*?\n)/m, "\\1\\2\\1mirror \"#{new_mirrors.join("\"\n\\1mirror \"")}\"\n", ] end @@ -483,7 +485,9 @@ module Homebrew if version.nil? specs = {} specs[:tag] = tag if tag.present? - version = Version.detect(T.must(url), **specs).to_s + return if url.blank? + + version = Version.detect(url, **specs).to_s return if version.blank? end From 4b83521061c7c859d9750baafe0273c963f2c8ea Mon Sep 17 00:00:00 2001 From: Issy Long Date: Wed, 3 Jul 2024 20:34:44 +0100 Subject: [PATCH 24/24] dev_cmd/irb: Straight away `require "formula"` - Otherwise we get: `uninitialized constant String::Formula (NameError)``` --- Library/Homebrew/dev-cmd/irb.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Library/Homebrew/dev-cmd/irb.rb b/Library/Homebrew/dev-cmd/irb.rb index 6599b73b22..40a3fd9fc9 100644 --- a/Library/Homebrew/dev-cmd/irb.rb +++ b/Library/Homebrew/dev-cmd/irb.rb @@ -2,6 +2,7 @@ # frozen_string_literal: true require "abstract_command" +require "formula" require "formulary" require "cask/cask_loader" @@ -9,7 +10,6 @@ class String # @!visibility private sig { params(args: Integer).returns(Formula) } def f(*args) - require "formula" Formulary.factory(self, *args) end @@ -76,7 +76,6 @@ module Homebrew require "irb" end - require "formula" require "keg" require "cask"