run_loop 2.1.6 → 2.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ff141b60144498a30b21eb09fa12ac5a6c8e95fd
4
- data.tar.gz: 8f8f501c79a466e8aefae117ead31fa5fc1b0d38
3
+ metadata.gz: 8451119a8e88cf2179b1b7a0bfc554a19459e9c5
4
+ data.tar.gz: 0b75d4af7f258d99780c624750dc3e3f241e5581
5
5
  SHA512:
6
- metadata.gz: e2654a32fa02ca8e27746102748201934a2d27fc5a995fe58dd10e94b147e4688876fc07c6625b513742410224800e2848e5f394416db6be15385061ff7300a5
7
- data.tar.gz: fa60c8ab92dfc6840f45bb242be4b2fec1e4d1394d2f89542e1e159a54c10f8b082d019724c83c26dd3d860ffb9a438faeb0db0d5f65c2defd0b09d73c0c6e99
6
+ metadata.gz: ad70df268ab1bcd8001f71cb81499653ec67428be5e5fd78a7a6a89d83e527b7fe3e2da982be52bb0c1480eee57de119b40b2a1c3a4b290e6a5d5b5c9565afb2
7
+ data.tar.gz: d75408caf251d7b4a4ebf532adfe361697dc7cf46e4aab6f15c6447818622604c13205a764202ff5796079e2e28ec0fed871fbe73309d63cdbf1f99e63eaeed5
data/lib/run_loop.rb CHANGED
@@ -48,6 +48,7 @@ require "run_loop/http/server"
48
48
  require "run_loop/http/request"
49
49
  require "run_loop/http/retriable_client"
50
50
  require "run_loop/physical_device/life_cycle"
51
+ require "run_loop/physical_device/ios_device_manager"
51
52
 
52
53
  module RunLoop
53
54
 
data/lib/run_loop/app.rb CHANGED
@@ -180,7 +180,7 @@ Bundle must:
180
180
  # See #marketing_version
181
181
  alias_method :short_bundle_version, :marketing_version
182
182
 
183
- # Returns the CFBundleVersionString of the app as Version instance.
183
+ # Returns the CFBundleVersion of the app as Version instance.
184
184
  #
185
185
  # Apple docs:
186
186
  #
@@ -195,14 +195,14 @@ Bundle must:
195
195
  # @return [RunLoop::Version, nil] Returns a Version instance if the
196
196
  # CFBundleVersion string is well formed and nil if not.
197
197
  def build_version
198
- string = plist_buddy.plist_read("CFBundleVersionString", info_plist_path)
198
+ string = plist_buddy.plist_read("CFBundleVersion", info_plist_path)
199
199
  begin
200
200
  version = RunLoop::Version.new(string)
201
201
  rescue
202
202
  if string && string != ""
203
- RunLoop.log_debug("CFBundleVersionString: '#{string}' is not a well formed version string")
203
+ RunLoop.log_debug("CFBundleVersion: '#{string}' is not a well formed version string")
204
204
  else
205
- RunLoop.log_debug("CFBundleVersionString is not defined in Info.plist")
205
+ RunLoop.log_debug("CFBundleVersion is not defined in Info.plist")
206
206
  end
207
207
  version = nil
208
208
  end
@@ -218,7 +218,7 @@ Bundle must:
218
218
  executables = []
219
219
  Dir.glob("#{path}/**/*") do |file|
220
220
  next if skip_executable_check?(file)
221
- if otool(file).executable?
221
+ if otool.executable?(file)
222
222
  executables << file
223
223
  end
224
224
  end
@@ -262,9 +262,13 @@ Bundle must:
262
262
  end
263
263
 
264
264
  # @!visibility private
265
- # An otool factory.
266
- def otool(file)
267
- RunLoop::Otool.new(file)
265
+ def otool
266
+ @otool ||= RunLoop::Otool.new(xcode)
267
+ end
268
+
269
+ # @!visibility private
270
+ def xcode
271
+ @xcode ||= RunLoop::Xcode.new
268
272
  end
