fastlane-plugin-create_simulator_devices 0.0.17 → 0.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8bf78a070d8cc87783033a6d6dfb1c778a2cacc388cf0e5f691308955e94f848
4
- data.tar.gz: 1a4fae00d92ff2e0c1f2a15a3f0804cb519fc9e2cedafa98e183ab0da6d39b74
3
+ metadata.gz: 97e225aefb5c19c442c8b1d91dc978988ae18112c67101675410f3c4619f1890
4
+ data.tar.gz: d6a331652a7dbd2eee226f7b82a7096ce1abb875bbfb0f5cc87e8a81bce94f42
5
5
  SHA512:
6
- metadata.gz: b47dc812e54c36acd0a95131838b5f45b0ab2fc9422965c961b4002acfdaf275ac9e1a870336a778043908cb62da3e6656ae3feb29c657bee6b80200dc320a24
7
- data.tar.gz: e21033bc755e645677f98e54ddb553cafbaf674ac01e6d34bd07dce967b17a2f1c5459c0928d0edf06de002abae337940e122bff507c63850a85101d749d2771
6
+ metadata.gz: aeebdd926046ca88b8614e02f2f3dc6b4f24a724fe1cccdc7f2ac412ef3528ca4b113d07c5eedc35af063be5b256b36ce42267c4bfe3d3280189729a1b837625
7
+ data.tar.gz: 8528b9428574f4ba9f8d31d9878d3d825bf7374095e79d8413269fc7d889aecb2f5d33561a8bb3ac0a2316f1d94e3045b0261e8af525fb5e1d1dfe23b88fb53d
@@ -22,7 +22,7 @@ module Fastlane
22
22
  required_devices = params[:devices]
23
23
  UI.user_error!('No devices specified') if required_devices.nil? || required_devices.empty?
24
24
 
25
- shell_helper = CreateSimulatorDevices::ShellHelper.new(print_command: params[:print_command], print_command_output: params[:print_command_output], action_context: self)
25
+ shell_helper = CreateSimulatorDevices::ShellHelper.new(verbose: verbose, print_command: params[:print_command], print_command_output: params[:print_command_output], action_context: self)
26
26
  runtime_helper = CreateSimulatorDevices::RuntimeHelper.new(cache_dir: params[:cache_dir], shell_helper: shell_helper, verbose: verbose)
27
27
 
28
28
  runner = CreateSimulatorDevices::Runner.new(
@@ -32,7 +32,8 @@ module Fastlane
32
32
  can_rename_devices: params[:rename_devices],
33
33
  can_delete_duplicate_devices: params[:delete_duplicate_devices],
34
34
  device_naming_style: params[:device_naming_style].to_sym,
35
- remove_cached_runtimes: params[:remove_cached_runtimes]
35
+ remove_cached_runtimes: params[:remove_cached_runtimes],
36
+ update_dyld_shared_cache: params[:update_dyld_shared_cache]
36
37
  )
37
38
 
38
39
  runner.run(required_devices)
@@ -113,7 +114,13 @@ module Fastlane
113
114
  description: 'Remove cached runtimes after successful installation',
114
115
  type: Boolean,
115
116
  optional: true,
116
- default_value: true)
117
+ default_value: true),
118
+ ::FastlaneCore::ConfigItem.new(key: :update_dyld_shared_cache,
119
+ env_name: 'CREATE_SIMULATOR_DEVICES_UPDATE_DYLD_SHARED_CACHE',
120
+ description: 'Update dyld shared cache',
121
+ type: Boolean,
122
+ optional: true,
123
+ default_value: false)
117
124
  ]
118
125
  end
119
126
 
@@ -24,7 +24,7 @@ module Fastlane
24
24
  required_devices = params[:devices]
25
25
  UI.user_error!('No devices specified') if required_devices.nil? || required_devices.empty?
26
26
 
27
- shell_helper = CreateSimulatorDevices::ShellHelper.new(print_command: params[:print_command], print_command_output: params[:print_command_output], action_context: self)
27
+ shell_helper = CreateSimulatorDevices::ShellHelper.new(verbose: verbose, print_command: params[:print_command], print_command_output: params[:print_command_output], action_context: self)
28
28
  runtime_helper = CreateSimulatorDevices::RuntimeHelper.new(cache_dir: nil, shell_helper: shell_helper, verbose: verbose)
29
29
 
