From 61a7ffb999963a2ef8d8f0b247956c8280cb831a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?fn=20=E2=8C=83=20=E2=8C=A5?= <70830482+FnControlOption@users.noreply.github.com> Date: Wed, 29 Sep 2021 15:12:53 -0700 Subject: [PATCH 1/3] development_tools: add type signatures --- Library/Homebrew/development_tools.rb | 30 +++++++++++++-- .../extend/os/linux/development_tools.rb | 2 + .../extend/os/mac/development_tools.rb | 3 ++ .../extend/os/mac/extend/ENV/shared.rb | 4 +- Library/Homebrew/os/mac.rb | 3 ++ Library/Homebrew/os/mac/sdk.rb | 38 ++++++++++++++----- Library/Homebrew/os/mac/xcode.rb | 24 +++++++++++- Library/Homebrew/os/mac/xcode.rbi | 9 +++++ 8 files changed, 97 insertions(+), 16 deletions(-) create mode 100644 Library/Homebrew/os/mac/xcode.rbi diff --git a/Library/Homebrew/development_tools.rb b/Library/Homebrew/development_tools.rb index 16418417c0..3961e14538 100644 --- a/Library/Homebrew/development_tools.rb +++ b/Library/Homebrew/development_tools.rb @@ -1,9 +1,14 @@ -# typed: false +# typed: true # frozen_string_literal: true +require "version" + # @private class DevelopmentTools class << self + extend T::Sig + + sig { params(tool: String).returns(T.nilable(Pathname)) } def locate(tool) # Don't call tools (cc, make, strip, etc.) directly! # Give the name of the binary you look for as a string to this method @@ -18,17 +23,27 @@ class DevelopmentTools end end + sig { returns(T::Boolean) } def installed? - locate("clang") || locate("gcc") + locate("clang").present? || locate("gcc").present? end + sig { returns(String) } def installation_instructions "Install Clang or run `brew install gcc`." end - alias custom_installation_instructions installation_instructions + sig { returns(String) } + def custom_installation_instructions + installation_instructions + end + + # TODO: This method appears to be unused. Can it be deleted? + sig { returns(T.nilable(String)) } def default_cc cc = DevelopmentTools.locate "cc" + return if cc.nil? + begin cc.realpath.basename.to_s rescue @@ -36,10 +51,12 @@ class DevelopmentTools end end + sig { returns(Symbol) } def default_compiler :clang end + sig { returns(Version) } def clang_version @clang_version ||= if (path = locate("clang")) && (build_version = `#{path} --version`[/(?:clang|LLVM) version (\d+\.\d(?:\.\d)?)/, 1]) @@ -49,6 +66,7 @@ class DevelopmentTools end end + sig { returns(Version) } def clang_build_version @clang_build_version ||= if (path = locate("clang")) && (build_version = `#{path} --version`[ @@ -59,6 +77,7 @@ class DevelopmentTools end end + sig { returns(Version) } def llvm_clang_build_version @llvm_clang_build_version ||= begin path = Formulary.factory("llvm").opt_prefix/"bin/clang" @@ -71,6 +90,7 @@ class DevelopmentTools end end + sig { params(cc: String).returns(Version) } def non_apple_gcc_version(cc) (@non_apple_gcc_version ||= {}).fetch(cc) do path = HOMEBREW_PREFIX/"opt/#{CompilerSelector.preferred_gcc}/bin"/cc @@ -85,19 +105,23 @@ class DevelopmentTools end end + sig { void } def clear_version_cache @clang_version = @clang_build_version = nil @non_apple_gcc_version = {} end + sig { returns(T::Boolean) } def curl_handles_most_https_certificates? true end + sig { returns(T::Boolean) } def subversion_handles_most_https_certificates? true end + sig { returns(T::Hash[String, T.untyped]) } def build_system_info { "os" => ENV["HOMEBREW_SYSTEM"], diff --git a/Library/Homebrew/extend/os/linux/development_tools.rb b/Library/Homebrew/extend/os/linux/development_tools.rb index 6ad96f7982..267c9a1516 100644 --- a/Library/Homebrew/extend/os/linux/development_tools.rb +++ b/Library/Homebrew/extend/os/linux/development_tools.rb @@ -5,6 +5,7 @@ class DevelopmentTools class << self extend T::Sig + sig { params(tool: String).returns(T.nilable(Pathname)) } def locate(tool) (@locate ||= {}).fetch(tool) do |key| @locate[key] = if (path = HOMEBREW_PREFIX/"bin/#{tool}").executable? @@ -20,6 +21,7 @@ class DevelopmentTools :gcc end + sig { returns(T::Hash[String, T.untyped]) } def build_system_info generic_build_system_info.merge({ "glibc_version" => OS::Linux::Glibc.version, diff --git a/Library/Homebrew/extend/os/mac/development_tools.rb b/Library/Homebrew/extend/os/mac/development_tools.rb index b7291aa9bf..993ba68ba3 100644 --- a/Library/Homebrew/extend/os/mac/development_tools.rb +++ b/Library/Homebrew/extend/os/mac/development_tools.rb @@ -12,6 +12,7 @@ class DevelopmentTools undef installed?, default_compiler, curl_handles_most_https_certificates?, subversion_handles_most_https_certificates? + sig { params(tool: String).returns(T.nilable(Pathname)) } def locate(tool) (@locate ||= {}).fetch(tool) do |key| @locate[key] = if (located_tool = generic_locate(tool)) @@ -26,6 +27,7 @@ class DevelopmentTools # Checks if the user has any developer tools installed, either via Xcode # or the CLT. Convenient for guarding against formula builds when building # is impossible. + sig { returns(T::Boolean) } def installed? MacOS::Xcode.installed? || MacOS::CLT.installed? end @@ -62,6 +64,7 @@ class DevelopmentTools EOS end + sig { returns(T::Hash[String, T.untyped]) } def build_system_info build_info = { "xcode" => MacOS::Xcode.version.to_s.presence, diff --git a/Library/Homebrew/extend/os/mac/extend/ENV/shared.rb b/Library/Homebrew/extend/os/mac/extend/ENV/shared.rb index 6162b42f60..a690791acc 100644 --- a/Library/Homebrew/extend/os/mac/extend/ENV/shared.rb +++ b/Library/Homebrew/extend/os/mac/extend/ENV/shared.rb @@ -18,8 +18,8 @@ module SharedEnvExtension def no_weak_imports_support? return false unless compiler == :clang - return false if MacOS::Xcode.version && MacOS::Xcode.version < "8.0" - return false if MacOS::CLT.version && MacOS::CLT.version < "8.0" + return false if !MacOS::Xcode.version.null? && MacOS::Xcode.version < "8.0" + return false if !MacOS::CLT.version.null? && MacOS::CLT.version < "8.0" true end diff --git a/Library/Homebrew/os/mac.rb b/Library/Homebrew/os/mac.rb index d878201a02..b3e6cff1ab 100644 --- a/Library/Homebrew/os/mac.rb +++ b/Library/Homebrew/os/mac.rb @@ -178,6 +178,7 @@ module OS paths.uniq end + sig { params(ids: String).returns(T.nilable(Pathname)) } def app_with_bundle_id(*ids) path = mdfind(*ids) .reject { |p| p.include?("/Backups.backupdb/") } @@ -185,6 +186,7 @@ module OS Pathname.new(path) if path.present? end + sig { params(ids: String).returns(T::Array[String]) } def mdfind(*ids) (@mdfind ||= {}).fetch(ids) do @mdfind[ids] = Utils.popen_read("/usr/bin/mdfind", mdfind_query(*ids)).split("\n") @@ -197,6 +199,7 @@ module OS end end + sig { params(ids: String).returns(String) } def mdfind_query(*ids) ids.map! { |id| "kMDItemCFBundleIdentifier == #{id}" }.join(" || ") end diff --git a/Library/Homebrew/os/mac/sdk.rb b/Library/Homebrew/os/mac/sdk.rb index 13ee10fc70..0b717e8ef2 100644 --- a/Library/Homebrew/os/mac/sdk.rb +++ b/Library/Homebrew/os/mac/sdk.rb @@ -9,11 +9,21 @@ module OS # # @api private class SDK + extend T::Sig + # 11.x SDKs are explicitly excluded - we want the MacOSX11.sdk symlink instead. VERSIONED_SDK_REGEX = /MacOSX(10\.\d+|\d+)\.sdk$/.freeze - attr_reader :version, :path, :source + sig { returns(OS::Mac::Version) } + attr_reader :version + sig { returns(Pathname) } + attr_reader :path + + sig { returns(Symbol) } + attr_reader :source + + sig { params(version: OS::Mac::Version, path: T.any(String, Pathname), source: Symbol).void } def initialize(version, path, source) @version = version @path = Pathname.new(path) @@ -25,8 +35,14 @@ module OS # # @api private class BaseSDKLocator + extend T::Sig + extend T::Helpers + + abstract! + class NoSDKError < StandardError; end + sig { params(v: OS::Mac::Version).returns(SDK) } def sdk_for(v) sdk = all_sdks.find { |s| s.version == v } raise NoSDKError if sdk.nil? @@ -34,6 +50,7 @@ module OS sdk end + sig { returns(T::Array[SDK]) } def all_sdks return @all_sdks if @all_sdks @@ -62,6 +79,7 @@ module OS @all_sdks end + sig { params(v: T.nilable(OS::Mac::Version)).returns(T.nilable(SDK)) } def sdk_if_applicable(v = nil) sdk = begin if v.blank? @@ -81,20 +99,20 @@ module OS sdk end - def source - nil - end + sig { abstract.returns(Symbol) } + def source; end private - def sdk_prefix - "" - end + sig { abstract.returns(String) } + def sdk_prefix; end + sig { returns(T.nilable(SDK)) } def latest_sdk all_sdks.max_by(&:version) end + sig { params(sdk_path: Pathname).returns(T.nilable(OS::Mac::Version)) } def read_sdk_version(sdk_path) sdk_settings = sdk_path/"SDKSettings.json" sdk_settings_string = sdk_settings.read if sdk_settings.exist? @@ -129,13 +147,14 @@ module OS class XcodeSDKLocator < BaseSDKLocator extend T::Sig - sig { returns(Symbol) } + sig { override.returns(Symbol) } def source :xcode end private + sig { override.returns(String) } def sdk_prefix @sdk_prefix ||= begin # Xcode.prefix is pretty smart, so let's look inside to find the sdk @@ -155,7 +174,7 @@ module OS class CLTSDKLocator < BaseSDKLocator extend T::Sig - sig { returns(Symbol) } + sig { override.returns(Symbol) } def source :clt end @@ -169,6 +188,7 @@ module OS # separate package, so we can't rely on their being present. # This will only look up SDKs on Xcode 10 or newer, and still # return nil SDKs for Xcode 9 and older. + sig { override.returns(String) } def sdk_prefix @sdk_prefix ||= if CLT.provides_sdk? "#{CLT::PKG_PATH}/SDKs" diff --git a/Library/Homebrew/os/mac/xcode.rb b/Library/Homebrew/os/mac/xcode.rb index a1f3e0d98c..9f857364b2 100755 --- a/Library/Homebrew/os/mac/xcode.rb +++ b/Library/Homebrew/os/mac/xcode.rb @@ -1,4 +1,4 @@ -# typed: false +# typed: true # frozen_string_literal: true module OS @@ -89,6 +89,7 @@ module OS # Returns a Pathname object corresponding to Xcode.app's Developer # directory or nil if Xcode.app is not installed. + sig { returns(Pathname) } def prefix @prefix ||= begin @@ -109,6 +110,7 @@ module OS Pathname("#{prefix}/Toolchains/XcodeDefault.xctoolchain") end + sig { returns(T.nilable(Pathname)) } def bundle_path # Use the default location if it exists. return DEFAULT_BUNDLE_PATH if DEFAULT_BUNDLE_PATH.exist? @@ -124,18 +126,22 @@ module OS !prefix.nil? end + sig { returns(XcodeSDKLocator) } def sdk_locator @sdk_locator ||= XcodeSDKLocator.new end + sig { params(v: T.nilable(MacOS::Version)).returns(T.nilable(SDK)) } def sdk(v = nil) sdk_locator.sdk_if_applicable(v) end + sig { params(v: T.nilable(MacOS::Version)).returns(T.nilable(Pathname)) } def sdk_path(v = nil) sdk(v)&.path end + sig { returns(String) } def installation_instructions if OS::Mac.version.prerelease? <<~EOS @@ -163,6 +169,7 @@ module OS end end + sig { returns(::Version) } def version # may return a version string # that is guessed based on the compiler, so do not @@ -174,6 +181,7 @@ module OS end end + sig { returns(T.nilable(String)) } def detect_version # This is a separate function as you can't cache the value out of a block # if return is used in the middle, which we do many times in here. @@ -231,6 +239,7 @@ module OS end end + sig { returns(T::Boolean) } def default_prefix? prefix.to_s == "/Applications/Xcode.app/Contents/Developer" end @@ -255,26 +264,32 @@ module OS !version.null? end + sig { returns(T::Boolean) } def separate_header_package? version >= "10" && MacOS.version >= "10.14" end + sig { returns(T::Boolean) } def provides_sdk? version >= "8" end + sig { returns(CLTSDKLocator) } def sdk_locator @sdk_locator ||= CLTSDKLocator.new end + sig { params(v: T.nilable(MacOS::Version)).returns(T.nilable(SDK)) } def sdk(v = nil) sdk_locator.sdk_if_applicable(v) end + sig { params(v: T.nilable(MacOS::Version)).returns(T.nilable(Pathname)) } def sdk_path(v = nil) sdk(v)&.path end + sig { returns(String) } def installation_instructions if MacOS.version == "10.14" # This is not available from `xcode-select` @@ -344,6 +359,7 @@ module OS end end + sig { returns(T::Boolean) } def below_minimum_version? return false unless installed? @@ -358,11 +374,13 @@ module OS ::Version.new(clang_version) < latest_clang_version end + sig { returns(T.nilable(String)) } def detect_clang_version version_output = Utils.popen_read("#{PKG_PATH}/usr/bin/clang", "--version") version_output[/clang-(\d+\.\d+\.\d+(\.\d+)?)/, 1] end + sig { returns(T.nilable(String)) } def detect_version_from_clang_version detect_clang_version&.sub(/^(\d+)0(\d)\./, "\\1.\\2.") end @@ -370,6 +388,7 @@ module OS # Version string (a pretty long one) of the CLT package. # Note that the different ways of installing the CLTs lead to different # version numbers. + sig { returns(::Version) } def version if @version ||= detect_version ::Version.new @version @@ -378,8 +397,9 @@ module OS end end + sig { returns(T.nilable(String)) } def detect_version - version = nil + version = T.let(nil, T.nilable(String)) [EXECUTABLE_PKG_ID, MAVERICKS_NEW_PKG_ID].each do |id| next unless File.exist?("#{PKG_PATH}/usr/bin/clang") diff --git a/Library/Homebrew/os/mac/xcode.rbi b/Library/Homebrew/os/mac/xcode.rbi new file mode 100644 index 0000000000..b0707a034e --- /dev/null +++ b/Library/Homebrew/os/mac/xcode.rbi @@ -0,0 +1,9 @@ +# typed: strict + +module OS + module Mac + module Xcode + include Kernel + end + end +end From 9638e3e8c0b1eb03516a39530ebfb9ba26e2ec0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?fn=20=E2=8C=83=20=E2=8C=A5?= <70830482+FnControlOption@users.noreply.github.com> Date: Wed, 29 Sep 2021 17:43:47 -0700 Subject: [PATCH 2/3] development_tools: update type signatures --- Library/Homebrew/development_tools.rb | 15 +-------------- .../Homebrew/extend/os/linux/development_tools.rb | 6 +++--- .../Homebrew/extend/os/mac/development_tools.rb | 2 +- Library/Homebrew/extend/os/mac/hardware.rb | 7 ++++++- Library/Homebrew/os/linux/glibc.rb | 3 +++ Library/Homebrew/os/mac.rb | 3 +++ Library/Homebrew/os/mac/xcode.rb | 2 +- 7 files changed, 18 insertions(+), 20 deletions(-) diff --git a/Library/Homebrew/development_tools.rb b/Library/Homebrew/development_tools.rb index 3961e14538..fc78720816 100644 --- a/Library/Homebrew/development_tools.rb +++ b/Library/Homebrew/development_tools.rb @@ -38,19 +38,6 @@ class DevelopmentTools installation_instructions end - # TODO: This method appears to be unused. Can it be deleted? - sig { returns(T.nilable(String)) } - def default_cc - cc = DevelopmentTools.locate "cc" - return if cc.nil? - - begin - cc.realpath.basename.to_s - rescue - nil - end - end - sig { returns(Symbol) } def default_compiler :clang @@ -126,7 +113,7 @@ class DevelopmentTools { "os" => ENV["HOMEBREW_SYSTEM"], "os_version" => OS_VERSION, - "cpu_family" => Hardware::CPU.family, + "cpu_family" => Hardware::CPU.family.to_s, } end alias generic_build_system_info build_system_info diff --git a/Library/Homebrew/extend/os/linux/development_tools.rb b/Library/Homebrew/extend/os/linux/development_tools.rb index 267c9a1516..2648ebca68 100644 --- a/Library/Homebrew/extend/os/linux/development_tools.rb +++ b/Library/Homebrew/extend/os/linux/development_tools.rb @@ -21,11 +21,11 @@ class DevelopmentTools :gcc end - sig { returns(T::Hash[String, T.untyped]) } + sig { returns(T::Hash[String, T.nilable(String)]) } def build_system_info generic_build_system_info.merge({ - "glibc_version" => OS::Linux::Glibc.version, - "oldest_cpu_family" => Hardware.oldest_cpu, + "glibc_version" => OS::Linux::Glibc.version.to_s.presence, + "oldest_cpu_family" => Hardware.oldest_cpu.to_s, }) end end diff --git a/Library/Homebrew/extend/os/mac/development_tools.rb b/Library/Homebrew/extend/os/mac/development_tools.rb index 993ba68ba3..353ae30428 100644 --- a/Library/Homebrew/extend/os/mac/development_tools.rb +++ b/Library/Homebrew/extend/os/mac/development_tools.rb @@ -64,7 +64,7 @@ class DevelopmentTools EOS end - sig { returns(T::Hash[String, T.untyped]) } + sig { returns(T::Hash[String, T.nilable(String)]) } def build_system_info build_info = { "xcode" => MacOS::Xcode.version.to_s.presence, diff --git a/Library/Homebrew/extend/os/mac/hardware.rb b/Library/Homebrew/extend/os/mac/hardware.rb index 2b6e8de4ee..43adfa1dea 100644 --- a/Library/Homebrew/extend/os/mac/hardware.rb +++ b/Library/Homebrew/extend/os/mac/hardware.rb @@ -4,7 +4,12 @@ module Hardware extend T::Sig sig { params(version: T.nilable(Version)).returns(Symbol) } - def self.oldest_cpu(version = MacOS.version) + def self.oldest_cpu(version = nil) + version = if version + MacOS::Version.new(version.to_s) + else + MacOS.version + end if CPU.arch == :arm64 :arm_vortex_tempest # TODO: this cannot be re-enabled until either Rosetta 2 supports AVX diff --git a/Library/Homebrew/os/linux/glibc.rb b/Library/Homebrew/os/linux/glibc.rb index 2d27c1cca1..7478701223 100644 --- a/Library/Homebrew/os/linux/glibc.rb +++ b/Library/Homebrew/os/linux/glibc.rb @@ -11,6 +11,7 @@ module OS module_function + sig { returns(Version) } def system_version @system_version ||= begin version = Utils.popen_read("/usr/bin/ldd", "--version")[/ (\d+\.\d+)/, 1] @@ -22,6 +23,7 @@ module OS end end + sig { returns(Version) } def version @version ||= begin version = Utils.popen_read(HOMEBREW_PREFIX/"opt/glibc/bin/ldd", "--version")[/ (\d+\.\d+)/, 1] @@ -38,6 +40,7 @@ module OS Version.new(ENV.fetch("HOMEBREW_LINUX_MINIMUM_GLIBC_VERSION")) end + sig { returns(T::Boolean) } def below_minimum_version? system_version < minimum_version end diff --git a/Library/Homebrew/os/mac.rb b/Library/Homebrew/os/mac.rb index b3e6cff1ab..47aaaf722a 100644 --- a/Library/Homebrew/os/mac.rb +++ b/Library/Homebrew/os/mac.rb @@ -24,16 +24,19 @@ module OS # This can be compared to numerics, strings, or symbols # using the standard Ruby Comparable methods. + sig { returns(Version) } def version @version ||= full_version.strip_patch end # This can be compared to numerics, strings, or symbols # using the standard Ruby Comparable methods. + sig { returns(Version) } def full_version @full_version ||= Version.new((ENV["HOMEBREW_MACOS_VERSION"]).chomp) end + sig { params(version: Version).void } def full_version=(version) @full_version = Version.new(version.chomp) @version = nil diff --git a/Library/Homebrew/os/mac/xcode.rb b/Library/Homebrew/os/mac/xcode.rb index 9f857364b2..fb36eabcf3 100755 --- a/Library/Homebrew/os/mac/xcode.rb +++ b/Library/Homebrew/os/mac/xcode.rb @@ -89,7 +89,7 @@ module OS # Returns a Pathname object corresponding to Xcode.app's Developer # directory or nil if Xcode.app is not installed. - sig { returns(Pathname) } + sig { returns(T.nilable(Pathname)) } def prefix @prefix ||= begin From bad19b88cd3c581e0be9d0180cce1308fff96ff7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?fn=20=E2=8C=83=20=E2=8C=A5?= <70830482+FnControlOption@users.noreply.github.com> Date: Wed, 29 Sep 2021 18:16:34 -0700 Subject: [PATCH 3/3] development_tools: update type signatures --- Library/Homebrew/development_tools.rb | 2 +- Library/Homebrew/os/mac.rb | 1 + Library/Homebrew/os/mac/xcode.rb | 3 +++ Library/Homebrew/sorbet/rbi/upstream.rbi | 11 +++++++++++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Library/Homebrew/development_tools.rb b/Library/Homebrew/development_tools.rb index fc78720816..89fd30e568 100644 --- a/Library/Homebrew/development_tools.rb +++ b/Library/Homebrew/development_tools.rb @@ -108,7 +108,7 @@ class DevelopmentTools true end - sig { returns(T::Hash[String, T.untyped]) } + sig { returns(T::Hash[String, T.nilable(String)]) } def build_system_info { "os" => ENV["HOMEBREW_SYSTEM"], diff --git a/Library/Homebrew/os/mac.rb b/Library/Homebrew/os/mac.rb index 47aaaf722a..4f3b153c84 100644 --- a/Library/Homebrew/os/mac.rb +++ b/Library/Homebrew/os/mac.rb @@ -75,6 +75,7 @@ module OS languages.first end + sig { returns(String) } def active_developer_dir @active_developer_dir ||= Utils.popen_read("/usr/bin/xcode-select", "-print-path").strip end diff --git a/Library/Homebrew/os/mac/xcode.rb b/Library/Homebrew/os/mac/xcode.rb index fb36eabcf3..4e8851d858 100755 --- a/Library/Homebrew/os/mac/xcode.rb +++ b/Library/Homebrew/os/mac/xcode.rb @@ -91,6 +91,9 @@ module OS # directory or nil if Xcode.app is not installed. sig { returns(T.nilable(Pathname)) } def prefix + return @prefix if defined?(@prefix) + + @prefix = T.let(@prefix, T.nilable(Pathname)) @prefix ||= begin dir = MacOS.active_developer_dir diff --git a/Library/Homebrew/sorbet/rbi/upstream.rbi b/Library/Homebrew/sorbet/rbi/upstream.rbi index dbade1d0dc..28a1b9b5b6 100644 --- a/Library/Homebrew/sorbet/rbi/upstream.rbi +++ b/Library/Homebrew/sorbet/rbi/upstream.rbi @@ -21,3 +21,14 @@ class Module end def define_method(arg0, arg1=T.unsafe(nil), &blk); end end + +class Pathname + # https://github.com/sorbet/sorbet/pull/4660 + sig do + params( + consider_symlink: T::Boolean, + ) + .returns(Pathname) + end + def cleanpath(consider_symlink=T.unsafe(nil)); end +end