run_loop 1.5.5 → 1.5.6.pre1
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/simctl.rb +37 -82
- data/lib/run_loop/core.rb +20 -17
- data/lib/run_loop/core_simulator.rb +648 -0
- data/lib/run_loop/device.rb +8 -8
- data/lib/run_loop/directory.rb +104 -17
- data/lib/run_loop/dot_dir.rb +83 -0
- data/lib/run_loop/environment.rb +27 -8
- data/lib/run_loop/instruments.rb +89 -1
- data/lib/run_loop/logging.rb +11 -0
- data/lib/run_loop/process_terminator.rb +5 -17
- data/lib/run_loop/sim_control.rb +114 -77
- data/lib/run_loop/version.rb +15 -3
- data/lib/run_loop.rb +9 -10
- metadata +6 -7
- data/lib/run_loop/life_cycle/core_simulator.rb +0 -515
- data/lib/run_loop/life_cycle/simulator.rb +0 -73
- data/lib/run_loop/simctl/bridge.rb +0 -499
data/lib/run_loop/version.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module RunLoop
|
2
|
-
VERSION = '1.5.
|
2
|
+
VERSION = '1.5.6.pre1'
|
3
3
|
|
4
4
|
# A model of a software release version that can be used to compare two versions.
|
5
5
|
#
|
@@ -44,7 +44,7 @@ module RunLoop
|
|
44
44
|
# version.minor => 10
|
45
45
|
# version.patch => 1
|
46
46
|
# version.pre => false
|
47
|
-
# version.
|
47
|
+
# version.pre_version => nil
|
48
48
|
#
|
49
49
|
# @example
|
50
50
|
# version = Version.new(1.6.3.pre5)
|
@@ -52,7 +52,7 @@ module RunLoop
|
|
52
52
|
# version.minor => 6
|
53
53
|
# version.patch => 3
|
54
54
|
# version.pre => true
|
55
|
-
# version.
|
55
|
+
# version.pre_version => 5
|
56
56
|
#
|
57
57
|
# @param [String] version the version string to parse.
|
58
58
|
# @raise [ArgumentError] if version is not in the form 5, 6.1, 7.1.2, 8.2.3.pre1
|
@@ -88,6 +88,18 @@ module RunLoop
|
|
88
88
|
"#<Version #{to_s}>"
|
89
89
|
end
|
90
90
|
|
91
|
+
# Compare this version to another for _object_ equality. This allows
|
92
|
+
# Version instances to be used as Hash keys.
|
93
|
+
# @param [Version] other the version to compare against.
|
94
|
+
def eql?(other)
|
95
|
+
hash == other.hash
|
96
|
+
end
|
97
|
+
|
98
|
+
# The hash method for this instance.
|
99
|
+
def hash
|
100
|
+
to_s.hash
|
101
|
+
end
|
102
|
+
|
91
103
|
# Compare this version to another for equality.
|
92
104
|
# @param [Version] other the version to compare against
|
93
105
|
# @return [Boolean] true if this Version is the same as `other`
|
data/lib/run_loop.rb
CHANGED
@@ -2,6 +2,7 @@ require 'run_loop/regex'
|
|
2
2
|
require 'run_loop/directory'
|
3
3
|
require 'run_loop/environment'
|
4
4
|
require 'run_loop/logging'
|
5
|
+
require 'run_loop/dot_dir'
|
5
6
|
require 'run_loop/xcrun'
|
6
7
|
require 'run_loop/xcode'
|
7
8
|
require 'run_loop/l10n'
|
@@ -24,9 +25,7 @@ require 'run_loop/cache/cache'
|
|
24
25
|
require 'run_loop/host_cache'
|
25
26
|
require 'run_loop/patches/awesome_print'
|
26
27
|
require 'run_loop/patches/retriable'
|
27
|
-
require 'run_loop/
|
28
|
-
require 'run_loop/life_cycle/core_simulator'
|
29
|
-
require 'run_loop/simctl/bridge'
|
28
|
+
require 'run_loop/core_simulator'
|
30
29
|
require 'run_loop/simctl/plists'
|
31
30
|
|
32
31
|
module RunLoop
|
@@ -59,13 +58,13 @@ module RunLoop
|
|
59
58
|
def self.run(options={})
|
60
59
|
|
61
60
|
if RunLoop::Instruments.new.instruments_app_running?
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
61
|
+
raise %q(The Instruments.app is open.
|
62
|
+
|
63
|
+
If the Instruments.app is open, the instruments command line tool cannot take
|
64
|
+
control of your application.
|
65
|
+
|
66
|
+
Please quit the Instruments.app and try again.)
|
67
|
+
|
69
68
|
end
|
70
69
|
|
71
70
|
uia_strategy = options[:uia_strategy]
|
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: 1.5.
|
4
|
+
version: 1.5.6.pre1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Karl Krukow
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-10-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -290,8 +290,10 @@ files:
|
|
290
290
|
- lib/run_loop/cli/instruments.rb
|
291
291
|
- lib/run_loop/cli/simctl.rb
|
292
292
|
- lib/run_loop/core.rb
|
293
|
+
- lib/run_loop/core_simulator.rb
|
293
294
|
- lib/run_loop/device.rb
|
294
295
|
- lib/run_loop/directory.rb
|
296
|
+
- lib/run_loop/dot_dir.rb
|
295
297
|
- lib/run_loop/dylib_injector.rb
|
296
298
|
- lib/run_loop/environment.rb
|
297
299
|
- lib/run_loop/fifo.rb
|
@@ -299,8 +301,6 @@ files:
|
|
299
301
|
- lib/run_loop/instruments.rb
|
300
302
|
- lib/run_loop/ipa.rb
|
301
303
|
- lib/run_loop/l10n.rb
|
302
|
-
- lib/run_loop/life_cycle/core_simulator.rb
|
303
|
-
- lib/run_loop/life_cycle/simulator.rb
|
304
304
|
- lib/run_loop/lipo.rb
|
305
305
|
- lib/run_loop/lldb.rb
|
306
306
|
- lib/run_loop/logging.rb
|
@@ -311,7 +311,6 @@ files:
|
|
311
311
|
- lib/run_loop/process_waiter.rb
|
312
312
|
- lib/run_loop/regex.rb
|
313
313
|
- lib/run_loop/sim_control.rb
|
314
|
-
- lib/run_loop/simctl/bridge.rb
|
315
314
|
- lib/run_loop/simctl/plists.rb
|
316
315
|
- lib/run_loop/version.rb
|
317
316
|
- lib/run_loop/xcode.rb
|
@@ -345,9 +344,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
345
344
|
version: '1.9'
|
346
345
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
347
346
|
requirements:
|
348
|
-
- - "
|
347
|
+
- - ">"
|
349
348
|
- !ruby/object:Gem::Version
|
350
|
-
version:
|
349
|
+
version: 1.3.1
|
351
350
|
requirements: []
|
352
351
|
rubyforge_project:
|
353
352
|
rubygems_version: 2.4.8
|
@@ -1,515 +0,0 @@
|
|
1
|
-
module RunLoop
|
2
|
-
module LifeCycle
|
3
|
-
|
4
|
-
class CoreSimulator < Simulator
|
5
|
-
|
6
|
-
require 'securerandom'
|
7
|
-
|
8
|
-
# @!visibility private
|
9
|
-
METADATA_PLIST = '.com.apple.mobile_container_manager.metadata.plist'
|
10
|
-
|
11
|
-
# @!visibility private
|
12
|
-
CORE_SIMULATOR_DEVICE_DIR = File.expand_path('~/Library/Developer/CoreSimulator/Devices')
|
13
|
-
|
14
|
-
# @!visibility private
|
15
|
-
# How long to wait after the simulator has launched.
|
16
|
-
SIM_POST_LAUNCH_WAIT = RunLoop::Environment.sim_post_launch_wait || 1.0
|
17
|
-
|
18
|
-
# @!visibility private
|
19
|
-
# How long to wait for for a device to reach a state.
|
20
|
-
WAIT_FOR_DEVICE_STATE_OPTS =
|
21
|
-
{
|
22
|
-
interval: 0.1,
|
23
|
-
timeout: 5
|
24
|
-
}
|
25
|
-
|
26
|
-
# @!visibility private
|
27
|
-
# How long to wait for the CoreSimulator processes to start.
|
28
|
-
WAIT_FOR_SIMULATOR_PROCESSES_OPTS =
|
29
|
-
{
|
30
|
-
timeout: 5,
|
31
|
-
raise_on_timeout: true
|
32
|
-
}
|
33
|
-
|
34
|
-
attr_reader :app
|
35
|
-
attr_reader :device
|
36
|
-
attr_reader :sim_control
|
37
|
-
attr_reader :pbuddy
|
38
|
-
|
39
|
-
# @param [RunLoop::App] app The application.
|
40
|
-
# @param [RunLoop::Device] device The device.
|
41
|
-
def initialize(app, device, sim_control=RunLoop::SimControl.new)
|
42
|
-
@app = app
|
43
|
-
@device = device
|
44
|
-
@sim_control = sim_control
|
45
|
-
|
46
|
-
# In order to manage the app on the device, we need to manage the
|
47
|
-
# CoreSimulator processes.
|
48
|
-
RunLoop::SimControl.terminate_all_sims
|
49
|
-
terminate_core_simulator_processes
|
50
|
-
end
|
51
|
-
|
52
|
-
# Launch simulator without specifying an app.
|
53
|
-
def launch_simulator
|
54
|
-
sim_path = sim_control.send(:sim_app_path)
|
55
|
-
args = ['open', '-g', '-a', sim_path, '--args', '-CurrentDeviceUDID', device.udid]
|
56
|
-
|
57
|
-
RunLoop.log_debug("Launching #{device} with:")
|
58
|
-
RunLoop.log_unix_cmd("xcrun #{args.join(' ')}")
|
59
|
-
|
60
|
-
start_time = Time.now
|
61
|
-
|
62
|
-
pid = spawn('xcrun', *args)
|
63
|
-
Process.detach(pid)
|
64
|
-
|
65
|
-
sim_name = sim_control.send(:sim_name)
|
66
|
-
|
67
|
-
RunLoop::ProcessWaiter.new(sim_name, WAIT_FOR_SIMULATOR_PROCESSES_OPTS).wait_for_any
|
68
|
-
|
69
|
-
device.simulator_wait_for_stable_state
|
70
|
-
|
71
|
-
elapsed = Time.now - start_time
|
72
|
-
RunLoop.log_debug("Took #{elapsed} seconds to launch the simulator")
|
73
|
-
|
74
|
-
true
|
75
|
-
end
|
76
|
-
|
77
|
-
# @!visibility private
|
78
|
-
def pbuddy
|
79
|
-
@pbuddy ||= RunLoop::PlistBuddy.new
|
80
|
-
end
|
81
|
-
|
82
|
-
# @!visibility private
|
83
|
-
def sdk_gte_8?
|
84
|
-
device.version >= RunLoop::Version.new('8.0')
|
85
|
-
end
|
86
|
-
|
87
|
-
# The data directory for the the device.
|
88
|
-
#
|
89
|
-
# ~/Library/Developer/CoreSimulator/Devices/<UDID>/data
|
90
|
-
def device_data_dir
|
91
|
-
@device_data_dir ||= File.join(CORE_SIMULATOR_DEVICE_DIR, device.udid, 'data')
|
92
|
-
end
|
93
|
-
|
94
|
-
# The applications directory for the device.
|
95
|
-
#
|
96
|
-
# ~/Library/Developer/CoreSimulator/Devices/<UDID>/Containers/Bundle/Application
|
97
|
-
def device_applications_dir
|
98
|
-
@device_app_dir ||= lambda do
|
99
|
-
if sdk_gte_8?
|
100
|
-
File.join(device_data_dir, 'Containers', 'Bundle', 'Application')
|
101
|
-
else
|
102
|
-
File.join(device_data_dir, 'Applications')
|
103
|
-
end
|
104
|
-
end.call
|
105
|
-
end
|
106
|
-
|
107
|
-
# The sandbox directory for the app.
|
108
|
-
#
|
109
|
-
# ~/Library/Developer/CoreSimulator/Devices/<UDID>/Containers/Data/Application
|
110
|
-
#
|
111
|
-
# Contains Library, Documents, and tmp directories.
|
112
|
-
def app_sandbox_dir
|
113
|
-
app_install_dir = installed_app_bundle_dir
|
114
|
-
return nil if app_install_dir.nil?
|
115
|
-
if sdk_gte_8?
|
116
|
-
app_sandbox_dir_sdk_gte_8
|
117
|
-
else
|
118
|
-
app_install_dir
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
# The Library directory in the sandbox.
|
123
|
-
def app_library_dir
|
124
|
-
base_dir = app_sandbox_dir
|
125
|
-
if base_dir.nil?
|
126
|
-
nil
|
127
|
-
else
|
128
|
-
File.join(base_dir, 'Library')
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
# The Library/Preferences directory in the sandbox.
|
133
|
-
def app_library_preferences_dir
|
134
|
-
base_dir = app_library_dir
|
135
|
-
if base_dir.nil?
|
136
|
-
nil
|
137
|
-
else
|
138
|
-
File.join(base_dir, 'Preferences')
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
# The Documents directory in the sandbox.
|
143
|
-
def app_documents_dir
|
144
|
-
base_dir = app_sandbox_dir
|
145
|
-
if base_dir.nil?
|
146
|
-
nil
|
147
|
-
else
|
148
|
-
File.join(base_dir, 'Documents')
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
# The tmp directory in the sandbox.
|
153
|
-
def app_tmp_dir
|
154
|
-
base_dir = app_sandbox_dir
|
155
|
-
if base_dir.nil?
|
156
|
-
nil
|
157
|
-
else
|
158
|
-
File.join(base_dir, 'tmp')
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
# Is this app installed?
|
163
|
-
def app_is_installed?
|
164
|
-
!installed_app_bundle_dir.nil?
|
165
|
-
end
|
166
|
-
|
167
|
-
# The sha1 of the installed app.
|
168
|
-
def installed_app_sha1
|
169
|
-
installed_bundle = installed_app_bundle_dir
|
170
|
-
if installed_bundle
|
171
|
-
RunLoop::Directory.directory_digest(installed_bundle)
|
172
|
-
else
|
173
|
-
nil
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
# Is the app that is install the same as the one we have in hand?
|
178
|
-
def same_sha1_as_installed?
|
179
|
-
app.sha1 == installed_app_sha1
|
180
|
-
end
|
181
|
-
|
182
|
-
# @!visibility private
|
183
|
-
#
|
184
|
-
# Returns the path to the installed app bundle directory (.app).
|
185
|
-
#
|
186
|
-
# If this method returns nil, the app is not installed.
|
187
|
-
def installed_app_bundle_dir
|
188
|
-
sim_app_dir = device_applications_dir
|
189
|
-
return nil if !File.exist?(sim_app_dir)
|
190
|
-
Dir.glob("#{sim_app_dir}/**/*.app").find do |path|
|
191
|
-
RunLoop::App.new(path).bundle_identifier == app.bundle_identifier
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
# Uninstall the app on the device.
|
196
|
-
def uninstall
|
197
|
-
installed_app_bundle = installed_app_bundle_dir
|
198
|
-
if installed_app_bundle
|
199
|
-
uninstall_app_and_sandbox(installed_app_bundle)
|
200
|
-
:uninstalled
|
201
|
-
else
|
202
|
-
RunLoop.log_debug('App was not installed. Nothing to do')
|
203
|
-
:not_installed
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
# Install the app on the device.
|
208
|
-
def install
|
209
|
-
installed_app_bundle = installed_app_bundle_dir
|
210
|
-
|
211
|
-
# App is not installed.
|
212
|
-
return install_new_app if installed_app_bundle.nil?
|
213
|
-
|
214
|
-
# App is installed but sha1 is different.
|
215
|
-
if !same_sha1_as_installed?
|
216
|
-
return reinstall_existing_app_and_clear_sandbox(installed_app_bundle)
|
217
|
-
end
|
218
|
-
|
219
|
-
RunLoop.log_debug('The installed app is the same as the app we are trying to install; skipping installation')
|
220
|
-
installed_app_bundle
|
221
|
-
end
|
222
|
-
|
223
|
-
# @!visibility private
|
224
|
-
#
|
225
|
-
# 1. Does nothing if the app is not installed.
|
226
|
-
# 2. Does nothing if the app the same as the app that is installed
|
227
|
-
# 3. Installs app if it is different from the installed app
|
228
|
-
#
|
229
|
-
# TODO needs unit tests and a better name?
|
230
|
-
def ensure_app_same
|
231
|
-
installed_app_bundle = installed_app_bundle_dir
|
232
|
-
|
233
|
-
if !installed_app_bundle
|
234
|
-
RunLoop.log_debug("App: #{app} is not installed")
|
235
|
-
return true
|
236
|
-
end
|
237
|
-
|
238
|
-
installed_sha = installed_app_sha1
|
239
|
-
app_sha = app.sha1
|
240
|
-
|
241
|
-
if installed_sha == app_sha
|
242
|
-
RunLoop.log_debug("Installed app is the same as #{app}")
|
243
|
-
return true
|
244
|
-
end
|
245
|
-
|
246
|
-
RunLoop.log_debug("The app you are trying to launch is not the same as the app that is installed.")
|
247
|
-
RunLoop.log_debug(" Installed app SHA: #{installed_sha}")
|
248
|
-
RunLoop.log_debug(" App to launch SHA: #{app_sha}")
|
249
|
-
RunLoop.log_debug("Will install #{app}")
|
250
|
-
|
251
|
-
|
252
|
-
FileUtils.rm_rf installed_app_bundle
|
253
|
-
RunLoop.log_debug('Deleted the existing app')
|
254
|
-
|
255
|
-
directory = File.expand_path(File.join(installed_app_bundle, '..'))
|
256
|
-
bundle_name = File.basename(app.path)
|
257
|
-
target = File.join(directory, bundle_name)
|
258
|
-
|
259
|
-
args = ['ditto', app.path, target]
|
260
|
-
RunLoop::Xcrun.new.exec(args, log_cmd: true)
|
261
|
-
|
262
|
-
RunLoop.log_debug("Installed #{app} on CoreSimulator #{device.udid}")
|
263
|
-
|
264
|
-
clear_device_launch_csstore
|
265
|
-
|
266
|
-
true
|
267
|
-
end
|
268
|
-
|
269
|
-
# Reset app sandbox.
|
270
|
-
def reset_app_sandbox
|
271
|
-
return true if !app_is_installed?
|
272
|
-
|
273
|
-
wait_for_device_state('Shutdown')
|
274
|
-
|
275
|
-
reset_app_sandbox_internal
|
276
|
-
end
|
277
|
-
|
278
|
-
private
|
279
|
-
|
280
|
-
def generate_uuid
|
281
|
-
SecureRandom.uuid.upcase!
|
282
|
-
end
|
283
|
-
|
284
|
-
def existing_app_container_uuids
|
285
|
-
if File.exist?(device_applications_dir)
|
286
|
-
Dir.entries(device_applications_dir)
|
287
|
-
else
|
288
|
-
[]
|
289
|
-
end
|
290
|
-
end
|
291
|
-
|
292
|
-
def generate_unique_uuid(existing, timeout=1.0)
|
293
|
-
begin
|
294
|
-
Timeout::timeout(timeout, Timeout::Error) do
|
295
|
-
uuid = generate_uuid
|
296
|
-
loop do
|
297
|
-
break if !existing.include?(uuid)
|
298
|
-
uuid = generate_uuid
|
299
|
-
end
|
300
|
-
uuid
|
301
|
-
end
|
302
|
-
rescue Timeout::Error => _
|
303
|
-
raise RuntimeError,
|
304
|
-
"Expected to be able to generate a unique uuid in #{timeout} seconds"
|
305
|
-
end
|
306
|
-
end
|
307
|
-
|
308
|
-
def install_new_app
|
309
|
-
wait_for_device_state('Shutdown')
|
310
|
-
|
311
|
-
existing = existing_app_container_uuids
|
312
|
-
udid = generate_unique_uuid(existing)
|
313
|
-
directory = File.join(device_applications_dir, udid)
|
314
|
-
|
315
|
-
bundle_name = File.basename(app.path)
|
316
|
-
target = File.join(directory, bundle_name)
|
317
|
-
|
318
|
-
args = ['ditto', app.path, target]
|
319
|
-
RunLoop::Xcrun.new.exec(args, log_cmd: true)
|
320
|
-
target
|
321
|
-
end
|
322
|
-
|
323
|
-
def reinstall_existing_app_and_clear_sandbox(installed_app_bundle)
|
324
|
-
wait_for_device_state('Shutdown')
|
325
|
-
|
326
|
-
reset_app_sandbox_internal
|
327
|
-
|
328
|
-
if File.exist?(installed_app_bundle)
|
329
|
-
FileUtils.rm_rf(installed_app_bundle)
|
330
|
-
RunLoop.log_debug("Deleted app bundle: #{installed_app_bundle}")
|
331
|
-
end
|
332
|
-
|
333
|
-
directory = File.dirname(installed_app_bundle)
|
334
|
-
bundle_name = File.basename(app.path)
|
335
|
-
target = File.join(directory, bundle_name)
|
336
|
-
|
337
|
-
args = ['ditto', app.path, target]
|
338
|
-
RunLoop::Xcrun.new.exec(args, log_cmd: true)
|
339
|
-
installed_app_bundle
|
340
|
-
end
|
341
|
-
|
342
|
-
def uninstall_app_and_sandbox(installed_app_bundle)
|
343
|
-
wait_for_device_state('Shutdown')
|
344
|
-
|
345
|
-
if sdk_gte_8?
|
346
|
-
# Must delete the sandbox first.
|
347
|
-
directory = app_sandbox_dir
|
348
|
-
if File.exist?(directory)
|
349
|
-
FileUtils.rm_rf(directory)
|
350
|
-
RunLoop.log_debug("Deleted app sandbox: #{directory}")
|
351
|
-
end
|
352
|
-
|
353
|
-
directory = File.dirname(installed_app_bundle)
|
354
|
-
if File.exist?(directory)
|
355
|
-
FileUtils.rm_rf(directory)
|
356
|
-
RunLoop.log_debug("Deleted app container: #{directory}")
|
357
|
-
end
|
358
|
-
else
|
359
|
-
# Sandbox _is_ in the container.
|
360
|
-
directory = File.dirname(installed_app_bundle)
|
361
|
-
if File.exist?(directory)
|
362
|
-
FileUtils.rm_rf(directory)
|
363
|
-
RunLoop.log_debug("Deleted app container: #{directory}")
|
364
|
-
end
|
365
|
-
end
|
366
|
-
end
|
367
|
-
|
368
|
-
# @!visibility private
|
369
|
-
def app_sandbox_dir_sdk_gte_8
|
370
|
-
containers_data_dir = File.join(device_data_dir, 'Containers', 'Data', 'Application')
|
371
|
-
apps = Dir.glob("#{containers_data_dir}/**/#{METADATA_PLIST}")
|
372
|
-
match = apps.find do |metadata_plist|
|
373
|
-
pbuddy.plist_read('MCMMetadataIdentifier', metadata_plist) == app.bundle_identifier
|
374
|
-
end
|
375
|
-
if match
|
376
|
-
File.dirname(match)
|
377
|
-
else
|
378
|
-
nil
|
379
|
-
end
|
380
|
-
end
|
381
|
-
|
382
|
-
# @!visibility private
|
383
|
-
def wait_for_device_state(target_state)
|
384
|
-
now = Time.now
|
385
|
-
timeout = WAIT_FOR_DEVICE_STATE_OPTS[:timeout]
|
386
|
-
poll_until = now + timeout
|
387
|
-
delay = WAIT_FOR_DEVICE_STATE_OPTS[:interval]
|
388
|
-
in_state = false
|
389
|
-
while Time.now < poll_until
|
390
|
-
in_state = device.update_simulator_state == target_state
|
391
|
-
break if in_state
|
392
|
-
sleep delay
|
393
|
-
end
|
394
|
-
|
395
|
-
elapsed = Time.now - now
|
396
|
-
RunLoop.log_debug("Waited for #{elapsed} seconds for device to have state: '#{target_state}'.")
|
397
|
-
|
398
|
-
unless in_state
|
399
|
-
raise "Expected '#{target_state} but found '#{device.state}' after waiting."
|
400
|
-
end
|
401
|
-
in_state
|
402
|
-
end
|
403
|
-
|
404
|
-
# @!visibility private
|
405
|
-
def device_caches_dir
|
406
|
-
@device_caches_dir ||= File.join(device_data_dir, 'Library', 'Caches')
|
407
|
-
end
|
408
|
-
|
409
|
-
# @!visibility private
|
410
|
-
def clear_device_launch_csstore
|
411
|
-
glob = File.join(device_caches_dir, "com.apple.LaunchServices-*.csstore")
|
412
|
-
Dir.glob(glob) do | ccstore |
|
413
|
-
FileUtils.rm_f ccstore
|
414
|
-
end
|
415
|
-
end
|
416
|
-
|
417
|
-
# @!visibility private
|
418
|
-
def reset_app_sandbox_internal_shared
|
419
|
-
[app_documents_dir, app_tmp_dir].each do |dir|
|
420
|
-
FileUtils.rm_rf dir
|
421
|
-
FileUtils.mkdir dir
|
422
|
-
end
|
423
|
-
end
|
424
|
-
|
425
|
-
# @!visibility private
|
426
|
-
def reset_app_sandbox_internal_sdk_gte_8
|
427
|
-
lib_dir = app_library_dir
|
428
|
-
RunLoop::Directory.recursive_glob_for_entries(lib_dir).each do |entry|
|
429
|
-
if entry.include?('Preferences')
|
430
|
-
# nop
|
431
|
-
else
|
432
|
-
if File.exist?(entry)
|
433
|
-
FileUtils.rm_rf(entry)
|
434
|
-
end
|
435
|
-
end
|
436
|
-
end
|
437
|
-
|
438
|
-
prefs_dir = app_library_preferences_dir
|
439
|
-
protected = ['com.apple.UIAutomation.plist',
|
440
|
-
'com.apple.UIAutomationPlugIn.plist']
|
441
|
-
RunLoop::Directory.recursive_glob_for_entries(prefs_dir).each do |entry|
|
442
|
-
unless protected.include?(File.basename(entry))
|
443
|
-
if File.exist?(entry)
|
444
|
-
FileUtils.rm_rf entry
|
445
|
-
end
|
446
|
-
end
|
447
|
-
end
|
448
|
-
end
|
449
|
-
|
450
|
-
# @!visibility private
|
451
|
-
def reset_app_sandbox_internal_sdk_lt_8
|
452
|
-
prefs_dir = app_library_preferences_dir
|
453
|
-
RunLoop::Directory.recursive_glob_for_entries(prefs_dir).each do |entry|
|
454
|
-
if entry.end_with?('.GlobalPreferences.plist') ||
|
455
|
-
entry.end_with?('com.apple.PeoplePicker.plist')
|
456
|
-
# nop
|
457
|
-
else
|
458
|
-
if File.exist?(entry)
|
459
|
-
FileUtils.rm_rf entry
|
460
|
-
end
|
461
|
-
end
|
462
|
-
end
|
463
|
-
|
464
|
-
# app preferences lives in device Library/Preferences
|
465
|
-
device_prefs_dir = File.join(app_sandbox_dir, 'Library', 'Preferences')
|
466
|
-
app_prefs_plist = File.join(device_prefs_dir, "#{app.bundle_identifier}.plist")
|
467
|
-
if File.exist?(app_prefs_plist)
|
468
|
-
FileUtils.rm_rf(app_prefs_plist)
|
469
|
-
end
|
470
|
-
end
|
471
|
-
|
472
|
-
# @!visibility private
|
473
|
-
def reset_app_sandbox_internal
|
474
|
-
reset_app_sandbox_internal_shared
|
475
|
-
|
476
|
-
if sdk_gte_8?
|
477
|
-
reset_app_sandbox_internal_sdk_gte_8
|
478
|
-
else
|
479
|
-
reset_app_sandbox_internal_sdk_lt_8
|
480
|
-
end
|
481
|
-
end
|
482
|
-
|
483
|
-
# @!visibility private
|
484
|
-
# For testing.
|
485
|
-
def launch
|
486
|
-
|
487
|
-
launch_simulator
|
488
|
-
|
489
|
-
args = ['simctl', 'install', device.udid, app.path]
|
490
|
-
RunLoop::Xcrun.new.exec(args, log_cmd: true, timeout: 10)
|
491
|
-
|
492
|
-
device.simulator_wait_for_stable_state
|
493
|
-
|
494
|
-
args = ['simctl', 'launch', device.udid, app.bundle_identifier]
|
495
|
-
hash = RunLoop::Xcrun.new.exec(args, log_cmd: true, timeout: 20)
|
496
|
-
|
497
|
-
exit_status = hash[:exit_status]
|
498
|
-
|
499
|
-
if exit_status != 0
|
500
|
-
err = hash[:err]
|
501
|
-
RunLoop.log_error(err)
|
502
|
-
raise RuntimeError, "Could not launch #{app.bundle_identifier} on #{device}"
|
503
|
-
end
|
504
|
-
|
505
|
-
RunLoop::ProcessWaiter.new(app.executable_name, {:timeout => 10,
|
506
|
-
:raise_on_timeout => true}).wait_for_any
|
507
|
-
|
508
|
-
|
509
|
-
device.simulator_wait_for_stable_state
|
510
|
-
|
511
|
-
true
|
512
|
-
end
|
513
|
-
end
|
514
|
-
end
|
515
|
-
end
|