diff --git a/Library/Homebrew/build.rb b/Library/Homebrew/build.rb index adebc41e33..702517fd03 100644 --- a/Library/Homebrew/build.rb +++ b/Library/Homebrew/build.rb @@ -1,4 +1,4 @@ -# typed: true # rubocop:todo Sorbet/StrictSigil +# typed: strict # frozen_string_literal: true # This script is loaded by formula_installer as a separate instance. @@ -23,28 +23,40 @@ require "extend/pathname/write_mkpath_extension" class Build include Utils::Output::Mixin - attr_reader :formula, :deps, :reqs, :args + sig { returns(Formula) } + attr_reader :formula + sig { returns(T::Array[Dependency]) } + attr_reader :deps + + sig { returns(Requirements) } + attr_reader :reqs + + sig { returns(Homebrew::Cmd::InstallCmd::Args) } + attr_reader :args + + sig { params(formula: Formula, options: Options, args: Homebrew::Cmd::InstallCmd::Args).void } def initialize(formula, options, args:) @formula = formula @formula.build = BuildOptions.new(options, formula.options) - @args = args + @args = T.let(args, Homebrew::Cmd::InstallCmd::Args) + @deps = T.let([], T::Array[Dependency]) + @reqs = T.let(Requirements.new, Requirements) - if args.ignore_dependencies? - @deps = [] - @reqs = [] - else - @deps = expand_deps - @reqs = expand_reqs - end + return if args.ignore_dependencies? + + @deps = expand_deps + @reqs = expand_reqs end + sig { params(dependent: Formula).returns(BuildOptions) } def effective_build_options_for(dependent) args = dependent.build.used_options args |= Tab.for_formula(dependent).used_options BuildOptions.new(args, dependent.options) end + sig { returns(Requirements) } def expand_reqs formula.recursive_requirements do |dependent, req| build = effective_build_options_for(dependent) @@ -54,6 +66,7 @@ class Build end end + sig { returns(T::Array[Dependency]) } def expand_deps formula.recursive_dependencies do |dependent, dep| build = effective_build_options_for(dependent) @@ -67,6 +80,7 @@ class Build end end + sig { void } def install formula_deps = deps.map(&:to_formula) keg_only_deps = formula_deps.select(&:keg_only?) @@ -79,7 +93,7 @@ class Build ENV.activate_extensions!(env: args.env) if superenv?(args.env) - superenv = T.cast(ENV, Superenv) + superenv = ENV superenv.keg_only_deps = keg_only_deps superenv.deps = formula_deps superenv.run_time_deps = run_time_deps @@ -192,7 +206,7 @@ class Build tab.write # Find and link metafiles - formula.prefix.install_metafiles formula.buildpath + formula.prefix.install_metafiles T.must(formula.buildpath) formula.prefix.install_metafiles formula.libexec if formula.libexec.exist? normalize_pod2man_outputs!(formula) @@ -202,6 +216,7 @@ class Build end end + sig { returns(T::Array[Symbol]) } def detect_stdlibs keg = Keg.new(formula.prefix) @@ -211,13 +226,15 @@ class Build keg.detect_cxx_stdlibs(skip_executables: true) end + sig { params(formula: Formula).void } def fixopt(formula) path = if formula.linked_keg.directory? && formula.linked_keg.symlink? formula.linked_keg.resolved_path elsif formula.prefix.directory? formula.prefix - elsif (kids = formula.rack.children).size == 1 && kids.first.directory? - kids.first + elsif (children = formula.rack.children.presence) && children.size == 1 && + (first_child = children.first.presence) && first_child.directory? + first_child else raise end @@ -226,6 +243,7 @@ class Build raise "#{formula.opt_prefix} not present or broken\nPlease reinstall #{formula.full_name}. Sorry :(" end + sig { params(formula: Formula).void } def normalize_pod2man_outputs!(formula) keg = Keg.new(formula.prefix) keg.normalize_pod2man_outputs! @@ -245,7 +263,7 @@ begin trap("INT", old_trap) - formula = args.named.to_formulae.first + formula = args.named.to_formulae.fetch(0) options = Options.create(args.flags_only) build = Build.new(formula, options, args:) diff --git a/Library/Homebrew/build_environment.rb b/Library/Homebrew/build_environment.rb index 48eac54ff6..2faca110d6 100644 --- a/Library/Homebrew/build_environment.rb +++ b/Library/Homebrew/build_environment.rb @@ -1,11 +1,11 @@ -# typed: true # rubocop:todo Sorbet/StrictSigil +# typed: strict # frozen_string_literal: true # Settings for the build environment. class BuildEnvironment sig { params(settings: Symbol).void } def initialize(*settings) - @settings = Set.new(settings) + @settings = T.let(Set.new(settings), T::Set[Symbol]) end sig { params(args: T::Enumerable[Symbol]).returns(T.self_type) } @@ -29,16 +29,17 @@ class BuildEnvironment module DSL # Initialise @env for each class which may use this DSL (e.g. each formula subclass). # `env` may never be called and it needs to be initialised before the class is frozen. + sig { params(child: T.untyped).void } def inherited(child) super child.instance_eval do - @env = BuildEnvironment.new + @env = T.let(BuildEnvironment.new, T.nilable(BuildEnvironment)) end end sig { params(settings: Symbol).returns(BuildEnvironment) } def env(*settings) - @env.merge(settings) + T.must(@env).merge(settings) end end diff --git a/Library/Homebrew/build_options.rb b/Library/Homebrew/build_options.rb index 3dff77598f..d6b4c94c16 100644 --- a/Library/Homebrew/build_options.rb +++ b/Library/Homebrew/build_options.rb @@ -1,11 +1,12 @@ -# typed: true # rubocop:todo Sorbet/StrictSigil +# typed: strict # frozen_string_literal: true # Options for a formula build. class BuildOptions + sig { params(args: Options, options: Options).void } def initialize(args, options) - @args = args - @options = options + @args = T.let(args, Options) + @options = T.let(options, Options) end # True if a {Formula} is being built with a specific option. @@ -29,8 +30,13 @@ class BuildOptions # args << "--with-example1" # end # ``` + sig { params(val: T.any(String, Requirement, Dependency)).returns(T::Boolean) } def with?(val) - option_names = val.respond_to?(:option_names) ? val.option_names : [val] + option_names = if val.is_a?(String) + [val] + else + val.option_names + end option_names.any? do |name| if option_defined? "with-#{name}" @@ -50,11 +56,13 @@ class BuildOptions # ```ruby # args << "--no-spam-plz" if build.without? "spam" # ``` + sig { params(val: T.any(String, Requirement, Dependency)).returns(T::Boolean) } def without?(val) !with?(val) end # True if a {Formula} is being built as a bottle (i.e. binary package). + sig { returns(T::Boolean) } def bottle? include? "build-bottle" end @@ -75,6 +83,7 @@ class BuildOptions # args << "--and-a-cold-beer" if build.with? "cold-beer" # end # ``` + sig { returns(T::Boolean) } def head? include? "HEAD" end @@ -87,29 +96,35 @@ class BuildOptions # ```ruby # args << "--some-feature" if build.stable? # ``` + sig { returns(T::Boolean) } def stable? !head? end # True if the build has any arguments or options specified. + sig { returns(T::Boolean) } def any_args_or_options? !@args.empty? || !@options.empty? end + sig { returns(Options) } def used_options @options & @args end + sig { returns(Options) } def unused_options @options - @args end private + sig { params(name: String).returns(T::Boolean) } def include?(name) @args.include?("--#{name}") end + sig { params(name: String).returns(T::Boolean) } def option_defined?(name) @options.include? name end