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


77
78
79
# File 'lib/run_loop/instruments.rb', line 77

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)

145
146
147
148
149
150
151
152
# File 'lib/run_loop/instruments.rb', line 145

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.


107
108
109
110
111
112
113
114
115
116
# File 'lib/run_loop/instruments.rb', line 107

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.


120
121
122
# File 'lib/run_loop/instruments.rb', line 120

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:

  • xcode (RunLoop::Xcode) (defaults to: RunLoop::Xcode.new)

    Used to make check the active Xcode version.


130
131
132
133
134
135
136
137
138
139
# File 'lib/run_loop/instruments.rb', line 130

def kill_instruments(xcode = RunLoop::Xcode.new)
  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

#pbuddyObject


79
80
81
# File 'lib/run_loop/instruments.rb', line 79

def pbuddy
  @pbuddy ||= RunLoop::PlistBuddy.new
end

#physical_devicesArray<RunLoop::Device>

Returns an array of the available physical devices.

Returns:


222
223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/run_loop/instruments.rb', line 222

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:


250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# File 'lib/run_loop/instruments.rb', line 250

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) &&
            !line_is_apple_tv?(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.


164
165
166
167
168
169
170
171
# File 'lib/run_loop/instruments.rb', line 164

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.


197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/run_loop/instruments.rb', line 197

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:


175
176
177
178
179
180
181
# File 'lib/run_loop/instruments.rb', line 175

def version
  @instruments_version ||= lambda do
    version_string = pbuddy.plist_read('CFBundleShortVersionString',
                                       path_to_instruments_app_plist)
    RunLoop::Version.new(version_string)
  end.call
end

#xcrunObject


87
88
89
# File 'lib/run_loop/instruments.rb', line 87

def xcrun
  RunLoop::Xcrun.new
end