run_loop 2.0.7 → 2.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/run_loop.rb +4 -0
- data/lib/run_loop/app.rb +90 -19
- data/lib/run_loop/detect_aut/detect.rb +96 -0
- data/lib/run_loop/detect_aut/errors.rb +127 -0
- data/lib/run_loop/detect_aut/xamarin_studio.rb +46 -0
- data/lib/run_loop/detect_aut/xcode.rb +136 -0
- data/lib/run_loop/environment.rb +43 -0
- data/lib/run_loop/ipa.rb +5 -0
- data/lib/run_loop/otool.rb +1 -1
- data/lib/run_loop/version.rb +1 -1
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a796cf1b151815127a2c4ee38c6fadf13be9cef8
|
4
|
+
data.tar.gz: 40e6b8e223325fba4d2a13683afa1609b2f9348c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d0b6d5bb57703550c6592a5d665c1d11d74db9075bf8b688156e2f6094efd6ab0e3efc72c19e9080228f1da8d003f8d115382f804303228a091d05043d3a7309
|
7
|
+
data.tar.gz: 8b53742a9c3b4fe65036f387e93dd189ff350e57bd24ebd90bb7c24e1f6635543a675aafb9500bdf34b92640d61ed6adb5c8eb81e9c9833fcab2f6588d28d7a7
|
data/lib/run_loop.rb
CHANGED
@@ -17,6 +17,10 @@ require 'run_loop/plist_buddy'
|
|
17
17
|
require "run_loop/codesign"
|
18
18
|
require 'run_loop/app'
|
19
19
|
require 'run_loop/ipa'
|
20
|
+
require "run_loop/detect_aut/errors"
|
21
|
+
require "run_loop/detect_aut/xamarin_studio"
|
22
|
+
require "run_loop/detect_aut/xcode"
|
23
|
+
require "run_loop/detect_aut/detect"
|
20
24
|
require 'run_loop/sim_control'
|
21
25
|
require 'run_loop/device'
|
22
26
|
require 'run_loop/instruments'
|
data/lib/run_loop/app.rb
CHANGED
@@ -25,7 +25,8 @@ Bundle must:
|
|
25
25
|
|
26
26
|
1. be a directory that exists,
|
27
27
|
2. have a .app extension,
|
28
|
-
3.
|
28
|
+
3. contain an Info.plist,
|
29
|
+
4. and the app binary (CFBundleExecutable) must exist
|
29
30
|
}
|
30
31
|
end
|
31
32
|
end
|
@@ -49,10 +50,12 @@ Bundle must:
|
|
49
50
|
def self.valid?(app_bundle_path)
|
50
51
|
return false if app_bundle_path.nil?
|
51
52
|
|
52
|
-
File.
|
53
|
-
|
54
|
-
|
55
|
-
|
53
|
+
return false if !File.directory?(app_bundle_path)
|
54
|
+
return false if !File.extname(app_bundle_path) == ".app"
|
55
|
+
|
56
|
+
return false if !self.info_plist_exist?(app_bundle_path)
|
57
|
+
return false if !self.executable_file_exist?(app_bundle_path)
|
58
|
+
true
|
56
59
|
end
|
57
60
|
|
58
61
|
# Returns the Info.plist path.
|
@@ -66,7 +69,7 @@ Bundle must:
|
|
66
69
|
# @raise [RuntimeError] If the plist cannot be read or the
|
67
70
|
# CFBundleIdentifier is empty or does not exist.
|
68
71
|
def bundle_identifier
|
69
|
-
identifier = plist_buddy.plist_read(
|
72
|
+
identifier = plist_buddy.plist_read("CFBundleIdentifier", info_plist_path)
|
70
73
|
unless identifier
|
71
74
|
raise "Expected key 'CFBundleIdentifier' in '#{info_plist_path}'"
|
72
75
|
end
|
@@ -78,11 +81,28 @@ Bundle must:
|
|
78
81
|
# @raise [RuntimeError] If the plist cannot be read or the
|
79
82
|
# CFBundleExecutable is empty or does not exist.
|
80
83
|
def executable_name
|
81
|
-
|
82
|
-
unless
|
84
|
+
name = plist_buddy.plist_read("CFBundleExecutable", info_plist_path)
|
85
|
+
unless name
|
83
86
|
raise "Expected key 'CFBundleExecutable' in '#{info_plist_path}'"
|
84
87
|
end
|
85
|
-
|
88
|
+
name
|
89
|
+
end
|
90
|
+
|
91
|
+
# Returns the arches for the binary.
|
92
|
+
def arches
|
93
|
+
@arches ||= lipo.info
|
94
|
+
end
|
95
|
+
|
96
|
+
# True if the app has been built for the simulator
|
97
|
+
def simulator?
|
98
|
+
arches.include?("i386") || arches.include?("x86_64")
|
99
|
+
end
|
100
|
+
|
101
|
+
# True if the app has been built for physical devices
|
102
|
+
def physical_device?
|
103
|
+
arches.any? do |arch|
|
104
|
+
arch[/arm/, 0]
|
105
|
+
end
|
86
106
|
end
|
87
107
|
|
88
108
|
# Inspects the app's file for the server version
|
@@ -115,7 +135,6 @@ Bundle must:
|
|
115
135
|
def executables
|
116
136
|
executables = []
|
117
137
|
Dir.glob("#{path}/**/*") do |file|
|
118
|
-
next if File.directory?(file)
|
119
138
|
next if skip_executable_check?(file)
|
120
139
|
if otool(file).executable?
|
121
140
|
executables << file
|
@@ -131,6 +150,30 @@ Bundle must:
|
|
131
150
|
|
132
151
|
private
|
133
152
|
|
153
|
+
# @!visibility private
|
154
|
+
def self.info_plist_exist?(app_bundle_path)
|
155
|
+
info_plist = File.join(app_bundle_path, "Info.plist")
|
156
|
+
File.exist?(info_plist)
|
157
|
+
end
|
158
|
+
|
159
|
+
# @!visibility private
|
160
|
+
def self.executable_file_exist?(app_bundle_path)
|
161
|
+
return false if !self.info_plist_exist?(app_bundle_path)
|
162
|
+
info_plist = File.join(app_bundle_path, "Info.plist")
|
163
|
+
pbuddy = RunLoop::PlistBuddy.new
|
164
|
+
name = pbuddy.plist_read("CFBundleExecutable", info_plist)
|
165
|
+
if name
|
166
|
+
File.exist?(File.join(app_bundle_path, name))
|
167
|
+
else
|
168
|
+
false
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# @!visibility private
|
173
|
+
def lipo
|
174
|
+
@lipo ||= RunLoop::Lipo.new(path)
|
175
|
+
end
|
176
|
+
|
134
177
|
# @!visibility private
|
135
178
|
def plist_buddy
|
136
179
|
@plist_buddy ||= RunLoop::PlistBuddy.new
|
@@ -150,17 +193,20 @@ Bundle must:
|
|
150
193
|
|
151
194
|
# @!visibility private
|
152
195
|
def skip_executable_check?(file)
|
153
|
-
|
196
|
+
File.directory?(file) ||
|
197
|
+
image?(file) ||
|
154
198
|
text?(file) ||
|
155
199
|
plist?(file) ||
|
156
200
|
lproj_asset?(file) ||
|
157
201
|
code_signing_asset?(file) ||
|
158
|
-
core_data_asset?(file)
|
202
|
+
core_data_asset?(file) ||
|
203
|
+
font?(file)
|
159
204
|
end
|
160
205
|
|
161
206
|
# @!visibility private
|
162
207
|
def text?(file)
|
163
208
|
extension = File.extname(file)
|
209
|
+
filename = File.basename(file)
|
164
210
|
|
165
211
|
extension == ".txt" ||
|
166
212
|
extension == ".md" ||
|
@@ -170,12 +216,25 @@ Bundle must:
|
|
170
216
|
extension == ".yaml" ||
|
171
217
|
extension == ".yml" ||
|
172
218
|
extension == ".rtf" ||
|
173
|
-
|
219
|
+
|
220
|
+
["NOTICE", "LICENSE", "README", "ABOUT"].any? do |elm|
|
221
|
+
filename[/#{elm}/]
|
222
|
+
end
|
174
223
|
end
|
175
224
|
|
176
225
|
# @!visibility private
|
177
226
|
def image?(file)
|
178
|
-
file
|
227
|
+
extension = File.extname(file)
|
228
|
+
|
229
|
+
extension == ".jpeg" ||
|
230
|
+
extension == ".jpg" ||
|
231
|
+
extension == ".gif" ||
|
232
|
+
extension == ".png" ||
|
233
|
+
extension == ".tiff" ||
|
234
|
+
extension == ".svg" ||
|
235
|
+
extension == ".pdf" ||
|
236
|
+
extension == ".car" ||
|
237
|
+
file[/iTunesArtwork/, 0]
|
179
238
|
end
|
180
239
|
|
181
240
|
# @!visibility private
|
@@ -186,9 +245,11 @@ Bundle must:
|
|
186
245
|
# @!visibility private
|
187
246
|
def lproj_asset?(file)
|
188
247
|
extension = File.extname(file)
|
248
|
+
dir_extension = File.extname(File.dirname(file))
|
189
249
|
|
190
|
-
|
191
|
-
|
250
|
+
dir_extension == ".lproj" ||
|
251
|
+
dir_extension == ".storyboard" ||
|
252
|
+
dir_extension == ".storyboardc" ||
|
192
253
|
extension == ".strings" ||
|
193
254
|
extension == ".xib" ||
|
194
255
|
extension == ".nib"
|
@@ -198,21 +259,31 @@ Bundle must:
|
|
198
259
|
def code_signing_asset?(file)
|
199
260
|
name = File.basename(file)
|
200
261
|
extension = File.extname(file)
|
262
|
+
dirname = File.basename(File.dirname(file))
|
201
263
|
|
202
264
|
name == "PkgInfo" ||
|
203
265
|
name == "embedded" ||
|
204
266
|
extension == ".mobileprovision" ||
|
205
267
|
extension == ".xcent" ||
|
206
|
-
|
268
|
+
dirname == "_CodeSignature"
|
207
269
|
end
|
208
270
|
|
209
271
|
# @!visibility private
|
210
272
|
def core_data_asset?(file)
|
211
273
|
extension = File.extname(file)
|
274
|
+
dir_extension = File.extname(File.dirname(file))
|
212
275
|
|
213
|
-
|
276
|
+
dir_extension == ".momd" ||
|
214
277
|
extension == ".mom" ||
|
215
|
-
extension == ".db"
|
278
|
+
extension == ".db" ||
|
279
|
+
extension == ".omo"
|
280
|
+
end
|
281
|
+
|
282
|
+
# @!visibility private
|
283
|
+
def font?(file)
|
284
|
+
extension = File.extname(file)
|
285
|
+
|
286
|
+
extension == ".tff" || extension == ".otf"
|
216
287
|
end
|
217
288
|
end
|
218
289
|
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module RunLoop
|
2
|
+
|
3
|
+
# @!visibility private
|
4
|
+
module DetectAUT
|
5
|
+
|
6
|
+
# @!visibility private
|
7
|
+
class Detect
|
8
|
+
include RunLoop::DetectAUT::Errors
|
9
|
+
include RunLoop::DetectAUT::XamarinStudio
|
10
|
+
include RunLoop::DetectAUT::Xcode
|
11
|
+
|
12
|
+
# @!visibility private
|
13
|
+
def app_for_simulator
|
14
|
+
path = RunLoop::Environment.path_to_app_bundle
|
15
|
+
return RunLoop::App.new(path) if path
|
16
|
+
|
17
|
+
if xcode_project?
|
18
|
+
apps, search_dirs = detect_xcode_apps
|
19
|
+
elsif xamarin_project?
|
20
|
+
search_dirs = [solution_directory]
|
21
|
+
apps = candidate_apps(search_dirs.first)
|
22
|
+
else
|
23
|
+
apps = []
|
24
|
+
search_dirs = []
|
25
|
+
end
|
26
|
+
|
27
|
+
# If this is a Xamarin project, we've already searched the local
|
28
|
+
# directory tree for .app.
|
29
|
+
if apps.empty? && !xamarin_project?
|
30
|
+
search_dirs << File.expand_path("./")
|
31
|
+
apps = candidate_apps(File.expand_path("./"))
|
32
|
+
end
|
33
|
+
|
34
|
+
if apps.empty?
|
35
|
+
raise_no_simulator_app_found(search_dirs)
|
36
|
+
end
|
37
|
+
|
38
|
+
app = select_most_recent_app(apps)
|
39
|
+
|
40
|
+
RunLoop.log_info2("Detected app at path:")
|
41
|
+
RunLoop.log_info2("#{app.path}")
|
42
|
+
time_str = mtime(app).strftime("%a %d %b %Y %H:%M:%S %Z")
|
43
|
+
RunLoop.log_info2("Modification time of app: #{time_str}")
|
44
|
+
RunLoop.log_info2("If this is incorrect, set the APP variable and/or rebuild your app")
|
45
|
+
RunLoop.log_info2("It is your responsibility to ensure you are testing the right app.")
|
46
|
+
|
47
|
+
app
|
48
|
+
end
|
49
|
+
|
50
|
+
# @!visibility private
|
51
|
+
# @param [Array<RunLoop::Detect>] apps
|
52
|
+
def select_most_recent_app(apps)
|
53
|
+
apps.max do |a, b|
|
54
|
+
mtime(a).to_i <=> mtime(b).to_i
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# @!visibility private
|
59
|
+
# @param [String] bundle_path
|
60
|
+
def app_with_bundle(bundle_path)
|
61
|
+
RunLoop::App.new(bundle_path)
|
62
|
+
end
|
63
|
+
|
64
|
+
# @!visibility private
|
65
|
+
# @param [String] base_dir where to start the recursive search
|
66
|
+
def candidate_apps(base_dir)
|
67
|
+
candidates = []
|
68
|
+
Dir.glob("#{base_dir}/**/*.app").each do |bundle_path|
|
69
|
+
app = app_or_nil(bundle_path)
|
70
|
+
candidates << app if app
|
71
|
+
end
|
72
|
+
candidates
|
73
|
+
end
|
74
|
+
|
75
|
+
# @!visibility private
|
76
|
+
# @param [String] bundle_path path to .app
|
77
|
+
def app_or_nil(bundle_path)
|
78
|
+
return nil if !RunLoop::App.valid?(bundle_path)
|
79
|
+
|
80
|
+
app = app_with_bundle(bundle_path)
|
81
|
+
if app.simulator? && app.calabash_server_version
|
82
|
+
app
|
83
|
+
else
|
84
|
+
nil
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# @!visibility private
|
89
|
+
# @param [RunLoop::Detect] app
|
90
|
+
def mtime(app)
|
91
|
+
path = File.join(app.path, app.executable_name)
|
92
|
+
File.mtime(path)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,127 @@
|
|
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.each { |path| puts " #{path}" }}
|
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)
|
110
|
+
raise RunLoop::NoSimulatorAppFoundError,
|
111
|
+
%Q[Searched these directories:
|
112
|
+
|
113
|
+
#{search_directories.each { |path| puts " #{path}" }}
|
114
|
+
|
115
|
+
but could not find any .app for the simulator that contains the Calabash iOS
|
116
|
+
server.
|
117
|
+
|
118
|
+
Make sure you have built your app for a simulator target from Xcode.
|
119
|
+
|
120
|
+
If you testing a stand-alone .app (you don't have an Xcode project), put your
|
121
|
+
.app in the same directory (or below) the directory you run `cucumber` from.
|
122
|
+
]
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
@@ -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,136 @@
|
|
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
|
+
Dir.glob("#{Dir.pwd}/**/*.xcodeproj")
|
34
|
+
end
|
35
|
+
|
36
|
+
# @!visibility private
|
37
|
+
def detect_xcode_apps
|
38
|
+
dirs_to_search = derived_data_search_dirs
|
39
|
+
|
40
|
+
dir_from_prefs = xcode_preferences_search_dir
|
41
|
+
if dir_from_prefs
|
42
|
+
dirs_to_search << dir_from_prefs
|
43
|
+
end
|
44
|
+
|
45
|
+
apps = []
|
46
|
+
dirs_to_search.each do |dir|
|
47
|
+
# defined in detect_aut/apps.rb
|
48
|
+
candidates = candidate_apps(dir)
|
49
|
+
apps = apps.concat(candidates)
|
50
|
+
end
|
51
|
+
|
52
|
+
return apps, dirs_to_search
|
53
|
+
end
|
54
|
+
|
55
|
+
# @!visibility private
|
56
|
+
PLIST_KEYS = {
|
57
|
+
:workspace => "WorkspacePath",
|
58
|
+
:shared_build => "IDESharedBuildFolderName",
|
59
|
+
:custom_build => "IDECustomBuildProductsPath"
|
60
|
+
}
|
61
|
+
|
62
|
+
# @!visibility private
|
63
|
+
# TODO Needs unit tests
|
64
|
+
def derived_data_search_dirs
|
65
|
+
project = xcodeproj
|
66
|
+
project_name = File.basename(project)
|
67
|
+
matches = []
|
68
|
+
|
69
|
+
# WorkspacePath could be a .xcodeproj or .xcworkspace
|
70
|
+
#
|
71
|
+
# # Exact match.
|
72
|
+
# xcodeproj = path/to/MyApp/MyApp.xcodeproj
|
73
|
+
# WorkspacePath = path/to/MyApp/MyApp.xcodeproj
|
74
|
+
#
|
75
|
+
# # CocoaPods projects are often configured like this. As are legacy
|
76
|
+
# # projects that have been added to a new workspace.
|
77
|
+
# xcodeproj = path/to/MyApp/MyApp.xcodeproj
|
78
|
+
# WorkspacePath = path/to/MyApp/MyApp.xcworkspace
|
79
|
+
#
|
80
|
+
# # This is the Xcode default when creating new iOS project
|
81
|
+
# xcodeproj = path/to/MyApp/MyApp/MyApp.xcodeproj
|
82
|
+
# WorkspacePath = path/to/MyApp/MyApp.xcworkspace
|
83
|
+
key = PLIST_KEYS[:workspace]
|
84
|
+
Dir.glob("#{derived_data}/*/info.plist") do |plist|
|
85
|
+
workspace = pbuddy.plist_read(key, plist)
|
86
|
+
if workspace == project
|
87
|
+
matches << File.dirname(plist)
|
88
|
+
else
|
89
|
+
base_dir = File.dirname(workspace)
|
90
|
+
if File.exist?(File.join(base_dir, project_name))
|
91
|
+
matches << File.dirname(plist)
|
92
|
+
elsif !Dir.glob("#{File.dirname(workspace)}/*/#{project_name}").empty?
|
93
|
+
matches << File.dirname(plist)
|
94
|
+
elsif !Dir.glob("#{File.dirname(workspace)}/**/#{project_name}").empty?
|
95
|
+
matches << File.dirname(plist)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
matches
|
100
|
+
end
|
101
|
+
|
102
|
+
# @!visibility private
|
103
|
+
def xcode_preferences_search_dir
|
104
|
+
plist = xcode_preferences_plist
|
105
|
+
|
106
|
+
shared_build_folder = pbuddy.plist_read(PLIST_KEYS[:shared_build], plist)
|
107
|
+
custom_build_folder = pbuddy.plist_read(PLIST_KEYS[:custom_build], plist)
|
108
|
+
|
109
|
+
if shared_build_folder
|
110
|
+
File.join(derived_data, shared_build_folder, "Products")
|
111
|
+
elsif custom_build_folder
|
112
|
+
File.join(File.dirname(xcodeproj), custom_build_folder)
|
113
|
+
else
|
114
|
+
nil
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# @!visibility private
|
119
|
+
def derived_data
|
120
|
+
RunLoop::Environment.derived_data ||
|
121
|
+
File.expand_path("~/Library/Developer/Xcode/DerivedData")
|
122
|
+
end
|
123
|
+
|
124
|
+
# @!visibility private
|
125
|
+
def xcode_preferences_plist
|
126
|
+
File.expand_path('~/Library/Preferences/com.apple.dt.Xcode.plist')
|
127
|
+
end
|
128
|
+
|
129
|
+
# @!visibility private
|
130
|
+
def pbuddy
|
131
|
+
@pbuddy ||= RunLoop::PlistBuddy.new
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
data/lib/run_loop/environment.rb
CHANGED
@@ -38,6 +38,49 @@ module RunLoop
|
|
38
38
|
ENV["DEVICE_ENDPOINT"]
|
39
39
|
end
|
40
40
|
|
41
|
+
# Returns the value of XCODEPROJ which can be used to specify an Xcode
|
42
|
+
# project directory (my.xcodeproj).
|
43
|
+
#
|
44
|
+
# This is useful if your project has multiple xcodeproj directories.
|
45
|
+
#
|
46
|
+
# Most users should not set this variable.
|
47
|
+
def self.xcodeproj
|
48
|
+
value = ENV["XCODEPROJ"]
|
49
|
+
if value.nil? || value == ""
|
50
|
+
return nil
|
51
|
+
else
|
52
|
+
File.expand_path(value)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns the value of DERIVED_DATA which can be used to specify an
|
57
|
+
# alternative DerivedData directory.
|
58
|
+
#
|
59
|
+
# The default is ~/Library/Xcode/DerivedData, but Xcode allows you to
|
60
|
+
# change this value.
|
61
|
+
def self.derived_data
|
62
|
+
value = ENV["DERIVED_DATA"]
|
63
|
+
if value.nil? || value == ""
|
64
|
+
nil
|
65
|
+
else
|
66
|
+
File.expand_path(value)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Returns the value of SOLUTION which can be used to specify a
|
71
|
+
# Xamarin Studio .sln
|
72
|
+
#
|
73
|
+
# This is useful if your project has multiple solutions (.sln)
|
74
|
+
# and Calabash cannot detect the correct one.
|
75
|
+
def self.solution
|
76
|
+
value = ENV["SOLUTION"]
|
77
|
+
if value.nil? || value == ""
|
78
|
+
nil
|
79
|
+
else
|
80
|
+
File.expand_path(value)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
41
84
|
# Returns the value of TRACE_TEMPLATE; the Instruments template to use
|
42
85
|
# during testing.
|
43
86
|
def self.trace_template
|
data/lib/run_loop/ipa.rb
CHANGED
@@ -45,6 +45,11 @@ module RunLoop
|
|
45
45
|
app.executable_name
|
46
46
|
end
|
47
47
|
|
48
|
+
# Returns the arches for the binary.
|
49
|
+
def arches
|
50
|
+
app.arches
|
51
|
+
end
|
52
|
+
|
48
53
|
# Inspects the app's executables for the server version
|
49
54
|
# @return[RunLoop::Version] a version instance
|
50
55
|
def calabash_server_version
|
data/lib/run_loop/otool.rb
CHANGED
data/lib/run_loop/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: run_loop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Karl Krukow
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-03-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -296,6 +296,10 @@ files:
|
|
296
296
|
- lib/run_loop/codesign.rb
|
297
297
|
- lib/run_loop/core.rb
|
298
298
|
- lib/run_loop/core_simulator.rb
|
299
|
+
- lib/run_loop/detect_aut/detect.rb
|
300
|
+
- lib/run_loop/detect_aut/errors.rb
|
301
|
+
- lib/run_loop/detect_aut/xamarin_studio.rb
|
302
|
+
- lib/run_loop/detect_aut/xcode.rb
|
299
303
|
- lib/run_loop/device.rb
|
300
304
|
- lib/run_loop/directory.rb
|
301
305
|
- lib/run_loop/dot_dir.rb
|
@@ -369,3 +373,4 @@ specification_version: 4
|
|
369
373
|
summary: The bridge between Calabash iOS and Xcode command-line tools like instruments
|
370
374
|
and simctl.
|
371
375
|
test_files: []
|
376
|
+
has_rdoc:
|