run_loop 2.1.1.pre2 → 2.1.1.pre3
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 +4 -4
- data/lib/run_loop/cli/instruments.rb +1 -1
- data/lib/run_loop/core_simulator.rb +44 -14
- data/lib/run_loop/sim_control.rb +4 -1
- data/lib/run_loop/simctl.rb +169 -7
- data/lib/run_loop/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b32b64f18fc3ecf44595683f3d6627093ecc5c75
|
4
|
+
data.tar.gz: 8f3b475ba5794cda548cbec873399ae16f377992
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: be639927d12b83cc3b3ddad8c891ebe5115ede7a6db10b67ebf89d449efc954047251ba4d11c9497a14c94df722f540195abf6e66354b7125dc38266e8e72f89
|
7
|
+
data.tar.gz: fbe8b2b8af7d8acd600bd0186ea0c83d3906873dbea938adb863bb0d9450b19d03967cf952220202fa2f98286eabbda3e6ce63b5c9ff7b9ac2d17d01ded0c660
|
@@ -104,7 +104,7 @@ module RunLoop
|
|
104
104
|
launch_options = {
|
105
105
|
:args => parse_app_launch_args(options),
|
106
106
|
:udid => detect_device_udid_from_options(options),
|
107
|
-
:
|
107
|
+
:app => detect_bundle_id_or_bundle_path(options)
|
108
108
|
}
|
109
109
|
run_loop = RunLoop.run(launch_options)
|
110
110
|
puts JSON.generate(run_loop)
|
@@ -404,20 +404,14 @@ $ bundle exec run-loop simctl manage-processes
|
|
404
404
|
|
405
405
|
RunLoop.log_debug("Trying #{tries} times to launch #{app.bundle_identifier} on #{device}")
|
406
406
|
|
407
|
-
tries.times do
|
408
|
-
|
407
|
+
tries.times do |try|
|
408
|
+
# Terminates CoreSimulatorService on failures.
|
409
|
+
hash = attempt_to_launch_app_with_simctl
|
410
|
+
|
409
411
|
exit_status = hash[:exit_status]
|
410
412
|
if exit_status != 0
|
411
|
-
|
412
|
-
|
413
|
-
out.split($-0).each do |line|
|
414
|
-
RunLoop.log_debug(" #{line}")
|
415
|
-
end
|
416
|
-
# Simulator is probably in a bad state, but this will be super disruptive.
|
417
|
-
# Let's try a softer approach first - sleep.
|
418
|
-
# self.terminate_core_simulator_processes
|
419
|
-
sleep(0.5)
|
420
|
-
last_error = out
|
413
|
+
# Last argument is how long to sleep after an error.
|
414
|
+
last_error = handle_failed_app_launch(hash, try, tries, 0.5)
|
421
415
|
else
|
422
416
|
last_error = nil
|
423
417
|
break
|
@@ -432,14 +426,17 @@ $ bundle exec run-loop simctl manage-processes
|
|
432
426
|
]
|
433
427
|
end
|
434
428
|
|
429
|
+
wait_for_app_launch
|
430
|
+
end
|
431
|
+
|
432
|
+
# @!visibility private
|
433
|
+
def wait_for_app_launch
|
435
434
|
options = {
|
436
435
|
:timeout => 10,
|
437
436
|
:raise_on_timeout => true
|
438
437
|
}
|
439
|
-
|
440
438
|
RunLoop::ProcessWaiter.new(app.executable_name, options).wait_for_any
|
441
439
|
device.simulator_wait_for_stable_state
|
442
|
-
|
443
440
|
true
|
444
441
|
end
|
445
442
|
|
@@ -623,6 +620,39 @@ Command had no output
|
|
623
620
|
xcrun.exec(args, log_cmd: true, timeout: timeout)
|
624
621
|
end
|
625
622
|
|
623
|
+
# @!visibility private
|
624
|
+
def handle_failed_app_launch(hash, try, tries, wait_time)
|
625
|
+
out = hash[:out]
|
626
|
+
RunLoop.log_debug("Failed to launch app on try #{try + 1} of #{tries}.")
|
627
|
+
out.split($-0).each do |line|
|
628
|
+
RunLoop.log_debug(" #{line}")
|
629
|
+
end
|
630
|
+
# If we timed out on the launch, the CoreSimulator processes are quit
|
631
|
+
# (see above). If at all possible, we want to avoid terminating
|
632
|
+
# CoreSimulatorService, because it takes a long time to launch.
|
633
|
+
sleep(wait_time) if wait_time > 0
|
634
|
+
|
635
|
+
out
|
636
|
+
end
|
637
|
+
|
638
|
+
# @!visibility private
|
639
|
+
def attempt_to_launch_app_with_simctl
|
640
|
+
begin
|
641
|
+
hash = launch_app_with_simctl
|
642
|
+
rescue RunLoop::Xcrun::TimeoutError => e
|
643
|
+
hash = {
|
644
|
+
:exit_status => 1,
|
645
|
+
:out => e.message
|
646
|
+
}
|
647
|
+
# Simulator is probably in a bad state. Terminates the
|
648
|
+
# CoreSimulatorService. Restarting this service is expensive!
|
649
|
+
RunLoop::CoreSimulator.terminate_core_simulator_processes
|
650
|
+
Kernel.sleep(0.5)
|
651
|
+
launch_simulator
|
652
|
+
end
|
653
|
+
hash
|
654
|
+
end
|
655
|
+
|
626
656
|
# Required for support of iOS 7 CoreSimulators. Can be removed when
|
627
657
|
# Xcode support is dropped.
|
628
658
|
def sdk_gte_8?
|
data/lib/run_loop/sim_control.rb
CHANGED
@@ -1146,7 +1146,10 @@ module RunLoop
|
|
1146
1146
|
line[/Apple Watch/, 0],
|
1147
1147
|
line[/watchOS/, 0],
|
1148
1148
|
line[/Apple TV/, 0],
|
1149
|
-
line[/tvOS/, 0]
|
1149
|
+
line[/tvOS/, 0],
|
1150
|
+
line[/Devices/, 0],
|
1151
|
+
line[/CoreSimulatorService/, 0],
|
1152
|
+
line[/simctl\[.+\]/, 0]
|
1150
1153
|
].any?
|
1151
1154
|
|
1152
1155
|
if not_ios
|
data/lib/run_loop/simctl.rb
CHANGED
@@ -30,18 +30,18 @@ module RunLoop
|
|
30
30
|
end
|
31
31
|
|
32
32
|
# @!visibility private
|
33
|
-
|
33
|
+
attr_reader :device
|
34
34
|
|
35
35
|
# @!visibility private
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
@
|
36
|
+
def initialize
|
37
|
+
@ios_devices = []
|
38
|
+
@tvos_devices = []
|
39
|
+
@watchos_devices = []
|
40
40
|
end
|
41
41
|
|
42
42
|
# @!visibility private
|
43
43
|
def to_s
|
44
|
-
"#<Simctl: #{
|
44
|
+
"#<Simctl: #{xcode.version}>"
|
45
45
|
end
|
46
46
|
|
47
47
|
# @!visibility private
|
@@ -49,6 +49,15 @@ module RunLoop
|
|
49
49
|
to_s
|
50
50
|
end
|
51
51
|
|
52
|
+
# @!visibility private
|
53
|
+
def simulators
|
54
|
+
simulators = ios_devices
|
55
|
+
if simulators.empty?
|
56
|
+
simulators = fetch_devices![:ios]
|
57
|
+
end
|
58
|
+
simulators
|
59
|
+
end
|
60
|
+
|
52
61
|
# @!visibility private
|
53
62
|
#
|
54
63
|
# This method is not supported on Xcode < 7 - returns nil.
|
@@ -62,8 +71,9 @@ module RunLoop
|
|
62
71
|
# TODO ensure a booted state.
|
63
72
|
#
|
64
73
|
# @param [String] bundle_id The CFBundleIdentifier of the app.
|
74
|
+
# @param [RunLoop::Device] device The device under test.
|
65
75
|
# @return [String] The path to the .app bundle if it exists; nil otherwise.
|
66
|
-
def app_container(bundle_id)
|
76
|
+
def app_container(device, bundle_id)
|
67
77
|
return nil if !xcode.version_gte_7?
|
68
78
|
cmd = ["simctl", "get_app_container", device.udid, bundle_id]
|
69
79
|
hash = execute(cmd, DEFAULTS)
|
@@ -78,12 +88,157 @@ module RunLoop
|
|
78
88
|
|
79
89
|
private
|
80
90
|
|
91
|
+
# @!visibility private
|
92
|
+
attr_reader :ios_devices, :tvos_devices, :watchos_devices
|
93
|
+
|
81
94
|
# @!visibility private
|
82
95
|
def execute(array, options)
|
83
96
|
merged = DEFAULTS.merge(options)
|
84
97
|
xcrun.exec(array, merged)
|
85
98
|
end
|
86
99
|
|
100
|
+
# @!visibility private
|
101
|
+
#
|
102
|
+
# Starting in Xcode 7, simctl allows a --json option for listing devices.
|
103
|
+
#
|
104
|
+
# On Xcode 6, we will fall back to SimControl which does a line-by-line
|
105
|
+
# processing of `simctl list devices`. tvOS and watchOS devices are not
|
106
|
+
# available on Xcode < 7.
|
107
|
+
#
|
108
|
+
# This is a destructive operation on `@ios_devices`, `@tvos_devices`, and
|
109
|
+
# `@watchos_devices`. Callers should check for existing devices to avoid
|
110
|
+
# the overhead of calling `simctl list devices --json`.
|
111
|
+
def fetch_devices!
|
112
|
+
if !xcode.version_gte_7?
|
113
|
+
return {
|
114
|
+
:ios => sim_control.simulators,
|
115
|
+
:tvos => [],
|
116
|
+
:watchos => []
|
117
|
+
}
|
118
|
+
end
|
119
|
+
|
120
|
+
@ios_devices = []
|
121
|
+
@tvos_devices = []
|
122
|
+
@watchos_devices = []
|
123
|
+
|
124
|
+
cmd = ["simctl", "list", "devices", "--json"]
|
125
|
+
hash = execute(cmd, DEFAULTS)
|
126
|
+
|
127
|
+
out = hash[:out]
|
128
|
+
exit_status = hash[:exit_status]
|
129
|
+
if exit_status != 0
|
130
|
+
raise RuntimeError, %Q[simctl exited #{exit_status}:
|
131
|
+
|
132
|
+
#{out}
|
133
|
+
|
134
|
+
while trying to list devices.
|
135
|
+
]
|
136
|
+
end
|
137
|
+
|
138
|
+
devices = json_to_hash(out)["devices"]
|
139
|
+
|
140
|
+
devices.each do |key, device_list|
|
141
|
+
version = device_key_to_version(key)
|
142
|
+
bucket = bucket_for_key(key)
|
143
|
+
|
144
|
+
device_list.each do |record|
|
145
|
+
if device_available?(record)
|
146
|
+
bucket << device_from_record(record, version)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
{
|
151
|
+
:ios => ios_devices,
|
152
|
+
:tvos => tvos_devices,
|
153
|
+
:watchos => watchos_devices
|
154
|
+
}
|
155
|
+
end
|
156
|
+
|
157
|
+
# @!visibility private
|
158
|
+
#
|
159
|
+
# command_runner_ng combines stderr and stdout and starting in Xcode 7.3,
|
160
|
+
# simctl has started generating stderr output. This must be filtered out
|
161
|
+
# so that we can parse the JSON response.
|
162
|
+
def filter_stderr(out)
|
163
|
+
out.split($-0).map do |line|
|
164
|
+
if stderr_line?(line)
|
165
|
+
nil
|
166
|
+
else
|
167
|
+
line
|
168
|
+
end
|
169
|
+
end.compact.join($-0)
|
170
|
+
end
|
171
|
+
|
172
|
+
# @!visibility private
|
173
|
+
def stderr_line?(line)
|
174
|
+
line[/CoreSimulatorService/, 0] || line[/simctl\[.+\]/, 0]
|
175
|
+
end
|
176
|
+
|
177
|
+
# @!visibility private
|
178
|
+
def json_to_hash(json)
|
179
|
+
filtered = filter_stderr(json)
|
180
|
+
begin
|
181
|
+
JSON.parse(filtered)
|
182
|
+
rescue TypeError, JSON::ParserError => e
|
183
|
+
raise RuntimeError, %Q[Could not parse simctl JSON response:
|
184
|
+
|
185
|
+
#{e}
|
186
|
+
]
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# @!visibility private
|
191
|
+
def device_key_is_ios?(key)
|
192
|
+
key[/iOS/, 0]
|
193
|
+
end
|
194
|
+
|
195
|
+
# @!visibility private
|
196
|
+
def device_key_is_tvos?(key)
|
197
|
+
key[/tvOS/, 0]
|
198
|
+
end
|
199
|
+
|
200
|
+
# @!visibility private
|
201
|
+
def device_key_is_watchos?(key)
|
202
|
+
key[/watchOS/, 0]
|
203
|
+
end
|
204
|
+
|
205
|
+
# @!visibility private
|
206
|
+
def device_key_to_version(key)
|
207
|
+
str = key.split(" ").last
|
208
|
+
RunLoop::Version.new(str)
|
209
|
+
end
|
210
|
+
|
211
|
+
# @!visibility private
|
212
|
+
def device_available?(record)
|
213
|
+
record["availability"] == "(available)"
|
214
|
+
end
|
215
|
+
|
216
|
+
# @!visibility private
|
217
|
+
def device_from_record(record, version)
|
218
|
+
RunLoop::Device.new(record["name"],
|
219
|
+
version,
|
220
|
+
record["udid"],
|
221
|
+
record["state"])
|
222
|
+
end
|
223
|
+
|
224
|
+
# @!visibility private
|
225
|
+
def bucket_for_key(key)
|
226
|
+
if device_key_is_ios?(key)
|
227
|
+
bin = @ios_devices
|
228
|
+
elsif device_key_is_tvos?(key)
|
229
|
+
bin = @tvos_devices
|
230
|
+
elsif device_key_is_watchos?(key)
|
231
|
+
bin = @watchos_devices
|
232
|
+
else
|
233
|
+
raise RuntimeError, "Unexpected key while processing simctl output:
|
234
|
+
|
235
|
+
key = #{key}
|
236
|
+
|
237
|
+
is not an iOS, tvOS, or watchOS device"
|
238
|
+
end
|
239
|
+
bin
|
240
|
+
end
|
241
|
+
|
87
242
|
# @!visibility private
|
88
243
|
def xcrun
|
89
244
|
@xcrun ||= RunLoop::Xcrun.new
|
@@ -93,5 +248,12 @@ module RunLoop
|
|
93
248
|
def xcode
|
94
249
|
@xcode ||= RunLoop::Xcode.new
|
95
250
|
end
|
251
|
+
|
252
|
+
# @!visibility private
|
253
|
+
# Support for Xcode < 7 when trying to collect simulators. Xcode 7 allows
|
254
|
+
# a --json option which is much easier to parse.
|
255
|
+
def sim_control
|
256
|
+
@sim_control ||= RunLoop::SimControl.new
|
257
|
+
end
|
96
258
|
end
|
97
259
|
end
|
data/lib/run_loop/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: run_loop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1.1.
|
4
|
+
version: 2.1.1.pre3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Karl Krukow
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-04-
|
11
|
+
date: 2016-04-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|