Merge pull request #13599 from Rylan12/cleanup-simulate-system

`SimulateSystem` improvements
This commit is contained in:
Rylan Polster 2022-07-28 10:05:13 -04:00 committed by GitHub
commit ef929a7c28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 276 additions and 137 deletions

View File

@ -15,8 +15,7 @@ module OnSystem
def arch_condition_met?(arch) def arch_condition_met?(arch)
raise ArgumentError, "Invalid arch condition: #{arch.inspect}" if ARCH_OPTIONS.exclude?(arch) raise ArgumentError, "Invalid arch condition: #{arch.inspect}" if ARCH_OPTIONS.exclude?(arch)
current_arch = Homebrew::SimulateSystem.arch || Hardware::CPU.type arch == Homebrew::SimulateSystem.current_arch
arch == current_arch
end end
sig { params(os_name: Symbol, or_condition: T.nilable(Symbol)).returns(T::Boolean) } sig { params(os_name: Symbol, or_condition: T.nilable(Symbol)).returns(T::Boolean) }
@ -26,14 +25,7 @@ module OnSystem
return true if [:macos, *MacOSVersions::SYMBOLS.keys].include?(os_name) return true if [:macos, *MacOSVersions::SYMBOLS.keys].include?(os_name)
end end
if BASE_OS_OPTIONS.include?(os_name) return Homebrew::SimulateSystem.send("simulating_or_running_on_#{os_name}?") if BASE_OS_OPTIONS.include?(os_name)
if Homebrew::SimulateSystem.none?
return OS.linux? if os_name == :linux
return OS.mac? if os_name == :macos
end
return Homebrew::SimulateSystem.send("#{os_name}?")
end
raise ArgumentError, "Invalid OS condition: #{os_name.inspect}" unless MacOSVersions::SYMBOLS.key?(os_name) raise ArgumentError, "Invalid OS condition: #{os_name.inspect}" unless MacOSVersions::SYMBOLS.key?(os_name)
@ -41,10 +33,10 @@ module OnSystem
raise ArgumentError, "Invalid OS `or_*` condition: #{or_condition.inspect}" raise ArgumentError, "Invalid OS `or_*` condition: #{or_condition.inspect}"
end end
return false if Homebrew::SimulateSystem.linux? || (Homebrew::SimulateSystem.none? && OS.linux?) return false if Homebrew::SimulateSystem.simulating_or_running_on_linux?
base_os = MacOS::Version.from_symbol(os_name) base_os = MacOS::Version.from_symbol(os_name)
current_os = MacOS::Version.from_symbol(Homebrew::SimulateSystem.os || MacOS.version.to_sym) current_os = MacOS::Version.from_symbol(Homebrew::SimulateSystem.current_os)
return current_os >= base_os if or_condition == :or_newer return current_os >= base_os if or_condition == :or_newer
return current_os <= base_os if or_condition == :or_older return current_os <= base_os if or_condition == :or_older

View File

@ -23,17 +23,4 @@ class Formula
sig { params(targets: T.nilable(T.any(Pathname, String))).void } sig { params(targets: T.nilable(T.any(Pathname, String))).void }
def deuniversalize_machos(*targets); end def deuniversalize_machos(*targets); end
class << self
undef ignore_missing_libraries
def ignore_missing_libraries(*libs)
libraries = libs.flatten
if libraries.any? { |x| !x.is_a?(String) && !x.is_a?(Regexp) }
raise FormulaSpecificationError, "#{__method__} can handle Strings and Regular Expressions only"
end
allowed_missing_libraries.merge(libraries)
end
end
end end

View File

@ -1,27 +0,0 @@
# typed: true
# frozen_string_literal: true
# The Library/Homebrew/extend/os/software_spec.rb conditional logic will need to be more nuanced
# if this file ever includes more than `uses_from_macos`.
class SoftwareSpec
undef uses_from_macos
def uses_from_macos(deps, bounds = {})
if deps.is_a?(Hash)
bounds = deps.dup
deps = [bounds.shift].to_h
end
@uses_from_macos_elements << deps
bounds = bounds.transform_values { |v| MacOS::Version.from_symbol(v) }
# Linux simulating macOS. Assume oldest macOS version.
return if Homebrew::EnvConfig.simulate_macos_on_linux? && !bounds.key?(:since)
# macOS new enough for dependency to not be required.
return if MacOS.version >= bounds[:since]
depends_on deps
end
end