269
273
 
270
274
  # @!visibility private
@@ -30,8 +30,8 @@ module RunLoop
30
30
  desc 'instruments', "Interact with Xcode's command-line instruments"
31
31
  subcommand 'instruments', RunLoop::CLI::Instruments
32
32
 
33
- desc 'simctl', "Interact with Xcode's command-line simctl"
34
- subcommand 'simctl', RunLoop::CLI::Simctl
33
+ desc "simctl", "Interact with Xcode's command-line simctl"
34
+ subcommand "simctl", RunLoop::CLI::Simctl
35
35
 
36
36
  desc "locale", "Tools for interacting with locales"
37
37
  subcommand "locale", RunLoop::CLI::Locale
@@ -103,11 +103,6 @@ module RunLoop
103
103
 
104
104
  begin
105
105
  RunLoop::CoreSimulator.terminate_core_simulator_processes
106
- process_name = "com.apple.CoreSimulator.CoreSimulatorService"
107
- RunLoop::ProcessWaiter.new(process_name).pids.each do |pid|
108
- kill_options = { :timeout => 0.5 }
109
- RunLoop::ProcessTerminator.new(pid, 'KILL', process_name, kill_options)
110
- end
111
106
  ensure
112
107
  ENV['DEBUG'] = original_value if debug
113
108
  end
data/lib/run_loop/core.rb CHANGED
@@ -65,7 +65,8 @@ module RunLoop
65
65
  xcode = options[:xcode] || RunLoop::Xcode.new
66
66
  instruments = options[:instruments] || RunLoop::Instruments.new
67
67
 
68
- if xcode.version_gte_8?
68
+ # Guard against Xcode version check on the XTC.
69
+ if !RunLoop::Environment.xtc? && xcode.version_gte_8?
69
70
  raise %Q[
70
71
  UIAutomation is not available on Xcode >= 8.*.
71
72
 
@@ -22,7 +22,8 @@ class RunLoop::CoreSimulator
22
22
  :install_app_timeout => RunLoop::Environment.ci? ? 120 : 30,
23
23
  :uninstall_app_timeout => RunLoop::Environment.ci? ? 120 : 30,
24
24
  :launch_app_timeout => RunLoop::Environment.ci? ? 120 : 30,
25
- :wait_for_state_timeout => RunLoop::Environment.ci? ? 120 : 30
25
+ :wait_for_state_timeout => RunLoop::Environment.ci? ? 120 : 30,
26
+ :app_launch_retries => RunLoop::Environment.ci? ? 5 : 3
26
27
  }
27
28
 
28
29
  # @!visibility private
@@ -178,9 +179,8 @@ class RunLoop::CoreSimulator
178
179
  #
179
180
  # @param [RunLoop::Device] simulator The simulator to erase
180
181
  # @param [Hash] options Control the behavior of the method.
181
- # @option options [Numeric] :timeout (180) How long tow wait for simctl to
182
- # shutdown and erase the simulator. The timeout is apply separately to
183
- # each command.
182
+ # @option options [Numeric] :timeout How long to wait for simctl to
183
+ # shutdown the simulator. This is necessary for the erase to succeed.
184
184
  #
185
185
  # @raise RuntimeError If the simulator cannot be shutdown
186
186
  # @raise RuntimeError If the simulator cannot be erased
@@ -191,61 +191,13 @@ class RunLoop::CoreSimulator
191
191
  "#{simulator} is a physical device. This method is only for Simulators"
192
192
  end
193
193
 
