**/diagnostic.rb: add Sorbet strict sigil.

Making more files `typed: strict` slowly but surely.
This commit is contained in:
Mike McQuaid 2025-08-19 09:10:24 +01:00
parent df589f47cb
commit 6db1f6a052
No known key found for this signature in database
3 changed files with 135 additions and 11 deletions

View File

@ -1,4 +1,4 @@
# typed: true # rubocop:todo Sorbet/StrictSigil # typed: strict
# frozen_string_literal: true # frozen_string_literal: true
require "keg" require "keg"
@ -16,7 +16,12 @@ require "system_command"
module Homebrew module Homebrew
# Module containing diagnostic checks. # Module containing diagnostic checks.
module Diagnostic module Diagnostic
def self.missing_deps(formulae, hide = []) sig {
params(formulae: T::Array[Formula], hide: T::Array[String], _block: T.nilable(
T.proc.params(formula_name: String, missing_dependencies: T::Array[Formula]).void,
)).returns(T::Hash[String, T::Array[String]])
}
def self.missing_deps(formulae, hide = [], &_block)
missing = {} missing = {}
formulae.each do |f| formulae.each do |f|
missing_dependencies = f.missing_dependencies(hide: hide) missing_dependencies = f.missing_dependencies(hide: hide)
@ -28,8 +33,9 @@ module Homebrew
missing missing
end end
sig { params(type: Symbol, fatal: T::Boolean).void }
def self.checks(type, fatal: true) def self.checks(type, fatal: true)
@checks ||= Checks.new @checks ||= T.let(Checks.new, T.nilable(Checks))
failed = T.let(false, T::Boolean) failed = T.let(false, T::Boolean)
@checks.public_send(type).each do |check| @checks.public_send(type).each do |check|
out = @checks.public_send(check) out = @checks.public_send(check)
@ -49,14 +55,21 @@ module Homebrew
class Checks class Checks
include SystemCommand::Mixin include SystemCommand::Mixin
sig { params(verbose: T::Boolean).void }
def initialize(verbose: true) def initialize(verbose: true)
@verbose = verbose @verbose = T.let(verbose, T::Boolean)
@found = T.let([], T::Array[String])
@seen_prefix_bin = T.let(false, T::Boolean)
@seen_prefix_sbin = T.let(false, T::Boolean)
@user_path_1_done = T.let(false, T::Boolean)
@non_core_taps = T.let([], T.nilable(T::Array[Tap]))
end end
############# @!group HELPERS ############# @!group HELPERS
# Finds files in `HOMEBREW_PREFIX` *and* /usr/local. # Finds files in `HOMEBREW_PREFIX` *and* /usr/local.
# Specify paths relative to a prefix, e.g. "include/foo.h". # Specify paths relative to a prefix, e.g. "include/foo.h".
# Sets @found for your convenience. # Sets @found for your convenience.
sig { params(relative_paths: T.any(String, T::Array[String])).void }
def find_relative_paths(*relative_paths) def find_relative_paths(*relative_paths)
@found = [HOMEBREW_PREFIX, "/usr/local"].uniq.reduce([]) do |found, prefix| @found = [HOMEBREW_PREFIX, "/usr/local"].uniq.reduce([]) do |found, prefix|
found + relative_paths.map { |f| File.join(prefix, f) }.select { |f| File.exist? f } found + relative_paths.map { |f| File.join(prefix, f) }.select { |f| File.exist? f }
@ -69,44 +82,52 @@ module Homebrew
.freeze .freeze
end end
sig { params(path: String).returns(String) }
def user_tilde(path) def user_tilde(path)
path.gsub(Dir.home, "~") path.gsub(Dir.home, "~")
end end
sig { returns(String) } sig { returns(T.nilable(String)) }
def none_string def none_string
"<NONE>" "<NONE>"
end end
sig { params(args: T.anything).returns(T.nilable(String)) }
def add_info(*args) def add_info(*args)
ohai(*args) if @verbose ohai(*args) if @verbose
end end
############# @!endgroup END HELPERS ############# @!endgroup END HELPERS
sig { returns(T::Array[String]) }
def fatal_preinstall_checks def fatal_preinstall_checks
%w[ %w[
check_access_directories check_access_directories
].freeze ].freeze
end end
sig { returns(T::Array[String]) }
def fatal_build_from_source_checks def fatal_build_from_source_checks
%w[ %w[
check_for_installed_developer_tools check_for_installed_developer_tools
].freeze ].freeze
end end
sig { returns(T::Array[String]) }
def fatal_setup_build_environment_checks def fatal_setup_build_environment_checks
[].freeze [].freeze
end end
sig { returns(T::Array[String]) }
def supported_configuration_checks def supported_configuration_checks
[].freeze [].freeze
end end
sig { returns(T::Array[String]) }
def build_from_source_checks def build_from_source_checks
[].freeze [].freeze
end end
sig { returns(T::Array[String]) }
def build_error_checks def build_error_checks
supported_configuration_checks + build_from_source_checks supported_configuration_checks + build_from_source_checks
end end
@ -156,6 +177,7 @@ module Homebrew
end end
end end
sig { params(tap: Tap).returns(T.nilable(String)) }
def broken_tap(tap) def broken_tap(tap)
return unless Utils::Git.available? return unless Utils::Git.available?
@ -177,6 +199,7 @@ module Homebrew
message message
end end
sig { returns(T.nilable(String)) }
def check_for_installed_developer_tools def check_for_installed_developer_tools
return if DevelopmentTools.installed? return if DevelopmentTools.installed?
@ -186,6 +209,7 @@ module Homebrew
EOS EOS
end end
sig { params(dir: String, pattern: String, allow_list: T::Array[String], message: String).returns(T.nilable(String)) }
def __check_stray_files(dir, pattern, allow_list, message) def __check_stray_files(dir, pattern, allow_list, message)
return unless File.directory?(dir) return unless File.directory?(dir)
@ -203,6 +227,7 @@ module Homebrew
inject_file_list(files, message) inject_file_list(files, message)
end end
sig { returns(T.nilable(String)) }
def check_for_stray_dylibs def check_for_stray_dylibs
# Dylibs which are generally OK should be added to this list, # Dylibs which are generally OK should be added to this list,
# with a short description of the software they come with. # with a short description of the software they come with.
@ -236,6 +261,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_for_stray_static_libs def check_for_stray_static_libs
# Static libs which are generally OK should be added to this list, # Static libs which are generally OK should be added to this list,
# with a short description of the software they come with. # with a short description of the software they come with.
@ -261,6 +287,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_for_stray_pcs def check_for_stray_pcs
# Package-config files which are generally OK should be added to this list, # Package-config files which are generally OK should be added to this list,
# with a short description of the software they come with. # with a short description of the software they come with.
@ -282,6 +309,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_for_stray_las def check_for_stray_las
allow_list = [ allow_list = [
"libfuse.la", # MacFuse "libfuse.la", # MacFuse
@ -303,6 +331,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_for_stray_headers def check_for_stray_headers
allow_list = [ allow_list = [
"fuse.h", # MacFuse "fuse.h", # MacFuse
@ -323,6 +352,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_for_broken_symlinks def check_for_broken_symlinks
broken_symlinks = [] broken_symlinks = []
@ -340,6 +370,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_tmpdir_sticky_bit def check_tmpdir_sticky_bit
world_writable = HOMEBREW_TEMP.stat.mode & 0777 == 0777 world_writable = HOMEBREW_TEMP.stat.mode & 0777 == 0777
return if !world_writable || HOMEBREW_TEMP.sticky? return if !world_writable || HOMEBREW_TEMP.sticky?
@ -351,6 +382,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_exist_directories def check_exist_directories
return if HOMEBREW_PREFIX.writable? return if HOMEBREW_PREFIX.writable?
@ -367,6 +399,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_access_directories def check_access_directories
not_writable_dirs = not_writable_dirs =
Keg.must_be_writable_directories.select(&:exist?) Keg.must_be_writable_directories.select(&:exist?)
@ -385,6 +418,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_multiple_cellars def check_multiple_cellars
return if HOMEBREW_PREFIX.to_s == HOMEBREW_REPOSITORY.to_s return if HOMEBREW_PREFIX.to_s == HOMEBREW_REPOSITORY.to_s
return unless (HOMEBREW_REPOSITORY/"Cellar").exist? return unless (HOMEBREW_REPOSITORY/"Cellar").exist?
@ -397,6 +431,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_user_path_1 def check_user_path_1
@seen_prefix_bin = false @seen_prefix_bin = false
@seen_prefix_sbin = false @seen_prefix_sbin = false
@ -436,8 +471,9 @@ module Homebrew
message unless message.empty? message unless message.empty?
end end
sig { returns(T.nilable(String)) }
def check_user_path_2 def check_user_path_2
check_user_path_1 unless defined?(@user_path_1_done) check_user_path_1 unless @user_path_1_done
return if @seen_prefix_bin return if @seen_prefix_bin
<<~EOS <<~EOS
@ -447,8 +483,9 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_user_path_3 def check_user_path_3
check_user_path_1 unless defined?(@user_path_1_done) check_user_path_1 unless @user_path_1_done
return if @seen_prefix_sbin return if @seen_prefix_sbin
# Don't complain about sbin not being in the path if it doesn't exist # Don't complain about sbin not being in the path if it doesn't exist
@ -465,6 +502,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_for_symlinked_cellar def check_for_symlinked_cellar
return unless HOMEBREW_CELLAR.exist? return unless HOMEBREW_CELLAR.exist?
return unless HOMEBREW_CELLAR.symlink? return unless HOMEBREW_CELLAR.symlink?
@ -484,6 +522,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_git_version def check_git_version
minimum_version = ENV.fetch("HOMEBREW_MINIMUM_GIT_VERSION") minimum_version = ENV.fetch("HOMEBREW_MINIMUM_GIT_VERSION")
return unless Utils::Git.available? return unless Utils::Git.available?
@ -499,6 +538,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_for_git def check_for_git
return if Utils::Git.available? return if Utils::Git.available?
@ -510,6 +550,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_git_newline_settings def check_git_newline_settings
return unless Utils::Git.available? return unless Utils::Git.available?
@ -528,11 +569,13 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_brew_git_origin def check_brew_git_origin
repo = GitRepository.new(HOMEBREW_REPOSITORY) repo = GitRepository.new(HOMEBREW_REPOSITORY)
examine_git_origin(repo, Homebrew::EnvConfig.brew_git_remote) examine_git_origin(repo, Homebrew::EnvConfig.brew_git_remote)
end end
sig { returns(T.nilable(String)) }
def check_coretap_integrity def check_coretap_integrity
core_tap = CoreTap.instance core_tap = CoreTap.instance
unless core_tap.installed? unless core_tap.installed?
@ -544,6 +587,7 @@ module Homebrew
broken_tap(core_tap) || examine_git_origin(core_tap.git_repository, Homebrew::EnvConfig.core_git_remote) broken_tap(core_tap) || examine_git_origin(core_tap.git_repository, Homebrew::EnvConfig.core_git_remote)
end end
sig { returns(T.nilable(String)) }
def check_casktap_integrity def check_casktap_integrity
core_cask_tap = CoreCaskTap.instance core_cask_tap = CoreCaskTap.instance
return unless core_cask_tap.installed? return unless core_cask_tap.installed?
@ -571,6 +615,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_deprecated_official_taps def check_deprecated_official_taps
tapped_deprecated_taps = tapped_deprecated_taps =
Tap.select(&:official?).map(&:repository) & DEPRECATED_OFFICIAL_TAPS Tap.select(&:official?).map(&:repository) & DEPRECATED_OFFICIAL_TAPS
@ -587,6 +632,7 @@ module Homebrew
EOS EOS
end end
sig { params(formula: Formula).returns(T::Boolean) }
def __check_linked_brew!(formula) def __check_linked_brew!(formula)
formula.installed_prefixes.each do |prefix| formula.installed_prefixes.each do |prefix|
prefix.find do |src| prefix.find do |src|
@ -600,6 +646,7 @@ module Homebrew
false false
end end
sig { returns(T.nilable(String)) }
def check_for_other_frameworks def check_for_other_frameworks
# Other frameworks that are known to cause problems when present # Other frameworks that are known to cause problems when present
frameworks_to_check = %w[ frameworks_to_check = %w[
@ -619,6 +666,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_tmpdir def check_tmpdir
tmpdir = ENV.fetch("TMPDIR", nil) tmpdir = ENV.fetch("TMPDIR", nil)
return if tmpdir.nil? || File.directory?(tmpdir) return if tmpdir.nil? || File.directory?(tmpdir)
@ -628,6 +676,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_missing_deps def check_missing_deps
return unless HOMEBREW_CELLAR.exist? return unless HOMEBREW_CELLAR.exist?
@ -646,6 +695,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_deprecated_disabled def check_deprecated_disabled
return unless HOMEBREW_CELLAR.exist? return unless HOMEBREW_CELLAR.exist?
@ -660,6 +710,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_cask_deprecated_disabled def check_cask_deprecated_disabled
deprecated_or_disabled = Cask::Caskroom.casks.select(&:deprecated?) deprecated_or_disabled = Cask::Caskroom.casks.select(&:deprecated?)
deprecated_or_disabled += Cask::Caskroom.casks.select(&:disabled?) deprecated_or_disabled += Cask::Caskroom.casks.select(&:disabled?)
@ -716,6 +767,7 @@ module Homebrew
message message
end end
sig { returns(T.nilable(String)) }
def check_for_non_prefixed_coreutils def check_for_non_prefixed_coreutils
coreutils = Formula["coreutils"] coreutils = Formula["coreutils"]
return unless coreutils.any_version_installed? return unless coreutils.any_version_installed?
@ -730,6 +782,7 @@ module Homebrew
nil nil
end end
sig { returns(T.nilable(String)) }
def check_for_pydistutils_cfg_in_home def check_for_pydistutils_cfg_in_home
return unless File.exist? "#{Dir.home}/.pydistutils.cfg" return unless File.exist? "#{Dir.home}/.pydistutils.cfg"
@ -741,6 +794,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_for_unreadable_installed_formula def check_for_unreadable_installed_formula
formula_unavailable_exceptions = [] formula_unavailable_exceptions = []
Formula.racks.each do |rack| Formula.racks.each do |rack|
@ -759,6 +813,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_for_unlinked_but_not_keg_only def check_for_unlinked_but_not_keg_only
unlinked = Formula.racks.reject do |rack| unlinked = Formula.racks.reject do |rack|
next true if (HOMEBREW_LINKED_KEGS/rack.basename).directory? next true if (HOMEBREW_LINKED_KEGS/rack.basename).directory?
@ -778,6 +833,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_for_external_cmd_name_conflict def check_for_external_cmd_name_conflict
cmds = Commands.tap_cmd_directories.flat_map { |p| Dir["#{p}/brew-*"] }.uniq cmds = Commands.tap_cmd_directories.flat_map { |p| Dir["#{p}/brew-*"] }.uniq
cmds = cmds.select { |cmd| File.file?(cmd) && File.executable?(cmd) } cmds = cmds.select { |cmd| File.file?(cmd) && File.executable?(cmd) }
@ -805,6 +861,7 @@ module Homebrew
message message
end end
sig { returns(T.nilable(String)) }
def check_for_tap_ruby_files_locations def check_for_tap_ruby_files_locations
bad_tap_files = {} bad_tap_files = {}
Tap.installed.each do |tap| Tap.installed.each do |tap|
@ -831,6 +888,7 @@ module Homebrew
end.join("\n") end.join("\n")
end end
sig { returns(T.nilable(String)) }
def check_homebrew_prefix def check_homebrew_prefix
return if Homebrew.default_prefix? return if Homebrew.default_prefix?
@ -844,6 +902,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_deleted_formula def check_deleted_formula
kegs = Keg.all kegs = Keg.all
@ -878,6 +937,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_for_unnecessary_core_tap def check_for_unnecessary_core_tap
return if Homebrew::EnvConfig.developer? return if Homebrew::EnvConfig.developer?
return if Homebrew::EnvConfig.no_install_from_api? return if Homebrew::EnvConfig.no_install_from_api?
@ -892,6 +952,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_for_unnecessary_cask_tap def check_for_unnecessary_cask_tap
return if Homebrew::EnvConfig.developer? return if Homebrew::EnvConfig.developer?
return if Homebrew::EnvConfig.no_install_from_api? return if Homebrew::EnvConfig.no_install_from_api?
@ -908,6 +969,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_deprecated_cask_taps def check_deprecated_cask_taps
tapped_caskroom_taps = ::Tap.select { |t| t.user == "caskroom" || t.name == "phinze/cask" } tapped_caskroom_taps = ::Tap.select { |t| t.user == "caskroom" || t.name == "phinze/cask" }
.map(&:name) .map(&:name)
@ -921,12 +983,14 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_cask_software_versions def check_cask_software_versions
add_info "Homebrew Version", HOMEBREW_VERSION add_info "Homebrew Version", HOMEBREW_VERSION
nil nil
end end
sig { returns(T.nilable(String)) }
def check_cask_install_location def check_cask_install_location
locations = Dir.glob(HOMEBREW_CELLAR.join("brew-cask", "*")).reverse locations = Dir.glob(HOMEBREW_CELLAR.join("brew-cask", "*")).reverse
return if locations.empty? return if locations.empty?
@ -936,6 +1000,7 @@ module Homebrew
end.join "\n" end.join "\n"
end end
sig { returns(T.nilable(String)) }
def check_cask_staging_location def check_cask_staging_location
# Skip this check when running CI since the staging path is not writable for security reasons # Skip this check when running CI since the staging path is not writable for security reasons
return if GitHub::Actions.env_set? return if GitHub::Actions.env_set?
@ -953,6 +1018,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_cask_taps def check_cask_taps
error_tap_paths = [] error_tap_paths = []
@ -975,6 +1041,7 @@ module Homebrew
"Unable to read from cask #{taps_string}: #{error_tap_paths.to_sentence}" if error_tap_paths.present? "Unable to read from cask #{taps_string}: #{error_tap_paths.to_sentence}" if error_tap_paths.present?
end end
sig { returns(T.nilable(String)) }
def check_cask_load_path def check_cask_load_path
paths = $LOAD_PATH.map { user_tilde(_1) } paths = $LOAD_PATH.map { user_tilde(_1) }
@ -983,6 +1050,7 @@ module Homebrew
"$LOAD_PATH is empty" if paths.blank? "$LOAD_PATH is empty" if paths.blank?
end end
sig { returns(T.nilable(String)) }
def check_cask_environment_variables def check_cask_environment_variables
environment_variables = %w[ environment_variables = %w[
RUBYLIB RUBYLIB
@ -1011,6 +1079,7 @@ module Homebrew
nil nil
end end
sig { returns(T.nilable(String)) }
def check_cask_xattr def check_cask_xattr
# If quarantine is not available, a warning is already shown by check_cask_quarantine_support so just return # If quarantine is not available, a warning is already shown by check_cask_quarantine_support so just return
return unless Cask::Quarantine.available? return unless Cask::Quarantine.available?
@ -1043,10 +1112,12 @@ module Homebrew
end end
end end
sig { returns(T::Array[Tap]) }
def non_core_taps def non_core_taps
@non_core_taps ||= Tap.installed.reject(&:core_tap?).reject(&:core_cask_tap?) @non_core_taps ||= Tap.installed.reject(&:core_tap?).reject(&:core_cask_tap?)
end end
sig { returns(T.nilable(String)) }
def check_for_duplicate_formulae def check_for_duplicate_formulae
return if ENV["HOMEBREW_TEST_BOT"].present? return if ENV["HOMEBREW_TEST_BOT"].present?
@ -1074,6 +1145,7 @@ module Homebrew
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_for_duplicate_casks def check_for_duplicate_casks
return if ENV["HOMEBREW_TEST_BOT"].present? return if ENV["HOMEBREW_TEST_BOT"].present?
@ -1101,14 +1173,17 @@ module Homebrew
EOS EOS
end end
sig { returns(T::Array[String]) }
def all def all
methods.map(&:to_s).grep(/^check_/).sort methods.map(&:to_s).grep(/^check_/).sort
end end
sig { returns(T::Array[String]) }
def cask_checks def cask_checks
all.grep(/^check_cask_/) all.grep(/^check_cask_/)
end end
sig { returns(String) }
def current_user def current_user
ENV.fetch("USER", "$(whoami)") ENV.fetch("USER", "$(whoami)")
end end

View File

@ -1,4 +1,4 @@
# typed: true # rubocop:disable Sorbet/StrictSigil # typed: strict
# frozen_string_literal: true # frozen_string_literal: true
require "tempfile" require "tempfile"
@ -16,6 +16,7 @@ module OS
requires_ancestor { Homebrew::Diagnostic::Checks } requires_ancestor { Homebrew::Diagnostic::Checks }
sig { returns(T::Array[String]) }
def fatal_preinstall_checks def fatal_preinstall_checks
%w[ %w[
check_access_directories check_access_directories
@ -24,6 +25,7 @@ module OS
].freeze ].freeze
end end
sig { returns(T::Array[String]) }
def supported_configuration_checks def supported_configuration_checks
%w[ %w[
check_glibc_minimum_version check_glibc_minimum_version
@ -32,6 +34,7 @@ module OS
].freeze ].freeze
end end
sig { returns(T.nilable(String)) }
def check_tmpdir_sticky_bit def check_tmpdir_sticky_bit
message = super message = super
return if message.nil? return if message.nil?
@ -45,6 +48,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_tmpdir_executable def check_tmpdir_executable
f = Tempfile.new(%w[homebrew_check_tmpdir_executable .sh], HOMEBREW_TEMP) f = Tempfile.new(%w[homebrew_check_tmpdir_executable .sh], HOMEBREW_TEMP)
f.write "#!/bin/sh\n" f.write "#!/bin/sh\n"
@ -63,6 +67,7 @@ module OS
f&.unlink f&.unlink
end end
sig { returns(T.nilable(String)) }
def check_umask_not_zero def check_umask_not_zero
return unless File.umask.zero? return unless File.umask.zero?
@ -74,6 +79,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_supported_architecture def check_supported_architecture
return if ::Hardware::CPU.intel? return if ::Hardware::CPU.intel?
return if Homebrew::EnvConfig.developer? && ENV["HOMEBREW_ARM64_TESTING"].present? && ::Hardware::CPU.arm? return if Homebrew::EnvConfig.developer? && ENV["HOMEBREW_ARM64_TESTING"].present? && ::Hardware::CPU.arm?
@ -86,6 +92,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_glibc_minimum_version def check_glibc_minimum_version
return unless OS::Linux::Glibc.below_minimum_version? return unless OS::Linux::Glibc.below_minimum_version?
@ -101,6 +108,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_glibc_version def check_glibc_version
return unless OS::Linux::Glibc.below_ci_version? return unless OS::Linux::Glibc.below_ci_version?
@ -119,6 +127,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_kernel_minimum_version def check_kernel_minimum_version
return unless OS::Linux::Kernel.below_minimum_version? return unless OS::Linux::Kernel.below_minimum_version?
@ -135,6 +144,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_linuxbrew_core def check_linuxbrew_core
return unless Homebrew::EnvConfig.no_install_from_api? return unless Homebrew::EnvConfig.no_install_from_api?
return unless CoreTap.instance.linuxbrew_core? return unless CoreTap.instance.linuxbrew_core?
@ -145,6 +155,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_linuxbrew_bottle_domain def check_linuxbrew_bottle_domain
return unless Homebrew::EnvConfig.bottle_domain.include?("linuxbrew") return unless Homebrew::EnvConfig.bottle_domain.include?("linuxbrew")
@ -155,6 +166,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_for_symlinked_home def check_for_symlinked_home
return unless File.symlink?("/home") return unless File.symlink?("/home")
@ -176,6 +188,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_gcc_dependent_linkage def check_gcc_dependent_linkage
gcc_dependents = ::Formula.installed.select do |formula| gcc_dependents = ::Formula.installed.select do |formula|
next false unless formula.tap&.core_tap? next false unless formula.tap&.core_tap?
@ -212,6 +225,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_cask_software_versions def check_cask_software_versions
super super
add_info "Linux", OS::Linux.os_version add_info "Linux", OS::Linux.os_version

View File

@ -1,14 +1,16 @@
# typed: true # rubocop:disable Sorbet/StrictSigil # typed: strict
# frozen_string_literal: true # frozen_string_literal: true
module OS module OS
module Mac module Mac
module Diagnostic module Diagnostic
class Volumes class Volumes
sig { void }
def initialize def initialize
@volumes = get_mounts @volumes = T.let(get_mounts, T::Array[String])
end end
sig { params(path: T.nilable(Pathname)).returns(Integer) }
def which(path) def which(path)
vols = get_mounts path vols = get_mounts path
@ -22,12 +24,13 @@ module OS
vol_index vol_index
end end
sig { params(path: T.nilable(Pathname)).returns(T::Array[String]) }
def get_mounts(path = nil) def get_mounts(path = nil)
vols = [] vols = []
# get the volume of path, if path is nil returns all volumes # get the volume of path, if path is nil returns all volumes
args = %w[/bin/df -P] args = %w[/bin/df -P]
args << path if path args << path.to_s if path
Utils.popen_read(*args) do |io| Utils.popen_read(*args) do |io|
io.each_line do |line| io.each_line do |line|
@ -47,6 +50,13 @@ module OS
requires_ancestor { Homebrew::Diagnostic::Checks } requires_ancestor { Homebrew::Diagnostic::Checks }
sig { params(verbose: T::Boolean).void }
def initialize(verbose: true)
super
@found = T.let([], T::Array[String])
end
sig { returns(T::Array[String]) }
def fatal_preinstall_checks def fatal_preinstall_checks
checks = %w[ checks = %w[
check_access_directories check_access_directories
@ -58,6 +68,7 @@ module OS
checks.freeze checks.freeze
end end
sig { returns(T::Array[String]) }
def fatal_build_from_source_checks def fatal_build_from_source_checks
%w[ %w[
check_xcode_license_approved check_xcode_license_approved
@ -69,6 +80,7 @@ module OS
].freeze ].freeze
end end
sig { returns(T::Array[String]) }
def fatal_setup_build_environment_checks def fatal_setup_build_environment_checks
%w[ %w[
check_xcode_minimum_version check_xcode_minimum_version
@ -77,12 +89,14 @@ module OS
].freeze ].freeze
end end
sig { returns(T::Array[String]) }
def supported_configuration_checks def supported_configuration_checks
%w[ %w[
check_for_unsupported_macos check_for_unsupported_macos
].freeze ].freeze
end end
sig { returns(T::Array[String]) }
def build_from_source_checks def build_from_source_checks
%w[ %w[
check_for_installed_developer_tools check_for_installed_developer_tools
@ -91,6 +105,7 @@ module OS
].freeze ].freeze
end end
sig { returns(T.nilable(String)) }
def check_for_non_prefixed_findutils def check_for_non_prefixed_findutils
findutils = ::Formula["findutils"] findutils = ::Formula["findutils"]
return unless findutils.any_version_installed? return unless findutils.any_version_installed?
@ -106,6 +121,7 @@ module OS
nil nil
end end
sig { returns(T.nilable(String)) }
def check_for_unsupported_macos def check_for_unsupported_macos
return if Homebrew::EnvConfig.developer? return if Homebrew::EnvConfig.developer?
return if ENV["HOMEBREW_INTEGRATION_TEST"] return if ENV["HOMEBREW_INTEGRATION_TEST"]
@ -131,6 +147,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_for_opencore def check_for_opencore
return if ::Hardware::CPU.physical_cpu_arm64? return if ::Hardware::CPU.physical_cpu_arm64?
@ -155,6 +172,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_xcode_up_to_date def check_xcode_up_to_date
return unless MacOS::Xcode.outdated? return unless MacOS::Xcode.outdated?
@ -191,6 +209,7 @@ module OS
message message
end end
sig { returns(T.nilable(String)) }
def check_clt_up_to_date def check_clt_up_to_date
return unless MacOS::CLT.outdated? return unless MacOS::CLT.outdated?
@ -211,6 +230,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_xcode_minimum_version def check_xcode_minimum_version
return unless MacOS::Xcode.below_minimum_version? return unless MacOS::Xcode.below_minimum_version?
@ -224,6 +244,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_clt_minimum_version def check_clt_minimum_version
return unless MacOS::CLT.below_minimum_version? return unless MacOS::CLT.below_minimum_version?
@ -233,6 +254,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_if_xcode_needs_clt_installed def check_if_xcode_needs_clt_installed
return unless MacOS::Xcode.needs_clt_installed? return unless MacOS::Xcode.needs_clt_installed?
@ -242,6 +264,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_xcode_prefix def check_xcode_prefix
prefix = MacOS::Xcode.prefix prefix = MacOS::Xcode.prefix
return if prefix.nil? return if prefix.nil?
@ -253,6 +276,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_xcode_prefix_exists def check_xcode_prefix_exists
prefix = MacOS::Xcode.prefix prefix = MacOS::Xcode.prefix
return if prefix.nil? || prefix.exist? return if prefix.nil? || prefix.exist?
@ -264,6 +288,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_xcode_select_path def check_xcode_select_path
return if MacOS::CLT.installed? return if MacOS::CLT.installed?
return unless MacOS::Xcode.installed? return unless MacOS::Xcode.installed?
@ -278,6 +303,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_xcode_license_approved def check_xcode_license_approved
# If the user installs Xcode-only, they have to approve the # If the user installs Xcode-only, they have to approve the
# license or no "xc*" tool will work. # license or no "xc*" tool will work.
@ -291,6 +317,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_filesystem_case_sensitive def check_filesystem_case_sensitive
dirs_to_check = [ dirs_to_check = [
HOMEBREW_PREFIX, HOMEBREW_PREFIX,
@ -324,6 +351,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_for_gettext def check_for_gettext
find_relative_paths("lib/libgettextlib.dylib", find_relative_paths("lib/libgettextlib.dylib",
"lib/libintl.dylib", "lib/libintl.dylib",
@ -359,6 +387,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_for_iconv def check_for_iconv
find_relative_paths("lib/libiconv.dylib", "include/iconv.h") find_relative_paths("lib/libiconv.dylib", "include/iconv.h")
return if @found.empty? return if @found.empty?
@ -389,6 +418,7 @@ module OS
end end
end end
sig { returns(T.nilable(String)) }
def check_for_multiple_volumes def check_for_multiple_volumes
return unless HOMEBREW_CELLAR.exist? return unless HOMEBREW_CELLAR.exist?
@ -424,6 +454,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_if_supported_sdk_available def check_if_supported_sdk_available
return unless ::DevelopmentTools.installed? return unless ::DevelopmentTools.installed?
return unless MacOS.sdk_root_needed? return unless MacOS.sdk_root_needed?
@ -454,6 +485,7 @@ module OS
# The CLT 10.x -> 11.x upgrade process on 10.14 contained a bug which broke the SDKs. # The CLT 10.x -> 11.x upgrade process on 10.14 contained a bug which broke the SDKs.
# Notably, MacOSX10.14.sdk would indirectly symlink to MacOSX10.15.sdk. # Notably, MacOSX10.14.sdk would indirectly symlink to MacOSX10.15.sdk.
# This diagnostic was introduced to check for this and recommend a full reinstall. # This diagnostic was introduced to check for this and recommend a full reinstall.
sig { returns(T.nilable(String)) }
def check_broken_sdks def check_broken_sdks
locator = MacOS.sdk_locator locator = MacOS.sdk_locator
@ -485,6 +517,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_cask_software_versions def check_cask_software_versions
super super
add_info "macOS", MacOS.full_version add_info "macOS", MacOS.full_version
@ -507,6 +540,7 @@ module OS
nil nil
end end
sig { returns(T.nilable(String)) }
def check_pkgconf_macos_sdk_mismatch def check_pkgconf_macos_sdk_mismatch
# We don't provide suitable bottles for these versions. # We don't provide suitable bottles for these versions.
return if OS::Mac.version.prerelease? || OS::Mac.version.outdated_release? return if OS::Mac.version.prerelease? || OS::Mac.version.outdated_release?
@ -543,6 +577,7 @@ module OS
EOS EOS
end end
sig { returns(T.nilable(String)) }
def check_cask_quarantine_support def check_cask_quarantine_support
status, check_output = ::Cask::Quarantine.check_quarantine_support status, check_output = ::Cask::Quarantine.check_quarantine_support