View File

@ -1,9 +1,4 @@
# typed: strict # typed: strict
# frozen_string_literal: true # frozen_string_literal: true
# This logic will need to be more nuanced if this file includes more than `uses_from_macos`. require "extend/os/linux/software_spec" if OS.linux?
if OS.mac? || Homebrew::EnvConfig.simulate_macos_on_linux?
require "extend/os/mac/software_spec"
elsif OS.linux?
require "extend/os/linux/software_spec"
end

View File

@ -3214,12 +3214,19 @@ class Formula
end end
# Permit links to certain libraries that don't exist. Available on Linux only. # Permit links to certain libraries that don't exist. Available on Linux only.
def ignore_missing_libraries(*) def ignore_missing_libraries(*libs)
return if Homebrew::SimulateSystem.linux? unless Homebrew::SimulateSystem.simulating_or_running_on_linux?
raise FormulaSpecificationError, "#{__method__} is available on Linux only" raise FormulaSpecificationError, "#{__method__} is available on Linux only"
end end
libraries = libs.flatten
if libraries.any? { |x| !x.is_a?(String) && !x.is_a?(Regexp) }
raise FormulaSpecificationError, "#{__method__} can handle Strings and Regular Expressions only"
end
allowed_missing_libraries.merge(libraries)
end
# @private # @private
def allowed_missing_libraries def allowed_missing_libraries
@allowed_missing_libraries ||= Set.new @allowed_missing_libraries ||= Set.new

View File

@ -32,19 +32,31 @@ module Homebrew
end end
sig { returns(T::Boolean) } sig { returns(T::Boolean) }
def none? def simulating_or_running_on_macos?
@os.nil? && @arch.nil? return OS.mac? if @os.blank?
end
sig { returns(T::Boolean) }
def macos?
[:macos, *MacOSVersions::SYMBOLS.keys].include?(@os) [:macos, *MacOSVersions::SYMBOLS.keys].include?(@os)
end end
sig { returns(T::Boolean) } sig { returns(T::Boolean) }
def linux? def simulating_or_running_on_linux?
return OS.linux? if @os.blank?
@os == :linux @os == :linux
end end
sig { returns(Symbol) }
def current_arch
@arch || Hardware::CPU.type
end
sig { returns(Symbol) }
def current_os
return @os if @os.present?
return :linux if OS.linux?
MacOS.version.to_sym
end
end end
end end
end end

View File

@ -162,12 +162,25 @@ class SoftwareSpec
add_dep_option(dep) if dep add_dep_option(dep) if dep
end end
def uses_from_macos(spec, _bounds = {}) def uses_from_macos(deps, bounds = {})
spec = [spec.dup.shift].to_h if spec.is_a?(Hash) if deps.is_a?(Hash)
bounds = deps.dup
deps = [bounds.shift].to_h
end
@uses_from_macos_elements << spec @uses_from_macos_elements << deps
depends_on(spec) # Linux simulating macOS. Assume oldest macOS version.
return if Homebrew::EnvConfig.simulate_macos_on_linux? && !bounds.key?(:since)
# macOS new enough for dependency to not be required.
if Homebrew::SimulateSystem.simulating_or_running_on_macos?
current_os = MacOS::Version.from_symbol(Homebrew::SimulateSystem.current_os)
since_os = MacOS::Version.from_symbol(bounds[:since]) if bounds.key?(:since)
return if current_os >= since_os
end
depends_on deps
end end
def uses_from_macos_names def uses_from_macos_names

View File