30
30
  create_simulator_devices_runner = ::Fastlane::CreateSimulatorDevices::Runner.new(
@@ -62,15 +62,15 @@ module Fastlane
62
62
  end
63
63
 
64
64
  def major
65
- @build_version.match(/^([0-9]+)([A-Z][0-9]{2,3})([0-9]+)/)[1]
65
+ @build_version.match(/^([0-9]+)([A-Z])([0-9]+)/)[1]
66
66
  end
67
67
 
68
68
  def minor
69
- @build_version.match(/^([0-9]+)([A-Z][0-9]{2,3})([0-9]+)/)[2]
69
+ @build_version.match(/^([0-9]+)([A-Z])([0-9]+)/)[2]
70
70
  end
71
71
 
72
72
  def patch
73
- @build_version.match(/^([0-9]+)([A-Z][0-9]{2,3})([0-9]+)/)[3]
73
+ @build_version.match(/^([0-9]+)([A-Z])([0-9]+)/)[3]
74
74
  end
75
75
 
76
76
  def <(other)
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'runtime_supported_device_type'
4
+ require_relative '../apple_build_version'
5
+
6
+ module Fastlane
7
+ module CreateSimulatorDevices
8
+ module SimCTL
9
+ # Represents a matched runtime from `xcrun simctl runtime match list --json` output.
10
+ class MatchedRuntime
11
+ attr_accessor :identifier, :default_build, :chosen_runtime_build, :sdk_build, :sdk_version, :platform
12
+
13
+ def initialize(identifier:, default_build:, chosen_runtime_build:, sdk_build:, sdk_version:, platform:) # rubocop:disable Metrics/ParameterLists
14
+ self.identifier = identifier
15
+ self.default_build = default_build
16
+ self.chosen_runtime_build = chosen_runtime_build
17
+ self.sdk_build = sdk_build
18
+ self.sdk_version = sdk_version
19
+ self.platform = platform
20
+ end
21
+
22
+ def self.from_hash(hash, identifier:)
23
+ new(
24
+ identifier: identifier.to_s,
25
+ default_build: AppleBuildVersion.new(hash[:defaultBuild]),
26
+ chosen_runtime_build: AppleBuildVersion.new(hash[:chosenRuntimeBuild]),
27
+ sdk_build: AppleBuildVersion.new(hash[:sdkBuild]),
28
+ sdk_version: Gem::Version.new(hash[:sdkVersion]),
29
+ platform: hash[:platform].to_s
30
+ )
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ # Example of a Runtime object from `xcrun simctl list runtimes --json` output:
38
+ #
39
+ # {"iphoneos26.1" : {
40
+ # "chosenRuntimeBuild" : "23B80",
41
+ # "defaultBuild" : "23B77",
42
+ # "platform" : "com.apple.platform.iphoneos",
43
+ # "sdkBuild" : "23B77",
44
+ # "sdkDirectory" : "\/Applications\/Xcode-26.1.1.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Developer\/SDKs\/iPhoneOS26.1.sdk",
45
+ # "sdkVersion" : "26.1"
46
+ # }
@@ -9,6 +9,7 @@ require_relative 'models/required_device'
9
9
  require_relative 'models/required_runtime'
10
10
  require_relative 'models/apple_build_version'
11
11
  require_relative 'models/device_naming_style'
12
+ require_relative 'models/simctl/matched_runtime'
12
13
  require 'fastlane'
13
14
 
14
15
  module Fastlane
@@ -9,12 +9,12 @@ module Fastlane
9
9
  # Create simulator devices.
10
10
  module CreateSimulatorDevices
11
11
  # Does all the work to create simulator devices.
12
- class Runner # rubocop:disable Metrics/ClassLength
12
+ class Runner
13
13
  UI = ::Fastlane::UI unless defined?(UI)
14
14
 
15
- attr_accessor :shell_helper, :verbose, :runtime_helper, :can_rename_devices, :can_delete_duplicate_devices, :device_naming_style, :remove_cached_runtimes
15
+ attr_accessor :shell_helper, :verbose, :runtime_helper, :can_rename_devices, :can_delete_duplicate_devices, :device_naming_style, :remove_cached_runtimes, :update_dyld_shared_cache
16
16
 
17
- def initialize(runtime_helper:, shell_helper:, verbose:, can_rename_devices:, can_delete_duplicate_devices:, device_naming_style:, remove_cached_runtimes:) # rubocop:disable Metrics/ParameterLists
17
+ def initialize(runtime_helper:, shell_helper:, verbose:, can_rename_devices:, can_delete_duplicate_devices:, device_naming_style:, remove_cached_runtimes:, update_dyld_shared_cache:) # rubocop:disable Metrics/ParameterLists
18
18
  self.shell_helper = shell_helper
19
19
  self.verbose = verbose
20
20
  self.runtime_helper = runtime_helper
@@ -22,6 +22,7 @@ module Fastlane
22
22
  self.can_delete_duplicate_devices = can_delete_duplicate_devices
23
23
  self.device_naming_style = device_naming_style
24
24
  self.remove_cached_runtimes = remove_cached_runtimes
25
+ self.update_dyld_shared_cache = update_dyld_shared_cache
25
26
  end
26
27
 
27
28
  def run(devices)
@@ -55,6 +56,11 @@ module Fastlane
55
56
 
56
57
  log_matched_devices(matched_devices: matched_devices)
57
58
 
59
+ if update_dyld_shared_cache
60
+ UI.message('Updating dyld shared cache...')
61
+ shell_helper.update_dyld_shared_cache
62
+ end
63
+
58
64
  matched_devices_names = matched_devices.map { |matched_device| returning_device_name_for_required_device(matched_device) }
59
65
  UI.message("Available simulator devices: #{matched_devices_names.join(', ')}")
60
66
 
@@ -25,6 +25,13 @@ module Fastlane
25
25
  'xrsimulator' => 'xrOS'
26
26
  }.freeze
