calabash 1.2.1 → 1.9.9.pre1

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.
Files changed (137) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +39 -0
  3. data/LICENSE +204 -21
  4. data/README.md +36 -6
  5. data/VERSIONING.md +16 -0
  6. data/bin/calabash +95 -0
  7. data/lib/calabash.rb +185 -1
  8. data/lib/calabash/android.rb +64 -0
  9. data/lib/calabash/android/adb.rb +277 -0
  10. data/lib/calabash/android/application.rb +110 -0
  11. data/lib/calabash/android/build.rb +12 -0
  12. data/lib/calabash/android/build/application.rb +13 -0
  13. data/lib/calabash/android/build/build_error.rb +11 -0
  14. data/lib/calabash/android/build/builder.rb +119 -0
  15. data/lib/calabash/android/build/java_keystore.rb +177 -0
  16. data/lib/calabash/android/build/resigner.rb +56 -0
  17. data/lib/calabash/android/build/test_server.rb +27 -0
  18. data/lib/calabash/android/console_helpers.rb +44 -0
  19. data/lib/calabash/android/cucumber.rb +3 -0
  20. data/lib/calabash/android/device.rb +965 -0
  21. data/lib/calabash/android/environment.rb +470 -0
  22. data/lib/calabash/android/gestures.rb +369 -0
  23. data/lib/calabash/android/interactions.rb +45 -0
  24. data/lib/calabash/android/lib/.irbrc +55 -0
  25. data/lib/calabash/android/lib/AndroidManifest.xml +51 -0
  26. data/lib/calabash/android/lib/TestServer.apk +0 -0
  27. data/lib/calabash/android/lib/calmd5/arm64-v8a/calmd5 +0 -0
  28. data/lib/calabash/android/lib/calmd5/arm64-v8a/calmd5-pie +0 -0
  29. data/lib/calabash/android/lib/calmd5/armeabi-v7a/calmd5 +0 -0
  30. data/lib/calabash/android/lib/calmd5/armeabi-v7a/calmd5-pie +0 -0
  31. data/lib/calabash/android/lib/calmd5/armeabi/calmd5 +0 -0
  32. data/lib/calabash/android/lib/calmd5/armeabi/calmd5-pie +0 -0
  33. data/lib/calabash/android/lib/calmd5/mips/calmd5 +0 -0
  34. data/lib/calabash/android/lib/calmd5/mips/calmd5-pie +0 -0
  35. data/lib/calabash/android/lib/calmd5/mips64/calmd5 +0 -0
  36. data/lib/calabash/android/lib/calmd5/mips64/calmd5-pie +0 -0
  37. data/lib/calabash/android/lib/calmd5/x86/calmd5 +0 -0
  38. data/lib/calabash/android/lib/calmd5/x86/calmd5-pie +0 -0
  39. data/lib/calabash/android/lib/calmd5/x86_64/calmd5 +0 -0
  40. data/lib/calabash/android/lib/calmd5/x86_64/calmd5-pie +0 -0
  41. data/lib/calabash/android/lib/screenshot_taker.jar +0 -0
  42. data/lib/calabash/android/life_cycle.rb +37 -0
  43. data/lib/calabash/android/orientation.rb +30 -0
  44. data/lib/calabash/android/physical_buttons.rb +39 -0
  45. data/lib/calabash/android/screenshot.rb +9 -0
  46. data/lib/calabash/android/scroll.rb +5 -0
  47. data/lib/calabash/android/server.rb +10 -0
  48. data/lib/calabash/android/text.rb +54 -0
  49. data/lib/calabash/application.rb +74 -0
  50. data/lib/calabash/cli.rb +12 -0
  51. data/lib/calabash/cli/build.rb +33 -0
  52. data/lib/calabash/cli/console.rb +90 -0
  53. data/lib/calabash/cli/generate.rb +110 -0
  54. data/lib/calabash/cli/helpers.rb +130 -0
  55. data/lib/calabash/cli/resign.rb +33 -0
  56. data/lib/calabash/cli/run.rb +99 -0
  57. data/lib/calabash/cli/setup_keystore.rb +39 -0
  58. data/lib/calabash/color.rb +32 -0
  59. data/lib/calabash/console_helpers.rb +90 -0
  60. data/lib/calabash/defaults.rb +56 -0
  61. data/lib/calabash/device.rb +401 -0
  62. data/lib/calabash/environment.rb +75 -0
  63. data/lib/calabash/gestures.rb +384 -0
  64. data/lib/calabash/http.rb +8 -0
  65. data/lib/calabash/http/error.rb +15 -0
  66. data/lib/calabash/http/request.rb +42 -0
  67. data/lib/calabash/http/retriable_client.rb +156 -0
  68. data/lib/calabash/interactions.rb +105 -0
  69. data/lib/calabash/ios.rb +37 -0
  70. data/lib/calabash/ios/application.rb +119 -0
  71. data/lib/calabash/ios/conditions.rb +79 -0
  72. data/lib/calabash/ios/console_helpers.rb +72 -0
  73. data/lib/calabash/ios/device.rb +24 -0
  74. data/lib/calabash/ios/device/device_implementation.rb +779 -0
  75. data/lib/calabash/ios/device/gestures_mixin.rb +167 -0
  76. data/lib/calabash/ios/device/keyboard_mixin.rb +133 -0
  77. data/lib/calabash/ios/device/physical_device_mixin.rb +266 -0
  78. data/lib/calabash/ios/device/rotation_mixin.rb +124 -0
  79. data/lib/calabash/ios/device/routes/backdoor_route_mixin.rb +86 -0
  80. data/lib/calabash/ios/device/routes/condition_route_mixin.rb +62 -0
  81. data/lib/calabash/ios/device/routes/error.rb +8 -0
  82. data/lib/calabash/ios/device/routes/handle_route_mixin.rb +102 -0
  83. data/lib/calabash/ios/device/routes/map_route_mixin.rb +38 -0
  84. data/lib/calabash/ios/device/routes/playback_route_mixin.rb +70 -0
  85. data/lib/calabash/ios/device/routes/response_parser.rb +48 -0
  86. data/lib/calabash/ios/device/routes/uia_route_mixin.rb +238 -0
  87. data/lib/calabash/ios/device/runtime_attributes.rb +184 -0
  88. data/lib/calabash/ios/device/status_bar_mixin.rb +17 -0
  89. data/lib/calabash/ios/device/text_mixin.rb +19 -0
  90. data/lib/calabash/ios/device/uia_keyboard_mixin.rb +188 -0
  91. data/lib/calabash/ios/device/uia_mixin.rb +12 -0
  92. data/lib/calabash/ios/environment.rb +41 -0
  93. data/lib/calabash/ios/interactions.rb +10 -0
  94. data/lib/calabash/ios/lib/.irbrc +55 -0
  95. data/lib/calabash/ios/lib/recordings/rotate_left_home_down_ipad.base64 +2 -0
  96. data/lib/calabash/ios/lib/recordings/rotate_left_home_down_iphone.base64 +2 -0
  97. data/lib/calabash/ios/lib/recordings/rotate_left_home_left_ipad.base64 +2 -0
  98. data/lib/calabash/ios/lib/recordings/rotate_left_home_left_iphone.base64 +2 -0
  99. data/lib/calabash/ios/lib/recordings/rotate_left_home_right_ipad.base64 +2 -0
  100. data/lib/calabash/ios/lib/recordings/rotate_left_home_right_iphone.base64 +2 -0
  101. data/lib/calabash/ios/lib/recordings/rotate_left_home_up_ipad.base64 +2 -0
  102. data/lib/calabash/ios/lib/recordings/rotate_left_home_up_iphone.base64 +2 -0
  103. data/lib/calabash/ios/lib/recordings/rotate_right_home_down_ipad.base64 +2 -0
  104. data/lib/calabash/ios/lib/recordings/rotate_right_home_down_iphone.base64 +2 -0
  105. data/lib/calabash/ios/lib/recordings/rotate_right_home_left_ipad.base64 +2 -0
  106. data/lib/calabash/ios/lib/recordings/rotate_right_home_left_iphone.base64 +2 -0
  107. data/lib/calabash/ios/lib/recordings/rotate_right_home_right_ipad.base64 +2 -0
  108. data/lib/calabash/ios/lib/recordings/rotate_right_home_right_iphone.base64 +2 -0
  109. data/lib/calabash/ios/lib/recordings/rotate_right_home_up_ipad.base64 +2 -0
  110. data/lib/calabash/ios/lib/recordings/rotate_right_home_up_iphone.base64 +2 -0
  111. data/lib/calabash/ios/orientation.rb +117 -0
  112. data/lib/calabash/ios/scroll.rb +504 -0
  113. data/lib/calabash/ios/server.rb +73 -0
  114. data/lib/calabash/ios/text.rb +248 -0
  115. data/lib/calabash/ios/uia.rb +24 -0
  116. data/lib/calabash/lib/skeleton/config/cucumber.yml +6 -0
  117. data/lib/calabash/lib/skeleton/features/sample.feature +5 -0
  118. data/lib/calabash/lib/skeleton/features/step_definitions/calabash_steps.rb +29 -0
  119. data/lib/calabash/lib/skeleton/features/support/env.rb +54 -0
  120. data/lib/calabash/lib/skeleton/features/support/hooks.rb +83 -0
  121. data/lib/calabash/life_cycle.rb +111 -0
  122. data/lib/calabash/location.rb +51 -0
  123. data/lib/calabash/logger.rb +87 -0
  124. data/lib/calabash/orientation.rb +84 -0
  125. data/lib/calabash/page.rb +35 -0
  126. data/lib/calabash/patch.rb +14 -0
  127. data/lib/calabash/patch/array.rb +16 -0
  128. data/lib/calabash/patch/run_loop.rb +90 -0
  129. data/lib/calabash/query.rb +160 -0
  130. data/lib/calabash/query_result.rb +85 -0
  131. data/lib/calabash/screenshot.rb +89 -0
  132. data/lib/calabash/server.rb +16 -0
  133. data/lib/calabash/text.rb +76 -0
  134. data/lib/calabash/utility.rb +58 -0
  135. data/lib/calabash/version.rb +3 -1
  136. data/lib/calabash/wait.rb +474 -0
  137. metadata +462 -24
