run_loop 1.2.6 → 1.2.7
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.rb +7 -0
- data/lib/run_loop/app.rb +67 -0
- data/lib/run_loop/core.rb +17 -128
- data/lib/run_loop/device.rb +15 -3
- data/lib/run_loop/dylib_injector.rb +125 -0
- data/lib/run_loop/environment.rb +15 -0
- data/lib/run_loop/host_cache.rb +2 -1
- data/lib/run_loop/instruments.rb +59 -65
- data/lib/run_loop/lldb.rb +55 -0
- data/lib/run_loop/plist_buddy.rb +18 -2
- data/lib/run_loop/process_terminator.rb +140 -0
- data/lib/run_loop/process_waiter.rb +85 -0
- data/lib/run_loop/sim_control.rb +4 -4
- data/lib/run_loop/simctl/bridge.rb +242 -0
- data/lib/run_loop/version.rb +1 -1
- data/lib/run_loop/xctools.rb +16 -0
- data/scripts/calabash_script_uia.js +3667 -3590
- metadata +48 -24
- data/bin/run-loop +0 -9
- data/lib/run_loop/cli.rb +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2654e1672654ee6ae0af23cb582fec43864992df
|
4
|
+
data.tar.gz: d481bf34a098f76d83d94826575b021ace8232ca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: db03ba41012e7bf8f5d4cefa4833a36c478d16f9359339e415eae29dfa4faf62e6fb3491ad301d872941bcb30a1ebb71c1aabd55f95ceb01210119f2f57f00ff
|
7
|
+
data.tar.gz: 30e5ec4733c0ef6da15aa590c9390c46e3a9a6fa5ddb08f4e609602ace3a05579ea76d538a132f4667708ea1d4cf83307aeb243573b90635cbd6609c8b0e21d3
|
data/lib/run_loop.rb
CHANGED
@@ -1,10 +1,17 @@
|
|
1
|
+
require 'run_loop/environment'
|
2
|
+
require 'run_loop/process_terminator'
|
3
|
+
require 'run_loop/process_waiter'
|
4
|
+
require 'run_loop/lldb'
|
5
|
+
require 'run_loop/dylib_injector'
|
1
6
|
require 'run_loop/core'
|
2
7
|
require 'run_loop/version'
|
3
8
|
require 'run_loop/xctools'
|
4
9
|
require 'run_loop/plist_buddy'
|
10
|
+
require 'run_loop/app'
|
5
11
|
require 'run_loop/sim_control'
|
6
12
|
require 'run_loop/device'
|
7
13
|
require 'run_loop/instruments'
|
8
14
|
require 'run_loop/lipo'
|
9
15
|
require 'run_loop/host_cache'
|
10
16
|
require 'run_loop/monkey_patch'
|
17
|
+
require 'run_loop/simctl/bridge'
|
data/lib/run_loop/app.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
module RunLoop
|
2
|
+
# A class for interacting with .app bundles.
|
3
|
+
class App
|
4
|
+
|
5
|
+
# @!attribute [r] path
|
6
|
+
# @return [String] The path to the app bundle .app
|
7
|
+
attr_reader :path
|
8
|
+
|
9
|
+
# Creates a new App instance.
|
10
|
+
#
|
11
|
+
# @note The `app_bundle_path` is expanded during initialization.
|
12
|
+
#
|
13
|
+
# @param [String] app_bundle_path A path to a .app
|
14
|
+
# @return [RunLoop::App] A instance of App with a path.
|
15
|
+
def initialize(app_bundle_path)
|
16
|
+
@path = File.expand_path(app_bundle_path)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Is this a valid app?
|
20
|
+
def valid?
|
21
|
+
[File.exist?(path),
|
22
|
+
File.directory?(path),
|
23
|
+
File.extname(path) == '.app'].all?
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns the Info.plist path.
|
27
|
+
# @raise [RuntimeError] If there is no Info.plist.
|
28
|
+
def info_plist_path
|
29
|
+
info_plist = File.join(path, 'Info.plist')
|
30
|
+
unless File.exist?(info_plist)
|
31
|
+
raise "Expected an Info.plist at '#{path}'"
|
32
|
+
end
|
33
|
+
info_plist
|
34
|
+
end
|
35
|
+
|
36
|
+
# Inspects the app's Info.plist for the bundle identifier.
|
37
|
+
# @return [String] The value of CFBundleIdentifier.
|
38
|
+
# @raise [RuntimeError] If the plist cannot be read or the
|
39
|
+
# CFBundleIdentifier is empty or does not exist.
|
40
|
+
def bundle_identifier
|
41
|
+
identifier = plist_buddy.plist_read('CFBundleIdentifier', info_plist_path)
|
42
|
+
unless identifier
|
43
|
+
raise "Expected key 'CFBundleIdentifier' in '#{info_plist_path}'"
|
44
|
+
end
|
45
|
+
identifier
|
46
|
+
end
|
47
|
+
|
48
|
+
# Inspects the app's Info.plist for the executable name.
|
49
|
+
# @return [String] The value of CFBundleIdentifier.
|
50
|
+
# @raise [RuntimeError] If the plist cannot be read or the
|
51
|
+
# CFBundleExecutable is empty or does not exist.
|
52
|
+
def executable_name
|
53
|
+
identifier = plist_buddy.plist_read('CFBundleExecutable', info_plist_path)
|
54
|
+
unless identifier
|
55
|
+
raise "Expected key 'CFBundleExecutable' in '#{info_plist_path}'"
|
56
|
+
end
|
57
|
+
identifier
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def plist_buddy
|
63
|
+
@plist_buddy ||= RunLoop::PlistBuddy.new
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
data/lib/run_loop/core.rb
CHANGED
@@ -135,7 +135,8 @@ module RunLoop
|
|
135
135
|
sim_control ||= options[:sim_control] || RunLoop::SimControl.new
|
136
136
|
xctools ||= options[:xctools] || sim_control.xctools
|
137
137
|
|
138
|
-
RunLoop::Instruments.new
|
138
|
+
instruments = RunLoop::Instruments.new
|
139
|
+
instruments.kill_instruments
|
139
140
|
|
140
141
|
device_target = options[:udid] || options[:device_target] || detect_connected_device || 'simulator'
|
141
142
|
if device_target && device_target.to_s.downcase == 'device'
|
@@ -157,7 +158,6 @@ module RunLoop
|
|
157
158
|
|
158
159
|
script = File.join(results_dir, '_run_loop.js')
|
159
160
|
|
160
|
-
|
161
161
|
code = File.read(options[:script])
|
162
162
|
code = code.gsub(/\$PATH/, results_dir)
|
163
163
|
code = code.gsub(/\$READ_SCRIPT_PATH/, READ_SCRIPT_PATH)
|
@@ -186,10 +186,6 @@ module RunLoop
|
|
186
186
|
|
187
187
|
args = options.fetch(:args, [])
|
188
188
|
|
189
|
-
inject_dylib = self.dylib_path_from_options options
|
190
|
-
# WIP This is brute-force call against all lldb processes.
|
191
|
-
self.ensure_lldb_not_running if inject_dylib
|
192
|
-
|
193
189
|
log_file ||= File.join(results_dir, 'run_loop.out')
|
194
190
|
|
195
191
|
after = Time.now
|
@@ -217,22 +213,11 @@ module RunLoop
|
|
217
213
|
|
218
214
|
self.log_run_loop_options(merged_options, xctools)
|
219
215
|
|
220
|
-
|
216
|
+
automation_template = automation_template(xctools)
|
221
217
|
|
222
218
|
log_header("Starting on #{device_target} App: #{bundle_dir_or_bundle_id}")
|
223
|
-
cmd_str = cmd.join(' ')
|
224
219
|
|
225
|
-
|
226
|
-
|
227
|
-
if !jruby? && RUBY_VERSION && RUBY_VERSION.start_with?('1.8')
|
228
|
-
pid = fork do
|
229
|
-
exec(cmd_str)
|
230
|
-
end
|
231
|
-
else
|
232
|
-
pid = spawn(cmd_str)
|
233
|
-
end
|
234
|
-
|
235
|
-
Process.detach(pid)
|
220
|
+
pid = instruments.spawn(automation_template, merged_options, log_file)
|
236
221
|
|
237
222
|
File.open(File.join(results_dir, 'run_loop.pid'), 'w') do |f|
|
238
223
|
f.write pid
|
@@ -249,7 +234,6 @@ module RunLoop
|
|
249
234
|
|
250
235
|
uia_timeout = options[:uia_timeout] || (ENV['UIA_TIMEOUT'] && ENV['UIA_TIMEOUT'].to_f) || 10
|
251
236
|
|
252
|
-
raw_lldb_output = nil
|
253
237
|
before = Time.now
|
254
238
|
begin
|
255
239
|
|
@@ -262,63 +246,25 @@ module RunLoop
|
|
262
246
|
read_response(run_loop, 0, uia_timeout)
|
263
247
|
end
|
264
248
|
end
|
265
|
-
|
266
|
-
# inject_dylib will be nil or a path to a dylib
|
267
|
-
if inject_dylib
|
268
|
-
lldb_template_file = File.join(scripts_path, 'calabash.lldb.erb')
|
269
|
-
lldb_template = ::ERB.new(File.read(lldb_template_file))
|
270
|
-
lldb_template.filename = lldb_template_file
|
271
|
-
|
272
|
-
# Special!
|
273
|
-
# These are required by the ERB in calabash.lldb.erb
|
274
|
-
# noinspection RubyUnusedLocalVariable
|
275
|
-
cf_bundle_executable = find_cf_bundle_executable(bundle_dir_or_bundle_id)
|
276
|
-
# noinspection RubyUnusedLocalVariable
|
277
|
-
dylib_path_for_target = inject_dylib
|
278
|
-
|
279
|
-
lldb_cmd = lldb_template.result(binding)
|
280
|
-
|
281
|
-
tmpdir = Dir.mktmpdir('lldb_cmd')
|
282
|
-
lldb_script = File.join(tmpdir, 'lldb')
|
283
|
-
|
284
|
-
File.open(lldb_script, 'w') { |f| f.puts(lldb_cmd) }
|
285
|
-
|
286
|
-
if ENV['DEBUG'] == '1'
|
287
|
-
puts "lldb script #{lldb_script}"
|
288
|
-
puts "=== lldb script ==="
|
289
|
-
counter = 0
|
290
|
-
File.open(lldb_script, 'r').readlines.each { |line|
|
291
|
-
puts "#{counter} #{line}"
|
292
|
-
counter = counter + 1
|
293
|
-
}
|
294
|
-
puts "=== lldb script ==="
|
295
|
-
end
|
296
|
-
|
297
|
-
# Forcing a timeout. Do not retry here. If lldb is hanging,
|
298
|
-
# RunLoop::Core.run* needs to be called again. Put another way,
|
299
|
-
# instruments and lldb must be terminated.
|
300
|
-
Retriable.retriable({:tries => 1, :timeout => 12, :interval => 1}) do
|
301
|
-
raw_lldb_output = `xcrun lldb -s #{lldb_script}`
|
302
|
-
if ENV['DEBUG'] == '1'
|
303
|
-
puts raw_lldb_output
|
304
|
-
end
|
305
|
-
end
|
306
|
-
end
|
307
249
|
rescue TimeoutError => e
|
308
250
|
if ENV['DEBUG'] == '1'
|
309
251
|
puts "Failed to launch."
|
310
252
|
puts "#{e}: #{e && e.message}"
|
311
|
-
if raw_lldb_output
|
312
|
-
puts "LLDB OUTPUT: #{raw_lldb_output}"
|
313
|
-
end
|
314
253
|
end
|
315
254
|
raise TimeoutError, "Time out waiting for UIAutomation run-loop to Start. \n Logfile #{log_file} \n\n #{File.read(log_file)}\n"
|
316
255
|
end
|
317
256
|
|
318
|
-
after = Time.now()
|
319
|
-
|
320
257
|
if ENV['DEBUG']=='1'
|
321
|
-
puts "Launching took #{
|
258
|
+
puts "Launching took #{Time.now-before} seconds"
|
259
|
+
end
|
260
|
+
|
261
|
+
dylib_path = self.dylib_path_from_options(merged_options)
|
262
|
+
|
263
|
+
if dylib_path
|
264
|
+
RunLoop::LLDB.kill_lldb_processes
|
265
|
+
app = RunLoop::App.new(options[:app])
|
266
|
+
lldb = RunLoop::DylibInjector.new(app.executable_name, dylib_path)
|
267
|
+
lldb.retriable_inject_dylib
|
322
268
|
end
|
323
269
|
|
324
270
|
run_loop
|
@@ -392,15 +338,6 @@ module RunLoop
|
|
392
338
|
dylib_path
|
393
339
|
end
|
394
340
|
|
395
|
-
def self.find_cf_bundle_executable(bundle_dir_or_bundle_id)
|
396
|
-
unless File.directory?(bundle_dir_or_bundle_id)
|
397
|
-
raise "Injecting dylibs currently only works with simulator and app bundles"
|
398
|
-
end
|
399
|
-
info_plist = Dir[File.join(bundle_dir_or_bundle_id, 'Info.plist')].first
|
400
|
-
raise "Unable to find Info.plist in #{bundle_dir_or_bundle_id}" if info_plist.nil?
|
401
|
-
`/usr/libexec/PlistBuddy -c "Print :CFBundleExecutable" "#{info_plist}"`.strip
|
402
|
-
end
|
403
|
-
|
404
341
|
# Returns the a default simulator to target. This default needs to be one
|
405
342
|
# that installed by default in the current Xcode version.
|
406
343
|
#
|
@@ -409,7 +346,9 @@ module RunLoop
|
|
409
346
|
# @param [RunLoop::XCTools] xcode_tools Used to detect the current xcode
|
410
347
|
# version.
|
411
348
|
def self.default_simulator(xcode_tools=RunLoop::XCTools.new)
|
412
|
-
if xcode_tools.
|
349
|
+
if xcode_tools.xcode_version_gte_63?
|
350
|
+
'iPhone 5s (8.3 Simulator)'
|
351
|
+
elsif xcode_tools.xcode_version_gte_62?
|
413
352
|
'iPhone 5s (8.2 Simulator)'
|
414
353
|
elsif xcode_tools.xcode_version_gte_61?
|
415
354
|
'iPhone 5s (8.1 Simulator)'
|
@@ -615,40 +554,6 @@ module RunLoop
|
|
615
554
|
RunLoop::Instruments.new.instruments_pids(&block)
|
616
555
|
end
|
617
556
|
|
618
|
-
def self.instruments_command_prefix(udid, results_dir_trace)
|
619
|
-
instruments_path = 'xcrun instruments'
|
620
|
-
if udid
|
621
|
-
instruments_path = "#{instruments_path} -w \"#{udid}\""
|
622
|
-
end
|
623
|
-
instruments_path << " -D \"#{results_dir_trace}\"" if results_dir_trace
|
624
|
-
instruments_path
|
625
|
-
end
|
626
|
-
|
627
|
-
|
628
|
-
def self.instruments_command(options, xctools=RunLoop::XCTools.new)
|
629
|
-
udid = options[:udid]
|
630
|
-
results_dir_trace = options[:results_dir_trace]
|
631
|
-
bundle_dir_or_bundle_id = options[:bundle_dir_or_bundle_id]
|
632
|
-
results_dir = options[:results_dir]
|
633
|
-
script = options[:script]
|
634
|
-
log_file = options[:log_file]
|
635
|
-
args= options[:args] || []
|
636
|
-
|
637
|
-
instruments_prefix = instruments_command_prefix(udid, results_dir_trace)
|
638
|
-
cmd = [
|
639
|
-
instruments_prefix,
|
640
|
-
'-t', "\"#{automation_template(xctools)}\"",
|
641
|
-
"\"#{bundle_dir_or_bundle_id}\"",
|
642
|
-
'-e', 'UIARESULTSPATH', results_dir,
|
643
|
-
'-e', 'UIASCRIPT', script,
|
644
|
-
args.join(' ')
|
645
|
-
]
|
646
|
-
if log_file
|
647
|
-
cmd << "&> #{log_file}"
|
648
|
-
end
|
649
|
-
cmd
|
650
|
-
end
|
651
|
-
|
652
557
|
def self.automation_template(xctools, candidate = ENV['TRACE_TEMPLATE'])
|
653
558
|
unless candidate && File.exist?(candidate)
|
654
559
|
candidate = default_tracetemplate xctools
|
@@ -710,22 +615,6 @@ module RunLoop
|
|
710
615
|
def self.instruments_pids
|
711
616
|
RunLoop::Instruments.new.instruments_pids
|
712
617
|
end
|
713
|
-
|
714
|
-
# @todo This is a WIP
|
715
|
-
# @todo Needs rspec test
|
716
|
-
def self.ensure_lldb_not_running
|
717
|
-
descripts = `xcrun ps x -o pid,command | grep "lldb" | grep -v grep`.strip.split("\n")
|
718
|
-
descripts.each do |process_desc|
|
719
|
-
pid = process_desc.split(' ').first
|
720
|
-
Open3.popen3("xcrun kill -9 #{pid} && xcrun wait #{pid}") do |_, stdout, stderr, _|
|
721
|
-
out = stdout.read.strip
|
722
|
-
err = stderr.read.strip
|
723
|
-
next if out.to_s.empty? and err.to_s.empty?
|
724
|
-
# there lots of 'ownership' problems trying to kill the lldb process
|
725
|
-
#puts "kill process '#{pid}' => stdout: '#{out}' | stderr: '#{err}'"
|
726
|
-
end
|
727
|
-
end
|
728
|
-
end
|
729
618
|
end
|
730
619
|
|
731
620
|
def self.default_script_for_uia_strategy(uia_strategy)
|
data/lib/run_loop/device.rb
CHANGED
@@ -4,17 +4,29 @@ module RunLoop
|
|
4
4
|
attr_reader :name
|
5
5
|
attr_reader :version
|
6
6
|
attr_reader :udid
|
7
|
+
attr_reader :state
|
7
8
|
|
8
|
-
|
9
|
+
# Create a new device.
|
10
|
+
#
|
11
|
+
# @param [String] name The name of the device. For sims this should be
|
12
|
+
# 'iPhone 5s' and for physical devices it will be the name the user gave
|
13
|
+
# to the device.
|
14
|
+
# @param [String, RunLoop::Version] version The iOS version that is running
|
15
|
+
# on the device. Can be a string or a Version instance.
|
16
|
+
# @param [String] udid The device identifier.
|
17
|
+
# @param [String] state (nil) This a simulator only value. It refers to
|
18
|
+
# the Booted/Shutdown/Creating state of the simulator. For pre-Xcode 6
|
19
|
+
# simulators, this value should be nil.
|
20
|
+
def initialize(name, version, udid, state=nil)
|
9
21
|
@name = name
|
22
|
+
@udid = udid
|
23
|
+
@state = state
|
10
24
|
|
11
25
|
if version.is_a? String
|
12
26
|
@version = RunLoop::Version.new version
|
13
27
|
else
|
14
28
|
@version = version
|
15
29
|
end
|
16
|
-
|
17
|
-
@udid = udid
|
18
30
|
end
|
19
31
|
|
20
32
|
# Returns and instruments-ready device identifier that is a suitable value
|
@@ -0,0 +1,125 @@
|
|
1
|
+
module RunLoop
|
2
|
+
|
3
|
+
# @!visibility private
|
4
|
+
#
|
5
|
+
# This is experimental.
|
6
|
+
#
|
7
|
+
# Injects dylibs into running executables using lldb.
|
8
|
+
class DylibInjector
|
9
|
+
|
10
|
+
# @!attribute [r] process_name
|
11
|
+
# The name of the process to inject the dylib into. This should be obtained
|
12
|
+
# by inspecting the Info.plist in the app bundle.
|
13
|
+
# @return [String] The process_name
|
14
|
+
attr_reader :process_name
|
15
|
+
|
16
|
+
# @!attribute [r] dylib_path
|
17
|
+
# The path to the dylib that is to be injected.
|
18
|
+
# @return [String] The dylib_path
|
19
|
+
attr_reader :dylib_path
|
20
|
+
|
21
|
+
# Create a new dylib injector.
|
22
|
+
# @param [String] process_name The name of the process to inject the dylib
|
23
|
+
# into. This should be obtained by inspecting the Info.plist in the app
|
24
|
+
# bundle.
|
25
|
+
# @param [String] dylib_path The path the dylib to inject.
|
26
|
+
def initialize(process_name, dylib_path)
|
27
|
+
@process_name = process_name
|
28
|
+
@dylib_path = dylib_path
|
29
|
+
end
|
30
|
+
|
31
|
+
# Injects a dylib into a a currently running process.
|
32
|
+
def inject_dylib
|
33
|
+
debug_logging = RunLoop::Environment.debug?
|
34
|
+
puts "Starting lldb." if debug_logging
|
35
|
+
|
36
|
+
stderr_output = nil
|
37
|
+
lldb_status = nil
|
38
|
+
lldb_start_time = Time.now
|
39
|
+
Open3.popen3('sh') do |stdin, stdout, stderr, process_status|
|
40
|
+
stdin.puts 'xcrun lldb --no-lldbinit<<EOF'
|
41
|
+
stdin.puts "process attach -n '#{@process_name}'"
|
42
|
+
stdin.puts "expr (void*)dlopen(\"#{@dylib_path}\", 0x2)"
|
43
|
+
stdin.puts 'detach'
|
44
|
+
stdin.puts 'exit'
|
45
|
+
stdin.puts 'EOF'
|
46
|
+
stdin.close
|
47
|
+
|
48
|
+
puts "#{stdout.read}" if debug_logging
|
49
|
+
|
50
|
+
lldb_status = process_status
|
51
|
+
stderr_output = stderr.read.strip
|
52
|
+
end
|
53
|
+
|
54
|
+
pid = lldb_status.pid
|
55
|
+
exit_status = lldb_status.value.exitstatus
|
56
|
+
|
57
|
+
if stderr_output == ''
|
58
|
+
if debug_logging
|
59
|
+
puts "lldb '#{pid}' exited with value '#{exit_status}'."
|
60
|
+
puts "Took #{Time.now-lldb_start_time} for lldb to inject calabash dylib."
|
61
|
+
end
|
62
|
+
else
|
63
|
+
puts "#{stderr_output}"
|
64
|
+
if debug_logging
|
65
|
+
puts "lldb '#{pid}' exited with value '#{exit_status}'."
|
66
|
+
puts "lldb tried for #{Time.now-lldb_start_time} to inject calabash dylib before giving up."
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
stderr_output == ''
|
71
|
+
end
|
72
|
+
|
73
|
+
def inject_dylib_with_timeout(timeout)
|
74
|
+
success = false
|
75
|
+
Timeout.timeout(timeout) do
|
76
|
+
success = inject_dylib
|
77
|
+
end
|
78
|
+
success
|
79
|
+
end
|
80
|
+
|
81
|
+
def retriable_inject_dylib(options={})
|
82
|
+
merged_options = RETRIABLE_OPTIONS.merge(options)
|
83
|
+
|
84
|
+
debug_logging = RunLoop::Environment.debug?
|
85
|
+
|
86
|
+
on_retry = Proc.new do |_, try, elapsed_time, next_interval|
|
87
|
+
if debug_logging
|
88
|
+
# Retriable 2.0
|
89
|
+
if elapsed_time && next_interval
|
90
|
+
puts "LLDB: attempt #{try} failed in '#{elapsed_time}'; will retry in '#{next_interval}'"
|
91
|
+
else
|
92
|
+
puts "LLDB: attempt #{try} failed; will retry in '#{merged_options[:interval]}'"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
RunLoop::LLDB.kill_lldb_processes
|
96
|
+
RunLoop::ProcessWaiter.new('lldb').wait_for_none
|
97
|
+
end
|
98
|
+
|
99
|
+
# For some reason, :timeout does not work here - the lldb process can
|
100
|
+
# hang indefinitely. Seems to work when
|
101
|
+
Retriable.retriable({:tries => merged_options[:retries],
|
102
|
+
# Retriable 2.0
|
103
|
+
:interval => merged_options[:interval],
|
104
|
+
:base_interval => merged_options[:interval],
|
105
|
+
:on_retry => on_retry}) do
|
106
|
+
#unless inject_dylib_with_timeout merged_options[:timeout]
|
107
|
+
unless inject_dylib_with_timeout merged_options[:timeout]
|
108
|
+
raise RuntimeError, "Could not inject dylib"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
true
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
RETRIABLE_OPTIONS =
|
117
|
+
{
|
118
|
+
:retries => 3,
|
119
|
+
:timeout => 10,
|
120
|
+
# Retriable 2.0 replaces :interval with :base_interval
|
121
|
+
:interval => 2,
|
122
|
+
:base_interval => 2
|
123
|
+
}
|
124
|
+
end
|
125
|
+
end
|