Class: RunLoop::Instruments

Inherits:
Object
  • Object
show all
Defined in:
lib/run_loop/instruments.rb

Overview

Note:

All instruments commands are run in the context of xcrun.

A class for interacting with the instruments command-line tool

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#xcodeObject (readonly)

Returns the value of attribute xcode.



10
11
12
# File 'lib/run_loop/instruments.rb', line 10

def xcode
  @xcode
end

Instance Method Details

#instruments_app_running?Boolean

Is the Instruments.app running?

If the Instruments.app is running, the instruments command line tool cannot take control of applications.

Returns:

  • (Boolean)


81
82
83
84
85
86
87
88
# File 'lib/run_loop/instruments.rb', line 81

def instruments_app_running?
  ps_output = `ps x -o pid,comm | grep Instruments.app | grep -v grep`.strip
  if ps_output[/Instruments\.app/, 0]
    true
  else
    false
  end
end

#instruments_pids(&block) ⇒ Array<Integer>

Note:

The block parameter is included for legacy API and will be deprecated. Replace your existing calls with with .each or .map. The block argument makes this method hard to mock.

Returns an Array of instruments process ids.

Returns:

  • (Array<Integer>)

    An array of instruments process ids.



36
37
38
39
40
41
42
43
44
45
# File 'lib/run_loop/instruments.rb', line 36

def instruments_pids(&block)
  pids = pids_from_ps_output
  if block_given?
    pids.each do |pid|
      block.call(pid)
    end
  else
    pids
  end
end

#instruments_running?Boolean

Are there any instruments processes running?

Returns:

  • (Boolean)

    True if there is are any instruments processes running.



49
50
51
# File 'lib/run_loop/instruments.rb', line 49

def instruments_running?
  instruments_pids.count > 0
end

#kill_instruments(xcode = RunLoop::Xcode.new) ⇒ Object

Send a kill signal to any running instruments processes.

Only one instruments process can be running at any one time.

Parameters:



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/run_loop/instruments.rb', line 59

def kill_instruments(xcode = RunLoop::Xcode.new)
  if xcode.is_a?(RunLoop::XCTools)
    RunLoop.deprecated('1.5.0',
                     %q(
RunLoop::XCTools has been replaced with RunLoop::Xcode.
Please update your sources to pass an instance of RunLoop::Xcode))
  end

  kill_signal = kill_signal(xcode)
  instruments_pids.each do |pid|
    terminator = RunLoop::ProcessTerminator.new(pid, kill_signal, 'instruments')
    unless terminator.kill_process
      terminator = RunLoop::ProcessTerminator.new(pid, 'KILL', 'instruments')
      terminator.kill_process
    end
  end
end

#physical_devicesArray<RunLoop::Device>

Returns an array of the available physical devices.

Returns:



159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/run_loop/instruments.rb', line 159

def physical_devices
  @instruments_physical_devices ||= lambda do
    fetch_devices[:out].chomp.split("\n").map do |line|
      udid = line[DEVICE_UDID_REGEX, 0]
      if udid
        version = line[VERSION_REGEX, 0]
        name = line.split('(').first.strip
        RunLoop::Device.new(name, version, udid)
      else
        nil
      end
    end.compact
  end.call
end

#simulatorsArray<RunLoop::Device>

Returns an array of the available simulators.

**Xcode 5.1**

  • iPad Retina - Simulator - iOS 7.1

**Xcode 6**

  • iPad Retina (8.3 Simulator) [EA79555F-ADB4-4D75-930C-A745EAC8FA8B]

**Xcode 7**

  • iPhone 6 (9.0) [3EDC9C6E-3096-48BF-BCEC-7A5CAF8AA706]

  • iPhone 6 (9.0) + Apple Watch - 38mm (2.0) [EE3C200C-69BA-4816-A087-0457C5FCEDA0]

Returns:



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/run_loop/instruments.rb', line 187

def simulators
  @instruments_simulators ||= lambda do
    fetch_devices[:out].chomp.split("\n").map do |line|
      stripped = line.strip
      if line_is_simulator?(stripped) &&
            !line_is_simulator_paired_with_watch?(stripped)

        version = stripped[VERSION_REGEX, 0]

        if line_is_xcode5_simulator?(stripped)
          name = line
          udid = line
        else
          name = stripped.split('(').first.strip
          udid = line[CORE_SIMULATOR_UDID_REGEX, 0]
        end

        RunLoop::Device.new(name, version, udid)
      else
        nil
      end
    end.compact
  end.call
end

#spawn(automation_template, options, log_file) ⇒ Integer

TODO:

Do I need to enumerate the launch options in the docs?

TODO:

Should this raise errors?

TODO:

Is this jruby compatible?

Spawn a new instruments process in the context of xcrun and detach.

Parameters:

  • automation_template (String)

    The template instruments will use when launching the application.

  • options (Hash)

    The launch options.

  • log_file (String)

    The file to log to.

Returns:

  • (Integer)

    Returns the process id of the instruments process.



100
101
102
103
104
105
106
107
# File 'lib/run_loop/instruments.rb', line 100

def spawn(automation_template, options, log_file)
  splat_args = spawn_arguments(automation_template, options)
  logger = options[:logger]
  RunLoop::Logging.log_debug(logger, "xcrun #{splat_args.join(' ')} >& #{log_file}")
  pid = Process.spawn('xcrun', *splat_args, {:out => log_file, :err => log_file})
  Process.detach(pid)
  pid.to_i
end

#templatesArray<String>

Returns an array of Instruments.app templates.

Depending on the Xcode version Instruments.app templates will either be:

  • A full path to the template. # Xcode 5 and Xcode > 5 betas

  • The name of a template. # Xcode >= 6 (non beta)

Maintainers! The rules above are important and explain why we can’t simply filter by ‘~= /tracetemplate/`.

Templates that users have saved will always be full paths - regardless of the Xcode version.

Returns:

  • (Array<String>)

    Instruments.app templates.



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/run_loop/instruments.rb', line 134

def templates
  @instruments_templates ||= lambda do
    args = ['instruments', '-s', 'templates']
    hash = xcrun.exec(args, log_cmd: true)
    if xcode.version_gte_6?
      hash[:out].chomp.split("\n").map do |elm|
        stripped = elm.strip.tr('"', '')
        if stripped == '' || stripped == 'Known Templates:'
          nil
        else
          stripped
        end
      end.compact
    else
      hash[:out].strip.split("\n").delete_if do |path|
        not path =~ /tracetemplate/
      end.map { |elm| elm.strip }
    end
  end.call
end

#versionRunLoop::Version

Returns the instruments version.

Returns:



111
112
113
114
115
116
117
118
# File 'lib/run_loop/instruments.rb', line 111

def version
  @instruments_version ||= lambda do
    args = ['instruments']
    hash = xcrun.exec(args, log_cmd: true)
    version_str = hash[:err][VERSION_REGEX, 0]
    RunLoop::Version.new(version_str)
  end.call
end

#xcrunObject



16
17
18
# File 'lib/run_loop/instruments.rb', line 16

def xcrun
  RunLoop::Xcrun.new
end