run_loop_tcc 2.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/bin/run-loop +19 -0
- data/lib/run_loop/abstract.rb +18 -0
- data/lib/run_loop/app.rb +372 -0
- data/lib/run_loop/cache/cache.rb +68 -0
- data/lib/run_loop/cli/cli.rb +48 -0
- data/lib/run_loop/cli/codesign.rb +24 -0
- data/lib/run_loop/cli/errors.rb +11 -0
- data/lib/run_loop/cli/instruments.rb +160 -0
- data/lib/run_loop/cli/locale.rb +31 -0
- data/lib/run_loop/cli/simctl.rb +257 -0
- data/lib/run_loop/cli/tcc.rb +139 -0
- data/lib/run_loop/codesign.rb +76 -0
- data/lib/run_loop/core.rb +902 -0
- data/lib/run_loop/core_simulator.rb +960 -0
- data/lib/run_loop/detect_aut/detect.rb +185 -0
- data/lib/run_loop/detect_aut/errors.rb +126 -0
- data/lib/run_loop/detect_aut/xamarin_studio.rb +46 -0
- data/lib/run_loop/detect_aut/xcode.rb +157 -0
- data/lib/run_loop/device.rb +722 -0
- data/lib/run_loop/device_agent/app/CBX-Runner.app.zip +0 -0
- data/lib/run_loop/device_agent/bin/xctestctl +0 -0
- data/lib/run_loop/device_agent/cbxrunner.rb +156 -0
- data/lib/run_loop/device_agent/frameworks/Frameworks.zip +0 -0
- data/lib/run_loop/device_agent/frameworks.rb +65 -0
- data/lib/run_loop/device_agent/ipa/CBX-Runner.app.zip +0 -0
- data/lib/run_loop/device_agent/launcher.rb +51 -0
- data/lib/run_loop/device_agent/xcodebuild.rb +91 -0
- data/lib/run_loop/device_agent/xctestctl.rb +109 -0
- data/lib/run_loop/directory.rb +179 -0
- data/lib/run_loop/dnssd.rb +148 -0
- data/lib/run_loop/dot_dir.rb +87 -0
- data/lib/run_loop/dylib_injector.rb +145 -0
- data/lib/run_loop/encoding.rb +56 -0
- data/lib/run_loop/environment.rb +361 -0
- data/lib/run_loop/fifo.rb +40 -0
- data/lib/run_loop/host_cache.rb +128 -0
- data/lib/run_loop/http/error.rb +15 -0
- data/lib/run_loop/http/request.rb +44 -0
- data/lib/run_loop/http/retriable_client.rb +166 -0
- data/lib/run_loop/http/server.rb +17 -0
- data/lib/run_loop/instruments.rb +436 -0
- data/lib/run_loop/ipa.rb +142 -0
- data/lib/run_loop/l10n.rb +93 -0
- data/lib/run_loop/language.rb +63 -0
- data/lib/run_loop/lipo.rb +132 -0
- data/lib/run_loop/lldb.rb +52 -0
- data/lib/run_loop/locale.rb +101 -0
- data/lib/run_loop/logging.rb +111 -0
- data/lib/run_loop/otool.rb +76 -0
- data/lib/run_loop/patches/awesome_print.rb +17 -0
- data/lib/run_loop/physical_device/life_cycle.rb +268 -0
- data/lib/run_loop/plist_buddy.rb +189 -0
- data/lib/run_loop/process_terminator.rb +128 -0
- data/lib/run_loop/process_waiter.rb +117 -0
- data/lib/run_loop/regex.rb +19 -0
- data/lib/run_loop/shell.rb +103 -0
- data/lib/run_loop/sim_control.rb +1264 -0
- data/lib/run_loop/simctl.rb +275 -0
- data/lib/run_loop/sqlite.rb +61 -0
- data/lib/run_loop/strings.rb +88 -0
- data/lib/run_loop/tcc/TCC.db +0 -0
- data/lib/run_loop/tcc/tcc.rb +240 -0
- data/lib/run_loop/template.rb +61 -0
- data/lib/run_loop/version.rb +182 -0
- data/lib/run_loop/xcode.rb +318 -0
- data/lib/run_loop/xcrun.rb +107 -0
- data/lib/run_loop/xcuitest.rb +550 -0
- data/lib/run_loop.rb +230 -0
- data/plists/simctl/com.apple.UIAutomation.plist +0 -0
- data/plists/simctl/com.apple.UIAutomationPlugIn.plist +0 -0
- data/scripts/calabash_script_uia.js +28184 -0
- data/scripts/lib/json2.min.js +26 -0
- data/scripts/lib/log.js +26 -0
- data/scripts/lib/on_alert.js +224 -0
- data/scripts/read-cmd.sh +2 -0
- data/scripts/run_dismiss_location.js +89 -0
- data/scripts/run_loop_basic.js +34 -0
- data/scripts/run_loop_fast_uia.js +188 -0
- data/scripts/run_loop_host.js +117 -0
- data/scripts/run_loop_shared_element.js +125 -0
- data/scripts/timeout3 +23 -0
- data/scripts/udidetect +0 -0
- data/vendor-licenses/FBSimulatorControl.LICENSE +30 -0
- data/vendor-licenses/xctestctl.LICENSE +32 -0
- metadata +443 -0
@@ -0,0 +1,185 @@
|
|
1
|
+
module RunLoop
|
2
|
+
|
3
|
+
# @!visibility private
|
4
|
+
module DetectAUT
|
5
|
+
|
6
|
+
# @!visibility private
|
7
|
+
def self.detect_app_under_test(options)
|
8
|
+
app = self.detect_app(options)
|
9
|
+
if app.is_a?(RunLoop::App) || app.is_a?(RunLoop::Ipa)
|
10
|
+
{
|
11
|
+
:app => app,
|
12
|
+
:bundle_id => app.bundle_identifier,
|
13
|
+
:is_ipa => app.is_a?(RunLoop::Ipa)
|
14
|
+
}
|
15
|
+
else
|
16
|
+
{
|
17
|
+
:app => nil,
|
18
|
+
:bundle_id => app,
|
19
|
+
:is_ipa => false
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# @!visibility private
|
25
|
+
class Detect
|
26
|
+
include RunLoop::DetectAUT::Errors
|
27
|
+
include RunLoop::DetectAUT::XamarinStudio
|
28
|
+
include RunLoop::DetectAUT::Xcode
|
29
|
+
|
30
|
+
# @!visibility private
|
31
|
+
DEFAULTS = {
|
32
|
+
:search_depth => 10
|
33
|
+
}
|
34
|
+
|
35
|
+
# @!visibility private
|
36
|
+
def app_for_simulator
|
37
|
+
path = RunLoop::Environment.path_to_app_bundle
|
38
|
+
return RunLoop::App.new(path) if path
|
39
|
+
|
40
|
+
if xcode_project?
|
41
|
+
apps, search_dirs = detect_xcode_apps
|
42
|
+
elsif xamarin_project?
|
43
|
+
search_dirs = [solution_directory]
|
44
|
+
apps = candidate_apps(search_dirs.first)
|
45
|
+
else
|
46
|
+
search_dirs = [Dir.pwd]
|
47
|
+
apps = candidate_apps(search_dirs.first)
|
48
|
+
end
|
49
|
+
|
50
|
+
if apps.empty?
|
51
|
+
raise_no_simulator_app_found(search_dirs, DEFAULTS[:search_depth])
|
52
|
+
end
|
53
|
+
|
54
|
+
app = select_most_recent_app(apps)
|
55
|
+
|
56
|
+
RunLoop.log_info2("Detected app at path:")
|
57
|
+
RunLoop.log_info2("#{app.path}")
|
58
|
+
time_str = mtime(app).strftime("%a %d %b %Y %H:%M:%S %Z")
|
59
|
+
RunLoop.log_info2("Modification time of app: #{time_str}")
|
60
|
+
RunLoop.log_info2("If this is incorrect, set the APP variable and/or rebuild your app")
|
61
|
+
RunLoop.log_info2("It is your responsibility to ensure you are testing the right app.")
|
62
|
+
|
63
|
+
app
|
64
|
+
end
|
65
|
+
|
66
|
+
# @!visibility private
|
67
|
+
# @param [Array<RunLoop::Detect>] apps
|
68
|
+
def select_most_recent_app(apps)
|
69
|
+
apps.max do |a, b|
|
70
|
+
mtime(a).to_i <=> mtime(b).to_i
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# @!visibility private
|
75
|
+
# @param [String] bundle_path
|
76
|
+
def app_with_bundle(bundle_path)
|
77
|
+
RunLoop::App.new(bundle_path)
|
78
|
+
end
|
79
|
+
|
80
|
+
# @!visibility private
|
81
|
+
# @param [String] base_dir where to start the recursive search
|
82
|
+
def candidate_apps(base_dir)
|
83
|
+
candidates = []
|
84
|
+
|
85
|
+
globs = globs_for_app_search(base_dir)
|
86
|
+
Dir.glob(globs).each do |bundle_path|
|
87
|
+
# Gems, like run-loop, can contain *.app if the user is building
|
88
|
+
# from :git =>, :github =>, or :path => sources.
|
89
|
+
next if bundle_path[/vendor\/cache/, 0] != nil
|
90
|
+
app = app_or_nil(bundle_path)
|
91
|
+
candidates << app if app
|
92
|
+
end
|
93
|
+
candidates
|
94
|
+
end
|
95
|
+
|
96
|
+
# @!visibility private
|
97
|
+
# @param [String] bundle_path path to .app
|
98
|
+
def app_or_nil(bundle_path)
|
99
|
+
return nil if !RunLoop::App.valid?(bundle_path)
|
100
|
+
|
101
|
+
app = app_with_bundle(bundle_path)
|
102
|
+
if app.simulator? && app.calabash_server_version
|
103
|
+
app
|
104
|
+
else
|
105
|
+
nil
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# @!visibility private
|
110
|
+
# @param [RunLoop::Detect] app
|
111
|
+
def mtime(app)
|
112
|
+
path = File.join(app.path, app.executable_name)
|
113
|
+
File.mtime(path)
|
114
|
+
end
|
115
|
+
|
116
|
+
# @!visibility private
|
117
|
+
def globs_for_app_search(base_dir)
|
118
|
+
search_depth = DEFAULTS[:search_depth]
|
119
|
+
Array.new(search_depth) do |depth|
|
120
|
+
File.join(base_dir, *Array.new(depth) { |_| "*"}, "*.app")
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
# @!visibility private
|
128
|
+
def self.app_from_options(options)
|
129
|
+
options[:app] || options[:bundle_id]
|
130
|
+
end
|
131
|
+
|
132
|
+
# @!visibility private
|
133
|
+
def self.app_from_environment
|
134
|
+
app_bundle_path = RunLoop::Environment.path_to_app_bundle
|
135
|
+
|
136
|
+
candidate = app_bundle_path
|
137
|
+
if app_bundle_path && !File.exist?(app_bundle_path)
|
138
|
+
candidate = File.basename(app_bundle_path)
|
139
|
+
end
|
140
|
+
|
141
|
+
candidate || RunLoop::Environment.bundle_id
|
142
|
+
end
|
143
|
+
|
144
|
+
# @!visibility private
|
145
|
+
def self.app_from_constant
|
146
|
+
(defined?(APP_BUNDLE_PATH) && APP_BUNDLE_PATH) ||
|
147
|
+
(defined?(APP) && APP)
|
148
|
+
end
|
149
|
+
|
150
|
+
# @!visibility private
|
151
|
+
def self.app_from_opts_or_env_or_constant(options)
|
152
|
+
self.app_from_options(options) ||
|
153
|
+
self.app_from_environment ||
|
154
|
+
self.app_from_constant
|
155
|
+
end
|
156
|
+
|
157
|
+
# @!visibility private
|
158
|
+
def self.detector
|
159
|
+
RunLoop::DetectAUT::Detect.new
|
160
|
+
end
|
161
|
+
|
162
|
+
# @!visibility private
|
163
|
+
def self.detect_app(options)
|
164
|
+
app = self.app_from_opts_or_env_or_constant(options)
|
165
|
+
|
166
|
+
# Options or constant defined an instance of App or Ipa
|
167
|
+
return app if app && (app.is_a?(RunLoop::App) || app.is_a?(RunLoop::Ipa))
|
168
|
+
|
169
|
+
# User provided no information, so we attempt to auto detect
|
170
|
+
if app.nil? || app == ""
|
171
|
+
return self.detector.app_for_simulator
|
172
|
+
end
|
173
|
+
|
174
|
+
extension = File.extname(app)
|
175
|
+
if extension == ".ipa" && File.exist?(app)
|
176
|
+
RunLoop::Ipa.new(app)
|
177
|
+
elsif extension == ".app" && File.exist?(app)
|
178
|
+
RunLoop::App.new(app)
|
179
|
+
else
|
180
|
+
# Probably a bundle identifier.
|
181
|
+
app
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module RunLoop
|
2
|
+
|
3
|
+
# @!visibility private
|
4
|
+
class SolutionMissingError < RuntimeError ; end
|
5
|
+
|
6
|
+
# @!visibility private
|
7
|
+
class XcodeprojMissingError < RuntimeError; end
|
8
|
+
|
9
|
+
# @!visibility private
|
10
|
+
class MultipleXcodeprojError < RuntimeError; end
|
11
|
+
|
12
|
+
# @!visibility private
|
13
|
+
class NoSimulatorAppFoundError < RuntimeError; end
|
14
|
+
|
15
|
+
# @!visibility private
|
16
|
+
module DetectAUT
|
17
|
+
|
18
|
+
# @!visibility private
|
19
|
+
module Errors
|
20
|
+
|
21
|
+
# @!visibility private
|
22
|
+
#
|
23
|
+
# Raised when XCODEPROJ is defined, but does not exist
|
24
|
+
def raise_xcodeproj_missing(xcodeproj)
|
25
|
+
raise RunLoop::XcodeprojMissingError,
|
26
|
+
%Q[The XCODEPROJ environment variable has been set to:
|
27
|
+
|
28
|
+
#{xcodeproj}
|
29
|
+
|
30
|
+
but no directory exists at that path.
|
31
|
+
|
32
|
+
You should only set XCODEPROJ variable if your Calabash project has more than
|
33
|
+
one .xcodeproj directory or your .xcodeproj directory is located above the
|
34
|
+
current directory (where you run `cucumber` from). Calabash will discover the
|
35
|
+
.xcodeproj if is below the current working directory.
|
36
|
+
|
37
|
+
# .xcodeproj is above the working directory
|
38
|
+
$ ls ../*.xcodeproj
|
39
|
+
MyApp.xcodeproj
|
40
|
+
|
41
|
+
$ XCODEPROJ=../*.xcodeproj cucumber
|
42
|
+
|
43
|
+
# There is more than one .xcodeproj
|
44
|
+
$ ls *.xcodeproj
|
45
|
+
MyiOSApp.xcodeproj
|
46
|
+
MyMacApp.xcodeproj
|
47
|
+
|
48
|
+
$ XCODEPROJ=MyiOSApp.xcodeproj
|
49
|
+
]
|
50
|
+
end
|
51
|
+
|
52
|
+
# @!visibility private
|
53
|
+
#
|
54
|
+
# Raised when there are more than > 1 .xcodeproj in **/*
|
55
|
+
# Is not raised when there are 0 .xcodeproj in **/*
|
56
|
+
#
|
57
|
+
# @param [Array<String>] projects a list of paths to .xcodeproj
|
58
|
+
def raise_multiple_xcodeproj(projects)
|
59
|
+
raise RunLoop::MultipleXcodeprojError,
|
60
|
+
%Q[Found multiple .xcodeproj directories:
|
61
|
+
|
62
|
+
#{projects.join($-0)}
|
63
|
+
|
64
|
+
Which project contains the target of the application you are trying to test?
|
65
|
+
|
66
|
+
Set the XCODEPROJ variable to specify the correct .xcodeproj directory.
|
67
|
+
|
68
|
+
# Examples
|
69
|
+
$ XCODEPROJ="../MyApp.xcodeproj" cucumber
|
70
|
+
$ XCODEPROJ="iOS/MyApp.xcodeproj" cucumber
|
71
|
+
]
|
72
|
+
end
|
73
|
+
|
74
|
+
# @!visibility private
|
75
|
+
#
|
76
|
+
# Raised when SOLUTION is defined but does not exist
|
77
|
+
def raise_solution_missing(solution)
|
78
|
+
raise RunLoop::SolutionMissingError,
|
79
|
+
%Q[The SOLUTION environment variable has been set to:
|
80
|
+
|
81
|
+
#{solution}
|
82
|
+
|
83
|
+
but no solution exists at that path.
|
84
|
+
|
85
|
+
You should only set SOLUTION variable if your .sln is not located in
|
86
|
+
the current directory or in the directory just above the current
|
87
|
+
directory (where you run `cucumber` from). Calabash will discover the
|
88
|
+
.snl if it is in the current working directory or the directory just
|
89
|
+
above.
|
90
|
+
|
91
|
+
# Calabash will discover solution - don't set SOLUTION
|
92
|
+
$ ls *.sln => MyApp.sln
|
93
|
+
$ ls ../*.sln => MyApp.sln
|
94
|
+
|
95
|
+
# Calabash will _not_ discover solution
|
96
|
+
$ ls ../../*.sln => MyApp.sln
|
97
|
+
$ SOLUTION=../../MyApp.sln cucumber
|
98
|
+
|
99
|
+
$ ls project/*.sln => MyApp.sln
|
100
|
+
$ SOLUTION=project/MyApp.sln cucumber
|
101
|
+
|
102
|
+
$ ls ~/some/other/directory/*.sln => MyApp.sln
|
103
|
+
$ SOLUTION=~/some/other/directory/MyApp.sln
|
104
|
+
]
|
105
|
+
end
|
106
|
+
|
107
|
+
# @!visibility private
|
108
|
+
# Raised when no app can found by the discovery algorithm
|
109
|
+
def raise_no_simulator_app_found(search_directories, search_depth)
|
110
|
+
raise RunLoop::NoSimulatorAppFoundError,
|
111
|
+
%Q[Recursively searched these directories to depth #{search_depth}:
|
112
|
+
|
113
|
+
#{search_directories.join($-0)}
|
114
|
+
|
115
|
+
but could not find any .app for the simulator that links the Calabash iOS server.
|
116
|
+
|
117
|
+
Make sure you have built your app for a simulator target from Xcode.
|
118
|
+
|
119
|
+
If you are testing a stand-alone .app (you don't have an Xcode project), put
|
120
|
+
your .app in the same directory (or below) the directory you run `cucumber` from.
|
121
|
+
]
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module RunLoop
|
2
|
+
# @!visibility private
|
3
|
+
module DetectAUT
|
4
|
+
|
5
|
+
# @!visibility private
|
6
|
+
module XamarinStudio
|
7
|
+
|
8
|
+
# @!visibility private
|
9
|
+
def xamarin_project?
|
10
|
+
solution_directory != nil
|
11
|
+
end
|
12
|
+
|
13
|
+
# @!visibility private
|
14
|
+
def solution_directory
|
15
|
+
solution = RunLoop::Environment.solution
|
16
|
+
|
17
|
+
if solution && !File.exist?(solution)
|
18
|
+
raise_solution_missing(solution)
|
19
|
+
end
|
20
|
+
|
21
|
+
# SOLUTION defined and exists
|
22
|
+
return File.dirname(solution) if solution
|
23
|
+
|
24
|
+
solution_dir = find_solution_directory
|
25
|
+
return nil if solution_dir.nil?
|
26
|
+
|
27
|
+
solution_dir
|
28
|
+
end
|
29
|
+
|
30
|
+
# @!visibility private
|
31
|
+
def find_solution_directory
|
32
|
+
pwd = Dir.pwd
|
33
|
+
solutions = Dir.glob("#{pwd}/*.sln")
|
34
|
+
|
35
|
+
if solutions.empty?
|
36
|
+
solutions = Dir.glob("#{pwd}/../*.sln")
|
37
|
+
end
|
38
|
+
|
39
|
+
return nil if solutions.empty?
|
40
|
+
|
41
|
+
File.expand_path(File.dirname(solutions.first))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
@@ -0,0 +1,157 @@
|
|
1
|
+
module RunLoop
|
2
|
+
# @!visibility private
|
3
|
+
module DetectAUT
|
4
|
+
# @!visibility private
|
5
|
+
module Xcode
|
6
|
+
|
7
|
+
# @!visibility private
|
8
|
+
def xcode_project?
|
9
|
+
xcodeproj != nil
|
10
|
+
end
|
11
|
+
|
12
|
+
# @!visibility private
|
13
|
+
def xcodeproj
|
14
|
+
xcodeproj = RunLoop::Environment.xcodeproj
|
15
|
+
|
16
|
+
if xcodeproj && !File.directory?(xcodeproj)
|
17
|
+
raise_xcodeproj_missing(xcodeproj)
|
18
|
+
end
|
19
|
+
|
20
|
+
# XCODEPROJ defined and exists
|
21
|
+
return xcodeproj if xcodeproj
|
22
|
+
|
23
|
+
projects = find_xcodeproj
|
24
|
+
|
25
|
+
return nil if projects.empty?
|
26
|
+
return projects[0] if projects.count == 1
|
27
|
+
|
28
|
+
raise_multiple_xcodeproj(projects)
|
29
|
+
end
|
30
|
+
|
31
|
+
# @!visibility private
|
32
|
+
def find_xcodeproj
|
33
|
+
xcode_projects = []
|
34
|
+
Dir.glob("#{Dir.pwd}/**/*.xcodeproj").each do |path|
|
35
|
+
next if ignore_xcodeproj?(path)
|
36
|
+
xcode_projects << path
|
37
|
+
end
|
38
|
+
xcode_projects
|
39
|
+
end
|
40
|
+
|
41
|
+
# @!visibility private
|
42
|
+
def ignore_xcodeproj?(path)
|
43
|
+
path[/CordovaLib/, 0] ||
|
44
|
+
path[/Pods/, 0] ||
|
45
|
+
path[/Carthage/, 0] ||
|
46
|
+
path[/Airship(Kit|Lib)/, 0] ||
|
47
|
+
path[/google-plus-ios-sdk/, 0]
|
48
|
+
end
|
49
|
+
|
50
|
+
# @!visibility private
|
51
|
+
def detect_xcode_apps
|
52
|
+
dirs_to_search = derived_data_search_dirs
|
53
|
+
|
54
|
+
dir_from_prefs = xcode_preferences_search_dir
|
55
|
+
if dir_from_prefs
|
56
|
+
dirs_to_search << dir_from_prefs
|
57
|
+
end
|
58
|
+
|
59
|
+
dirs_to_search << Dir.pwd
|
60
|
+
dirs_to_search.uniq!
|
61
|
+
|
62
|
+
apps = []
|
63
|
+
dirs_to_search.each do |dir|
|
64
|
+
# defined in detect_aut/apps.rb
|
65
|
+
candidates = candidate_apps(dir)
|
66
|
+
apps = apps.concat(candidates)
|
67
|
+
end
|
68
|
+
|
69
|
+
return apps, dirs_to_search
|
70
|
+
end
|
71
|
+
|
72
|
+
# @!visibility private
|
73
|
+
PLIST_KEYS = {
|
74
|
+
:workspace => "WorkspacePath",
|
75
|
+
:shared_build => "IDESharedBuildFolderName",
|
76
|
+
:custom_build => "IDECustomBuildProductsPath"
|
77
|
+
}
|
78
|
+
|
79
|
+
# @!visibility private
|
80
|
+
# TODO Needs unit tests
|
81
|
+
def derived_data_search_dirs
|
82
|
+
project = xcodeproj
|
83
|
+
project_name = File.basename(project)
|
84
|
+
matches = []
|
85
|
+
|
86
|
+
# WorkspacePath could be a .xcodeproj or .xcworkspace
|
87
|
+
#
|
88
|
+
# # Exact match.
|
89
|
+
# xcodeproj = path/to/MyApp/MyApp.xcodeproj
|
90
|
+
# WorkspacePath = path/to/MyApp/MyApp.xcodeproj
|
91
|
+
#
|
92
|
+
# # CocoaPods projects are often configured like this. As are legacy
|
93
|
+
# # projects that have been added to a new workspace.
|
94
|
+
# xcodeproj = path/to/MyApp/MyApp.xcodeproj
|
95
|
+
# WorkspacePath = path/to/MyApp/MyApp.xcworkspace
|
96
|
+
#
|
97
|
+
# # This is the Xcode default when creating new iOS project
|
98
|
+
# xcodeproj = path/to/MyApp/MyApp/MyApp.xcodeproj
|
99
|
+
# WorkspacePath = path/to/MyApp/MyApp.xcworkspace
|
100
|
+
key = PLIST_KEYS[:workspace]
|
101
|
+
Dir.glob("#{derived_data}/*/info.plist") do |plist|
|
102
|
+
workspace = pbuddy.plist_read(key, plist)
|
103
|
+
if workspace == project
|
104
|
+
matches << File.dirname(plist)
|
105
|
+
else
|
106
|
+
base_dir = File.dirname(workspace)
|
107
|
+
if File.exist?(File.join(base_dir, project_name))
|
108
|
+
matches << File.dirname(plist)
|
109
|
+
elsif !Dir.glob("#{File.dirname(workspace)}/*/#{project_name}").empty?
|
110
|
+
matches << File.dirname(plist)
|
111
|
+
elsif !Dir.glob("#{File.dirname(workspace)}/**/#{project_name}").empty?
|
112
|
+
matches << File.dirname(plist)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
matches
|
117
|
+
end
|
118
|
+
|
119
|
+
# @!visibility private
|
120
|
+
def xcode_preferences_search_dir
|
121
|
+
plist = xcode_preferences_plist
|
122
|
+
|
123
|
+
shared_build_folder = pbuddy.plist_read(PLIST_KEYS[:shared_build], plist)
|
124
|
+
custom_build_folder = pbuddy.plist_read(PLIST_KEYS[:custom_build], plist)
|
125
|
+
|
126
|
+
if shared_build_folder
|
127
|
+
File.join(derived_data, shared_build_folder, "Products")
|
128
|
+
elsif custom_build_folder
|
129
|
+
File.join(File.dirname(xcodeproj), custom_build_folder)
|
130
|
+
else
|
131
|
+
nil
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# @!visibility private
|
136
|
+
def derived_data
|
137
|
+
RunLoop::Environment.derived_data ||
|
138
|
+
File.join(RunLoop::Environment.user_home_directory,
|
139
|
+
"Library", "Developer", "Xcode", "DerivedData")
|
140
|
+
end
|
141
|
+
|
142
|
+
# @!visibility private
|
143
|
+
def xcode_preferences_plist
|
144
|
+
File.join(RunLoop::Environment.user_home_directory,
|
145
|
+
"Library",
|
146
|
+
"Preferences",
|
147
|
+
"com.apple.dt.Xcode.plist")
|
148
|
+
end
|
149
|
+
|
150
|
+
# @!visibility private
|
151
|
+
def pbuddy
|
152
|
+
@pbuddy ||= RunLoop::PlistBuddy.new
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|