194
- default_options = {
195
- :timeout => 60*3
196
- }
197
-
198
- merged_options = default_options.merge(options)
199
-
200
- self.quit_simulator
201
-
202
- xcrun = merged_options[:xcrun] || RunLoop::Xcrun.new
203
- timeout = merged_options[:timeout]
204
- xcrun_opts = {
205
- :log_cmd => true,
206
- :timeout => timeout
207
- }
208
-
209
- if simulator.update_simulator_state != "Shutdown"
210
- args = ["simctl", "shutdown", simulator.udid]
211
- xcrun.run_command_in_context(args, xcrun_opts)
212
- begin
213
- self.wait_for_simulator_state(simulator, "Shutdown")
214
- rescue RuntimeError => _
215
- raise RuntimeError, %Q{
216
- Could not erase simulator because it could not be Shutdown.
194
+ merged_options = DEFAULT_OPTIONS.merge(options)
195
+ simctl = merged_options[:simctl] || RunLoop::Simctl.new
196
+ timeout = merged_options[:timeout] || merged_options[:wait_for_state_timeout]
217
197
 
218
- This usually means your CoreSimulator processes need to be restarted.
219
-
220
- You can restart the CoreSimulator processes with this command:
221
-
222
- $ bundle exec run-loop simctl manage-processes
223
-
224
- }
225
-
226
- end
227
- end
228
-
229
- args = ["simctl", "erase", simulator.udid]
230
- hash = xcrun.run_command_in_context(args, xcrun_opts)
231
-
232
- if hash[:exit_status] != 0
233
- raise RuntimeError, %Q{
234
- Could not erase simulator because simctl returned this error:
235
-
236
- #{hash[:out]}
237
-
238
- This usually means your CoreSimulator processes need to be restarted.
239
-
240
- You can restart the CoreSimulator processes with this command:
241
-
242
- $ bundle exec run-loop simctl manage-processes
243
-
244
- }
245
-
246
- end
247
-
248
- hash
198
+ simctl.erase(simulator,
199
+ timeout,
200
+ WAIT_FOR_SIMULATOR_STATE_INTERVAL)
249
201
  end
250
202
 
251
203
  # @!visibility private
@@ -351,6 +303,11 @@ $ bundle exec run-loop simctl manage-processes
351
303
  @xcrun ||= RunLoop::Xcrun.new
352
304
  end
353
305
 
306
+ # @!visibility private
307
+ def simctl
308
+ @simctl ||= RunLoop::Simctl.new
309
+ end
310
+
354
311
  # Launch the simulator indicated by device.
355
312
  def launch_simulator
356
313
 
@@ -404,29 +361,19 @@ $ bundle exec run-loop simctl manage-processes
404
361
  # relaunch it.
405
362
  launch_simulator
406
363
 
407
- tries = RunLoop::Environment.ci? ? 5 : 3
408
- last_error = nil
364
+ tries = app_launch_retries
409
365
 
410
366
  RunLoop.log_debug("Trying #{tries} times to launch #{app.bundle_identifier} on #{device}")
411
367
 
412
- tries.times do |try|
413
- # Terminates CoreSimulatorService on failures.
414
- hash = attempt_to_launch_app_with_simctl
415
-
416
- exit_status = hash[:exit_status]
417
- if exit_status != 0
418
- # Last argument is how long to sleep after an error.
419
- last_error = handle_failed_app_launch(hash, try, tries, 0.5)
420
- else
421
- last_error = nil
422
- break
423
- end
424
- end
368
+ last_error = try_to_launch_app_n_times(tries)
425
369
 
426
370
  if last_error
