Class: FastlaneCore::DeviceManager

Inherits:
Object
  • Object
show all
Defined in:
fastlane_core/lib/fastlane_core/device_manager.rb

Defined Under Namespace

Classes: Device

Class Method Summary collapse

Class Method Details

.all(requested_os_type = "") ⇒ Object

[View source]

10
11
12
# File 'fastlane_core/lib/fastlane_core/device_manager.rb', line 10

def all(requested_os_type = "")
  return connected_devices(requested_os_type) + simulators(requested_os_type)
end

.connected_devices(requested_os_type) ⇒ Object

[View source]

69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'fastlane_core/lib/fastlane_core/device_manager.rb', line 69

def connected_devices(requested_os_type)
  UI.verbose("Fetching available connected devices")

  device_types = if requested_os_type == "tvOS"
                   ["AppleTV"]
                 elsif requested_os_type == "iOS"
                   ["iPhone", "iPad", "iPod"]
                 else
                   []
                 end

  devices = [] # Return early if no supported devices are being searched for
  if device_types.count == 0
    return devices
  end

  usb_devices_output = ''
  Open3.popen3("system_profiler SPUSBDataType -xml") do |stdin, stdout, stderr, wait_thr|
    usb_devices_output = stdout.read
  end

  device_uuids = []
  result = Plist.parse_xml(usb_devices_output)

  discover_devices(result[0], device_types, device_uuids) if result[0]

  if device_uuids.count > 0 # instruments takes a little while to return so skip it if we have no devices
    instruments_devices_output = ''
    Open3.popen3("instruments -s devices") do |stdin, stdout, stderr, wait_thr|
      instruments_devices_output = stdout.read
    end

    instruments_devices_output.split(/\n/).each do |instruments_device|
      device_uuids.each do |device_uuid|
        match = instruments_device.match(/(.+) \(([0-9.]+)\) \[(\h{40}|\h{8}-\h{16})\]?/)
        if match && match[3].delete("-") == device_uuid
          devices << Device.new(name: match[1], udid: match[3], os_type: requested_os_type, os_version: match[2], state: "Booted", is_simulator: false)
          UI.verbose("USB Device Found - \"" + match[1] + "\" (" + match[2] + ") UUID:" + match[3])
        end
      end
    end
  end

  return devices
end

.discover_devices(usb_item, device_types, discovered_device_udids) ⇒ Object

Recursively handle all USB items, discovering devices that match the desired types.

[View source]

117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'fastlane_core/lib/fastlane_core/device_manager.rb', line 117

def discover_devices(usb_item, device_types, discovered_device_udids)
  (usb_item['_items'] || []).each do |child_item|
    discover_devices(child_item, device_types, discovered_device_udids)
  end

  is_supported_device = device_types.any?(usb_item['_name'])
  serial_num = usb_item['serial_num'] || ''
  has_serial_number = serial_num.length == 40 || serial_num.length == 24

  if is_supported_device && has_serial_number
    discovered_device_udids << serial_num
  end
end

.latest_simulator_version_for_device(device) ⇒ Object

[View source]

131
132
133
134
135
136
# File 'fastlane_core/lib/fastlane_core/device_manager.rb', line 131

def latest_simulator_version_for_device(device)
  simulators.select { |s| s.name == device }
            .sort_by { |s| Gem::Version.create(s.os_version) }
            .last
            .os_version
end

.runtime_build_os_versionsObject

[View source]

14
15
16
17
18
19
20
21
22
23
24
25
# File 'fastlane_core/lib/fastlane_core/device_manager.rb', line 14

def runtime_build_os_versions
  @runtime_build_os_versions ||= begin
    output, status = Open3.capture2('xcrun simctl list -j runtimes')
    raise status unless status.success?
    json = JSON.parse(output)
    json['runtimes'].map { |h| [h['buildversion'], h['version']] }.to_h
  rescue StandardError => e
    UI.error(e)
    UI.error('xcrun simctl CLI broken; cun `xcrun simctl list runtimes` and make sure it works')
    UI.user_error!('xcrun simctl not working')
  end
end

.simulators(requested_os_type = "") ⇒ Object

[View source]

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'fastlane_core/lib/fastlane_core/device_manager.rb', line 27

def simulators(requested_os_type = "")
  UI.verbose("Fetching available simulator devices")

  @devices = []
  os_type = 'unknown'
  os_version = 'unknown'
  output = ''
  Open3.popen3('xcrun simctl list devices') do |stdin, stdout, stderr, wait_thr|
    output = stdout.read
  end

  unless output.include?("== Devices ==")
    UI.error("xcrun simctl CLI broken, run `xcrun simctl list devices` and make sure it works")
    UI.user_error!("xcrun simctl not working.")
  end

  output.split(/\n/).each do |line|
    next if line =~ /unavailable/
    next if line =~ /^== /
    if line =~ /^-- /
      (os_type, os_version) = line.gsub(/-- (.*) --/, '\1').split
    else
      next if os_type =~ /^Unavailable/

      # "    iPad (5th generation) (852A5796-63C3-4641-9825-65EBDC5C4259) (Shutdown)"
      # This line will turn the above string into
      # ["iPad (5th generation)", "(852A5796-63C3-4641-9825-65EBDC5C4259)", "(Shutdown)"]
      matches = line.strip.scan(/^(.*?) (\([^)]*?\)) (\([^)]*?\))$/).flatten.reject(&:empty?)
      state = matches.pop.to_s.delete('(').delete(')')
      udid = matches.pop.to_s.delete('(').delete(')')
      name = matches.join(' ')

      if matches.count && (os_type == requested_os_type || requested_os_type == "")
        # This is disabled here because the Device is defined later in the file, and that's a problem for the cop
        @devices << Device.new(name: name, os_type: os_type, os_version: os_version, udid: udid, state: state, is_simulator: true)
      end
    end
  end

  return @devices
end