27
27
 
28
+ OS_NAME_TO_MATCHED_RUNTIME_IDENTIFIER = {
29
+ 'iOS' => 'iphoneos',
30
+ 'tvOS' => 'appletvos',
31
+ 'watchOS' => 'watchos',
32
+ 'xrOS' => 'xros'
33
+ }.freeze
34
+
28
35
  def delete_unusable_runtimes
29
36
  deletable_runtimes = shell_helper.installed_runtimes_with_state
30
37
  .select { |runtime| runtime.unusable? && runtime.deletable? }
@@ -153,6 +160,16 @@ module Fastlane
153
160
  AppleBuildVersion.new(build_version)
154
161
  end
155
162
 
163
+ def matched_runtime_for_missing_runtime(missing_runtime)
164
+ matched_runtimes = shell_helper.simctl_matched_runtimes(force: true)
165
+
166
+ matched_runtime_identifier = "#{OS_NAME_TO_MATCHED_RUNTIME_IDENTIFIER[missing_runtime.os_name]}#{missing_runtime.product_version}"
167
+
168
+ matched_runtimes = matched_runtimes.select { |matched_runtime| matched_runtime.identifier == matched_runtime_identifier && matched_runtime.sdk_build == missing_runtime.product_build_version }
169
+
170
+ matched_runtimes.max_by(&:chosen_runtime_build)
171
+ end
172
+
156
173
  def cached_runtime_file(missing_runtime)
157
174
  FileUtils.mkdir_p(cache_dir)
158
175
 
@@ -164,10 +181,10 @@ module Fastlane
164
181
  # E.g. Xcode 26.0 Beta 3 has iOS 26.0 (23A5287e) SDK, but
165
182
  # xcodebuild downloads iphonesimulator_26.0_23A5287g.dmg as latest.
166
183
  product_build_version = missing_runtime.product_build_version
184
+
167
185
  if product_build_version
168
186
  runtime_dmg_search_pattern += product_build_version.major.to_s
169
187
  runtime_dmg_search_pattern += product_build_version.minor.to_s
170
- runtime_dmg_search_pattern += product_build_version.patch.to_s
171
188
  end
172
189
  runtime_dmg_search_pattern += '*.dmg'
173
190
 
@@ -177,9 +194,17 @@ module Fastlane
177
194
  UI.message("Available files with pattern: #{Dir.glob(runtime_dmg_search_pattern)}")
178
195
  end
179
196
 
180
- runtime_file = Dir
197
+ runtime_file = nil
198
+ runtime_files = Dir
181
199
  .glob(runtime_dmg_search_pattern)
182
- .max_by { |filename| runtime_build_version_for_filename(filename) }
200
+
201
+ return nil if runtime_files.empty?
202
+
203
+ matched_runtime = matched_runtime_for_missing_runtime(missing_runtime)
204
+
205
+ runtime_file = runtime_files.detect { |filename| filename.end_with?("_#{matched_runtime.chosen_runtime_build}.dmg") } unless matched_runtime.nil?
206
+
207
+ runtime_file ||= runtime_files.max_by { |filename| runtime_build_version_for_filename(filename) }
183
208
 
184
209
  return nil if runtime_file.nil?
185
210
 
@@ -11,9 +11,10 @@ module Fastlane
11
11
  UI = ::Fastlane::UI unless defined?(UI)
12
12
 
13
13
  # Proprty verbose
