lib/run_loop/app.rb in run_loop-2.0.5 vs lib/run_loop/app.rb in run_loop-2.0.6

- old
+ new

@@ -12,10 +12,24 @@ # # @param [String] app_bundle_path A path to a .app # @return [RunLoop::App] A instance of App with a path. def initialize(app_bundle_path) @path = File.expand_path(app_bundle_path) + + if !App.valid?(app_bundle_path) + raise ArgumentError, +%Q{App does not exist at path or is not an app bundle. + +#{app_bundle_path} + +Bundle must: + +1. be a directory that exists, +2. have a .app extension, +3. and contain an Info.plist. +} + end end # @!visibility private def to_s "#<APP: #{path}>" @@ -26,23 +40,27 @@ to_s end # Is this a valid app? def valid? - [File.exist?(path), - File.directory?(path), - File.extname(path) == '.app'].all? + App.valid?(path) end + # @!visibility private + def self.valid?(app_bundle_path) + return false if app_bundle_path.nil? + + File.exist?(app_bundle_path) && + File.directory?(app_bundle_path) && + File.extname(app_bundle_path) == '.app' && + File.exist?(File.join(app_bundle_path, "Info.plist")) + end + # Returns the Info.plist path. # @raise [RuntimeError] If there is no Info.plist. def info_plist_path - info_plist = File.join(path, 'Info.plist') - unless File.exist?(info_plist) - raise "Expected an Info.plist at '#{path}'" - end - info_plist + @info_plist_path ||= File.join(path, 'Info.plist') end # Inspects the app's Info.plist for the bundle identifier. # @return [String] The value of CFBundleIdentifier. # @raise [RuntimeError] If the plist cannot be read or the @@ -67,34 +85,120 @@ identifier end # Inspects the app's file for the server version def calabash_server_version - if valid? - path_to_bin = File.join(path, executable_name) - xcrun ||= RunLoop::Xcrun.new - hash = xcrun.exec(["strings", path_to_bin]) - unless hash.nil? - version_str = hash[:out][/CALABASH VERSION: \d+\.\d+\.\d+/, 0] - unless version_str.nil? || version_str == "" - server_ver = version_str.split(":")[1].delete(' ') - RunLoop::Version.new(server_ver) - end + version = nil + executables.each do |executable| + version = strings(executable).server_version + break if version + end + version + end + + # @!visibility private + # Collects the paths to executables in the bundle. + def executables + executables = [] + Dir.glob("#{path}/**/*") do |file| + next if File.directory?(file) + next if skip_executable_check?(file) + if otool(file).executable? + executables << file end - else - raise 'Path is not valid' end + executables end # Returns the sha1 of the application. def sha1 RunLoop::Directory.directory_digest(path) end private + # @!visibility private def plist_buddy @plist_buddy ||= RunLoop::PlistBuddy.new end + # @!visibility private + # An otool factory. + def otool(file) + RunLoop::Otool.new(file) + end + + # @!visibility private + # A strings factory + def strings(file) + RunLoop::Strings.new(file) + end + + # @!visibility private + def skip_executable_check?(file) + image?(file) || + text?(file) || + plist?(file) || + lproj_asset?(file) || + code_signing_asset?(file) || + core_data_asset?(file) + end + + # @!visibility private + def text?(file) + extension = File.extname(file) + + extension == ".txt" || + extension == ".md" || + extension == ".html" || + extension == ".xml" || + extension == ".json" || + extension == ".yaml" || + extension == ".yml" || + extension == ".rtf" || + file[/NOTICE|LICENSE|README|ABOUT/, 0] + end + + # @!visibility private + def image?(file) + file[/jpeg|jpg|gif|png|tiff|svg|pdf|car|iTunesArtwork/, 0] + end + + # @!visibility private + def plist?(file) + File.extname(file) == ".plist" + end + + # @!visibility private + def lproj_asset?(file) + extension = File.extname(file) + + file[/lproj/, 0] || + file[/storyboard/, 0] || + extension == ".strings" || + extension == ".xib" || + extension == ".nib" + end + + # @!visibility private + def code_signing_asset?(file) + name = File.basename(file) + extension = File.extname(file) + + name == "PkgInfo" || + name == "embedded" || + extension == ".mobileprovision" || + extension == ".xcent" || + file[/_CodeSignature/, 0] + end + + # @!visibility private + def core_data_asset?(file) + extension = File.extname(file) + + file[/momd/, 0] || + extension == ".mom" || + extension == ".db" + end end end +