calabash 1.2.1 → 1.9.9.pre1

Sign up to get free protection for your applications and to get access to all the features.
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,12 @@
1
+ module Calabash
2
+ module Android
3
+ module Build
4
+ require 'calabash/android/build/application'
5
+ require 'calabash/android/build/build_error'
6
+ require 'calabash/android/build/builder'
7
+ require 'calabash/android/build/java_keystore'
8
+ require 'calabash/android/build/resigner'
9
+ require 'calabash/android/build/test_server'
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ module Calabash
2
+ module Android
3
+ # @!visibility private
4
+ module Build
5
+ # @!visibility private
6
+ class Application < Android::Application
7
+ def initialize(application_path, options = {})
8
+ super(application_path, nil, options)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ module Calabash
2
+ module Android
3
+ # @!visibility private
4
+ module Build
5
+ # @!visibility private
6
+ class BuildError < RuntimeError
7
+
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,119 @@
1
+ require 'zip'
2
+
3
+ module Calabash
4
+ module Android
5
+ module Build
6
+ # @!visibility private
7
+ class Builder
8
+ def initialize(application_path, options={})
9
+ @application_path = application_path
10
+
11
+ if options[:logger]
12
+ @logger = options[:logger] || Logger.new
13
+ else
14
+ @logger = Logger.new
15
+ @logger.default_log_level = :info
16
+ end
17
+ end
18
+
19
+ def build
20
+ apk_fingerprint = fingerprint_from_apk
21
+ @logger.log "#{@application_path} was signed with a certificate with fingerprint #{apk_fingerprint}", :debug
22
+
23
+ keystores = JavaKeystore.get_keystores
24
+ if keystores.empty?
25
+ @logger.log "No default keystores found."
26
+ @logger.log "Please create one or run calabash setup-keystore to configure calabash to use an existing keystore."
27
+
28
+ raise BuildError.new('No keystores found')
29
+ end
30
+ keystore = keystores.find { |k| k.fingerprint == apk_fingerprint}
31
+
32
+ unless keystore
33
+ @logger.log "#{@application_path} is not signed with any of the available keystores."
34
+ @logger.log "Tried the following keystores:"
35
+ keystores.each do |k|
36
+ @logger.log k.location
37
+ end
38
+ @logger.log ""
39
+ @logger.log "You can resign the app with #{keystores.first.location} by running:
40
+ calabash resign #{@application_path}"
41
+
42
+ @logger.log ""
43
+ @logger.log "Notice that resigning an app might break some functionality."
44
+ @logger.log "Getting a copy of the certificate used when the app was build will in general be more reliable."
45
+
46
+ raise BuildError.new("#{@application_path} is not signed with any of the available keystores")
47
+ end
48
+
49
+ application = Calabash::Application.from_path(@application_path)
50
+
51
+ test_server_file_name = TestServer.new(@application_path).path
52
+ FileUtils.mkdir_p File.dirname(test_server_file_name) unless File.exist? File.dirname(test_server_file_name)
53
+
54
+ Dir.mktmpdir do |workspace_dir|
55
+ Dir.chdir(workspace_dir) do
56
+ FileUtils.cp(UNSIGNED_TEST_SERVER_APK, "TestServer.apk")
57
+ FileUtils.cp(ANDROID_MANIFEST_PATH, "AndroidManifest.xml")
58
+
59
+ contents = File.read('AndroidManifest.xml')
60
+ contents.gsub!(/#targetPackage#/, application.identifier)
61
+ contents.gsub!(/#testPackage#/, "#{application.identifier}.test")
62
+
63
+ File.open('AndroidManifest.xml_tmp', 'w') {|file| file.write(contents)}
64
+ FileUtils.mv('AndroidManifest.xml_tmp', 'AndroidManifest.xml')
65
+
66
+ unless system %Q{"#{Environment.aapt_path}" package -M AndroidManifest.xml -I "#{Environment.android_jar_path}" -F dummy.apk}
67
+ raise "Could not create dummy.apk"
68
+ end
69
+
70
+ Zip::File.new("dummy.apk").extract("AndroidManifest.xml","customAndroidManifest.xml")
71
+ Zip::File.open("TestServer.apk") do |zip_file|
72
+ zip_file.add("AndroidManifest.xml", "customAndroidManifest.xml")
73
+ end
74
+ end
75
+ keystore.sign_apk("#{workspace_dir}/TestServer.apk", test_server_file_name)
76
+ begin
77
+
78
+ rescue => e
79
+ @logger.log e, :debug
80
+ raise BuildError.new("Could not sign test server")
81
+ end
82
+ end
83
+ @logger.log "Done signing the test server. Moved it to #{test_server_file_name}"
84
+ end
85
+
86
+ def fingerprint_from_apk
87
+ application_path = File.expand_path(@application_path)
88
+
89
+ Dir.mktmpdir do |tmp_dir|
90
+ Dir.chdir(tmp_dir) do
91
+ FileUtils.cp(application_path, "app.apk")
92
+ FileUtils.mkdir("META-INF")
93
+ Zip::File.foreach("app.apk") do |z|
94
+ z.extract if /^META-INF\/\w+.(rsa|dsa)/i =~ z.name
95
+ end
96
+ signature_files = Dir["#{tmp_dir}/META-INF/*"]
97
+
98
+ Logger.debug 'Signature files:'
99
+
100
+ signature_files.each do |signature_file|
101
+ Logger.debug signature_file
102
+ end
103
+
104
+ raise "No signature files found in META-INF. Cannot proceed." if signature_files.empty?
105
+ raise "More than one signature file (DSA or RSA) found in META-INF. Cannot proceed." if signature_files.length > 1
106
+
107
+ cmd = "#{Calabash::Android::Environment.keytool_path} -v -printcert -J\"-Dfile.encoding=utf-8\" -file \"#{signature_files.first}\""
108
+ Logger.debug cmd
109
+ fingerprints = `#{cmd}`
110
+ md5_fingerprint = JavaKeystore.extract_md5_fingerprint(fingerprints)
111
+ Logger.debug "MD5 fingerprint for signing cert (#{application_path}): #{md5_fingerprint}"
112
+ md5_fingerprint
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,177 @@
1
+ require 'escape'
2
+
3
+ module Calabash
4
+ module Android
5
+ module Build
6
+ class JavaKeystore
7
+ CALABASH_KEYSTORE_SETTINGS_FILENAME = 'calabash_keystore_settings.json'
8
+
9
+ attr_reader :errors, :location, :keystore_alias, :store_password
10
+ attr_reader :key_password, :fingerprint, :signature_algorithm_name
11
+
12
+ def initialize(location, keystore_alias, store_password, key_password, options={})
13
+ @logger = options[:logger] || Calabash::Logger.new
14
+
15
+ raise "No such keystore file '#{location}'" unless File.exists?(File.expand_path(location))
16
+
17
+ if key_password.nil? || key_password.empty?
18
+ key_password = store_password.dup
19
+ end
20
+
21
+ @logger.log "Reading keystore data from keystore file '#{File.expand_path(location)}'", :debug
22
+
23
+ keystore_data = system_with_stdout_on_success(Environment.keytool_path, '-list', '-v', '-alias', keystore_alias, '-keystore', location, '-storepass', store_password, '-keypass', key_password, '-J"-Dfile.encoding=utf-8"')
24
+
25
+ if keystore_data.nil?
26
+ if keystore_alias.empty?
27
+ @logger.log "Could not obtain keystore data. Will try to extract alias automatically", :debug
28
+
29
+ keystore_data = system_with_stdout_on_success(Environment.keytool_path, '-list', '-v', '-keystore', location, '-storepass', store_password, '-keypass', key_password, '-J"-Dfile.encoding=utf-8"')
30
+
31
+ if keystore_data.nil?
32
+ error = 'Could not read keystore alias. Probably because the credentials were incorrect.'
33
+ @errors = [{message: error}]
34
+ @logger.log error, :error
35
+ raise error
36
+ end
37
+
38
+ aliases = keystore_data.scan(/Alias name\:\s*(.*)/).flatten
39
+
40
+ if aliases.length == 0
41
+ raise 'Could not extract alias automatically. Please specify alias using calabash setup-keystore'
42
+ elsif aliases.length > 1
43
+ raise 'Multiple aliases found in keystore. Please specify alias using calabash setup-keystore'
44
+ else
45
+ keystore_alias = aliases.first
46
+ @logger.log "Extracted keystore alias '#{keystore_alias}'. Continuing", :debug
47
+
48
+ return initialize(location, keystore_alias, store_password, key_password)
49
+ end
50
+ else
51
+ error = "Could not list certificates in keystore. Probably because the credentials were incorrect."
52
+ @errors = [{:message => error}]
53
+ @logger.log error, :error
54
+ raise error
55
+ end
56
+ end
57
+
58
+ @location = location
59
+ @keystore_alias = keystore_alias
60
+ @store_password = store_password
61
+ @key_password = key_password
62
+ @logger.log "Key store data:", :debug
63
+ @logger.log keystore_data, :debug
64
+ @fingerprint = JavaKeystore.extract_md5_fingerprint(keystore_data)
65
+ @signature_algorithm_name = JavaKeystore.extract_signature_algorithm_name(keystore_data)
66
+ @logger.log "Fingerprint: #{fingerprint}", :debug
67
+ @logger.log "Signature algorithm name: #{signature_algorithm_name}", :debug
68
+ end
69
+
70
+ def sign_apk(apk_path, dest_path)
71
+ raise "Cannot sign with a miss configured keystore" if errors
72
+ raise "No such file: #{apk_path}" unless File.exists?(apk_path)
73
+
74
+ # E.g. MD5withRSA or MD5withRSAandMGF1
75
+ encryption = signature_algorithm_name.split('with')[1].split('and')[0]
76
+ signing_algorithm = "SHA1with#{encryption}"
77
+ digest_algorithm = 'SHA1'
78
+
79
+ Logger.info "Signing using the signature algorithm: '#{signing_algorithm}'"
80
+ Logger.info "Signing using the digest algorithm: '#{digest_algorithm}'"
81
+
82
+ unless system_with_stdout_on_success(Environment.jarsigner_path, '-sigfile', 'CERT', '-sigalg', signing_algorithm, '-digestalg', digest_algorithm, '-signedjar', dest_path, '-storepass', store_password, '-keypass', key_password, '-keystore', location, apk_path, keystore_alias)
83
+ Logger.error 'Could not sign the application. The keystore credentials are most like incorrect'
84
+ raise "Could not sign app '#{apk_path}'"
85
+ end
86
+ end
87
+
88
+ def system_with_stdout_on_success(cmd, *args)
89
+ a = Escape.shell_command(args)
90
+ cmd = "#{cmd} #{a.gsub("'", '"')}"
91
+ @logger.log cmd, :debug
92
+ out = `#{cmd}`
93
+ if $?.exitstatus == 0
94
+ out
95
+ else
96
+ nil
97
+ end
98
+ end
99
+
100
+ def fail_wrong_info
101
+ raise "Could not read keystore with the given credentials. Please ensure "
102
+ end
103
+
104
+ def self.read_keystore_with_default_password_and_alias(path)
105
+ path = File.expand_path path
106
+
107
+ if File.exists? path
108
+ keystore = nil
109
+
110
+ begin
111
+ keystore = JavaKeystore.new(path, 'androiddebugkey', 'android', 'android')
112
+ rescue => _
113
+ Logger.debug "Trying to read keystore from: #{path} - got error"
114
+ return nil
115
+ end
116
+
117
+ if keystore.errors
118
+ Logger.debug "Got errors #{keystore.errors}"
119
+ nil
120
+ else
121
+ Logger.debug "Unlocked keystore at #{path} - fingerprint: #{keystore.fingerprint}"
122
+ keystore
123
+ end
124
+ else
125
+ Logger.debug "Trying to read keystore from: #{path} - no such file"
126
+ nil
127
+ end
128
+ end
129
+
130
+ def self.get_keystores
131
+ if keystore = keystore_from_settings
132
+ [ keystore ]
133
+ else
134
+ [
135
+ read_keystore_with_default_password_and_alias(File.join(ENV["HOME"], "/.android/debug.keystore")),
136
+ read_keystore_with_default_password_and_alias("debug.keystore"),
137
+ read_keystore_with_default_password_and_alias(File.join(ENV["HOME"], ".local/share/Xamarin/Mono\\ for\\ Android/debug.keystore")),
138
+ read_keystore_with_default_password_and_alias(File.join(ENV["HOME"], "AppData/Local/Xamarin/Mono for Android/debug.keystore")),
139
+ ].compact
140
+ end
141
+ end
142
+
143
+ def self.keystore_from_settings
144
+ if File.exist?(CALABASH_KEYSTORE_SETTINGS_FILENAME)
145
+ Logger.info "Reading keystore information specified in #{CALABASH_KEYSTORE_SETTINGS_FILENAME}"
146
+
147
+ begin
148
+ keystore = JSON.parse(IO.read(CALABASH_KEYSTORE_SETTINGS_FILENAME))
149
+ rescue JSON::ParserError => e
150
+ Logger.error('Could not parse keystore settings. Please run calabash setup-keystore again')
151
+
152
+ raise e
153
+ end
154
+
155
+ JavaKeystore.new(keystore["keystore_location"], keystore["keystore_alias"], keystore["keystore_store_password"], keystore["keystore_key_password"])
156
+ end
157
+ end
158
+
159
+ def self.fail_if_key_missing(map, key)
160
+ raise "Found #{CALABASH_KEYSTORE_SETTINGS_FILENAME} but no #{key} defined." unless map[key]
161
+ end
162
+
163
+ def self.extract_md5_fingerprint(fingerprints)
164
+ m = fingerprints.scan(/MD5.*((?:[a-fA-F\d]{2}:){15}[a-fA-F\d]{2})/).flatten
165
+ raise "No MD5 fingerprint found:\n #{fingerprints}" if m.empty?
166
+ m.first
167
+ end
168
+
169
+ def self.extract_signature_algorithm_name(fingerprints)
170
+ m = fingerprints.scan(/Signature algorithm name: (.*)/).flatten
171
+ raise "No signature algorithm names found:\n #{fingerprints}" if m.empty?
172
+ m.first
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,56 @@
1
+ module Calabash
2
+ module Android
3
+ module Build
4
+ # @!visibility private
5
+ class Resigner
6
+ def initialize(application_path, options={})
7
+ @application_path = application_path
8
+
9
+ if options[:logger]
10
+ @logger = options[:logger] || Logger.new
11
+ else
12
+ @logger = Logger.new
13
+ @logger.default_log_level = :info
14
+ end
15
+ end
16
+
17
+ def resign!
18
+ Dir.mktmpdir do |tmp_dir|
19
+ @logger.log 'Resigning apk', :debug
20
+ unsigned_path = File.join(tmp_dir, 'unsigned.apk')
21
+ unaligned_path = File.join(tmp_dir, 'unaligned.apk')
22
+ FileUtils.cp(@application_path, unsigned_path)
23
+ unsign(unsigned_path)
24
+ sign(unsigned_path, unaligned_path)
25
+ zipalign(unaligned_path, @application_path)
26
+ end
27
+ end
28
+
29
+ def unsign(unsigned_path)
30
+ files_to_remove = `"#{Environment.aapt_path}" list "#{unsigned_path}"`.lines.collect(&:strip).grep(/^META-INF\//)
31
+ if files_to_remove.empty?
32
+ @logger.log "App wasn't signed. Will not try to unsign it.", :debug
33
+ else
34
+ system("\"#{Environment.aapt_path}\" remove \"#{unsigned_path}\" #{files_to_remove.join(" ")}")
35
+ end
36
+ end
37
+
38
+ def zipalign(unaligned_path, app_path)
39
+ cmd = %Q("#{Environment.zipalign_path}" -f 4 "#{unaligned_path}" "#{app_path}")
40
+ @logger.log "Zipaligning using: #{cmd}", :debug
41
+ system(cmd)
42
+ end
43
+
44
+ def sign(app_path, dest_path)
45
+ java_keystore = JavaKeystore.get_keystores.first
46
+
47
+ if java_keystore.nil?
48
+ raise 'No keystores found. You can specify the keystore location and credentials using calabash setup-keystore'
49
+ end
50
+
51
+ java_keystore.sign_apk(app_path, dest_path)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,27 @@
1
+ module Calabash
2
+ module Android
3
+ module Build
4
+ # @!visibility private
5
+ class TestServer
6
+ def initialize(application_path)
7
+ @application_path = application_path
8
+ end
9
+
10
+ def path
11
+ File.expand_path("test_servers/#{checksum(@application_path)}_#{VERSION}.apk")
12
+ end
13
+
14
+ def exists?
15
+ File.exists?(path)
16
+ end
17
+
18
+ private
19
+
20
+ def checksum(file_path)
21
+ require 'digest/md5'
22
+ Digest::MD5.file(file_path).hexdigest
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,44 @@
1
+ module Calabash
2
+ module ConsoleHelpers
3
+ def self.render(data, indentation)
4
+ if visible?(data)
5
+ type = data['type']
6
+ simple_name = type.split('.').last.split('$').last
7
+
8
+ str_type = if data['type'] == 'dom'
9
+ "#{Color.yellow("[")}#{simple_name}:#{Color.yellow("#{data['nodeName']}]")} "
10
+ else
11
+ Color.yellow("[#{simple_name}] ")
12
+ end
13
+
14
+ text = nil
15
+
16
+ if data['value']
17
+ unless data['value'].empty?
18
+ if data['value'].length > 45
19
+ text = "#{data['value'][0,45]}[...]"
20
+ else
21
+ text = data['value']
22
+ end
23
+
24
+ newline_index = text.index("\n")
25
+
26
+ unless newline_index.nil?
27
+ text = "#{text[0,newline_index]}[...]"
28
+ end
29
+ end
30
+ end
31
+
32
+ str_id = data['id'] ? "[id:#{Color.blue(data['id'])}] " : ''
33
+ str_label = data['label'] ? "[contentDescription:#{Color.green(data['label'])}] " : ''
34
+ str_text = text ? "[text:#{Color.magenta(text)}] " : ''
35
+ output("#{str_type}#{str_id}#{str_label}#{str_text}", indentation)
36
+ output("\n", indentation)
37
+ end
38
+ end
39
+
40
+ def self.visible?(data)
41
+ data['visible'] || data['children'].map{|child| visible?(child)}.any?
42
+ end
43
+ end
44
+ end