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)


141
142
143
144
145
146
147
148
# File 'lib/run_loop/instruments.rb', line 141

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(_ = nil) ⇒ Object

Send a kill signal to any running ‘instruments` processes.

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



127
128
129
130
131
132
133
134
135
# File 'lib/run_loop/instruments.rb', line 127

def kill_instruments(_=nil)
  instruments_pids.each do |pid|
    terminator = RunLoop::ProcessTerminator.new(pid, "QUIT", "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:



212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/run_loop/instruments.rb', line 212

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:



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'lib/run_loop/instruments.rb', line 240

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.



160
161
162
163
164
165
166
167
# File 'lib/run_loop/instruments.rb', line 160

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.



193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/run_loop/instruments.rb', line 193

def templates
  @instruments_templates ||= lambda do
    args = ['instruments', '-s', 'templates']
    hash = xcrun.run_command_in_context(args, log_cmd: true)
    hash[:out].chomp.split("\n").map do |elm|
      stripped = elm.strip.tr('"', '')
      if stripped == '' || stripped == 'Known Templates:'
        nil
      else
        stripped
      end
    end.compact
  end.call
end

#versionRunLoop::Version

Returns the instruments version.

Returns:



171
172
173
174
175
176
177
# File 'lib/run_loop/instruments.rb', line 171

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