require 'run_loop' if RunLoop.const_defined?(:Ipa) "\033[34mRunLoop::Ipa patch can be removed.\033[0m" else "\033[34mApplying RunLoop::Ipa patch.\033[0m" # @!visibility private module RunLoop # A model of the an .ipa - a application binary for iOS devices. class Ipa # The path to this .ipa. # @!attribute [r] path # @return [String] A path to this .ipa. attr_reader :path # The bundle identifier of this ipa. # @!attribute [r] bundle_identifier # @return [String] The bundle identifier of this ipa; obtained by inspecting # the app's Info.plist. attr_reader :bundle_identifier # Create a new ipa instance. # @param [String] path_to_ipa The path the .ipa file. # @return [Calabash::Ipa] A new ipa instance. # @raise [RuntimeError] If the file does not exist. # @raise [RuntimeError] If the file does not end in .ipa. def initialize(path_to_ipa) unless File.exist? path_to_ipa raise "Expected an ipa at '#{path_to_ipa}'" end unless path_to_ipa.end_with?('.ipa') raise "Expected '#{path_to_ipa}' to be an ipa" end @path = path_to_ipa end # @!visibility private def to_s "#<Ipa: #{bundle_identifier}: '#{path}'>" end # The bundle identifier of this ipa. # @return [String] A string representation of this ipa's CFBundleIdentifier # @raise [RuntimeError] If ipa does not expand into a Payload/<app name>.app # directory. # @raise [RuntimeError] If an Info.plist does exist in the .app. def bundle_identifier unless File.exist?(bundle_dir) raise "Expected a '#{File.basename(path).split('.').first}.app'\nat path '#{payload_dir}'" end @bundle_identifier ||= lambda { info_plist_path = File.join(bundle_dir, 'Info.plist') unless File.exist? info_plist_path raise "Expected an 'Info.plist' at '#{bundle_dir}'" end pbuddy = RunLoop::PlistBuddy.new pbuddy.plist_read('CFBundleIdentifier', info_plist_path) }.call end private def tmpdir @tmpdir ||= Dir.mktmpdir end def payload_dir @payload_dir ||= lambda { FileUtils.cp(path, tmpdir) zip_path = File.join(tmpdir, File.basename(path)) Dir.chdir(tmpdir) do system('unzip', *['-q', zip_path]) end File.join(tmpdir, 'Payload') }.call end def bundle_dir @bundle_dir ||= lambda { Dir.glob(File.join(payload_dir, '*')).detect {|f| File.directory?(f) && f.end_with?('.app')} }.call end end end end