From 7720485f40e25188bf921213c0ceef564bf77f45 Mon Sep 17 00:00:00 2001 From: Douglas Eichelberger Date: Sat, 25 Mar 2023 08:36:56 -0700 Subject: [PATCH 1/3] Enable types in Formula files --- Library/Homebrew/extend/object.rbi | 6 ---- .../extend/os/mac/formula_cellar_checks.rb | 2 +- Library/Homebrew/formula_auditor.rb | 18 ++++++------ Library/Homebrew/formula_cellar_checks.rb | 15 ++++++++-- Library/Homebrew/formula_cellar_checks.rbi | 5 ++++ Library/Homebrew/formula_installer.rb | 8 +++--- Library/Homebrew/formulary.rb | 28 ++++++++++--------- Library/Homebrew/formulary.rbi | 5 ++++ Library/Homebrew/resource.rb | 1 + 9 files changed, 53 insertions(+), 35 deletions(-) delete mode 100644 Library/Homebrew/extend/object.rbi create mode 100644 Library/Homebrew/formula_cellar_checks.rbi create mode 100644 Library/Homebrew/formulary.rbi diff --git a/Library/Homebrew/extend/object.rbi b/Library/Homebrew/extend/object.rbi deleted file mode 100644 index cc39405568..0000000000 --- a/Library/Homebrew/extend/object.rbi +++ /dev/null @@ -1,6 +0,0 @@ -# typed: strict - -class Object - sig { returns(T::Boolean) } - def present?; end -end diff --git a/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb b/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb index 021122eec8..c6fcda74db 100644 --- a/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb +++ b/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb @@ -1,4 +1,4 @@ -# typed: false +# typed: true # frozen_string_literal: true require "cache_store" diff --git a/Library/Homebrew/formula_auditor.rb b/Library/Homebrew/formula_auditor.rb index 99aa219f5b..4174530677 100644 --- a/Library/Homebrew/formula_auditor.rb +++ b/Library/Homebrew/formula_auditor.rb @@ -1,4 +1,4 @@ -# typed: false +# typed: true # frozen_string_literal: true require "deprecate_disable" @@ -391,7 +391,7 @@ module Homebrew "canonical name (#{conflicting_formula.name}) instead of #{conflict.name}" end - reverse_conflict_found = false + reverse_conflict_found = T.let(false, T::Boolean) conflicting_formula.conflicts.each do |reverse_conflict| reverse_conflict_formula = Formulary.factory(reverse_conflict.name) if tap.formula_renames.key?(reverse_conflict.name) || tap.aliases.include?(reverse_conflict.name) @@ -732,14 +732,14 @@ module Homebrew current_revision = formula.revision current_url = formula.stable.url - previous_version = nil - previous_version_scheme = nil - previous_revision = nil + previous_version = T.let(nil, T.nilable(Version)) + previous_version_scheme = T.let(nil, T.nilable(Integer)) + previous_revision = T.let(nil, T.nilable(Integer)) - newest_committed_version = nil - newest_committed_checksum = nil - newest_committed_revision = nil - newest_committed_url = nil + newest_committed_version = T.let(nil, T.nilable(Version)) + newest_committed_checksum = T.let(nil, T.nilable(String)) + newest_committed_revision = T.let(nil, T.nilable(Integer)) + newest_committed_url = T.let(nil, T.nilable(String)) fv.rev_list("origin/HEAD") do |rev| begin diff --git a/Library/Homebrew/formula_cellar_checks.rb b/Library/Homebrew/formula_cellar_checks.rb index 700ed7c0ad..ed988b1d7c 100644 --- a/Library/Homebrew/formula_cellar_checks.rb +++ b/Library/Homebrew/formula_cellar_checks.rb @@ -1,4 +1,4 @@ -# typed: false +# typed: true # frozen_string_literal: true require "utils/shell" @@ -7,6 +7,17 @@ require "utils/shell" # # @api private module FormulaCellarChecks + extend T::Sig + extend T::Helpers + + abstract! + + sig { abstract.returns(Formula) } + def formula; end + + sig { abstract.params(output: T.nilable(String)).void } + def problem_if_output(output); end + def check_env_path(bin) # warn the user if stuff was installed outside of their PATH return unless bin.directory? @@ -407,7 +418,7 @@ module FormulaCellarChecks end end - has_cpuid_instruction = false + has_cpuid_instruction = T.let(false, T::Boolean) Utils.popen_read(objdump, "--disassemble", file) do |io| until io.eof? instruction = io.readline.split("\t")[@instruction_column_index[objdump]]&.strip diff --git a/Library/Homebrew/formula_cellar_checks.rbi b/Library/Homebrew/formula_cellar_checks.rbi new file mode 100644 index 0000000000..7e451676f9 --- /dev/null +++ b/Library/Homebrew/formula_cellar_checks.rbi @@ -0,0 +1,5 @@ +# typed: strict + +module FormulaCellarChecks + include Kernel +end diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb index 0edde1f5fe..b6f21f2e52 100644 --- a/Library/Homebrew/formula_installer.rb +++ b/Library/Homebrew/formula_installer.rb @@ -1,4 +1,4 @@ -# typed: false +# typed: true # frozen_string_literal: true require "formula" @@ -653,7 +653,7 @@ on_request: installed_on_request?, options: options) inherited_options end - sig { params(deps: T::Array[[Formula, Options]]).void } + sig { params(deps: T::Array[[Dependency, Options]]).void } def install_dependencies(deps) if deps.empty? && only_deps? puts "All dependencies for #{formula.full_name} are satisfied." @@ -745,7 +745,7 @@ on_request: installed_on_request?, options: options) fi.finish rescue Exception => e # rubocop:disable Lint/RescueException ignore_interrupts do - tmp_keg.rename(installed_keg) if tmp_keg && !installed_keg.directory? + tmp_keg.rename(installed_keg.to_s) if tmp_keg && !installed_keg.directory? linked_keg.link(verbose: verbose?) if keg_was_linked end raise unless e.is_a? FormulaInstallationAlreadyAttemptedError @@ -1266,7 +1266,7 @@ on_request: installed_on_request?, options: options) keg.relocate_build_prefix(keg, prefix, HOMEBREW_PREFIX) end - sig { params(output: T.nilable(String)).void } + sig { override.params(output: T.nilable(String)).void } def problem_if_output(output) return unless output diff --git a/Library/Homebrew/formulary.rb b/Library/Homebrew/formulary.rb index 767b8b9536..588b29c2e1 100644 --- a/Library/Homebrew/formulary.rb +++ b/Library/Homebrew/formulary.rb @@ -1,4 +1,4 @@ -# typed: false +# typed: true # frozen_string_literal: true require "digest/md5" @@ -56,7 +56,7 @@ module Formulary namespace = Utils.deconstantize(klass.name) next if Utils.deconstantize(namespace) != name - remove_const(Utils.demodulize(namespace)) + remove_const(Utils.demodulize(namespace).to_sym) end end @@ -67,6 +67,7 @@ module Formulary module PathnameWriteMkpath refine Pathname do def write(content, offset = nil, **open_args) + T.bind(self, Pathname) raise "Will not overwrite #{self}" if exist? && !offset && !open_args[:mode]&.match?(/^a\+?$/) dirname.mkpath @@ -132,7 +133,7 @@ module Formulary namespace = "FormulaNamespaceAPI#{Digest::MD5.hexdigest(name)}" mod = Module.new - remove_const(namespace) if const_defined?(namespace) + remove_const(namespace.to_sym) if const_defined?(namespace) const_set(namespace, mod) mod.const_set(:BUILD_FLAGS, flags) @@ -268,6 +269,7 @@ module Formulary service_hash = Homebrew::Service.deserialize(service_hash) run_params = service_hash.delete(:run) service do + T.bind(self, Homebrew::Service) if run_params.is_a?(Hash) run(**run_params) else @@ -306,7 +308,7 @@ module Formulary end end - klass.loaded_from_api = true + T.cast(klass, T.class_of(Formula)).loaded_from_api = true mod.const_set(class_s, klass) cache[:api] ||= {} @@ -351,7 +353,7 @@ module Formulary def self.class_s(name) class_name = name.capitalize - class_name.gsub!(/[-_.\s]([a-zA-Z0-9])/) { Regexp.last_match(1).upcase } + class_name.gsub!(/[-_.\s]([a-zA-Z0-9])/) { T.must(Regexp.last_match(1)).upcase } class_name.tr!("+", "x") class_name.sub!(/(.)@(\d)/, "\\1AT\\2") class_name @@ -489,17 +491,17 @@ module Formulary def initialize(url, from: nil) @url = url @from = from - uri = URI(url) - formula = File.basename(uri.path, ".rb") - super formula, HOMEBREW_CACHE_FORMULA/File.basename(uri.path) + uri_path = T.must(URI(url).path) + formula = File.basename(uri_path, ".rb") + super formula, HOMEBREW_CACHE_FORMULA/File.basename(uri_path) end def load_file(flags:, ignore_errors:) if @from != :formula_installer - if %r{githubusercontent.com/[\w-]+/[\w-]+/[a-f0-9]{40}(?:/Formula)?/(?[\w+-.@]+).rb} =~ url + if (md = %r{githubusercontent.com/[\w-]+/[\w-]+/[a-f0-9]{40}(?:/Formula)?/(?[\w+-.@]+).rb}.match(url)) raise UnsupportedInstallationMethod, - "Installation of #{formula_name} from a GitHub commit URL is unsupported! " \ - "`brew extract #{formula_name}` to a stable tap on GitHub instead." + "Installation of #{md[:name]} from a GitHub commit URL is unsupported! " \ + "`brew extract #{md[:name]}` to a stable tap on GitHub instead." elsif url.match?(%r{^(https?|ftp)://}) raise UnsupportedInstallationMethod, "Non-checksummed download of #{name} formula file from an arbitrary URL is unsupported! " \ @@ -512,8 +514,8 @@ module Formulary curl_download url, to: path super rescue MethodDeprecatedError => e - if %r{github.com/(?[\w-]+)/(?[\w-]+)/} =~ url - e.issues_url = "https://github.com/#{user}/#{repo}/issues/new" + if (match_data = %r{github.com/(?[\w-]+)/(?[\w-]+)/}.match(url)) + e.issues_url = "https://github.com/#{match_data[:user]}/#{match_data[:repo]}/issues/new" end raise end diff --git a/Library/Homebrew/formulary.rbi b/Library/Homebrew/formulary.rbi new file mode 100644 index 0000000000..5c149eeb10 --- /dev/null +++ b/Library/Homebrew/formulary.rbi @@ -0,0 +1,5 @@ +# typed: strict + +module Formulary + include Kernel +end diff --git a/Library/Homebrew/resource.rb b/Library/Homebrew/resource.rb index 38ee171a3e..475b7f320f 100644 --- a/Library/Homebrew/resource.rb +++ b/Library/Homebrew/resource.rb @@ -28,6 +28,7 @@ class Resource # formula name before initialization of the formula. attr_accessor :name + sig { params(name: T.nilable(String), block: T.nilable(T.proc.bind(Resource).void)).void } def initialize(name = nil, &block) # Ensure this is synced with `initialize_dup` and `freeze` (excluding simple objects like integers and booleans) @name = name From 1c411f608648ac7d12ae43b5996629cf06441127 Mon Sep 17 00:00:00 2001 From: Douglas Eichelberger Date: Sat, 25 Mar 2023 17:39:39 -0700 Subject: [PATCH 2/3] Code review changes --- Library/Homebrew/formula_installer.rb | 2 +- Library/Homebrew/formulary.rb | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb index b6f21f2e52..d69d38b367 100644 --- a/Library/Homebrew/formula_installer.rb +++ b/Library/Homebrew/formula_installer.rb @@ -745,7 +745,7 @@ on_request: installed_on_request?, options: options) fi.finish rescue Exception => e # rubocop:disable Lint/RescueException ignore_interrupts do - tmp_keg.rename(installed_keg.to_s) if tmp_keg && !installed_keg.directory? + tmp_keg.rename(installed_keg.to_path) if tmp_keg && !installed_keg.directory? linked_keg.link(verbose: verbose?) if keg_was_linked end raise unless e.is_a? FormulaInstallationAlreadyAttemptedError diff --git a/Library/Homebrew/formulary.rb b/Library/Homebrew/formulary.rb index 588b29c2e1..5233478d0d 100644 --- a/Library/Homebrew/formulary.rb +++ b/Library/Homebrew/formulary.rb @@ -130,10 +130,10 @@ module Formulary end def self.load_formula_from_api(name, flags:) - namespace = "FormulaNamespaceAPI#{Digest::MD5.hexdigest(name)}" + namespace = :"FormulaNamespaceAPI#{Digest::MD5.hexdigest(name)}" mod = Module.new - remove_const(namespace.to_sym) if const_defined?(namespace) + remove_const(namespace) if const_defined?(namespace) const_set(namespace, mod) mod.const_set(:BUILD_FLAGS, flags) @@ -491,14 +491,16 @@ module Formulary def initialize(url, from: nil) @url = url @from = from - uri_path = T.must(URI(url).path) + uri_path = URI(url).path + raise ArgumentError, "URL has no path component" unless uri_path + formula = File.basename(uri_path, ".rb") super formula, HOMEBREW_CACHE_FORMULA/File.basename(uri_path) end def load_file(flags:, ignore_errors:) if @from != :formula_installer - if (md = %r{githubusercontent.com/[\w-]+/[\w-]+/[a-f0-9]{40}(?:/Formula)?/(?[\w+-.@]+).rb}.match(url)) + if (md = url.match(%r{githubusercontent.com/[\w-]+/[\w-]+/[a-f0-9]{40}(?:/Formula)?/(?[\w+-.@]+).rb})) raise UnsupportedInstallationMethod, "Installation of #{md[:name]} from a GitHub commit URL is unsupported! " \ "`brew extract #{md[:name]}` to a stable tap on GitHub instead." @@ -514,7 +516,7 @@ module Formulary curl_download url, to: path super rescue MethodDeprecatedError => e - if (match_data = %r{github.com/(?[\w-]+)/(?[\w-]+)/}.match(url)) + if (match_data = url.match(%r{github.com/(?[\w-]+)/(?[\w-]+)/})) e.issues_url = "https://github.com/#{match_data[:user]}/#{match_data[:repo]}/issues/new" end raise From ccfc1be6fe24da32108c2db2795d93074090bf2f Mon Sep 17 00:00:00 2001 From: Douglas Eichelberger Date: Mon, 27 Mar 2023 09:39:18 -0700 Subject: [PATCH 3/3] Rename lvar --- Library/Homebrew/formulary.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Library/Homebrew/formulary.rb b/Library/Homebrew/formulary.rb index 5233478d0d..6724e6db7e 100644 --- a/Library/Homebrew/formulary.rb +++ b/Library/Homebrew/formulary.rb @@ -500,10 +500,11 @@ module Formulary def load_file(flags:, ignore_errors:) if @from != :formula_installer - if (md = url.match(%r{githubusercontent.com/[\w-]+/[\w-]+/[a-f0-9]{40}(?:/Formula)?/(?[\w+-.@]+).rb})) + match = url.match(%r{githubusercontent.com/[\w-]+/[\w-]+/[a-f0-9]{40}(?:/Formula)?/(?[\w+-.@]+).rb}) + if match raise UnsupportedInstallationMethod, - "Installation of #{md[:name]} from a GitHub commit URL is unsupported! " \ - "`brew extract #{md[:name]}` to a stable tap on GitHub instead." + "Installation of #{match[:name]} from a GitHub commit URL is unsupported! " \ + "`brew extract #{match[:name]}` to a stable tap on GitHub instead." elsif url.match?(%r{^(https?|ftp)://}) raise UnsupportedInstallationMethod, "Non-checksummed download of #{name} formula file from an arbitrary URL is unsupported! " \