@ -1845,4 +1845,52 @@ describe Formula do
expect(f.test).to eq(2) expect(f.test).to eq(2)
end end
end end
describe "#ignore_missing_libraries" do
after do
Homebrew::SimulateSystem.clear
end
it "adds library to allowed_missing_libraries on Linux", :needs_linux do
Homebrew::SimulateSystem.clear
f = formula do
url "foo-1.0"
ignore_missing_libraries "bar.so"
end
expect(f.class.allowed_missing_libraries.to_a).to eq(["bar.so"])
end
it "adds library to allowed_missing_libraries on macOS when simulating Linux", :needs_macos do
Homebrew::SimulateSystem.os = :linux
f = formula do
url "foo-1.0"
ignore_missing_libraries "bar.so"
end
expect(f.class.allowed_missing_libraries.to_a).to eq(["bar.so"])
end
it "raises an error on macOS", :needs_macos do
Homebrew::SimulateSystem.clear
expect {
formula do
url "foo-1.0"
ignore_missing_libraries "bar.so"
end
}.to raise_error("ignore_missing_libraries is available on Linux only")
end
it "raises an error on Linux when simulating macOS", :needs_linux do
Homebrew::SimulateSystem.os = :macos
expect {
formula do
url "foo-1.0"
ignore_missing_libraries "bar.so"
end
}.to raise_error("ignore_missing_libraries is available on Linux only")
end
end
end end

View File

@ -1,51 +0,0 @@
# typed: false
# frozen_string_literal: true
require "software_spec"
describe SoftwareSpec do
subject(:spec) { described_class.new }
describe "#uses_from_macos" do
before do
allow(OS).to receive(:mac?).and_return(true)
allow(OS::Mac).to receive(:version).and_return(OS::Mac::Version.from_symbol(:sierra))
end
it "adds a macOS dependency if the OS version meets requirements" do
spec.uses_from_macos("foo", since: :el_capitan)
expect(spec.deps).to be_empty
expect(spec.uses_from_macos_elements.first).to eq("foo")
end
it "doesn't add a macOS dependency if the OS version doesn't meet requirements" do
spec.uses_from_macos("foo", since: :high_sierra)
expect(spec.deps.first.name).to eq("foo")
expect(spec.uses_from_macos_elements).to eq(["foo"])
end
it "works with tags" do
spec.uses_from_macos("foo" => :build, :since => :high_sierra)
dep = spec.deps.first
expect(dep.name).to eq("foo")
expect(dep.tags).to include(:build)
end
it "doesn't add a dependency if no OS version is specified" do
spec.uses_from_macos("foo")
spec.uses_from_macos("bar" => :build)
expect(spec.deps).to be_empty
end
it "raises an error if passing invalid OS versions" do
expect {
spec.uses_from_macos("foo", since: :bar)
}.to raise_error(MacOSVersionError, "unknown or unsupported macOS version: :bar")
end
end
end

View File

@ -0,0 +1,118 @@
# typed: false
# frozen_string_literal: true
require "settings"
describe Homebrew::SimulateSystem do
after do
described_class.clear
end
describe "::simulating_or_running_on_macos?" do
it "returns true on macOS", :needs_macos do
described_class.clear
expect(described_class.simulating_or_running_on_macos?).to be true
end
it "returns false on Linux", :needs_linux do
described_class.clear
expect(described_class.simulating_or_running_on_macos?).to be false
end
it "returns false on macOS when simulating Linux", :needs_macos do
described_class.clear
described_class.os = :linux
expect(described_class.simulating_or_running_on_macos?).to be false
end
it "returns true on Linux when simulating a generic macOS version", :needs_linux do
described_class.clear
described_class.os = :macos
expect(described_class.simulating_or_running_on_macos?).to be true
end
it "returns true on Linux when simulating a specific macOS version", :needs_linux do
described_class.clear
described_class.os = :monterey
expect(described_class.simulating_or_running_on_macos?).to be true
end
end
describe "::simulating_or_running_on_linux?" do
it "returns true on Linux", :needs_linux do
described_class.clear
expect(described_class.simulating_or_running_on_linux?).to be true
end
it "returns false on macOS", :needs_macos do
described_class.clear
expect(described_class.simulating_or_running_on_linux?).to be false
end
it "returns true on macOS when simulating Linux", :needs_macos do
described_class.clear
described_class.os = :linux
expect(described_class.simulating_or_running_on_linux?).to be true
end
it "returns false on Linux when simulating a generic macOS version", :needs_linux do
described_class.clear
described_class.os = :macos
expect(described_class.simulating_or_running_on_linux?).to be false
end
it "returns false on Linux when simulating a specific macOS version", :needs_linux do
described_class.clear
described_class.os = :monterey
expect(described_class.simulating_or_running_on_linux?).to be false
end
end
describe "::current_arch" do
it "returns the current architecture" do
described_class.clear
expect(described_class.current_arch).to eq Hardware::CPU.type
end
it "returns the simulated architecture" do
described_class.clear
simulated_arch = if Hardware::CPU.arm?
:intel
else
:arm
end
described_class.arch = simulated_arch
expect(described_class.current_arch).to eq simulated_arch
end
end
describe "::current_os" do
it "returns the current macOS version on macOS", :needs_macos do
described_class.clear
expect(described_class.current_os).to eq MacOS.version.to_sym
end
it "returns `:linux` on Linux", :needs_linux do
described_class.clear
expect(described_class.current_os).to eq :linux
end
it "returns `:linux` when simulating Linux on macOS", :needs_macos do
described_class.clear
described_class.os = :linux
expect(described_class.current_os).to eq :linux
end
it "returns `:macos` when simulating a generic macOS version on Linux", :needs_linux do
described_class.clear
described_class.os = :macos
expect(described_class.current_os).to eq :macos
end
it "returns `:macos` when simulating a specific macOS version on Linux", :needs_linux do
described_class.clear
described_class.os = :monterey
expect(described_class.current_os).to eq :monterey
end
end
end

