lib/luffa/ios/ideviceinstaller.rb in luffa-1.0.4 vs lib/luffa/ios/ideviceinstaller.rb in luffa-1.0.5
- old
+ new
@@ -1,6 +1,7 @@
require 'retriable'
+require 'open3'
module Luffa
class IDeviceInstaller
attr_reader :ipa
@@ -9,108 +10,150 @@
def initialize(ipa, bundle_id)
@ipa = ipa
@bundle_id = bundle_id
end
- def bin_path
- @bin_path ||= `which ideviceinstaller`.chomp!
- end
-
def ideviceinstaller_available?
path = bin_path
path and File.exist? bin_path
end
- def install(udid, cmd)
- case cmd
- when :install_internal
- ipa
- Retriable.retriable do
- uninstall udid
+ def idevice_id_available?
+ path = idevice_id_bin_path
+ path and File.exist? path
+ end
+
+ def install(udid, options={})
+ unless options.is_a? Hash
+ 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
+ else
+ merged_options = DEFAULT_OPTIONS.merge(options)
+ end
+
+ uninstall(udid, merged_options)
+ install_internal(udid, merged_options)
+ end
+
+ # Can only be called when RunLoop is available.
+ def physical_devices_for_testing(xcode_tools)
+ # 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.
+ @physical_devices_for_testing ||= lambda {
+ devices = xcode_tools.instruments(:devices)
+ if idevice_id_available?
+ white_list = `#{idevice_id_bin_path} -l`.strip.split("\n")
+ devices.select do | device |
+ white_list.include?(device.udid) && white_list.count(device.udid) == 1
end
- Retriable.retriable do
- install_internal udid
- end
- when :uninstall
- Retriable.retriable do
- uninstall udid
- end
else
- cmds = [:install_internal, :uninstall]
- raise ArgumentError, "expected '#{cmd}' to be one of '#{cmds}'"
- end
+ devices
+ end
+ }.call
end
- def bundle_installed?(udid)
- cmd = "#{bin_path} --udid #{udid} --list-apps"
- Luffa.log_unix_cmd(cmd) if Luffa::Environment.debug?
+ private
- Open3.popen3(cmd) do |_, stdout, stderr, _|
- err = stderr.read.strip
- Luffa.log_fail(err) if err && err != ''
+ DEFAULT_OPTIONS = { :timeout => 10.0, :tries => 2 }
- out = stdout.read.strip
- out.strip.split(/\s/).include? bundle_id
- end
+ def bin_path
+ @bin_path ||= `which ideviceinstaller`.chomp!
end
- def install_internal(udid)
- return true if bundle_installed? udid
+ def run_command_with_args(args, options={})
+ merged_options = DEFAULT_OPTIONS.merge(options)
- cmd = "#{bin_path} --udid #{udid} --install #{ipa}"
+ cmd = "#{bin_path} #{args.join(' ')}"
Luffa.log_unix_cmd(cmd) if Luffa::Environment.debug?
- Open3.popen3(cmd) do |_, _, stderr, _|
- err = stderr.read.strip
- Luffa.log_fail(err) if err && err != ''
+ 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 "LLDB: attempt #{try} failed in '#{elapsed_time}'; will retry in '#{next_interval}'"
+ else
+ Luffa.log_info "LLDB: attempt #{try} failed; will retry"
+ end
end
- unless bundle_installed? udid
- raise "could not install '#{ipa}' on '#{udid}' with '#{bundle_id}'"
+ Retriable.retriable({tries: tries, on: on, on_retry: on_retry} ) do
+ Timeout.timeout(timeout, TimeoutError) do
+ Open3.popen3(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
- true
+ {
+ :out => out,
+ :err => err,
+ :pid => pid,
+ :exit_status => exit_status
+ }
end
- def uninstall(udid)
- return true unless bundle_installed? udid
+ def bundle_installed?(udid, options={})
+ merged_options = DEFAULT_OPTIONS.merge(options)
- cmd = "#{bin_path} -udid #{udid} --uninstall #{bundle_id}"
- Luffa.log_unix_cmd(cmd) if Luffa::Environment.debug?
+ args = ['--udid', udid, '--list-apps']
- Open3.popen3(cmd) do |_, _, stderr, _|
- err = stderr.read.strip
- Luffa.log_fail(err) if err && err != ''
- end
+ hash = run_command_with_args(args, merged_options)
+ out = hash[:out]
+ out.split(/\s/).include? bundle_id
+ end
- if bundle_installed? udid
- raise "could not uninstall '#{bundle_id}' on '#{udid}'"
+ 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
- def idevice_id_bin_path
- @idevice_id_bin_path ||= `which idevice_id`.chomp!
- end
+ def uninstall(udid, options={})
+ merged_options = DEFAULT_OPTIONS.merge(options)
- def idevice_id_available?
- path = idevice_id_bin_path
- path and File.exist? path
- end
+ return true unless bundle_installed?(udid, merged_options)
+ args = ['--udid', udid, '--uninstall', bundle_id]
+ run_command_with_args(args)
- def physical_devices_for_testing(xcode_tools)
- # 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.
- @physical_devices_for_testing ||= lambda {
- devices = xcode_tools.instruments(:devices)
- if idevice_id_available?
- white_list = `#{idevice_id_bin_path} -l`.strip.split("\n")
- devices.select { | device | white_list.include?(device.udid) }
- else
- devices
- end
- }.call
+ if bundle_installed?(udid, merged_options)
+ raise "Could not uninstall '#{bundle_id}' on '#{udid}'"
+ end
+ true
end
+ def idevice_id_bin_path
+ @idevice_id_bin_path ||= `which idevice_id`.chomp!
+ end
end
end