From e2e478ef89a9d0b26c419125249397c6cf76a912 Mon Sep 17 00:00:00 2001 From: Arkadiusz Konopacki Date: Wed, 6 Jan 2016 12:24:15 +0100 Subject: [PATCH 01/10] SimLauncher: fix autodetection of app bundle 0.17.0 Cannot automatically detect app #959 --- .../calabash-cucumber/launch/simulator_launcher.rb | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb b/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb index 5409ff5a7..e02611573 100644 --- a/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb +++ b/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb @@ -251,8 +251,17 @@ def app_bundle_or_raise(path=nil, device_build_dir='iPhoneSimulator') puts('-'*37) end else - bo_dir = build_output_dir_for_project - sim_dirs = Dir.glob(File.join(bo_dir, '*-iphonesimulator', '*.app')) + search_dir = build_output_dir_for_project || DERIVED_DATA + sim_dirs = '' + apps = `find #{search_dir} -name "*.app" | sort -n`.split("\n") + apps.each do |app_path| + if app_path.split("/")[-2].include('iphonesimulator') + path_to_bin = app_path + "/" + app_path.split("/")[-1].split(".")[0] + if `xcrun strings "#{path_to_bin}" | grep -E 'CALABASH VERSION'`.include? "CALABASH VERSION" + sim_dirs = Dir.glob(app_path) + end + end + end if sim_dirs.empty? msg = ['Unable to auto detect APP_BUNDLE_PATH.'] From bf73acba0d5962c8061d8dfa855d6fe3491eddd3 Mon Sep 17 00:00:00 2001 From: Arkadiusz Konopacki Date: Tue, 12 Jan 2016 11:35:12 +0100 Subject: [PATCH 02/10] Updated executable auto detection --- .../lib/calabash-cucumber/launch/simulator_launcher.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb b/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb index e02611573..4423780da 100644 --- a/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb +++ b/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb @@ -256,7 +256,9 @@ def app_bundle_or_raise(path=nil, device_build_dir='iPhoneSimulator') apps = `find #{search_dir} -name "*.app" | sort -n`.split("\n") apps.each do |app_path| if app_path.split("/")[-2].include('iphonesimulator') - path_to_bin = app_path + "/" + app_path.split("/")[-1].split(".")[0] + app = RunLoop::App.new(app_path) + executable_name = app.executable_name + path_to_bin = app_path + "/" + executable_name if `xcrun strings "#{path_to_bin}" | grep -E 'CALABASH VERSION'`.include? "CALABASH VERSION" sim_dirs = Dir.glob(app_path) end From a2b4a680c74e9862d9ddc486c87dc03bb63afc3e Mon Sep 17 00:00:00 2001 From: Arkadiusz Konopacki Date: Tue, 12 Jan 2016 13:40:16 +0100 Subject: [PATCH 03/10] Fix searched dir in error message --- .../lib/calabash-cucumber/launch/simulator_launcher.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb b/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb index 4423780da..2ad30c4e7 100644 --- a/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb +++ b/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb @@ -268,7 +268,7 @@ def app_bundle_or_raise(path=nil, device_build_dir='iPhoneSimulator') if sim_dirs.empty? msg = ['Unable to auto detect APP_BUNDLE_PATH.'] msg << 'Have you built your app for simulator?' - msg << "Searched dir: #{bo_dir}" + msg << "Searched dir: #{search_dir}" msg << 'Please build your app from Xcode' msg << 'You should build the -cal target.' msg << '' From 5560af56df12a41abecd45490ea3e2c6f2766c49 Mon Sep 17 00:00:00 2001 From: Arkadiusz Konopacki Date: Tue, 12 Jan 2016 14:33:56 +0100 Subject: [PATCH 04/10] Minor fix in detecting iphonesimulator folder --- .../lib/calabash-cucumber/launch/simulator_launcher.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb b/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb index 2ad30c4e7..42c9ba8b8 100644 --- a/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb +++ b/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb @@ -255,7 +255,7 @@ def app_bundle_or_raise(path=nil, device_build_dir='iPhoneSimulator') sim_dirs = '' apps = `find #{search_dir} -name "*.app" | sort -n`.split("\n") apps.each do |app_path| - if app_path.split("/")[-2].include('iphonesimulator') + if app_path.split("/")[-2].include? 'iphonesimulator' app = RunLoop::App.new(app_path) executable_name = app.executable_name path_to_bin = app_path + "/" + executable_name From b60d7132d36f3d182dcc95751d3c8b04d3336be9 Mon Sep 17 00:00:00 2001 From: Arkadiusz Konopacki Date: Wed, 13 Jan 2016 12:36:01 +0100 Subject: [PATCH 05/10] Minor fixes after review --- .../lib/calabash-cucumber/launch/simulator_launcher.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb b/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb index 42c9ba8b8..785821964 100644 --- a/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb +++ b/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb @@ -255,10 +255,12 @@ def app_bundle_or_raise(path=nil, device_build_dir='iPhoneSimulator') sim_dirs = '' apps = `find #{search_dir} -name "*.app" | sort -n`.split("\n") apps.each do |app_path| - if app_path.split("/")[-2].include? 'iphonesimulator' + lipo = RunLoop::Lipo.new(app_path) + arches = lipo.info + if arches.include?("x86_64") || arches.include?("i386") app = RunLoop::App.new(app_path) executable_name = app.executable_name - path_to_bin = app_path + "/" + executable_name + path_to_bin = File.join(app_path, executable_name) if `xcrun strings "#{path_to_bin}" | grep -E 'CALABASH VERSION'`.include? "CALABASH VERSION" sim_dirs = Dir.glob(app_path) end From 9e6ba0bfe7c2a93fdd3e4a7da1abd39d991523d0 Mon Sep 17 00:00:00 2001 From: Arkadiusz Konopacki Date: Wed, 13 Jan 2016 13:43:21 +0100 Subject: [PATCH 06/10] Fixed find mechanism with correct order --- .../lib/calabash-cucumber/launch/simulator_launcher.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb b/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb index 785821964..f07dc1673 100644 --- a/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb +++ b/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb @@ -253,7 +253,7 @@ def app_bundle_or_raise(path=nil, device_build_dir='iPhoneSimulator') else search_dir = build_output_dir_for_project || DERIVED_DATA sim_dirs = '' - apps = `find #{search_dir} -name "*.app" | sort -n`.split("\n") + apps = `find #{search_dir} -type d -name "*.app" -exec stat -f "%m %N" {} \\; | sort -rn | cut -d" " -f2`.split("\n") apps.each do |app_path| lipo = RunLoop::Lipo.new(app_path) arches = lipo.info From 4dae3511260666f6408812cc4d91afced8e3661d Mon Sep 17 00:00:00 2001 From: Arkadiusz Konopacki Date: Wed, 13 Jan 2016 19:52:58 +0100 Subject: [PATCH 07/10] Added break to stop iterations after first file with calabash --- .../lib/calabash-cucumber/launch/simulator_launcher.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb b/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb index f07dc1673..bfffa1657 100644 --- a/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb +++ b/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb @@ -263,6 +263,7 @@ def app_bundle_or_raise(path=nil, device_build_dir='iPhoneSimulator') path_to_bin = File.join(app_path, executable_name) if `xcrun strings "#{path_to_bin}" | grep -E 'CALABASH VERSION'`.include? "CALABASH VERSION" sim_dirs = Dir.glob(app_path) + break end end end From b1f0add44a44d790aaf68220f05cbf4301510c41 Mon Sep 17 00:00:00 2001 From: Arkadiusz Konopacki Date: Fri, 5 Feb 2016 14:15:46 +0100 Subject: [PATCH 08/10] Update patch to use app.calabash_server_version method Added UTF-8 filter to cut invalid byte sequence each replaced with find --- .../calabash-cucumber/launch/simulator_launcher.rb | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb b/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb index bfffa1657..b34f62457 100644 --- a/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb +++ b/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb @@ -253,17 +253,18 @@ def app_bundle_or_raise(path=nil, device_build_dir='iPhoneSimulator') else search_dir = build_output_dir_for_project || DERIVED_DATA sim_dirs = '' - apps = `find #{search_dir} -type d -name "*.app" -exec stat -f "%m %N" {} \\; | sort -rn | cut -d" " -f2`.split("\n") - apps.each do |app_path| + apps = `find #{search_dir} -type d -name "*.app" -exec stat -f "%m %N" {} \\; | sort -rn | cut -d" " -f2` + .encode('UTF-8', 'UTF-8', invalid: :replace, undef: :replace, replace: '') + .chars.select(&:valid_encoding?).join + .split("\n") + apps.find do |app_path| lipo = RunLoop::Lipo.new(app_path) arches = lipo.info if arches.include?("x86_64") || arches.include?("i386") app = RunLoop::App.new(app_path) - executable_name = app.executable_name - path_to_bin = File.join(app_path, executable_name) - if `xcrun strings "#{path_to_bin}" | grep -E 'CALABASH VERSION'`.include? "CALABASH VERSION" + if !app.calabash_server_version.nil? && + app.calabash_server_version.is_a?(RunLoop::Version) sim_dirs = Dir.glob(app_path) - break end end end From bcfb77ebd8d76fc50a188ea1716b7b320f736662 Mon Sep 17 00:00:00 2001 From: Joshua Moody Date: Mon, 15 Feb 2016 23:19:10 +0100 Subject: [PATCH 09/10] Detect app: extract search and select to methods and add examples --- .../launch/simulator_launcher.rb | 41 ++++- .../lib/launch/simulator_launcher_spec.rb | 143 ++++++++++++++++++ 2 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 calabash-cucumber/spec/lib/launch/simulator_launcher_spec.rb diff --git a/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb b/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb index b34f62457..2ee684f13 100644 --- a/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb +++ b/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb @@ -607,7 +607,46 @@ def version_check(version) _deprecated('0.9.169', 'check is now done in Launcher', :warn) raise(NotImplementedError, 'this method has been deprecated and will be removed') end - end + private + + # @!visibility private + def app(bundle_path) + RunLoop::App.new(bundle_path) + end + + # @!visibility private + def lipo(bundle_path) + RunLoop::Lipo.new(bundle_path) + end + + # @!visibility private + def collect_app_bundles(base_dir) + bundles = [] + + Dir.glob("#{base_dir}/**/*.app") do |bundle| + next if !RunLoop::App.valid?(bundle) + + lipo = lipo(bundle) + arches = lipo.info + if arches.include?("x86_64") || arches.include?("i386") + app = app(bundle) + if app.calabash_server_version + bundles << bundle + end + end + end + + bundles + end + + # @!visibility private + def select_most_recent_bundle(base_dir) + bundles = collect_app_bundles(base_dir) + bundles.max do |a, b| + File.mtime(a) <=> File.mtime(b) + end + end + end end end diff --git a/calabash-cucumber/spec/lib/launch/simulator_launcher_spec.rb b/calabash-cucumber/spec/lib/launch/simulator_launcher_spec.rb new file mode 100644 index 000000000..d69f8bd58 --- /dev/null +++ b/calabash-cucumber/spec/lib/launch/simulator_launcher_spec.rb @@ -0,0 +1,143 @@ + +describe Calabash::Cucumber::SimulatorLauncher do + let(:base_dir) { File.join("tmp", "bundle-detection") } + let(:a) { File.join(base_dir, "A.app") } + let(:b) { File.join(base_dir, "B.app") } + let(:c) { File.join(base_dir, "C.app") } + let(:d) { File.join(base_dir, "D.app") } + let(:launcher) { Calabash::Cucumber::SimulatorLauncher.new } + + before do + base_dir = File.join("tmp", "bundle-detection") + FileUtils.rm_rf(base_dir) + FileUtils.mkdir_p(base_dir) + + make_bundle = lambda do |bundle_path| + FileUtils.mkdir_p(bundle_path) + name = File.basename(bundle_path).split(".")[0] + FileUtils.touch(File.join(bundle_path, name)) + + pbuddy = RunLoop::PlistBuddy.new + info_plist = File.join(bundle_path, "Info.plist") + pbuddy.create_plist(info_plist) + bundle_id = "com.example.#{name}" + pbuddy.plist_set("CFBundleIdentifier", "string", bundle_id, info_plist) + pbuddy.plist_set("CFBundleExecutable", "string", name, info_plist) + end + + make_bundle.call(a) + make_bundle.call(b) + make_bundle.call(c) + make_bundle.call(d) + end + + describe "#collect_app_bundles" do + let(:app_a) { RunLoop::App.new(a) } + let(:app_b) { RunLoop::App.new(b) } + let(:app_c) { RunLoop::App.new(c) } + let(:app_d) { RunLoop::App.new(d) } + + let(:lipo_a) { RunLoop::Lipo.new(a) } + let(:lipo_b) { RunLoop::Lipo.new(b) } + let(:lipo_c) { RunLoop::Lipo.new(c) } + let(:lipo_d) { RunLoop::Lipo.new(d) } + + let(:v8) { RunLoop::Version.new("8.0") } + let(:v6) { RunLoop::Version.new("6.0") } + + let(:i386) { ["i386"] } + let(:x86_64) { ["x86_64"] } + let(:fat) { i386 + x86_64 } + + before do + allow(launcher).to receive(:app).with(a).and_return(app_a) + allow(launcher).to receive(:app).with(b).and_return(app_b) + allow(launcher).to receive(:app).with(c).and_return(app_c) + allow(launcher).to receive(:app).with(d).and_return(app_d) + + allow(launcher).to receive(:lipo).with(a).and_return(lipo_a) + allow(launcher).to receive(:lipo).with(b).and_return(lipo_b) + allow(launcher).to receive(:lipo).with(c).and_return(lipo_c) + allow(launcher).to receive(:lipo).with(d).and_return(lipo_d) + end + + it "collects valid bundles" do + expect(app_a).to receive(:calabash_server_version).and_return(v8) + expect(app_b).to receive(:calabash_server_version).and_return(v8) + expect(app_c).to receive(:calabash_server_version).and_return(v8) + expect(app_d).to receive(:calabash_server_version).and_return(v8) + + expect(lipo_a).to receive(:info).and_return(fat) + expect(lipo_b).to receive(:info).and_return(i386) + expect(lipo_c).to receive(:info).and_return(x86_64) + expect(lipo_d).to receive(:info).and_return(x86_64) + + actual = launcher.send(:collect_app_bundles, base_dir) + expected = [a, b, c, d] + expect(actual).to be == expected + end + + it "rejects invalid bundles" do + expect(RunLoop::App).to receive(:valid?).with(a).and_return false + expect(RunLoop::App).to receive(:valid?).with(b).and_return false + expect(RunLoop::App).to receive(:valid?).with(c).and_return false + expect(RunLoop::App).to receive(:valid?).with(d).and_return false + + actual = launcher.send(:collect_app_bundles, base_dir) + expect(actual).to be == [] + end + + it "rejects arm bundles" do + expect(app_b).to receive(:calabash_server_version).and_return(v8) + expect(app_c).to receive(:calabash_server_version).and_return(v8) + + expect(lipo_a).to receive(:info).and_return(["arm64"]) + expect(lipo_b).to receive(:info).and_return(i386) + expect(lipo_c).to receive(:info).and_return(x86_64) + expect(lipo_d).to receive(:info).and_return(["armv7"]) + + actual = launcher.send(:collect_app_bundles, base_dir) + expected = [b, c] + expect(actual).to be == expected + end + + it "rejects bundles without calabash server" do + expect(app_a).to receive(:calabash_server_version).and_return(v8) + expect(app_b).to receive(:calabash_server_version).and_return(nil) + expect(app_c).to receive(:calabash_server_version).and_return(nil) + expect(app_d).to receive(:calabash_server_version).and_return(v8) + + expect(lipo_a).to receive(:info).and_return(fat) + expect(lipo_b).to receive(:info).and_return(i386) + expect(lipo_c).to receive(:info).and_return(x86_64) + expect(lipo_d).to receive(:info).and_return(x86_64) + + actual = launcher.send(:collect_app_bundles, base_dir) + expected = [a, d] + expect(actual).to be == expected + end + end + + describe "#select_most_recent_bundle" do + it "returns nil if no bundles are collected" do + expect(launcher).to receive(:collect_app_bundles).with(base_dir).and_return([]) + + actual = launcher.send(:select_most_recent_bundle, base_dir) + expect(actual).to be == nil + end + + it "returns the most recently modified" do + array = [a, b, c, d] + expect(File).to receive(:mtime).with(a).at_least(:once).and_return(0) + expect(File).to receive(:mtime).with(b).at_least(:once).and_return(1) + expect(File).to receive(:mtime).with(c).at_least(:once).and_return(2) + expect(File).to receive(:mtime).with(d).at_least(:once).and_return(3) + + expect(launcher).to receive(:collect_app_bundles).with(base_dir).and_return(array) + + actual = launcher.send(:select_most_recent_bundle, base_dir) + expect(actual).to be == d + end + end +end + From f4a710d4369f310e665d1790344e14d057a91f08 Mon Sep 17 00:00:00 2001 From: Joshua Moody Date: Mon, 15 Feb 2016 23:23:23 +0100 Subject: [PATCH 10/10] Detect app: use methods we extracted * Improve error message when no .app can be found --- .../launch/simulator_launcher.rb | 77 +++++-------------- 1 file changed, 21 insertions(+), 56 deletions(-) diff --git a/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb b/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb index 2ee684f13..b5f64bd13 100644 --- a/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb +++ b/calabash-cucumber/lib/calabash-cucumber/launch/simulator_launcher.rb @@ -241,67 +241,32 @@ def app_bundle_or_raise(path=nil, device_build_dir='iPhoneSimulator') msg << "Make sure you build for Simulator and that you're using the Calabash components" raise msg.join("\n") end - if full_console_logging? - puts('-'*37) - puts "Auto detected APP_BUNDLE_PATH:\n\n" - - puts "APP_BUNDLE_PATH= '#{bundle_path}'\n\n" - puts 'Please verify!' - puts "If this is wrong please set it as APP_BUNDLE_PATH in features/support/01_launch.rb\n" - puts('-'*37) - end else search_dir = build_output_dir_for_project || DERIVED_DATA - sim_dirs = '' - apps = `find #{search_dir} -type d -name "*.app" -exec stat -f "%m %N" {} \\; | sort -rn | cut -d" " -f2` - .encode('UTF-8', 'UTF-8', invalid: :replace, undef: :replace, replace: '') - .chars.select(&:valid_encoding?).join - .split("\n") - apps.find do |app_path| - lipo = RunLoop::Lipo.new(app_path) - arches = lipo.info - if arches.include?("x86_64") || arches.include?("i386") - app = RunLoop::App.new(app_path) - if !app.calabash_server_version.nil? && - app.calabash_server_version.is_a?(RunLoop::Version) - sim_dirs = Dir.glob(app_path) - end - end - end - - if sim_dirs.empty? - msg = ['Unable to auto detect APP_BUNDLE_PATH.'] - msg << 'Have you built your app for simulator?' - msg << "Searched dir: #{search_dir}" - msg << 'Please build your app from Xcode' - msg << 'You should build the -cal target.' - msg << '' - msg << 'Alternatively, specify APP_BUNDLE_PATH in features/support/01_launch.rb' - msg << "This should point to the location of your built app linked with calabash.\n" - raise msg.join("\n") - end - preferred_dir = find_preferred_dir(sim_dirs) - if preferred_dir.nil? - msg = ['Error... Unable to find APP_BUNDLE_PATH.'] - msg << 'Cannot find a built app that is linked with calabash.framework' - msg << 'Please build your app from Xcode' - msg << 'You should build your calabash target.' - msg << '' - msg << 'Alternatively, specify APP_BUNDLE_PATH in features/support/01_launch.rb' - msg << "This should point to the location of your built app linked with calabash.\n" - raise msg.join("\n") - end - if full_console_logging? - puts('-'*37) - puts "Auto detected APP_BUNDLE_PATH:\n\n" + bundle_path = select_most_recent_bundle(search_dir) + + if bundle_path.nil? + raise RuntimeError, +%Q{ +Unable to auto detect a .app that is linked Calabash. + +Searched: #{search_dir} - puts "APP_BUNDLE_PATH=#{preferred_dir || sim_dirs[0]}\n\n" - puts 'Please verify!' - puts "If this is wrong please set it as APP_BUNDLE_PATH in features/support/01_launch.rb\n" - puts('-'*37) +Have you built your app for simulator? + +Please build your app from Xcode + +Alternatively, specify APP in features/support/01_launch.rb +or as an environment variable: + +$ APP=/path/to/Your.app bundle exec cucumber +} end - bundle_path = sim_dirs[0] end + + Calabash::Cucumber.log_debug("Auto detected app at path:") + Calabash::Cucumber.log_debug(bundle_path) + Calabash::Cucumber.log_debug("If this is incorrect, set the APP variable") bundle_path end