427
- raise RuntimeError, %Q[Could not launch #{app.bundle_identifier} on #{device}
371
+ raise RuntimeError, %Q[
372
+ Could not launch #{app.bundle_identifier} on #{device} after trying #{tries} times:
428
373
 
429
- #{last_error}
374
+ #{last_error}:
375
+
376
+ #{last_error.message}
430
377
 
431
378
  ]
432
379
  end
@@ -487,10 +434,8 @@ $ bundle exec run-loop simctl manage-processes
487
434
 
488
435
  launch_simulator
489
436
 
490
- args = ['simctl', 'uninstall', device.udid, app.bundle_identifier]
491
-
492
437
  timeout = DEFAULT_OPTIONS[:uninstall_app_timeout]
493
- xcrun.run_command_in_context(args, log_cmd: true, timeout: timeout)
438
+ simctl.uninstall(device, app, timeout)
494
439
 
495
440
  device.simulator_wait_for_stable_state
496
441
  true
@@ -610,9 +555,8 @@ Command had no output
610
555
  def install_app_with_simctl
611
556
  launch_simulator
612
557
 
613
- args = ['simctl', 'install', device.udid, app.path]
614
558
  timeout = DEFAULT_OPTIONS[:install_app_timeout]
615
- xcrun.run_command_in_context(args, log_cmd: true, timeout: timeout)
559
+ simctl.install(device, app, timeout)
616
560
 
617
561
  device.simulator_wait_for_stable_state
618
562
  installed_app_bundle_dir
@@ -620,42 +564,48 @@ Command had no output
620
564
 
621
565
  # @!visibility private
622
566
  def launch_app_with_simctl
623
- args = ['simctl', 'launch', device.udid, app.bundle_identifier]
624
567
  timeout = DEFAULT_OPTIONS[:launch_app_timeout]
625
- xcrun.run_command_in_context(args, log_cmd: true, timeout: timeout)
568
+ simctl.launch(device, app, timeout)
626
569
  end
627
570
 
628
571
  # @!visibility private
629
- def handle_failed_app_launch(hash, try, tries, wait_time)
630
- out = hash[:out]
631
- RunLoop.log_debug("Failed to launch app on try #{try + 1} of #{tries}.")
632
- out.split($-0).each do |line|
633
- RunLoop.log_debug(" #{line}")
572
+ #
573
+ # Returns nil if launch_app_with_simctl succeeds and the error if it fails.
574
+ def try_to_launch_app
575
+ begin
576
+ launch_app_with_simctl
577
+ nil
578
+ rescue RuntimeError, RunLoop::Xcrun::TimeoutError => error
579
+ # Simulator is probably in a bad state. Restart the service.
580
+ RunLoop::CoreSimulator.terminate_core_simulator_processes
581
+ Kernel.sleep(0.5)
582
+ launch_simulator
583
+ error
634
584
  end
635
- # If we timed out on the launch, the CoreSimulator processes are quit
636
- # (see above). If at all possible, we want to avoid terminating
637
- # CoreSimulatorService, because it takes a long time to launch.
638
- sleep(wait_time) if wait_time > 0
585
+ end
639
586
 
640
- out
587
+ # @!visibility private
588
+ def app_launch_retries
589
+ DEFAULT_OPTIONS[:app_launch_retries]
641
590
  end
642
591
 
643
592
  # @!visibility private
644
- def attempt_to_launch_app_with_simctl
645
- begin
646
- hash = launch_app_with_simctl
647
- rescue RunLoop::Xcrun::TimeoutError => e
648
- hash = {
649
- :exit_status => 1,
650
- :out => e.message
651
- }
652
- # Simulator is probably in a bad state. Terminates the
653
- # CoreSimulatorService. Restarting this service is expensive!
654
- RunLoop::CoreSimulator.terminate_core_simulator_processes
655
- Kernel.sleep(0.5)
656
- launch_simulator
593
+ #
594
+ # Returns nil if launch_app_with_simctl succeeds and the error if it fails.
595
+ def try_to_launch_app_n_times(tries)
596
+ last_error = nil
597
+
598
+ tries.times do |try|
599
+ # Terminates CoreSimulatorService on failures and launches the simulator again.
600
+ # Returns nil if app launched.
601
+ # Returns rescued Runtime or Timeout errors.
602
+ last_error = try_to_launch_app
603
+
604
+ break if last_error.nil?
605
+ RunLoop.log_debug("Failed to launch app on try #{try + 1} of #{tries}.")
657
606
  end
658
- hash
607
+
608
+ last_error
659
609
  end
660
610
 
661
611
  # Required for support of iOS 7 CoreSimulators. Can be removed when
@@ -4,6 +4,9 @@ module RunLoop
4
4
  require 'securerandom'
5
5
  include RunLoop::Regex
6
6
 
7
+ require "run_loop/shell"
8
+ include RunLoop::Shell
9
+
7
10
  # Starting in Xcode 7, iOS 9 simulators have a new "booting" state.
8
11
  #
9
12
  # The simulator must completely boot before run-loop tries to do things
@@ -39,7 +42,6 @@ module RunLoop
39
42
  attr_reader :simulator_accessibility_plist_path
40
43
  attr_reader :simulator_preferences_plist_path
41
44
  attr_reader :simulator_log_file_path
42
- attr_reader :pbuddy
43
45
 
44
46
  # Create a new device.
45
47
  #
@@ -268,7 +270,7 @@ version: #{version}
268
270
  raise RuntimeError, 'This method is available only for simulators'
269
271
  end
270
272
 
271
- @state = fetch_simulator_state
273
+ @state = simctl.simulator_state_as_string(self)
272
274
  end
273
275
 
274
276
  # @!visibility private
@@ -498,20 +500,35 @@ version: #{version}
498
500
  global_plist = simulator_global_preferences_path
499
501
 
500
502
  cmd = [
501
- "PlistBuddy",
503
+ "/usr/libexec/PlistBuddy",
502
504
  "-c",
503
505
  "Add :AppleLanguages:0 string '#{lang_code}'",
504
506
  global_plist
505
507
  ]
506
508
 
507
509
  # RunLoop::PlistBuddy cannot add items to arrays.
508
- xcrun.run_command_in_context(cmd, {:log_cmd => true})
510
+ hash = run_shell_command(cmd, {:log_cmd => true})
511
+
512
+ if hash[:exit_status] != 0
513
+ raise RuntimeError, %Q[
514
+ Could not update the Simulator languages because this command:
515
+
516
+ #{cmd.join(" ")}
517
+
518
+ failed with this output:
519
+
520
+ #{hash[:out]}
521
+
522
+ ]
523
+ end
509
524
 
510
525
  simulator_languages
511
526
  end
512
527
 
513
528
  private
514
529
 
530
+ attr_reader :pbuddy, :simctl, :xcrun
531
+
515
532
  # @!visibility private
516
533
  def xcrun
517
534
  RunLoop::Xcrun.new
@@ -523,43 +540,8 @@ version: #{version}
523
540
  end
524
541
 
525
542
  # @!visibility private
526
- def detect_state_from_line(line)
527
-
528
- if line[/unavailable/, 0]
529
- RunLoop.log_debug("Simulator state is unavailable: #{line}")
530
- return 'Unavailable'
531
- end
532
-
533
- state = line[/(Booted|Shutdown|Shutting Down)/,0]
534
-
535
- if state.nil?
536
- RunLoop.log_debug("Simulator state is unknown: #{line}")
537
- 'Unknown'
538
- else
539
- state
540
- end
541
- end
542
-
543
- # @!visibility private
544
- def fetch_simulator_state
545
- if physical_device?
546
- raise RuntimeError, 'This method is available only for simulators'
547
- end
548
-
549
- args = ['simctl', 'list', 'devices']
550
- hash = xcrun.run_command_in_context(args)
551
- out = hash[:out]
552
-
553
- matched_line = out.split("\n").find do |line|
554
- line.include?(udid)
555
- end
556
-
557
- if matched_line.nil?
558
- raise RuntimeError,
559
- "Expected a simulator with udid '#{udid}', but found none"
560
- end
561
-
562
- detect_state_from_line(matched_line)
543
+ def simctl
544
+ @simctl ||= RunLoop::Simctl.new
563
545
  end
564
546
 
565
547
  # @!visibility private