lib/scan/detect_values.rb in scan-0.12.0 vs lib/scan/detect_values.rb in scan-0.12.1
- old
+ new
@@ -18,12 +18,12 @@
config.load_configuration_file(Scan.scanfile_name)
end
Scan.project.select_scheme
- default_device_ios if Scan.project.ios?
- default_device_tvos if Scan.project.tvos?
+ detect_simulator_ios if Scan.project.ios?
+ detect_simulator_tvos if Scan.project.tvos?
detect_destination
default_derived_data
return config
@@ -37,106 +37,126 @@
default_path = File.expand_path("../../..", default_path)
UI.verbose("Detected derived data path '#{default_path}'")
Scan.config[:derived_data_path] = default_path
end
- def self.filter_simulators(simulators, deployment_target)
- # Filter out any simulators that are not the same major and minor version of our deployment target
+ def self.filter_simulators(simulators, operator = :greater_than_or_equal, deployment_target)
deployment_target_version = Gem::Version.new(deployment_target)
simulators.select do |s|
- sim_version = Gem::Version.new(s.ios_version)
- (sim_version >= deployment_target_version)
+ sim_version = Gem::Version.new(s.os_version)
+ if operator == :greater_than_or_equal
+ sim_version >= deployment_target_version
+ elsif operator == :equal
+ sim_version == deployment_target_version
+ else
+ false # this will show an error message in the detect_simulator method
+ end
end
end
- def self.default_device_ios
+ def self.regular_expression_for_split_on_whitespace_followed_by_parenthesized_version
+ # %r{
+ # \s # a whitespace character
+ # (?= # followed by -- using lookahead
+ # \( # open parenthesis
+ # [\d\.]+ # our version -- one or more digits or full stops
+ # \) # close parenthesis
+ # $ # end of line
+ # ) # end of lookahead
+ # }
+ /\s(?=\([\d\.]+\)$)/
+ end
+
+ def self.detect_simulator_ios
+ # An iPhone 5s is a reasonably small and useful default for tests
+ detect_simulator('iOS', 'IPHONEOS_DEPLOYMENT_TARGET', 'iPhone 5s', nil)
+ end
+
+ def self.detect_simulator_tvos
+ detect_simulator('tvOS', 'TVOS_DEPLOYMENT_TARGET', 'Apple TV 1080p', 'TV')
+ end
+
+ def self.detect_simulator(requested_os_type, deployment_target_key, default_device_name, simulator_type_descriptor)
+ require 'set'
devices = Scan.config[:devices] || Array(Scan.config[:device]) # important to use Array(nil) for when the value is nil
- found_devices = []
- xcode_target = Scan.project.build_settings(key: "IPHONEOS_DEPLOYMENT_TARGET")
- if devices.any?
- # Optionally, we only do this if the user specified a custom device or an array of devices
- devices.each do |device|
- lookup_device = device.to_s.strip
- has_version = lookup_device.include?(xcode_target) || lookup_device.include?('(')
- lookup_device = lookup_device.tr('()', '') # Remove parenthesis
- # Default to Xcode target version if no device version is specified.
- lookup_device = lookup_device + " " + xcode_target unless has_version
+ deployment_target_version = Scan.project.build_settings(key: deployment_target_key)
- found = FastlaneCore::Simulator.all.detect do |d|
- (d.name + " " + d.ios_version).include? lookup_device
+ simulators = filter_simulators(
+ FastlaneCore::DeviceManager.simulators(requested_os_type).tap do |array|
+ if array.empty?
+ UI.user_error!(['No', simulator_type_descriptor, 'simulators found on local machine'].reject(&:nil?).join(' '))
end
-
- if found
- found_devices.push(found)
- else
- UI.error("Ignoring '#{device}', couldn't find matching simulator")
- end
+ end,
+ :greater_than_or_equal,
+ deployment_target_version
+ ).tap do |sims|
+ if sims.empty?
+ UI.error("No simulators found that are greater than or equal to the version of deployment target (#{deployment_target_version})")
end
-
- if found_devices.any?
- Scan.devices = found_devices
- return
- else
- UI.error("Couldn't find any matching simulators for '#{devices}' - falling back to default simulator")
- end
end
- sims = FastlaneCore::Simulator.all
- sims = filter_simulators(sims, xcode_target)
+ # At this point we have all simulators for the given deployment target (or higher)
- # An iPhone 5s is reasonable small and useful for tests
- found = sims.detect { |d| d.name == "iPhone 5s" }
- found ||= sims.first # anything is better than nothing
+ # We create 2 lambdas, which we iterate over later on
+ # If the first lambda `matches` found a simulator to use
+ # we'll never call the second one
- if found
- Scan.devices = [found]
- else
- UI.user_error!("No simulators found on local machine")
- end
- end
+ matches = lambda do
+ set_of_simulators = devices.inject(
+ Set.new # of simulators
+ ) do |set, device_string|
+ pieces = device_string.split(regular_expression_for_split_on_whitespace_followed_by_parenthesized_version)
- def self.default_device_tvos
- devices = Scan.config[:devices] || Array(Scan.config[:device]) # important to use Array(nil) for when the value is nil
- found_devices = []
+ selector = ->(sim) { pieces.count > 0 && sim.name == pieces.first }
- if devices.any?
- # Optionally, we only do this if the user specified a custom device or an array of devices
- devices.each do |device|
- lookup_device = device.to_s.strip.tr('()', '') # Remove parenthesis
-
- found = FastlaneCore::SimulatorTV.all.detect do |d|
- (d.name + " " + d.os_version).include? lookup_device
+ set + (
+ if pieces.count == 0
+ [] # empty array
+ elsif pieces.count == 1
+ simulators
+ .select(&selector)
+ .reverse # more efficient, because `simctl` prints higher versions first
+ .sort_by! { |sim| Gem::Version.new(sim.os_version) }
+ .pop(1)
+ else # pieces.count == 2 -- mathematically, because of the 'end of line' part of our regular expression
+ version = pieces[1].tr('()', '')
+ potential_emptiness_error = lambda do |sims|
+ UI.error("No simulators found that are equal to the version " \
+ "of specifier (#{version}) and greater than or equal to the version " \
+ "of deployment target (#{deployment_target_version})") if sims.empty?
+ end
+ filter_simulators(simulators, :equal, version).tap(&potential_emptiness_error).select(&selector)
+ end
+ ).tap do |array|
+ UI.error("Ignoring '#{device_string}', couldn’t find matching simulator") if array.empty?
end
-
- if found
- found_devices.push(found)
- else
- UI.error("Ignoring '#{device}', couldn't find matching simulator")
- end
end
- if found_devices.any?
- Scan.devices = found_devices
- return
- else
- UI.error("Couldn't find any matching simulators for '#{devices}' - falling back to default simulator")
- end
+ set_of_simulators.to_a
end
- sims = FastlaneCore::SimulatorTV.all
- xcode_target = Scan.project.build_settings(key: "TVOS_DEPLOYMENT_TARGET")
- sims = filter_simulators(sims, xcode_target)
+ default = lambda do
+ UI.error("Couldn't find any matching simulators for '#{devices}' - falling back to default simulator")
- # Apple TV 1080p is useful for tests
- found = sims.detect { |d| d.name == "Apple TV 1080p" }
- found ||= sims.first # anything is better than nothing
+ result = Array(
+ simulators
+ .select { |sim| sim.name == default_device_name }
+ .reverse # more efficient, because `simctl` prints higher versions first
+ .sort_by! { |sim| Gem::Version.new(sim.os_version) }
+ .last || simulators.first
+ )
- if found
- Scan.devices = [found]
- else
- UI.user_error!("No TV simulators found on the local machine")
+ UI.error("Found simulator \"#{result.first.name} (#{result.first.os_version})\"") if result.first
+
+ result
end
+
+ # grab the first unempty evaluated array
+ Scan.devices = [matches, default].lazy.map { |x|
+ arr = x.call
+ arr unless arr.empty?
+ }.reject(&:nil?).first
end
def self.min_xcode8?
Helper.xcode_version.split(".").first.to_i >= 8
end