From 9dfe11870ed14b14f6fd9575cdfd640a75b4f87b Mon Sep 17 00:00:00 2001 From: Issy Long Date: Sat, 30 Mar 2024 18:29:38 +0000 Subject: [PATCH 1/2] Convert the `EnvConfig` RBI generator to a Tapioca compiler --- Library/Homebrew/dev-cmd/typecheck.rb | 3 - Library/Homebrew/env_config.rbi | 243 ----------------- .../sorbet/custom_generators/env_config.rb | 42 --- .../sorbet/rbi/dsl/homebrew/env_config.rbi | 249 ++++++++++++++++++ .../sorbet/tapioca/compilers/env_config.rb | 44 ++++ 5 files changed, 293 insertions(+), 288 deletions(-) delete mode 100644 Library/Homebrew/env_config.rbi delete mode 100644 Library/Homebrew/sorbet/custom_generators/env_config.rb create mode 100644 Library/Homebrew/sorbet/rbi/dsl/homebrew/env_config.rbi create mode 100644 Library/Homebrew/sorbet/tapioca/compilers/env_config.rb diff --git a/Library/Homebrew/dev-cmd/typecheck.rb b/Library/Homebrew/dev-cmd/typecheck.rb index 0072ddf8c4..2d1c19ffeb 100644 --- a/Library/Homebrew/dev-cmd/typecheck.rb +++ b/Library/Homebrew/dev-cmd/typecheck.rb @@ -50,9 +50,6 @@ module Homebrew # Prefer adding args here: Library/Homebrew/sorbet/tapioca/config.yml tapioca_args = args.update_all? ? ["--all"] : [] - ohai "Updating homegrown RBI files..." - safe_system "bundle", "exec", "ruby", "sorbet/custom_generators/env_config.rb" - ohai "Updating Tapioca RBI files..." safe_system "bundle", "exec", "tapioca", "gem", *tapioca_args safe_system "bundle", "exec", "parlour" diff --git a/Library/Homebrew/env_config.rbi b/Library/Homebrew/env_config.rbi deleted file mode 100644 index 1fa98249b3..0000000000 --- a/Library/Homebrew/env_config.rbi +++ /dev/null @@ -1,243 +0,0 @@ -# typed: strict - -module Homebrew::EnvConfig - sig { returns(T.nilable(String)) } - def self.all_proxy; end - - sig { returns(Integer) } - def self.api_auto_update_secs; end - - sig { returns(String) } - def self.api_domain; end - - sig { returns(String) } - def self.arch; end - - sig { returns(T.nilable(String)) } - def self.artifact_domain; end - - sig { returns(T.nilable(String)) } - def self.auto_update_secs; end - - sig { returns(T::Boolean) } - def self.autoremove?; end - - sig { returns(T::Boolean) } - def self.bat?; end - - sig { returns(T.nilable(String)) } - def self.bat_config_path; end - - sig { returns(T.nilable(String)) } - def self.bat_theme; end - - sig { returns(T::Boolean) } - def self.bootsnap?; end - - sig { returns(String) } - def self.bottle_domain; end - - sig { returns(String) } - def self.brew_git_remote; end - - sig { returns(T.nilable(String)) } - def self.browser; end - - sig { returns(String) } - def self.cache; end - - sig { returns(Integer) } - def self.cleanup_max_age_days; end - - sig { returns(Integer) } - def self.cleanup_periodic_full_days; end - - sig { returns(T::Boolean) } - def self.color?; end - - sig { returns(String) } - def self.core_git_remote; end - - sig { returns(String) } - def self.curl_path; end - - sig { returns(Integer) } - def self.curl_retries; end - - sig { returns(T::Boolean) } - def self.curl_verbose?; end - - sig { returns(T.nilable(String)) } - def self.curlrc; end - - sig { returns(T::Boolean) } - def self.debug?; end - - sig { returns(T::Boolean) } - def self.developer?; end - - sig { returns(T::Boolean) } - def self.disable_load_formula?; end - - sig { returns(T.nilable(String)) } - def self.display; end - - sig { returns(T::Boolean) } - def self.display_install_times?; end - - sig { returns(T.nilable(String)) } - def self.docker_registry_basic_auth_token; end - - sig { returns(T.nilable(String)) } - def self.docker_registry_token; end - - sig { returns(T.nilable(String)) } - def self.editor; end - - sig { returns(T::Boolean) } - def self.eval_all?; end - - sig { returns(Integer) } - def self.fail_log_lines; end - - sig { returns(T.nilable(String)) } - def self.forbidden_licenses; end - - sig { returns(T::Boolean) } - def self.force_brewed_ca_certificates?; end - - sig { returns(T::Boolean) } - def self.force_brewed_curl?; end - - sig { returns(T::Boolean) } - def self.force_brewed_git?; end - - sig { returns(T::Boolean) } - def self.force_vendor_ruby?; end - - sig { returns(T.nilable(String)) } - def self.ftp_proxy; end - - sig { returns(T.nilable(String)) } - def self.git_email; end - - sig { returns(T.nilable(String)) } - def self.git_name; end - - sig { returns(String) } - def self.git_path; end - - sig { returns(T.nilable(String)) } - def self.github_api_token; end - - sig { returns(T.nilable(String)) } - def self.github_packages_token; end - - sig { returns(T.nilable(String)) } - def self.github_packages_user; end - - sig { returns(T.nilable(String)) } - def self.http_proxy; end - - sig { returns(T.nilable(String)) } - def self.https_proxy; end - - sig { returns(String) } - def self.install_badge; end - - sig { returns(String) } - def self.livecheck_watchlist; end - - sig { returns(String) } - def self.logs; end - - sig { returns(T::Boolean) } - def self.no_analytics?; end - - sig { returns(T::Boolean) } - def self.no_auto_update?; end - - sig { returns(T::Boolean) } - def self.no_bootsnap?; end - - sig { returns(T.nilable(String)) } - def self.no_cleanup_formulae; end - - sig { returns(T::Boolean) } - def self.no_color?; end - - sig { returns(T::Boolean) } - def self.no_emoji?; end - - sig { returns(T::Boolean) } - def self.no_env_hints?; end - - sig { returns(T::Boolean) } - def self.no_github_api?; end - - sig { returns(T::Boolean) } - def self.no_insecure_redirect?; end - - sig { returns(T::Boolean) } - def self.no_install_cleanup?; end - - sig { returns(T::Boolean) } - def self.no_install_from_api?; end - - sig { returns(T::Boolean) } - def self.no_install_upgrade?; end - - sig { returns(T::Boolean) } - def self.no_installed_dependents_check?; end - - sig { returns(T.nilable(String)) } - def self.no_proxy; end - - sig { returns(T::Boolean) } - def self.no_update_report_new?; end - - sig { returns(T.nilable(String)) } - def self.pip_index_url; end - - sig { returns(T::Boolean) } - def self.pry?; end - - sig { returns(T::Boolean) } - def self.simulate_macos_on_linux?; end - - sig { returns(T::Boolean) } - def self.skip_or_later_bottles?; end - - sig { returns(T::Boolean) } - def self.sorbet_runtime?; end - - sig { returns(T.nilable(String)) } - def self.ssh_config_path; end - - sig { returns(T.nilable(String)) } - def self.sudo_askpass; end - - sig { returns(T::Boolean) } - def self.sudo_through_sudo_user?; end - - sig { returns(T.nilable(String)) } - def self.svn; end - - sig { returns(T::Boolean) } - def self.system_env_takes_priority?; end - - sig { returns(String) } - def self.temp; end - - sig { returns(T::Boolean) } - def self.update_to_tag?; end - - sig { returns(T::Boolean) } - def self.upgrade_greedy?; end - - sig { returns(T::Boolean) } - def self.verbose?; end - - sig { returns(T::Boolean) } - def self.verbose_using_dots?; end -end diff --git a/Library/Homebrew/sorbet/custom_generators/env_config.rb b/Library/Homebrew/sorbet/custom_generators/env_config.rb deleted file mode 100644 index cacad3b4d6..0000000000 --- a/Library/Homebrew/sorbet/custom_generators/env_config.rb +++ /dev/null @@ -1,42 +0,0 @@ -# typed: true -# frozen_string_literal: true - -require_relative "../../global" -require_relative "../../env_config" - -File.open("#{__dir__}/../../env_config.rbi", "w") do |file| - file.write(<<~RUBY) - # typed: strict - - module Homebrew::EnvConfig - RUBY - - dynamic_methods = {} - Homebrew::EnvConfig::ENVS.each do |env, hash| - next if Homebrew::EnvConfig::CUSTOM_IMPLEMENTATIONS.include?(env) - - name = Homebrew::EnvConfig.env_method_name(env, hash) - dynamic_methods[name] = { default: hash[:default] } - end - - methods = Homebrew::EnvConfig.methods(false).map(&:to_s).select { |method| dynamic_methods.key?(method) }.sort - - methods.each do |method| - return_type = if method.end_with?("?") - T::Boolean - elsif (default = dynamic_methods[method][:default]) - default.class - else - T.nilable(String) - end - - file.write(<<-RUBY) - sig { returns(#{return_type}) } - def self.#{method}; end - RUBY - - file.write("\n") if method != methods.last - end - - file.puts "end" -end diff --git a/Library/Homebrew/sorbet/rbi/dsl/homebrew/env_config.rbi b/Library/Homebrew/sorbet/rbi/dsl/homebrew/env_config.rbi new file mode 100644 index 0000000000..f9c7a8d962 --- /dev/null +++ b/Library/Homebrew/sorbet/rbi/dsl/homebrew/env_config.rbi @@ -0,0 +1,249 @@ +# typed: true + +# DO NOT EDIT MANUALLY +# This is an autogenerated file for dynamic methods in `Homebrew::EnvConfig`. +# Please instead update this file by running `bin/tapioca dsl Homebrew::EnvConfig`. + +module Homebrew::EnvConfig + class << self + sig { returns(T.nilable(::String)) } + def all_proxy; end + + sig { returns(Integer) } + def api_auto_update_secs; end + + sig { returns(String) } + def api_domain; end + + sig { returns(String) } + def arch; end + + sig { returns(T.nilable(::String)) } + def artifact_domain; end + + sig { returns(T.nilable(::String)) } + def auto_update_secs; end + + sig { returns(T::Boolean) } + def autoremove?; end + + sig { returns(T::Boolean) } + def bat?; end + + sig { returns(T.nilable(::String)) } + def bat_config_path; end + + sig { returns(T.nilable(::String)) } + def bat_theme; end + + sig { returns(T::Boolean) } + def bootsnap?; end + + sig { returns(String) } + def bottle_domain; end + + sig { returns(String) } + def brew_git_remote; end + + sig { returns(T.nilable(::String)) } + def browser; end + + sig { returns(String) } + def cache; end + + sig { returns(Integer) } + def cleanup_max_age_days; end + + sig { returns(Integer) } + def cleanup_periodic_full_days; end + + sig { returns(T::Boolean) } + def color?; end + + sig { returns(String) } + def core_git_remote; end + + sig { returns(String) } + def curl_path; end + + sig { returns(Integer) } + def curl_retries; end + + sig { returns(T::Boolean) } + def curl_verbose?; end + + sig { returns(T.nilable(::String)) } + def curlrc; end + + sig { returns(T::Boolean) } + def debug?; end + + sig { returns(T::Boolean) } + def developer?; end + + sig { returns(T::Boolean) } + def disable_load_formula?; end + + sig { returns(T.nilable(::String)) } + def display; end + + sig { returns(T::Boolean) } + def display_install_times?; end + + sig { returns(T.nilable(::String)) } + def docker_registry_basic_auth_token; end + + sig { returns(T.nilable(::String)) } + def docker_registry_token; end + + sig { returns(T.nilable(::String)) } + def editor; end + + sig { returns(T::Boolean) } + def eval_all?; end + + sig { returns(Integer) } + def fail_log_lines; end + + sig { returns(T.nilable(::String)) } + def forbidden_licenses; end + + sig { returns(T::Boolean) } + def force_brewed_ca_certificates?; end + + sig { returns(T::Boolean) } + def force_brewed_curl?; end + + sig { returns(T::Boolean) } + def force_brewed_git?; end + + sig { returns(T::Boolean) } + def force_vendor_ruby?; end + + sig { returns(T.nilable(::String)) } + def ftp_proxy; end + + sig { returns(T.nilable(::String)) } + def git_email; end + + sig { returns(T.nilable(::String)) } + def git_name; end + + sig { returns(String) } + def git_path; end + + sig { returns(T.nilable(::String)) } + def github_api_token; end + + sig { returns(T.nilable(::String)) } + def github_packages_token; end + + sig { returns(T.nilable(::String)) } + def github_packages_user; end + + sig { returns(T.nilable(::String)) } + def http_proxy; end + + sig { returns(T.nilable(::String)) } + def https_proxy; end + + sig { returns(String) } + def install_badge; end + + sig { returns(String) } + def livecheck_watchlist; end + + sig { returns(String) } + def logs; end + + sig { returns(T::Boolean) } + def no_analytics?; end + + sig { returns(T::Boolean) } + def no_auto_update?; end + + sig { returns(T::Boolean) } + def no_bootsnap?; end + + sig { returns(T.nilable(::String)) } + def no_cleanup_formulae; end + + sig { returns(T::Boolean) } + def no_color?; end + + sig { returns(T::Boolean) } + def no_emoji?; end + + sig { returns(T::Boolean) } + def no_env_hints?; end + + sig { returns(T::Boolean) } + def no_github_api?; end + + sig { returns(T::Boolean) } + def no_insecure_redirect?; end + + sig { returns(T::Boolean) } + def no_install_cleanup?; end + + sig { returns(T::Boolean) } + def no_install_from_api?; end + + sig { returns(T::Boolean) } + def no_install_upgrade?; end + + sig { returns(T::Boolean) } + def no_installed_dependents_check?; end + + sig { returns(T.nilable(::String)) } + def no_proxy; end + + sig { returns(T::Boolean) } + def no_update_report_new?; end + + sig { returns(T.nilable(::String)) } + def pip_index_url; end + + sig { returns(T::Boolean) } + def pry?; end + + sig { returns(T::Boolean) } + def simulate_macos_on_linux?; end + + sig { returns(T::Boolean) } + def skip_or_later_bottles?; end + + sig { returns(T::Boolean) } + def sorbet_runtime?; end + + sig { returns(T.nilable(::String)) } + def ssh_config_path; end + + sig { returns(T.nilable(::String)) } + def sudo_askpass; end + + sig { returns(T::Boolean) } + def sudo_through_sudo_user?; end + + sig { returns(T.nilable(::String)) } + def svn; end + + sig { returns(T::Boolean) } + def system_env_takes_priority?; end + + sig { returns(String) } + def temp; end + + sig { returns(T::Boolean) } + def update_to_tag?; end + + sig { returns(T::Boolean) } + def upgrade_greedy?; end + + sig { returns(T::Boolean) } + def verbose?; end + + sig { returns(T::Boolean) } + def verbose_using_dots?; end + end +end diff --git a/Library/Homebrew/sorbet/tapioca/compilers/env_config.rb b/Library/Homebrew/sorbet/tapioca/compilers/env_config.rb new file mode 100644 index 0000000000..5a17cdaa22 --- /dev/null +++ b/Library/Homebrew/sorbet/tapioca/compilers/env_config.rb @@ -0,0 +1,44 @@ +# typed: strict +# frozen_string_literal: true + +require_relative "../../../global" +require "env_config" + +module Tapioca + module Compilers + class EnvConfig < Tapioca::Dsl::Compiler + # FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed. + # rubocop:disable Style/MutableConstant + ConstantType = type_member { { fixed: Module } } + # rubocop:enable Style/MutableConstant + + sig { override.returns(T::Enumerable[Module]) } + def self.gather_constants = [Homebrew::EnvConfig] + + sig { override.void } + def decorate + root.create_module(T.must(constant.name)) do |mod| + dynamic_methods = {} + Homebrew::EnvConfig::ENVS.each do |env, hash| + next if Homebrew::EnvConfig::CUSTOM_IMPLEMENTATIONS.include?(env) + + name = Homebrew::EnvConfig.env_method_name(env, hash) + dynamic_methods[name] = { default: hash[:default] } + end + + dynamic_methods.each_key do |method| + return_type = if method.end_with?("?") + T::Boolean + elsif (default = dynamic_methods[method][:default]) + default.class + else + T.nilable(String) + end + + mod.create_method(method, return_type:, class_method: true) + end + end + end + end + end +end From 75db3b8e2181e585b5919bfddc7e318ff93573b2 Mon Sep 17 00:00:00 2001 From: Issy Long Date: Sat, 30 Mar 2024 19:54:51 +0000 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Douglas Eichelberger <697964+dduugg@users.noreply.github.com> --- Library/Homebrew/sorbet/tapioca/compilers/env_config.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Library/Homebrew/sorbet/tapioca/compilers/env_config.rb b/Library/Homebrew/sorbet/tapioca/compilers/env_config.rb index 5a17cdaa22..c57ff4a113 100644 --- a/Library/Homebrew/sorbet/tapioca/compilers/env_config.rb +++ b/Library/Homebrew/sorbet/tapioca/compilers/env_config.rb @@ -23,13 +23,13 @@ module Tapioca next if Homebrew::EnvConfig::CUSTOM_IMPLEMENTATIONS.include?(env) name = Homebrew::EnvConfig.env_method_name(env, hash) - dynamic_methods[name] = { default: hash[:default] } + dynamic_methods[name] = hash[:default] end - dynamic_methods.each_key do |method| + dynamic_methods.each do |method, default| return_type = if method.end_with?("?") T::Boolean - elsif (default = dynamic_methods[method][:default]) + elsif default default.class else T.nilable(String)