From 0839e21425d203e9e636855c5074bc2086d472d0 Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Wed, 15 Nov 2023 18:38:53 +0000 Subject: [PATCH 1/6] Deprecate `MacOS` methods on Linux --- Library/Homebrew/os/linux.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Library/Homebrew/os/linux.rb b/Library/Homebrew/os/linux.rb index e813f1f13bee0..197c5ebda2c52 100644 --- a/Library/Homebrew/os/linux.rb +++ b/Library/Homebrew/os/linux.rb @@ -55,49 +55,60 @@ module Mac raise "Loaded OS::Linux on generic OS!" if ENV["HOMEBREW_TEST_GENERIC_OS"] def self.version + odeprecated "`MacOS.version` on Linux" MacOSVersion::NULL end def self.full_version + odeprecated "`MacOS.full_version` on Linux" MacOSVersion::NULL end def self.languages + odeprecated "`MacOS.languages` on Linux" @languages ||= Array(ENV["LANG"]&.slice(/[a-z]+/)).uniq end def self.language + odeprecated "`MacOS.language` on Linux" languages.first end def self.sdk_root_needed? + odeprecated "`MacOS.sdk_root_needed?` on Linux" false end def self.sdk_path_if_needed(_version = nil) + odeprecated "`MacOS.sdk_path_if_needed` on Linux" nil end def self.sdk_path(_version = nil) + odeprecated "`MacOS.sdk_path` on Linux" nil end module Xcode def self.version + odeprecated "`MacOS::Xcode.version` on Linux" ::Version::NULL end def self.installed? + odeprecated "`MacOS::Xcode.installed?` on Linux" false end end module CLT def self.version + odeprecated "`MacOS::CLT.version` on Linux" ::Version::NULL end def self.installed? + odeprecated "`MacOS::CLT.installed?` on Linux" false end end From 8704e79cc0f4c6f5ae50bdbeb35cc2312f8788aa Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Wed, 15 Nov 2023 19:52:21 +0000 Subject: [PATCH 2/6] Separate `MacOS` references --- Library/Homebrew/cmd/gist-logs.rb | 4 +--- Library/Homebrew/extend/os/linkage_checker.rb | 6 ++++- Library/Homebrew/extend/os/mac/formula.rb | 22 +++++++++++++++++++ .../Homebrew/extend/os/mac/linkage_checker.rb | 13 +++++++++++ Library/Homebrew/extend/os/mac/utils/curl.rb | 15 +++++++++++++ Library/Homebrew/extend/os/utils/curl.rb | 4 ++++ Library/Homebrew/formula.rb | 12 ++-------- Library/Homebrew/linkage_checker.rb | 8 +++++-- Library/Homebrew/utils/curl.rb | 14 +++++++----- 9 files changed, 76 insertions(+), 22 deletions(-) create mode 100644 Library/Homebrew/extend/os/mac/linkage_checker.rb create mode 100644 Library/Homebrew/extend/os/mac/utils/curl.rb create mode 100644 Library/Homebrew/extend/os/utils/curl.rb diff --git a/Library/Homebrew/cmd/gist-logs.rb b/Library/Homebrew/cmd/gist-logs.rb index dba4217ee27fa..829cec0c4b410 100644 --- a/Library/Homebrew/cmd/gist-logs.rb +++ b/Library/Homebrew/cmd/gist-logs.rb @@ -73,9 +73,7 @@ def gistify_logs(formula, args:) EOS end - if args.new_issue? - url = GitHub.create_issue(formula.tap, "#{formula.name} failed to build on #{MacOS.full_version}", url) - end + url = GitHub.create_issue(formula.tap, "#{formula.name} failed to build on #{OS_VERSION}", url) if args.new_issue? puts url if url end diff --git a/Library/Homebrew/extend/os/linkage_checker.rb b/Library/Homebrew/extend/os/linkage_checker.rb index 3e8904e5eb0ef..175e201324b0e 100644 --- a/Library/Homebrew/extend/os/linkage_checker.rb +++ b/Library/Homebrew/extend/os/linkage_checker.rb @@ -1,4 +1,8 @@ # typed: strict # frozen_string_literal: true -require "extend/os/linux/linkage_checker" if OS.linux? +if OS.mac? + require "extend/os/mac/linkage_checker" +else + require "extend/os/linux/linkage_checker" +end diff --git a/Library/Homebrew/extend/os/mac/formula.rb b/Library/Homebrew/extend/os/mac/formula.rb index 0d65ad84fee9c..a5dbd1684c62c 100644 --- a/Library/Homebrew/extend/os/mac/formula.rb +++ b/Library/Homebrew/extend/os/mac/formula.rb @@ -3,9 +3,31 @@ class Formula undef valid_platform? + undef std_cmake_args sig { returns(T::Boolean) } def valid_platform? requirements.none?(LinuxRequirement) end + + sig { + params( + install_prefix: T.any(String, Pathname), + install_libdir: T.any(String, Pathname), + find_framework: String, + ).returns(T::Array[String]) + } + def std_cmake_args(install_prefix: prefix, install_libdir: "lib", find_framework: "LAST") + args = generic_std_cmake_args(install_prefix: install_prefix, install_libdir: install_libdir, + find_framework: find_framework) + + # Avoid false positives for clock_gettime support on 10.11. + # CMake cache entries for other weak symbols may be added here as needed. + args << "-DHAVE_CLOCK_GETTIME:INTERNAL=0" if MacOS.version == "10.11" && MacOS::Xcode.version >= "8.0" + + # Ensure CMake is using the same SDK we are using. + args << "-DCMAKE_OSX_SYSROOT=#{MacOS.sdk_for_formula(self).path}" if MacOS.sdk_root_needed? + + args + end end diff --git a/Library/Homebrew/extend/os/mac/linkage_checker.rb b/Library/Homebrew/extend/os/mac/linkage_checker.rb new file mode 100644 index 0000000000000..9baba42a7d250 --- /dev/null +++ b/Library/Homebrew/extend/os/mac/linkage_checker.rb @@ -0,0 +1,13 @@ +# typed: true +# frozen_string_literal: true + +class LinkageChecker + undef system_libraries_exist_in_cache? + + private + + def system_libraries_exist_in_cache? + # In macOS Big Sur and later, system libraries do not exist on-disk and instead exist in a cache. + MacOS.version >= :big_sur + end +end diff --git a/Library/Homebrew/extend/os/mac/utils/curl.rb b/Library/Homebrew/extend/os/mac/utils/curl.rb new file mode 100644 index 0000000000000..56c7e56f51797 --- /dev/null +++ b/Library/Homebrew/extend/os/mac/utils/curl.rb @@ -0,0 +1,15 @@ +# typed: true +# frozen_string_literal: true + +module Utils + module Curl + undef return_value_for_empty_http_status_code + + def return_value_for_empty_http_status_code(url_type, url) + # Hack around https://github.com/Homebrew/brew/issues/3199 + return if MacOS.version == :el_capitan + + generic_return_value_for_empty_http_status_code url_type, url + end + end +end diff --git a/Library/Homebrew/extend/os/utils/curl.rb b/Library/Homebrew/extend/os/utils/curl.rb new file mode 100644 index 0000000000000..fbd35e61e4d9f --- /dev/null +++ b/Library/Homebrew/extend/os/utils/curl.rb @@ -0,0 +1,4 @@ +# typed: strict +# frozen_string_literal: true + +require "extend/os/mac/utils/curl" if OS.mac? diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index 1b04c8484d2f4..2ab55beccdccb 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -1646,7 +1646,7 @@ def std_cargo_args(root: prefix, path: ".") ).returns(T::Array[String]) } def std_cmake_args(install_prefix: prefix, install_libdir: "lib", find_framework: "LAST") - args = %W[ + %W[ -DCMAKE_INSTALL_PREFIX=#{install_prefix} -DCMAKE_INSTALL_LIBDIR=#{install_libdir} -DCMAKE_BUILD_TYPE=Release @@ -1655,16 +1655,8 @@ def std_cmake_args(install_prefix: prefix, install_libdir: "lib", find_framework -Wno-dev -DBUILD_TESTING=OFF ] - - # Avoid false positives for clock_gettime support on 10.11. - # CMake cache entries for other weak symbols may be added here as needed. - args << "-DHAVE_CLOCK_GETTIME:INTERNAL=0" if MacOS.version == "10.11" && MacOS::Xcode.version >= "8.0" - - # Ensure CMake is using the same SDK we are using. - args << "-DCMAKE_OSX_SYSROOT=#{MacOS.sdk_for_formula(self).path}" if MacOS.sdk_root_needed? - - args end + alias generic_std_cmake_args std_cmake_args # Standard parameters for Go builds. sig { diff --git a/Library/Homebrew/linkage_checker.rb b/Library/Homebrew/linkage_checker.rb index b3b00bbeb36ed..d3befd6423ab7 100644 --- a/Library/Homebrew/linkage_checker.rb +++ b/Library/Homebrew/linkage_checker.rb @@ -196,9 +196,8 @@ def check_dylibs(rebuild_cache:) if (dep = dylib_to_dep(dylib)) @broken_deps[dep] |= [dylib] - elsif MacOS.version >= :big_sur && dylib_found_via_dlopen(dylib) + elsif system_libraries_exist_in_cache? && dylib_found_via_dlopen(dylib) # If we cannot associate the dylib with a dependency, then it may be a system library. - # In macOS Big Sur and later, system libraries do not exist on-disk and instead exist in a cache. # If dlopen finds the dylib, then the linkage is not broken. @system_dylibs << dylib elsif !system_framework?(dylib) @@ -227,6 +226,11 @@ def check_dylibs(rebuild_cache:) end alias generic_check_dylibs check_dylibs + def system_libraries_exist_in_cache? + false + end + alias generic_system_libraries_exist_in_cache? system_libraries_exist_in_cache? + def dylib_found_via_dlopen(dylib) Fiddle.dlopen(dylib).close true diff --git a/Library/Homebrew/utils/curl.rb b/Library/Homebrew/utils/curl.rb index 5f594cc8df07a..a1b1c1b44b6a4 100644 --- a/Library/Homebrew/utils/curl.rb +++ b/Library/Homebrew/utils/curl.rb @@ -320,12 +320,7 @@ def curl_check_http_content(url, url_type, specs: {}, user_agents: [:default], r break if http_status_ok?(details[:status_code]) end - unless details[:status_code] - # Hack around https://github.com/Homebrew/brew/issues/3199 - return if MacOS.version == :el_capitan - - return "The #{url_type} #{url} is not reachable" - end + return return_value_for_empty_http_status_code(url_type, url) unless details[:status_code] unless http_status_ok?(details[:status_code]) return if details[:responses].any? do |response| @@ -486,6 +481,11 @@ def http_status_ok?(status) (100..299).cover?(status.to_i) end + def return_value_for_empty_http_status_code(url_type, url) + "The #{url_type} #{url} is not reachable" + end + alias generic_return_value_for_empty_http_status_code return_value_for_empty_http_status_code + # Separates the output text from `curl` into an array of HTTP responses and # the final response body (i.e. content). Response hashes contain the # `:status_code`, `:status_text`, and `:headers`. @@ -619,3 +619,5 @@ def parse_curl_response(response_text) end end end + +require "extend/os/utils/curl" From 529f7b7953d75657ef996059bfe50cff40f90d00 Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Thu, 16 Nov 2023 11:47:48 -0500 Subject: [PATCH 3/6] Remove El Capitan system curl workaround --- Library/Homebrew/extend/os/mac/utils/curl.rb | 15 --------------- Library/Homebrew/extend/os/utils/curl.rb | 4 ---- Library/Homebrew/utils/curl.rb | 9 +-------- 3 files changed, 1 insertion(+), 27 deletions(-) delete mode 100644 Library/Homebrew/extend/os/mac/utils/curl.rb delete mode 100644 Library/Homebrew/extend/os/utils/curl.rb diff --git a/Library/Homebrew/extend/os/mac/utils/curl.rb b/Library/Homebrew/extend/os/mac/utils/curl.rb deleted file mode 100644 index 56c7e56f51797..0000000000000 --- a/Library/Homebrew/extend/os/mac/utils/curl.rb +++ /dev/null @@ -1,15 +0,0 @@ -# typed: true -# frozen_string_literal: true - -module Utils - module Curl - undef return_value_for_empty_http_status_code - - def return_value_for_empty_http_status_code(url_type, url) - # Hack around https://github.com/Homebrew/brew/issues/3199 - return if MacOS.version == :el_capitan - - generic_return_value_for_empty_http_status_code url_type, url - end - end -end diff --git a/Library/Homebrew/extend/os/utils/curl.rb b/Library/Homebrew/extend/os/utils/curl.rb deleted file mode 100644 index fbd35e61e4d9f..0000000000000 --- a/Library/Homebrew/extend/os/utils/curl.rb +++ /dev/null @@ -1,4 +0,0 @@ -# typed: strict -# frozen_string_literal: true - -require "extend/os/mac/utils/curl" if OS.mac? diff --git a/Library/Homebrew/utils/curl.rb b/Library/Homebrew/utils/curl.rb index a1b1c1b44b6a4..8973d43d3c4f3 100644 --- a/Library/Homebrew/utils/curl.rb +++ b/Library/Homebrew/utils/curl.rb @@ -320,7 +320,7 @@ def curl_check_http_content(url, url_type, specs: {}, user_agents: [:default], r break if http_status_ok?(details[:status_code]) end - return return_value_for_empty_http_status_code(url_type, url) unless details[:status_code] + return "The #{url_type} #{url} is not reachable" unless details[:status_code] unless http_status_ok?(details[:status_code]) return if details[:responses].any? do |response| @@ -481,11 +481,6 @@ def http_status_ok?(status) (100..299).cover?(status.to_i) end - def return_value_for_empty_http_status_code(url_type, url) - "The #{url_type} #{url} is not reachable" - end - alias generic_return_value_for_empty_http_status_code return_value_for_empty_http_status_code - # Separates the output text from `curl` into an array of HTTP responses and # the final response body (i.e. content). Response hashes contain the # `:status_code`, `:status_text`, and `:headers`. @@ -619,5 +614,3 @@ def parse_curl_response(response_text) end end end - -require "extend/os/utils/curl" From f98b8f948ce20a57ae58ad5b9a0535ecee05d77b Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Wed, 22 Nov 2023 20:22:02 -0500 Subject: [PATCH 4/6] Add rubocop to remove `MacOS` references --- Library/Homebrew/rubocops/lines.rb | 15 +++ .../shared/on_system_conditionals_helper.rb | 26 +++- .../test/rubocops/text/macos_on_linux_spec.rb | 127 ++++++++++++++++++ 3 files changed, 161 insertions(+), 7 deletions(-) create mode 100644 Library/Homebrew/test/rubocops/text/macos_on_linux_spec.rb diff --git a/Library/Homebrew/rubocops/lines.rb b/Library/Homebrew/rubocops/lines.rb index e44623e4595f4..fbb5c8208186a 100644 --- a/Library/Homebrew/rubocops/lines.rb +++ b/Library/Homebrew/rubocops/lines.rb @@ -441,6 +441,21 @@ def audit_formula(_node, _class_node, _parent_class_node, body_node) end end + # This cop makes sure the `MacOS` module is not used in Linux-facing formula code + # + # @api private + class MacOSOnLinux < FormulaCop + include OnSystemConditionalsHelper + + ON_MACOS_BLOCKS = [:macos, *MACOS_VERSION_OPTIONS].map { |os| :"on_#{os}" }.freeze + + def audit_formula(_node, _class_node, _parent_class_node, body_node) + audit_macos_references(body_node, + allowed_methods: OnSystemConditionals::NO_ON_SYSTEM_METHOD_NAMES, + allowed_blocks: OnSystemConditionals::NO_ON_SYSTEM_BLOCK_NAMES + ON_MACOS_BLOCKS) + end + end + # This cop makes sure that the `generate_completions_from_executable` DSL is used. # # @api private diff --git a/Library/Homebrew/rubocops/shared/on_system_conditionals_helper.rb b/Library/Homebrew/rubocops/shared/on_system_conditionals_helper.rb index c6e0142afb1d4..bee4847630a5a 100644 --- a/Library/Homebrew/rubocops/shared/on_system_conditionals_helper.rb +++ b/Library/Homebrew/rubocops/shared/on_system_conditionals_helper.rb @@ -17,6 +17,7 @@ module OnSystemConditionalsHelper BASE_OS_OPTIONS = [:macos, :linux].freeze MACOS_VERSION_OPTIONS = MacOSVersion::SYMBOLS.keys.freeze ON_SYSTEM_OPTIONS = [*ARCH_OPTIONS, *BASE_OS_OPTIONS, *MACOS_VERSION_OPTIONS, :system].freeze + MACOS_MODULE_NAMES = ["MacOS", "OS::Mac"].freeze MACOS_VERSION_CONDITIONALS = { "==" => nil, @@ -82,7 +83,7 @@ def audit_arch_conditionals(body_node, allowed_methods: [], allowed_blocks: []) ARCH_OPTIONS.each do |arch_option| else_method = (arch_option == :arm) ? :on_intel : :on_arm if_arch_node_search(body_node, arch: :"#{arch_option}?") do |if_node, else_node| - next if if_node_is_allowed?(if_node, allowed_methods: allowed_methods, allowed_blocks: allowed_blocks) + next if node_is_allowed?(if_node, allowed_methods: allowed_methods, allowed_blocks: allowed_blocks) if_statement_problem(if_node, "if Hardware::CPU.#{arch_option}?", "on_#{arch_option}", else_method: else_method, else_node: else_node) @@ -93,7 +94,7 @@ def audit_arch_conditionals(body_node, allowed_methods: [], allowed_blocks: []) hardware_cpu_search(body_node, method: method) do |method_node| # These should already be caught by `if_arch_node_search` next if method_node.parent.source.start_with? "if #{method_node.source}" - next if if_node_is_allowed?(method_node, allowed_methods: allowed_methods, allowed_blocks: allowed_blocks) + next if node_is_allowed?(method_node, allowed_methods: allowed_methods, allowed_blocks: allowed_blocks) offending_node(method_node) problem "Don't use `#{method_node.source}`, use `on_arm` and `on_intel` blocks instead." @@ -109,7 +110,7 @@ def audit_base_os_conditionals(body_node, allowed_methods: [], allowed_blocks: [ [:linux?, :on_macos] end if_base_os_node_search(body_node, base_os: os_method) do |if_node, else_node| - next if if_node_is_allowed?(if_node, allowed_methods: allowed_methods, allowed_blocks: allowed_blocks) + next if node_is_allowed?(if_node, allowed_methods: allowed_methods, allowed_blocks: allowed_blocks) if_statement_problem(if_node, "if OS.#{os_method}", "on_#{base_os_option}", else_method: else_method, else_node: else_node) @@ -121,7 +122,7 @@ def audit_macos_version_conditionals(body_node, allowed_methods: [], allowed_blo recommend_on_system: true) MACOS_VERSION_OPTIONS.each do |macos_version_option| if_macos_version_node_search(body_node, os_version: macos_version_option) do |if_node, operator, else_node| - next if if_node_is_allowed?(if_node, allowed_methods: allowed_methods, allowed_blocks: allowed_blocks) + next if node_is_allowed?(if_node, allowed_methods: allowed_methods, allowed_blocks: allowed_blocks) autocorrect = else_node.blank? && MACOS_VERSION_CONDITIONALS.key?(operator.to_s) on_system_method_string = if recommend_on_system && operator == :< @@ -141,7 +142,7 @@ def audit_macos_version_conditionals(body_node, allowed_methods: [], allowed_blo macos_version_comparison_search(body_node, os_version: macos_version_option) do |method_node| # These should already be caught by `if_macos_version_node_search` next if method_node.parent.source.start_with? "if #{method_node.source}" - next if if_node_is_allowed?(method_node, allowed_methods: allowed_methods, allowed_blocks: allowed_blocks) + next if node_is_allowed?(method_node, allowed_methods: allowed_methods, allowed_blocks: allowed_blocks) offending_node(method_node) problem "Don't use `#{method_node.source}`, use `on_{macos_version}` blocks instead." @@ -149,6 +150,17 @@ def audit_macos_version_conditionals(body_node, allowed_methods: [], allowed_blo end end + def audit_macos_references(body_node, allowed_methods: [], allowed_blocks: []) + MACOS_MODULE_NAMES.each do |macos_module_name| + find_const(body_node, macos_module_name) do |node| + next if node_is_allowed?(node, allowed_methods: allowed_methods, allowed_blocks: allowed_blocks) + + offending_node(node) + problem "Don't use `#{macos_module_name}` where it could be called on Linux." + end + end + end + private def if_statement_problem(if_node, if_statement_string, on_system_method_string, @@ -170,10 +182,10 @@ def if_statement_problem(if_node, if_statement_string, on_system_method_string, end end - def if_node_is_allowed?(if_node, allowed_methods: [], allowed_blocks: []) + def node_is_allowed?(node, allowed_methods: [], allowed_blocks: []) # TODO: check to see if it's legal valid = T.let(false, T::Boolean) - if_node.each_ancestor do |ancestor| + node.each_ancestor do |ancestor| valid_method_names = case ancestor.type when :def allowed_methods diff --git a/Library/Homebrew/test/rubocops/text/macos_on_linux_spec.rb b/Library/Homebrew/test/rubocops/text/macos_on_linux_spec.rb new file mode 100644 index 0000000000000..c72c2395feed1 --- /dev/null +++ b/Library/Homebrew/test/rubocops/text/macos_on_linux_spec.rb @@ -0,0 +1,127 @@ +# frozen_string_literal: true + +require "rubocops/lines" + +describe RuboCop::Cop::FormulaAudit::MacOSOnLinux do + subject(:cop) { described_class.new } + + it "reports an offense when `MacOS` is used in the `Formula` class" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + if MacOS::Xcode.version >= "12.0" + ^^^^^ FormulaAudit/MacOSOnLinux: Don't use `MacOS` where it could be called on Linux. + url 'https://brew.sh/linux-1.0.tgz' + end + end + RUBY + end + + it "reports an offense when `MacOS` is used in a `resource` block" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/linux-1.0.tgz' + + resource "foo" do + url "https://brew.sh/linux-1.0.tgz" if MacOS::full_version >= "12.0" + ^^^^^ FormulaAudit/MacOSOnLinux: Don't use `MacOS` where it could be called on Linux. + end + end + RUBY + end + + it "reports an offense when `MacOS` is used in an `on_linux` block" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + on_linux do + if MacOS::Xcode.version >= "12.0" + ^^^^^ FormulaAudit/MacOSOnLinux: Don't use `MacOS` where it could be called on Linux. + url 'https://brew.sh/linux-1.0.tgz' + end + end + end + RUBY + end + + it "reports an offense when `MacOS` is used in an `on_arm` block" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + on_arm do + if MacOS::Xcode.version >= "12.0" + ^^^^^ FormulaAudit/MacOSOnLinux: Don't use `MacOS` where it could be called on Linux. + url 'https://brew.sh/linux-1.0.tgz' + end + end + end + RUBY + end + + it "reports an offense when `MacOS` is used in an `on_intel` block" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + on_intel do + if MacOS::Xcode.version >= "12.0" + ^^^^^ FormulaAudit/MacOSOnLinux: Don't use `MacOS` where it could be called on Linux. + url 'https://brew.sh/linux-1.0.tgz' + end + end + end + RUBY + end + + it "reports no offenses when `MacOS` is used in an `on_macos` block" do + expect_no_offenses(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + on_macos do + if MacOS::Xcode.version >= "12.0" + url 'https://brew.sh/linux-1.0.tgz' + end + end + end + RUBY + end + + it "reports no offenses when `MacOS` is used in an `on_ventura` block" do + expect_no_offenses(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + on_ventura :or_older do + if MacOS::Xcode.version >= "12.0" + url 'https://brew.sh/linux-1.0.tgz' + end + end + end + RUBY + end + + it "reports no offenses when `MacOS` is used in the `install` method" do + expect_no_offenses(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/linux-1.0.tgz' + + def install + MacOS.version + end + end + RUBY + end + + it "reports no offenses when `MacOS` is used in the `test` block" do + expect_no_offenses(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/linux-1.0.tgz' + + test do + MacOS.version + end + end + RUBY + end +end From 4efd7cdb2837858a13f24f2ca49d511320eff3da Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Wed, 22 Nov 2023 21:21:29 -0500 Subject: [PATCH 5/6] Comment out `MacOS` on Linux deprecations --- Library/Homebrew/os/linux.rb | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Library/Homebrew/os/linux.rb b/Library/Homebrew/os/linux.rb index 197c5ebda2c52..877255268def7 100644 --- a/Library/Homebrew/os/linux.rb +++ b/Library/Homebrew/os/linux.rb @@ -55,60 +55,60 @@ module Mac raise "Loaded OS::Linux on generic OS!" if ENV["HOMEBREW_TEST_GENERIC_OS"] def self.version - odeprecated "`MacOS.version` on Linux" + # odeprecated "`MacOS.version` on Linux" MacOSVersion::NULL end def self.full_version - odeprecated "`MacOS.full_version` on Linux" + # odeprecated "`MacOS.full_version` on Linux" MacOSVersion::NULL end def self.languages - odeprecated "`MacOS.languages` on Linux" + # odeprecated "`MacOS.languages` on Linux" @languages ||= Array(ENV["LANG"]&.slice(/[a-z]+/)).uniq end def self.language - odeprecated "`MacOS.language` on Linux" + # odeprecated "`MacOS.language` on Linux" languages.first end def self.sdk_root_needed? - odeprecated "`MacOS.sdk_root_needed?` on Linux" + # odeprecated "`MacOS.sdk_root_needed?` on Linux" false end def self.sdk_path_if_needed(_version = nil) - odeprecated "`MacOS.sdk_path_if_needed` on Linux" + # odeprecated "`MacOS.sdk_path_if_needed` on Linux" nil end def self.sdk_path(_version = nil) - odeprecated "`MacOS.sdk_path` on Linux" + # odeprecated "`MacOS.sdk_path` on Linux" nil end module Xcode def self.version - odeprecated "`MacOS::Xcode.version` on Linux" + # odeprecated "`MacOS::Xcode.version` on Linux" ::Version::NULL end def self.installed? - odeprecated "`MacOS::Xcode.installed?` on Linux" + # odeprecated "`MacOS::Xcode.installed?` on Linux" false end end module CLT def self.version - odeprecated "`MacOS::CLT.version` on Linux" + # odeprecated "`MacOS::CLT.version` on Linux" ::Version::NULL end def self.installed? - odeprecated "`MacOS::CLT.installed?` on Linux" + # odeprecated "`MacOS::CLT.installed?` on Linux" false end end From b7532a86e14c7879f2815ae4c0a85e3daf7aa2ac Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Wed, 22 Nov 2023 21:22:00 -0500 Subject: [PATCH 6/6] Add commented out deprecations for `MacOS` when simulating Linux --- Library/Homebrew/os/mac.rb | 10 ++++++++++ Library/Homebrew/os/mac/xcode.rb | 4 ++++ Library/Homebrew/readall.rb | 8 +++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Library/Homebrew/os/mac.rb b/Library/Homebrew/os/mac.rb index 84a1775947eb3..ed9a875e04627 100644 --- a/Library/Homebrew/os/mac.rb +++ b/Library/Homebrew/os/mac.rb @@ -7,6 +7,9 @@ require "os/mac/sdk" require "os/mac/keg" +# TODO: remove this once the `MacOS` module is undefined on Linux +require "simulate_system" + module OS # Helper module for querying system information on macOS. module Mac @@ -21,6 +24,7 @@ module Mac # using the standard Ruby Comparable methods. sig { returns(MacOSVersion) } def self.version + # odeprecated "`MacOS.version` on Linux" if Homebrew::SimulateSystem.simulating_or_running_on_linux? @version ||= full_version.strip_patch end @@ -28,6 +32,7 @@ def self.version # using the standard Ruby Comparable methods. sig { returns(MacOSVersion) } def self.full_version + # odeprecated "`MacOS.full_version` on Linux" if Homebrew::SimulateSystem.simulating_or_running_on_linux? @full_version ||= if ENV["HOMEBREW_FAKE_EL_CAPITAN"] # for Portable Ruby building MacOSVersion.new("10.11.6") else @@ -60,6 +65,7 @@ def self.preferred_perl_version end def self.languages + # odeprecated "`MacOS.languages` on Linux" if Homebrew::SimulateSystem.simulating_or_running_on_linux? return @languages if @languages os_langs = Utils.popen_read("defaults", "read", "-g", "AppleLanguages") @@ -73,6 +79,7 @@ def self.languages end def self.language + # odeprecated "`MacOS.language` on Linux" if Homebrew::SimulateSystem.simulating_or_running_on_linux? languages.first end @@ -83,6 +90,7 @@ def self.active_developer_dir sig { returns(T::Boolean) } def self.sdk_root_needed? + # odeprecated "`MacOS.sdk_root_needed?` on Linux" if Homebrew::SimulateSystem.simulating_or_running_on_linux? if MacOS::CLT.installed? # If there's no CLT SDK, return false return false unless MacOS::CLT.provides_sdk? @@ -131,11 +139,13 @@ def self.sdk_for_formula(formula, version = nil, check_only_runtime_requirements # Returns the path to an SDK or nil, following the rules set by {sdk}. def self.sdk_path(version = nil) + # odeprecated "`MacOS.sdk_path` on Linux" if Homebrew::SimulateSystem.simulating_or_running_on_linux? s = sdk(version) s&.path end def self.sdk_path_if_needed(version = nil) + # odeprecated "`MacOS.sdk_path_if_needed` on Linux" if Homebrew::SimulateSystem.simulating_or_running_on_linux? # Prefer CLT SDK when both Xcode and the CLT are installed. # Expected results: # 1. On Xcode-only systems, return the Xcode SDK. diff --git a/Library/Homebrew/os/mac/xcode.rb b/Library/Homebrew/os/mac/xcode.rb index 9402bf5d6e11d..e589d2d670c8e 100755 --- a/Library/Homebrew/os/mac/xcode.rb +++ b/Library/Homebrew/os/mac/xcode.rb @@ -126,6 +126,7 @@ def self.bundle_path sig { returns(T::Boolean) } def self.installed? + # odeprecated "`MacOS::Xcode.installed?` on Linux" if Homebrew::SimulateSystem.simulating_or_running_on_linux? !prefix.nil? end @@ -174,6 +175,7 @@ def self.update_instructions sig { returns(::Version) } def self.version + # odeprecated "`MacOS::Xcode.version` on Linux" if Homebrew::SimulateSystem.simulating_or_running_on_linux? # may return a version string # that is guessed based on the compiler, so do not # use it in order to check if Xcode is installed. @@ -264,6 +266,7 @@ module CLT # Returns true even if outdated tools are installed. sig { returns(T::Boolean) } def self.installed? + # odeprecated "`MacOS::CLT.installed?` on Linux" if Homebrew::SimulateSystem.simulating_or_running_on_linux? !version.null? end @@ -397,6 +400,7 @@ def self.detect_version_from_clang_version # version numbers. sig { returns(::Version) } def self.version + # odeprecated "`MacOS::CLT.version` on Linux" if Homebrew::SimulateSystem.simulating_or_running_on_linux? if @version ||= detect_version ::Version.new @version else diff --git a/Library/Homebrew/readall.rb b/Library/Homebrew/readall.rb index bfe714e02d9f6..8faa67554a6fa 100644 --- a/Library/Homebrew/readall.rb +++ b/Library/Homebrew/readall.rb @@ -11,6 +11,10 @@ module Readall class << self include Cachable + # TODO: remove this once the `MacOS` module is undefined on Linux + MACOS_MODULE_REGEX = /\b(MacOS|OS::Mac)(\.|::)\b/.freeze + private_constant :MACOS_MODULE_REGEX + private :cache def valid_ruby_syntax?(ruby_files) @@ -59,7 +63,9 @@ def valid_formulae?(tap, bottle_tag: nil) flags: [], ignore_errors: false) readall_formula = readall_formula_class.new(formula_name, file, :stable, tap: tap) readall_formula.to_hash - cache[:valid_formulae][file] = if readall_formula.on_system_blocks_exist? + # TODO: Remove check for MACOS_MODULE_REGEX once the `MacOS` module is undefined on Linux + cache[:valid_formulae][file] = if readall_formula.on_system_blocks_exist? || + formula_contents.match?(MACOS_MODULE_REGEX) [bottle_tag, *cache[:valid_formulae][file]] else true