14
- attr_accessor :print_command, :print_command_output, :action_context
14
+ attr_accessor :verbose, :print_command, :print_command_output, :action_context
15
15
 
16
- def initialize(print_command: false, print_command_output: false, action_context: nil)
16
+ def initialize(verbose: false, print_command: false, print_command_output: false, action_context: nil)
17
+ self.verbose = verbose
17
18
  self.print_command = print_command
18
19
  self.print_command_output = print_command_output
19
20
  self.action_context = action_context
@@ -103,6 +104,17 @@ module Fastlane
103
104
  @simctl_runtimes
104
105
  end
105
106
 
107
+ def simctl_matched_runtimes(force: false)
108
+ return @simctl_matched_runtimes unless force || @simctl_matched_runtimes.nil?
109
+
110
+ UI.message('Fetching matched runtimes...')
111
+ json = sh(command: 'xcrun simctl runtime match list --json')
112
+
113
+ @simctl_matched_runtimes = JSON
114
+ .parse(json, symbolize_names: true)
115
+ .map { |identifier, runtime| SimCTL::MatchedRuntime.from_hash(runtime, identifier: identifier) }
116
+ end
117
+
106
118
  def installed_runtimes_with_state
107
119
  UI.message('Fetching runtimes with state...')
108
120
  json = sh(command: 'xcrun simctl runtime list --json')
@@ -141,8 +153,6 @@ module Fastlane
141
153
  end
142
154
 
143
155
  def download_runtime(missing_runtime, cache_dir)
144
- UI.message("Downloading #{missing_runtime.runtime_name} to #{cache_dir}. This may take a while...")
145
-
146
156
  command = [
147
157
  'xcrun',
148
158
  'xcodebuild',
@@ -162,6 +172,30 @@ module Fastlane
162
172
  command << missing_runtime.product_version.to_s.shellescape
163
173
  end
164
174
 
175
+ simulator_architecture_variant = 'universal'
176
+
177
+ if Fastlane::Helper.xcode_at_least?('26') && missing_runtime.product_version >= '26'
178
+ xcode_binary_path = File.join(Fastlane::Helper.xcode_path, '..', 'MacOS', 'Xcode')
179
+ xcode_binary_path = File.expand_path(xcode_binary_path)
180
+
181
+ UI.message('Getting Xcode architecture variants with lipo...') if verbose
182
+
183
+ xcode_architecture_variants = sh(command: "lipo -archs #{xcode_binary_path.shellescape}", print_command: print_command, print_command_output: print_command_output).split
184
+
185
+ UI.message("Xcode architecture variants: #{xcode_architecture_variants}") if verbose
186
+
187
+ simulator_architecture_variant = if xcode_architecture_variants.include?('x86_64')
188
+ 'universal'
189
+ else
190
+ 'arm64'
191
+ end
192
+
193
+ command << '-architectureVariant'
194
+ command << simulator_architecture_variant.shellescape
195
+ end
196
+
197
+ UI.message("Downloading #{missing_runtime.runtime_name} (arch: #{simulator_architecture_variant}) to #{cache_dir}. This may take a while...")
198
+
165
199
  sh(command: command.join(' '), print_command: true, print_command_output: true)
166
200
  end
167
201
 
@@ -175,6 +209,12 @@ module Fastlane
175
209
  end
176
210
  end
177
211
 
212
+ def update_dyld_shared_cache
213
+ sh(
214
+ command: 'xcrun simctl runtime dyld_shared_cache update --all'
215
+ )
216
+ end
217
+
178
218
  def device_info_by_udid(udid)
179
219
  sh(
180
220
  command: "xcrun simctl list devices --json | jq '.devices | to_entries[].value[] | select(.udid==\"#{udid.shellescape}\")'",
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Fastlane
4
4
  module CreateSimulatorDevices
5
- VERSION = '0.0.17'
5
+ VERSION = '0.0.18'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane-plugin-create_simulator_devices
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.17
4
+ version: 0.0.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vitalii Budnik
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-09-04 00:00:00.000000000 Z
11
+ date: 2025-11-12 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email: developers@setapp.com
@@ -28,6 +28,7 @@ files:
28
28
  - lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/models/required_runtime.rb
29
29
  - lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/models/simctl/device.rb
30
30
  - lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/models/simctl/device_type.rb
31
+ - lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/models/simctl/matched_runtime.rb
31
32
  - lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/models/simctl/runtime.rb
32
33
  - lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/models/simctl/runtime_supported_device_type.rb
33
34
  - lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/models/xcodebuild/sdk.rb