@@ -0,0 +1,470 @@
1
+ require 'rexml/document'
2
+ require 'timeout'
3
+ require 'luffa'
4
+ require 'timeout'
5
+
6
+ if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
7
+ require 'win32/registry'
8
+ end
9
+
10
+ module Calabash
11
+ module Android
12
+ class Environment < Calabash::Environment
13
+ class InvalidEnvironmentError < RuntimeError; end
14
+ class InvalidJavaSDKHome < RuntimeError; end
15
+
16
+ private
17
+
18
+ def self.set_android_dependencies(android_dependencies)
19
+ @@android_dependencies = android_dependencies
20
+ end
21
+
22
+ def self.set_java_dependencies(java_dependencies)
23
+ @@java_dependencies = java_dependencies
24
+ end
25
+
26
+ def self.android_dependencies(key)
27
+ if @@android_dependencies.has_key?(key)
28
+ file = @@android_dependencies[key]
29
+
30
+ unless File.exists?(file)
31
+ raise "No such file '#{file}'"
32
+ end
33
+
34
+ file
35
+ else
36
+ raise "No such dependency '#{key}'"
37
+ end
38
+ end
39
+
40
+ def self.java_dependencies(key)
41
+ if key == :ant_path
42
+ ant_executable
43
+ elsif @@java_dependencies.has_key?(key)
44
+ file = @@java_dependencies[key]
45
+
46
+ unless File.exists?(file)
47
+ raise "No such file '#{file}'"
48
+ end
49
+
50
+ file
51
+ else
52
+ raise "No such dependency '#{key}'"
53
+ end
54
+ end
55
+
56
+ public
57
+
58
+ def self.adb_path
59
+ android_dependencies(:adb_path)
60
+ end
61
+
62
+ def self.aapt_path
63
+ android_dependencies(:aapt_path)
64
+ end
65
+
66
+ def self.zipalign_path
67
+ android_dependencies(:zipalign_path)
68
+ end
69
+
70
+ def self.android_jar_path
71
+ android_dependencies(:android_jar_path)
72
+ end
73
+
74
+ def self.java_path
75
+ java_dependencies(:java_path)
76
+ end
77
+
78
+ def self.keytool_path
79
+ java_dependencies(:keytool_path)
80
+ end
81
+
82
+ def self.jarsigner_path
83
+ java_dependencies(:jarsigner_path)
84
+ end
85
+
86
+ def self.ant_path
87
+ java_dependencies(:ant_path)
88
+ end
89
+
90
+ def self.setup
91
+ if Environment.variable('ANDROID_HOME')
92
+ android_sdk_location = Environment.variable('ANDROID_HOME')
93
+ Logger.debug("Setting Android SDK location to $ANDROID_HOME")
94
+ else
95
+ android_sdk_location = detect_android_sdk_location
96
+ end
97
+
98
+ if android_sdk_location.nil?
99
+ Logger.error 'Could not find an Android SDK please make sure it is installed.'
100
+ Logger.error 'You can read about how Calabash is searching for an Android SDK and how you can help here:'
101
+ Logger.error 'https://github.com/calabash/calabash-android/blob/master/documentation/installation.md#prerequisites'
102
+
103
+ raise 'Could not find an Android SDK'
104
+ end
105
+
106
+ Logger.debug("Android SDK location set to '#{android_sdk_location}'")
107
+
108
+ begin
109
+ set_android_dependencies(locate_android_dependencies(android_sdk_location))
110
+ rescue InvalidEnvironmentError => e
111
+ Logger.error 'Could not locate Android dependency'
112
+ Logger.error 'You can read about how Calabash is searching for an Android SDK and how you can help here:'
113
+ Logger.error 'https://github.com/calabash/calabash-android/blob/master/documentation/installation.md#prerequisites'
114
+
115
+ raise e
116
+ end
117
+
118
+ if Environment.variable('JAVA_HOME')
119
+ java_sdk_home = Environment.variable('JAVA_HOME')
120
+ Logger.debug("Setting Java SDK location to $JAVA_HOME")
121
+ else
122
+ java_sdk_home = detect_java_sdk_location
123
+ end
124
+
125
+ Logger.debug("Java SDK location set to '#{java_sdk_home}'")
126
+
127
+ begin
128
+ set_java_dependencies(locate_java_dependencies(java_sdk_home))
129
+ rescue InvalidJavaSDKHome => e
130
+ Logger.error "Could not find Java Development Kit please make sure it is installed."
131
+ Logger.error "You can read about how Calabash is searching for a JDK and how you can help here:"
132
+ Logger.error "https://github.com/calabash/calabash-android/blob/master/documentation/installation.md#prerequisites"
133
+
134
+ raise e
135
+ rescue InvalidEnvironmentError => e
136
+ Logger.error "Could not find Java dependency"
137
+ Logger.error "You can read about how Calabash is searching for a JDK and how you can help here:"
138
+ Logger.error "https://github.com/calabash/calabash-android/blob/master/documentation/installation.md#prerequisites"
139
+
140
+ raise e
141
+ end
142
+ end
143
+
144
+ private
145
+
146
+ def self.tools_directory
147
+ tools_directories = tools_directories(Environment.variable('ANDROID_HOME'))
148
+
149
+ File.join(Environment.variable('ANDROID_HOME'), tools_directories.first)
150
+ end
151
+
152
+ def self.tools_directories(android_sdk_location)
153
+ build_tools_files = list_files(File.join(android_sdk_location, 'build-tools')).select {|file| File.directory?(file)}
154
+
155
+ build_tools_directories =
156
+ build_tools_files.select do |dir|
157
+ begin
158
+ Luffa::Version.new(File.basename(dir))
159
+ true
160
+ rescue ArgumentError
161
+ false
162
+ end
163
+ end.sort do |a, b|
164
+ Luffa::Version.compare(Luffa::Version.new(File.basename(a)), Luffa::Version.new(File.basename(b)))
165
+ end.reverse.map{|dir| File.join('build-tools', File.basename(dir))}
166
+
167
+ if build_tools_directories.empty?
168
+ build_tools_directories = [File.join('build-tools', File.basename(build_tools_files.reverse.first))]
169
+ end
170
+
171
+ build_tools_directories + ['platform-tools', 'tools']
172
+ end
173
+
174
+ def self.platform_directory(android_sdk_location)
175
+ files = list_files(File.join(android_sdk_location, 'platforms'))
176
+ .select {|file| File.directory?(file)}
177
+
178
+ sorted_files = files.sort_by {|item| '%08s' % item.split('-').last}.reverse
179
+
180
+ File.join('platforms', File.basename(sorted_files.first))
181
+ end
182
+
183
+ def self.locate_android_dependencies(android_sdk_location)
184
+ adb_path = scan_for_path(android_sdk_location, adb_executable, ['platform-tools'])
185
+ aapt_path = scan_for_path(android_sdk_location, aapt_executable, tools_directories(android_sdk_location))
186
+ zipalign_path = scan_for_path(android_sdk_location, zipalign_executable, tools_directories(android_sdk_location))
187
+
188
+ if adb_path.nil?
189
+ raise InvalidEnvironmentError,
190
+ "Could not find '#{adb_executable}' in '#{android_sdk_location}'"
191
+ end
192
+
193
+ if aapt_path.nil?
194
+ raise InvalidEnvironmentError,
195
+ "Could not find '#{aapt_executable}' in '#{android_sdk_location}'"
196
+ end
197
+
198
+ if zipalign_path.nil?
199
+ raise InvalidEnvironmentError,
200
+ "Could not find '#{zipalign_executable}' in '#{android_sdk_location}'"
201
+ end
202
+
203
+ Logger.debug("Set aapt path to '#{aapt_path}'")
204
+ Logger.debug("Set zipalign path to '#{zipalign_path}'")
205
+ Logger.debug("Set adb path to '#{adb_path}'")
206
+
207
+ android_jar_path = scan_for_path(File.join(android_sdk_location, 'platforms'), 'android.jar', [File.basename(platform_directory(android_sdk_location))])
208
+
209
+ if android_jar_path.nil?
210
+ raise InvalidEnvironmentError,
211
+ "Could not find 'android.jar' in '#{File.join(android_sdk_location, 'platforms')}'"
212
+ end
213
+
214
+ Logger.debug("Set android jar path to '#{android_jar_path}'")
215
+
216
+ {
217
+ aapt_path: aapt_path,
218
+ zipalign_path: zipalign_path,
219
+ adb_path: adb_path,
220
+ android_jar_path: android_jar_path
221
+ }
222
+ end
223
+
224
+ def self.locate_java_dependencies(java_sdk_location)
225
+ # For the Java dependencies, we will use the PATH elements of they exist
226
+ on_path = find_executable_on_path(java_executable)
227
+
228
+ if on_path
229
+ Logger.debug('Found java on PATH')
230
+ java_path = on_path
231
+ else
232
+ if java_sdk_location.nil? || java_sdk_location.empty?
233
+ raise InvalidJavaSDKHome,
234
+ "Could not locate '#{java_executable}' on path, and Java SDK Home is invalid."
235
+ end
236
+
237
+ java_path = scan_for_path(java_sdk_location, java_executable, ['bin'])
238
+ end
239
+
240
+ Logger.debug("Set java path to '#{java_path}'")
241
+
242
+ on_path = find_executable_on_path(keytool_executable)
243
+
244
+ if on_path
245
+ Logger.debug('Found keytool on PATH')
246
+ keytool_path = on_path
247
+ else
248
+ if java_sdk_location.nil? || java_sdk_location.empty?
249
+ raise InvalidJavaSDKHome,
250
+ "Could not locate '#{keytool_executable}' on path, and Java SDK Home is invalid."
251
+ end
252
+
253
+ keytool_path = scan_for_path(java_sdk_location, keytool_executable, ['bin'])
254
+ end
255
+
256
+ Logger.debug("Set keytool path to '#{keytool_path}'")
257
+
258
+ on_path = find_executable_on_path(jarsigner_executable)
259
+
260
+ if on_path
261
+ Logger.debug('Found jarsigner on PATH')
262
+ jarsigner_path = on_path
263
+ else
264
+ if java_sdk_location.nil? || java_sdk_location.empty?
265
+ raise InvalidJavaSDKHome,
266
+ "Could not locate '#{jarsigner_executable}' on path, and Java SDK Home is invalid."
267
+ end
268
+
269
+ jarsigner_path = scan_for_path(java_sdk_location, jarsigner_executable, ['bin'])
270
+ end
271
+
272
+ Logger.debug("Set jarsigner path to '#{jarsigner_path}'")
273
+
274
+ if java_path.nil?
275
+ raise InvalidEnvironmentError,
276
+ "Could not find '#{java_executable}' on PATH or in '#{java_sdk_location}'"
277
+ end
278
+
279
+ if keytool_path.nil?
280
+ raise InvalidEnvironmentError,
281
+ "Could not find '#{keytool_executable}' on PATH or in '#{java_sdk_location}'"
282
+ end
283
+
284
+ if jarsigner_path.nil?
285
+ raise InvalidEnvironmentError,
286
+ "Could not find '#{jarsigner_executable}' on PATH or in '#{java_sdk_location}'"
287
+ end
288
+
289
+ {
290
+ java_path: java_path,
291
+ keytool_path: keytool_path,
292
+ jarsigner_path: jarsigner_path
293
+ }
294
+ end
295
+
296
+ def self.scan_for_path(path, file_name, expected_sub_folders = nil)
297
+ # Optimization for expected folders
298
+ if expected_sub_folders && !expected_sub_folders.empty?
299
+ expected_sub_folders.each do |expected_sub_folder|
300
+ result = scan_for_path(File.join(path, expected_sub_folder), file_name)
301
+
302
+ return result if result
303
+ end
304
+
305
+ Logger.warn("Did not find '#{file_name}' in any standard directory of '#{path}'. Calabash will therefore take longer to load")
306
+ Logger.debug(" - Expected to find '#{file_name}' in any of:")
307
+
308
+ expected_sub_folders.each do |expected_sub_folder|
309
+ Logger.debug(" - #{File.join(path, expected_sub_folder)}")
310
+ end
311
+ end
312
+
313
+ files = list_files(path).sort.reverse
314
+
315
+ if files.reject{|file| File.directory?(file)}.
316
+ map{|file| File.basename(file)}.include?(file_name)
317
+ return File.join(path, file_name)
318
+ else
319
+ files.select{|file| File.directory?(file)}.each do |dir|
320
+ result = scan_for_path(dir, file_name)
321
+
322
+ return result if result
323
+ end
324
+ end
325
+
326
+ nil
327
+ end
328
+
329
+ def self.detect_android_sdk_location
330
+ if File.exist?(monodroid_config_file)
331
+ sdk_location = read_attribute_from_monodroid_config('android-sdk', 'path')
332
+
333
+ if sdk_location
334
+ Logger.debug("Setting Android SDK location from '#{monodroid_config_file}'")
335
+
336
+ return sdk_location
337
+ end
338
+ end
339
+
340
+ if File.exist?('~/Library/Developer/Xamarin/android-sdk-mac_x86/')
341
+ return '~/Library/Developer/Xamarin/android-sdk-mac_x86/'
342
+ end
343
+
344
+ if File.exist?('C:\\Android\\android-sdk')
345
+ return 'C:\\Android\\android-sdk'
346
+ end
347
+
348
+ if is_windows?
349
+ from_registry = read_registry(::Win32::Registry::HKEY_CURRENT_USER, "Software\\Novell\\Mono for Android", 'AndroidSdkDirectory')
350
+
351
+ if from_registry && File.exist?(from_registry)
352
+ Logger.debug("Setting Android SDK location from HKEY_CURRENT_USER Software\\Novell\\Mono for Android")
353
+ return from_registry
354
+ end
355
+
356
+ from_registry = read_registry(::Win32::Registry::HKEY_LOCAL_MACHINE, 'Software\\Android SDK Tools', 'Path')
357
+
358
+ if from_registry && File.exist?(from_registry)
359
+ Logger.debug("Setting Android SDK location from HKEY_LOCAL_MACHINE Software\\Android SDK Tools")
360
+ return from_registry
361
+ end
362
+ end
363
+
364
+ nil
365
+ end
366
+
367
+ def self.detect_java_sdk_location
368
+ if File.exist?(monodroid_config_file)
369
+ sdk_location = read_attribute_from_monodroid_config('java-sdk', 'path')
370
+
371
+ if sdk_location
372
+ Logger.debug("Setting Java SDK location from '#{monodroid_config_file}'")
373
+
374
+ return sdk_location
375
+ end
376
+ end
377
+
378
+ java_versions = ['1.9', '1.8', '1.7', '1.6']
379
+
380
+ if is_windows?
381
+ java_versions.each do |java_version|
382
+ key = "SOFTWARE\\JavaSoft\\Java Development Kit\\#{java_version}"
383
+ from_registry = read_registry(::Win32::Registry::HKEY_LOCAL_MACHINE, key, 'JavaHome')
384
+
385
+ if from_registry && File.exist?(from_registry)
386
+ Logger.debug("Setting Java SDK location from HKEY_LOCAL_MACHINE #{key}")
387
+ return from_registry
388
+ end
389
+ end
390
+ end
391
+
392
+ nil
393
+ end
394
+
395
+ def self.monodroid_config_file
396
+ File.expand_path('~/.config/xbuild/monodroid-config.xml')
397
+ end
398
+
399
+ def self.read_attribute_from_monodroid_config(element, attribute)
400
+ REXML::Document.new(IO.read(monodroid_config_file)).elements["//#{element}"].attributes[attribute]
401
+ end
402
+
403
+ def self.find_executable_on_path(executable)
404
+ path_elements.each do |x|
405
+ f = File.join(x, executable)
406
+ return f if File.exists?(f)
407
+ end
408
+
409
+ nil
410
+ end
411
+
412
+ def self.path_elements
413
+ return [] unless Environment.variable('PATH')
414
+ Environment.variable('PATH').split (/[:;]/)
415
+ end
416
+
417
+ def self.zipalign_executable
418
+ is_windows? ? 'zipalign.exe' : 'zipalign'
419
+ end
420
+
421
+ def self.jarsigner_executable
422
+ is_windows? ? 'jarsigner.exe' : 'jarsigner'
423
+ end
424
+
425
+ def self.java_executable
426
+ is_windows? ? 'java.exe' : 'java'
427
+ end
428
+
429
+ def self.keytool_executable
430
+ is_windows? ? 'keytool.exe' : 'keytool'
431
+ end
432
+
433
+ def self.adb_executable
434
+ is_windows? ? 'adb.exe' : 'adb'
435
+ end
436
+
437
+ def self.aapt_executable
438
+ is_windows? ? 'aapt.exe' : 'aapt'
439
+ end
440
+
441
+ def self.ant_executable
442
+ is_windows? ? 'ant.exe' : 'ant'
443
+ end
444
+
445
+ def self.is_windows?
446
+ (RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/)
447
+ end
448
+
449
+ def self.read_registry(root_key, key, value)
450
+ begin
451
+ root_key.open(key)[value]
452
+ rescue
453
+ nil
454
+ end
455
+ end
456
+
457
+ def self.list_files(path)
458
+ # Dir.glob does not accept backslashes, even on windows. We have to
459
+ # substitute all backwards slashes to forward.
460
+ # C:\foo becomes C:/foo
461
+
462
+ if is_windows?
463
+ Dir.glob(File.join(path, '*').gsub('\\', '/'))
464
+ else
465
+ Dir.glob(File.join(path, '*'))
466
+ end
467
+ end
468
+ end
469
+ end
470
+ end