reset-simulators.rb 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. #!/usr/bin/ruby
  2. require 'json'
  3. def platform_for_runtime(runtime)
  4. runtime['identifier'].gsub(/com.apple.CoreSimulator.SimRuntime.([^-]+)-.*/, '\1')
  5. end
  6. def platform_for_device_type(device_type)
  7. case device_type['identifier']
  8. when /Watch/
  9. 'watchOS'
  10. when /TV/
  11. 'tvOS'
  12. else
  13. 'iOS'
  14. end
  15. end
  16. def wait_for_core_simulator_service
  17. # Run until we get a result since switching simulator versions often causes CoreSimulatorService to throw an exception.
  18. while `xcrun simctl list devices`.empty?
  19. end
  20. end
  21. def running_devices(devices)
  22. devices.select { |device| device['state'] != 'Shutdown' }
  23. end
  24. def shutdown_simulator_devices(devices)
  25. # Shut down any simulators that need it.
  26. running_devices(devices).each do |device|
  27. puts "Shutting down simulator #{device['udid']}"
  28. system("xcrun simctl shutdown #{device['udid']}") or puts " Failed to shut down simulator #{device['udid']}"
  29. end
  30. end
  31. attempts = 0
  32. begin
  33. # Kill all the current simulator processes as they may be from a different Xcode version
  34. print 'Killing running Simulator processes...'
  35. while system('pgrep -q Simulator')
  36. system('pkill Simulator 2>/dev/null')
  37. # CoreSimulatorService doesn't exit when sent SIGTERM
  38. system('pkill -9 Simulator 2>/dev/null')
  39. end
  40. wait_for_core_simulator_service
  41. puts ' done!'
  42. print 'Shut down existing simulator devices...'
  43. # Shut down any running simulator devices. This may take multiple attempts if some
  44. # simulators are currently in the process of booting or being created.
  45. all_available_devices = []
  46. (0..5).each do |shutdown_attempt|
  47. begin
  48. devices_json = `xcrun simctl list devices -j`
  49. all_devices = JSON.parse(devices_json)['devices'].flat_map { |_, devices| devices }
  50. rescue JSON::ParserError
  51. sleep shutdown_attempt if shutdown_attempt > 0
  52. next
  53. end
  54. # Exclude devices marked as unavailable as they're from a different version of Xcode.
  55. all_available_devices = all_devices.reject { |device| device['availability'] =~ /unavailable/ }
  56. break if running_devices(all_available_devices).empty?
  57. shutdown_simulator_devices all_available_devices
  58. sleep shutdown_attempt if shutdown_attempt > 0
  59. end
  60. puts ' done!'
  61. # Delete all simulators.
  62. print 'Deleting all simulators...'
  63. all_available_devices.each do |device|
  64. system("xcrun simctl delete #{device['udid']}") or raise "Failed to delete simulator #{device['udid']}"
  65. end
  66. puts ' done!'
  67. # Recreate all simulators.
  68. runtimes = JSON.parse(`xcrun simctl list runtimes -j`)['runtimes']
  69. device_types = JSON.parse(`xcrun simctl list devicetypes -j`)['devicetypes']
  70. runtimes_by_platform = Hash.new { |hash, key| hash[key] = [] }
  71. runtimes.each do |runtime|
  72. next unless runtime['availability'] == '(available)' || runtime['isAvailable'] == true
  73. runtimes_by_platform[platform_for_runtime(runtime)] << runtime
  74. end
  75. print 'Creating fresh simulators...'
  76. device_types.each do |device_type|
  77. platform = platform_for_device_type(device_type)
  78. runtimes_by_platform[platform].each do |runtime|
  79. output = `xcrun simctl create '#{device_type['name']}' '#{device_type['identifier']}' '#{runtime['identifier']}' 2>&1`
  80. next if $? == 0
  81. # Error code 161 and 162 indicate that the given device is not supported by the runtime, such as the iPad 2 and
  82. # iPhone 4s not being supported by the iOS 10 simulator runtime.
  83. next if output =~ /(domain=com.apple.CoreSimulator.SimError, code=16[12])/
  84. puts "Failed to create device of type #{device_type['identifier']} with runtime #{runtime['identifier']}:"
  85. output.each_line do |line|
  86. puts " #{line}"
  87. end
  88. end
  89. end
  90. puts ' done!'
  91. print 'Booting iPhone 8 simulator...'
  92. system("xcrun simctl boot 'iPhone 8'") or raise "Failed to boot iPhone 8 simulator"
  93. puts ' done!'
  94. rescue => e
  95. if (attempts += 1) < 5
  96. puts ''
  97. puts e.message
  98. e.backtrace.each { |line| puts line }
  99. puts ''
  100. puts 'Retrying...'
  101. retry
  102. end
  103. system('ps auxwww')
  104. system('xcrun simctl list')
  105. raise
  106. end