class Luffa::IDeviceInstaller

Constants

DEFAULT_OPTIONS

Attributes

bundle_id[R]
ipa[R]

Public Class Methods

idevice_id_available?() click to toggle source
# File lib/luffa/ios/ideviceinstaller.rb, line 20
def self.idevice_id_available?
  path = self.idevice_id_bin_path
  path and File.exist? path
end
ideviceinstaller_available?() click to toggle source
# File lib/luffa/ios/ideviceinstaller.rb, line 15
def self.ideviceinstaller_available?
  path = self.bin_path
  path and File.exist? self.bin_path
end
new(ipa, bundle_id) click to toggle source
# File lib/luffa/ios/ideviceinstaller.rb, line 10
def initialize(ipa, bundle_id)
  @ipa = ipa
  @bundle_id = bundle_id
end
physical_devices_for_testing(instruments) click to toggle source

Can only be called when RunLoop is available.

# File lib/luffa/ios/ideviceinstaller.rb, line 39
def self.physical_devices_for_testing(instruments)
  # Xcode 6 + iOS 8 - devices on the same network, whether development or
  # not, appear when calling $ xcrun instruments -s devices. For the
  # purposes of testing, we will only try to connect to devices that are
  # connected via USB.
  #
  # Also idevice_id, which ideviceinstaller relies on, will sometimes report
  # devices 2x which will cause ideviceinstaller to fail.
  devices = instruments.physical_devices
  if IDeviceInstaller.idevice_id_available?
    white_list = `#{self.idevice_id_bin_path} -l`.strip.split("\n")
    devices.select do | device |
      white_list.include?(device.udid) && white_list.count(device.udid) == 1
    end
  else
    devices
  end
end

Private Class Methods

bin_path() click to toggle source
# File lib/luffa/ios/ideviceinstaller.rb, line 62
def self.bin_path
  @@bin_path ||= `which ideviceinstaller`.chomp!
end
idevice_id_bin_path() click to toggle source
# File lib/luffa/ios/ideviceinstaller.rb, line 153
def self.idevice_id_bin_path
  @@idevice_id_bin_path ||= `which idevice_id`.chomp!
end

Public Instance Methods

install(udid, options={}) click to toggle source
# File lib/luffa/ios/ideviceinstaller.rb, line 25
def install(udid, options={})
  if options.is_a? Hash
    merged_options = DEFAULT_OPTIONS.merge(options)
  else
    Luffa.log_warn 'API CHANGE: install now takes an options hash as 2nd arg'
    Luffa.log_warn "API CHANGE: ignoring '#{options}'; will use defaults"
    merged_options = DEFAULT_OPTIONS
  end

  uninstall(udid, merged_options)
  install_internal(udid, merged_options)
end

Private Instance Methods

bundle_installed?(udid, options={}) click to toggle source
# File lib/luffa/ios/ideviceinstaller.rb, line 117
def bundle_installed?(udid, options={})
  merged_options = DEFAULT_OPTIONS.merge(options)

  args = ['--udid', udid, '--list-apps']

  hash = run_command_with_args(args, merged_options)
  out = hash[:out]
  out.split(/\s/).include? bundle_id
end
install_internal(udid, options={}) click to toggle source
# File lib/luffa/ios/ideviceinstaller.rb, line 127
def install_internal(udid, options={})
  merged_options = DEFAULT_OPTIONS.merge(options)

  return true if bundle_installed?(udid, merged_options)
  args = ['--udid', udid, '--install', ipa]
  run_command_with_args(args, merged_options)

  unless bundle_installed?(udid, merged_options)
    raise "could not install '#{ipa}' on '#{udid}' with '#{bundle_id}'"
  end
  true
end
run_command_with_args(args, options={}) click to toggle source
# File lib/luffa/ios/ideviceinstaller.rb, line 66
def run_command_with_args(args, options={})
  merged_options = DEFAULT_OPTIONS.merge(options)

  cmd = "#{IDeviceInstaller.bin_path} #{args.join(' ')}"
  Luffa.log_unix_cmd(cmd) if Luffa::Environment.debug?

  exit_status = nil
  out = nil
  pid = nil
  err = nil

  tries = merged_options[:tries]
  timeout = merged_options[:timeout]

  on = [Timeout::Error, RuntimeError]
  on_retry = Proc.new do |_, try, elapsed_time, next_interval|
    # Retriable 2.0
    if elapsed_time && next_interval
      Luffa.log_info "ideviceinstaller: attempt #{try} failed in '#{elapsed_time}'; will retry in '#{next_interval}'"
    else
      Luffa.log_info "ideviceinstaller: attempt #{try} failed; will retry"
    end
  end

  Retriable.retriable({tries: tries, on: on, on_retry: on_retry} ) do
    Timeout.timeout(timeout, TimeoutError) do
      Open3.popen3(IDeviceInstaller.bin_path, *args) do  |_, stdout,  stderr, process_status|
        err = stderr.read.strip
        if err && err != ''
          unless err[/iTunesMetadata.plist/,0] || err[/SC_Info/,0]
            Luffa.log_fail(err)
          end
        end
        out = stdout.read.strip
        pid = process_status.pid
        exit_status = process_status.value.exitstatus
      end
    end

    if exit_status != 0
      raise RuntimeError, "Could not execute #{args.join(' ')}"
    end
  end
  {
        :out => out,
        :err => err,
        :pid => pid,
        :exit_status => exit_status
  }
end
uninstall(udid, options={}) click to toggle source
# File lib/luffa/ios/ideviceinstaller.rb, line 140
def uninstall(udid, options={})
  merged_options = DEFAULT_OPTIONS.merge(options)

  return true unless bundle_installed?(udid, merged_options)
  args = ['--udid', udid, '--uninstall', bundle_id]
  run_command_with_args(args)

  if bundle_installed?(udid, merged_options)
    raise "Could not uninstall '#{bundle_id}' on '#{udid}'"
  end
  true
end