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)


85
86
87
88
89
90
91
92
# File 'lib/run_loop/instruments.rb', line 85

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.



40
41
42
43
44
45
46
47
48
49
# File 'lib/run_loop/instruments.rb', line 40

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.



53
54
55
# File 'lib/run_loop/instruments.rb', line 53

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:



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/run_loop/instruments.rb', line 63

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

#pbuddyObject



12
13
14
# File 'lib/run_loop/instruments.rb', line 12

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

#physical_devicesArray<RunLoop::Device>

Returns an array of the available physical devices.

Returns:



162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/run_loop/instruments.rb', line 162

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:



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

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.



104
105
106
107
108
109
110
111
# File 'lib/run_loop/instruments.rb', line 104

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.



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

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:



115
116
117
118
119
120
121
# File 'lib/run_loop/instruments.rb', line 115

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



20
21
22
# File 'lib/run_loop/instruments.rb', line 20

def xcrun
  RunLoop::Xcrun.new
end