View File

@ -135,21 +135,22 @@ describe SoftwareSpec do
end end
end end
describe "#uses_from_macos" do describe "#uses_from_macos", :needs_linux do
it "allows specifying dependencies", :needs_linux do context "when running on Linux", :needs_linux do
it "allows specifying dependencies" do
spec.uses_from_macos("foo") spec.uses_from_macos("foo")
expect(spec.deps.first.name).to eq("foo") expect(spec.deps.first.name).to eq("foo")
end end
it "works with tags", :needs_linux do it "works with tags" do
spec.uses_from_macos("foo" => :build) spec.uses_from_macos("foo" => :build)
expect(spec.deps.first.name).to eq("foo") expect(spec.deps.first.name).to eq("foo")
expect(spec.deps.first.tags).to include(:build) expect(spec.deps.first.tags).to include(:build)
end end
it "ignores OS version specifications", :needs_linux do it "ignores OS version specifications" do
spec.uses_from_macos("foo", since: :mojave) spec.uses_from_macos("foo", since: :mojave)
spec.uses_from_macos("bar" => :build, :since => :mojave) spec.uses_from_macos("bar" => :build, :since => :mojave)
@ -159,6 +160,50 @@ describe SoftwareSpec do
end end
end end
context "when running on macOS", :needs_macos do
before do
allow(OS).to receive(:mac?).and_return(true)
allow(OS::Mac).to receive(:version).and_return(OS::Mac::Version.from_symbol(:sierra))
end
it "adds a macOS dependency if the OS version meets requirements" do
spec.uses_from_macos("foo", since: :el_capitan)
expect(spec.deps).to be_empty
expect(spec.uses_from_macos_elements.first).to eq("foo")
end
it "doesn't add a macOS dependency if the OS version doesn't meet requirements" do
spec.uses_from_macos("foo", since: :high_sierra)
expect(spec.deps.first.name).to eq("foo")
expect(spec.uses_from_macos_elements).to eq(["foo"])
end
it "works with tags" do
spec.uses_from_macos("foo" => :build, :since => :high_sierra)
dep = spec.deps.first
expect(dep.name).to eq("foo")
expect(dep.tags).to include(:build)
end
it "doesn't add a dependency if no OS version is specified" do
spec.uses_from_macos("foo")
spec.uses_from_macos("bar" => :build)
expect(spec.deps).to be_empty
end
it "raises an error if passing invalid OS versions" do
expect {
spec.uses_from_macos("foo", since: :bar)
}.to raise_error(MacOSVersionError, "unknown or unsupported macOS version: :bar")
end
end
end
specify "explicit options override defaupt depends_on option description" do specify "explicit options override defaupt depends_on option description" do
spec.option("with-foo", "blah") spec.option("with-foo", "blah")
spec.depends_on("foo" => :optional) spec.depends_on("foo" => :optional)