ruboto 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +5 -3
  3. data/README.md +1 -1
  4. data/RELEASE_CANDICATE_DOC.md +22 -5
  5. data/RELEASE_DOC.md +58 -26
  6. data/Rakefile +68 -163
  7. data/Vagrantfile +46 -0
  8. data/assets/rakelib/ruboto.device.rb +170 -0
  9. data/assets/rakelib/ruboto.rake +121 -239
  10. data/assets/rakelib/ruboto.stdlib.rake +1 -1
  11. data/assets/src/org/ruboto/JRubyAdapter.java +1 -0
  12. data/lib/ruboto/sdk_versions.rb +5 -4
  13. data/lib/ruboto/util/emulator.rb +6 -4
  14. data/lib/ruboto/util/setup.rb +40 -23
  15. data/lib/ruboto/util/update.rb +61 -13
  16. data/lib/ruboto/version.rb +1 -1
  17. data/test/activity/dir_and_file_activity_test.rb +3 -3
  18. data/test/activity/json_activity.rb +11 -0
  19. data/test/activity/navigation_activity_test.rb +2 -1
  20. data/test/activity/stack_activity_test.rb +16 -12
  21. data/test/app_test_methods.rb +4 -4
  22. data/test/arjdbc_test.rb +18 -7
  23. data/test/broadcast_receiver_test.rb +1 -1
  24. data/test/gem_test.rb +1 -1
  25. data/test/git_based_gem_test.rb +1 -1
  26. data/test/minimal_app_test.rb +7 -5
  27. data/test/rake_test.rb +3 -3
  28. data/test/ruboto_activity_test.rb +1 -1
  29. data/test/ruboto_gen_test.rb +25 -11
  30. data/test/ruboto_setup_test.rb +1 -1
  31. data/test/ruboto_update_test.rb +3 -3
  32. data/test/sample_broadcast_receiver_test.rb +1 -1
  33. data/test/service_block_test.rb +1 -1
  34. data/test/service_gen_class_test.rb +1 -1
  35. data/test/service_infile_class_test.rb +1 -1
  36. data/test/splash_test.rb +1 -1
  37. data/test/sqldroid_test.rb +1 -1
  38. data/test/test_helper.rb +22 -18
  39. data/test/update_test_methods.rb +1 -1
  40. data/test/updated_example_test_methods.rb +1 -1
  41. data/test/uppercase_package_name_test.rb +3 -3
  42. metadata +20 -3
@@ -0,0 +1,46 @@
1
+ # -*- mode: ruby -*-
2
+ # vi: set ft=ruby :
3
+
4
+ # @param swap_size_mb [Integer] swap size in megabytes
5
+ # @param swap_file [String] full path for swap file, default is /swapfile1
6
+ # @return [String] the script text for shell inline provisioning
7
+ def create_swap(swap_size_mb, swap_file = '/swapfile')
8
+ <<-EOS
9
+ if [ ! -f #{swap_file} ]; then
10
+ echo "Creating #{swap_size_mb}mb swap file=#{swap_file}. This could take a while..."
11
+ dd if=/dev/zero of=#{swap_file} bs=1024 count=#{swap_size_mb * 1024}
12
+ mkswap #{swap_file}
13
+ chmod 0600 #{swap_file}
14
+ swapon #{swap_file}
15
+ if ! grep -Fxq "#{swap_file} swap swap defaults 0 0" /etc/fstab
16
+ then
17
+ echo "#{swap_file} swap swap defaults 0 0" >> /etc/fstab
18
+ fi
19
+ fi
20
+ EOS
21
+ end
22
+
23
+
24
+ Vagrant.configure(2) do |config|
25
+ config.vm.provider 'virtualbox' do |vb|
26
+ # vb.gui = true
27
+ vb.memory = '3072'
28
+ end
29
+
30
+ config.vm.define 'ubuntu' do |ubuntu|
31
+ ubuntu.vm.box = 'ubuntu/trusty64'
32
+ ubuntu.vm.provision :shell, inline: create_swap(1536)
33
+ ubuntu.vm.provision :shell, inline: <<-SHELL
34
+ sudo apt-get -y install git libc6-i386 lib32stdc++6 lib32gcc1 lib32ncurses5 lib32z1
35
+ su - vagrant -c 'command curl -sSL https://rvm.io/mpapis.asc | gpg --import -'
36
+ su - vagrant -c 'curl -sSL https://get.rvm.io | bash -s stable --ruby'
37
+ su - vagrant -c 'mkdir -p ruboto'
38
+ su - vagrant -c 'rsync -acPuv --exclude adb_logcat.log --exclude /tmp /vagrant/* ruboto/'
39
+ SHELL
40
+ end
41
+
42
+ config.vm.define 'windows' do |db|
43
+ db.vm.box = 'designerror/windows-7'
44
+ end
45
+
46
+ end
@@ -0,0 +1,170 @@
1
+ ######################################
2
+ #
3
+ # Methods for package installation
4
+ #
5
+
6
+ APK_FILE_REGEXP = /^-rw-r--r--\s+(?:system|\d+\s+\d+)\s+(?:system|\d+)\s+(\d+)\s+(\d{4}-\d{2}-\d{2} \d{2}:\d{2}|\w{3} \d{2}\s+(?:\d{4}|\d{2}:\d{2}))\s+(.*)$/
7
+ PROJECT_DIR = File.expand_path('..', File.dirname(__FILE__))
8
+ UPDATE_MARKER_FILE = File.join(PROJECT_DIR, 'bin', 'LAST_UPDATE')
9
+
10
+ # Determine if the package is installed.
11
+ # Return true if the package is installed and is identical to the local package.
12
+ # Return false if the package is installed, but differs from the local package.
13
+ # Return nil if the package is not installed.
14
+ def package_installed?(package_name, apk_file)
15
+ loop do
16
+ path_line = `adb shell pm path #{package_name}`.chomp
17
+ path_line.gsub! /^WARNING:.*$/, ''
18
+ return nil if $? == 0 && path_line.empty?
19
+ break if $? == 0 && path_line =~ /^package:(.*)$/
20
+ puts path_line
21
+ sleep 0.5
22
+ end
23
+ path = $1
24
+ o = `adb shell ls -l #{path}`.chomp
25
+ raise "Unexpected ls output: #{o}" unless o =~ APK_FILE_REGEXP
26
+ installed_apk_size = $1.to_i
27
+ installed_timestamp = Time.parse($2)
28
+ !File.exists?(apk_file) || (installed_apk_size == File.size(apk_file) &&
29
+ installed_timestamp >= File.mtime(apk_file))
30
+ end
31
+
32
+ def scripts_path(package)
33
+ @sdcard_path ||= "/mnt/sdcard/Android/data/#{package}/files/scripts"
34
+ end
35
+
36
+ def mark_update(time = Time.now)
37
+ FileUtils.mkdir_p File.dirname(UPDATE_MARKER_FILE)
38
+ File.open(UPDATE_MARKER_FILE, 'w') { |f| f << time.iso8601 }
39
+ end
40
+
41
+ def clear_update(package, apk_file)
42
+ mark_update File.ctime apk_file
43
+ if device_path_exists?(scripts_path(package))
44
+ sh "adb shell rm -r #{scripts_path(package)}"
45
+ puts "Deleted scripts directory #{scripts_path(package)}"
46
+ end
47
+ end
48
+
49
+ def device_path_exists?(path)
50
+ path_output =`adb shell ls #{path}`
51
+ path_output.chomp !~ /No such file or directory|opendir failed, Permission denied/
52
+ end
53
+
54
+ def wait_for_valid_device
55
+ while `adb shell echo "ping"`.strip != 'ping'
56
+ `adb kill-server`
57
+ `adb devices`
58
+ sleep 5
59
+ end
60
+ end
61
+
62
+ def install_apk(package, apk_file)
63
+ wait_for_valid_device
64
+
65
+ failure_pattern = /^Failure \[(.*)\]/
66
+ success_pattern = /^Success/
67
+ case package_installed?(package, apk_file)
68
+ when true
69
+ puts "Package #{package} already installed."
70
+ return
71
+ when false
72
+ puts "Package #{package} already installed, but of different size or timestamp. Replacing package."
73
+ sh "adb shell date -s #{Time.now.strftime '%Y%m%d.%H%M%S'}"
74
+ output = nil
75
+ install_retry_count = 0
76
+ begin
77
+ timeout 300 do
78
+ output = `adb install -r "#{apk_file}" 2>&1`
79
+ end
80
+ rescue Timeout::Error
81
+ puts "Installing package #{package} timed out."
82
+ install_retry_count += 1
83
+ if install_retry_count <= 3
84
+ puts 'Retrying install...'
85
+ retry
86
+ end
87
+ puts 'Trying one final time to install the package:'
88
+ output = `adb install -r "#{apk_file}" 2>&1`
89
+ end
90
+ if $? == 0 && output !~ failure_pattern && output =~ success_pattern
91
+ clear_update(package, apk_file)
92
+ return
93
+ end
94
+ case $1
95
+ when 'INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES'
96
+ puts 'Found package signed with different certificate. Uninstalling it and retrying install.'
97
+ else
98
+ puts "'adb install' returned an unknown error: (#$?) #{$1 ? "[#$1}]" : output}."
99
+ puts "Uninstalling #{package} and retrying install."
100
+ end
101
+ uninstall_apk(package, apk_file)
102
+ else
103
+ # Package not installed.
104
+ sh "adb shell date -s #{Time.now.strftime '%Y%m%d.%H%M%S'}"
105
+ end
106
+ puts "Installing package #{package}"
107
+ output = nil
108
+ install_retry_count = 0
109
+ begin
110
+ timeout 300 do
111
+ output = `adb install "#{apk_file}" 2>&1`
112
+ end
113
+ rescue Timeout::Error
114
+ puts "Installing package #{package} timed out."
115
+ install_retry_count += 1
116
+ if install_retry_count <= 3
117
+ puts 'Retrying install...'
118
+ retry
119
+ end
120
+ puts 'Trying one final time to install the package:'
121
+ install_start = Time.now
122
+ output = `adb install "#{apk_file}" 2>&1`
123
+ puts "Install took #{(Time.now - install_start).to_i}s."
124
+ end
125
+ puts output
126
+ raise "Install failed (#{$?}) #{$1 ? "[#$1}]" : output}" if $? != 0 || output =~ failure_pattern || output !~ success_pattern
127
+ clear_update(package, apk_file)
128
+ end
129
+
130
+ def uninstall_apk(package_name, apk_file)
131
+ return if package_installed?(package_name, apk_file).nil?
132
+ puts "Uninstalling package #{package_name}"
133
+ system "adb uninstall #{package_name}"
134
+ if $? != 0 && package_installed?(package, apk_file)
135
+ puts "Uninstall failed exit code #{$?}"
136
+ exit $?
137
+ end
138
+ end
139
+
140
+ def update_scripts(package)
141
+ # FIXME(uwe): Simplify when we stop supporting Android 2.3
142
+ if sdk_level < 15
143
+ scripts_path(package).split('/').tap do |parts|
144
+ parts.size.times do |i|
145
+ path = parts[0..i].join('/')
146
+ puts(`adb shell mkdir #{path}`) unless device_path_exists?(path)
147
+ end
148
+ end
149
+ else
150
+ puts(`adb shell mkdir -p #{scripts_path(package)}`) unless device_path_exists?(scripts_path(package))
151
+ end
152
+ # EMXIF
153
+
154
+ raise "Unable to create device scripts dir: #{scripts_path(package)}" unless device_path_exists?(scripts_path(package))
155
+ last_update = File.exists?(UPDATE_MARKER_FILE) ? Time.parse(File.read(UPDATE_MARKER_FILE)) : Time.parse('1970-01-01T00:00:00')
156
+ Dir.chdir('src') do
157
+ source_files = Dir['**/*.rb']
158
+ changed_files = source_files.select { |f| !File.directory?(f) && File.mtime(f) >= last_update && f !~ /~$/ }
159
+ unless changed_files.empty?
160
+ puts 'Pushing files to apk public file area:'
161
+ changed_files.each do |script_file|
162
+ print "#{script_file}: "; $stdout.flush
163
+ system "adb push #{script_file} #{scripts_path(package)}/#{script_file}"
164
+ end
165
+ mark_update
166
+ return changed_files
167
+ end
168
+ end
169
+ nil
170
+ end
@@ -4,6 +4,7 @@ require 'time'
4
4
  require 'rake/clean'
5
5
  require 'rexml/document'
6
6
  require 'timeout'
7
+ require_relative 'ruboto.device'
7
8
 
8
9
  ON_WINDOWS = (RbConfig::CONFIG['host_os'] =~ /mswin|mingw/i)
9
10
 
@@ -37,8 +38,8 @@ end
37
38
 
38
39
  adb_version_str = `adb version`
39
40
  (puts 'Android SDK platform tools not in PATH (adb command not found).'; exit 1) unless $? == 0
40
- (puts "Unrecognized adb version: #$1"; exit 1) unless adb_version_str =~ /Android Debug Bridge version (\d+\.\d+\.\d+)/
41
- (puts "adb version 1.0.31 or later required. Version found: #$1"; exit 1) unless Gem::Version.new($1) >= Gem::Version.new('1.0.31')
41
+ (puts "Unrecognized adb version: #{$1}"; exit 1) unless adb_version_str =~ /Android Debug Bridge version (\d+\.\d+\.\d+)/
42
+ (puts "adb version 1.0.31 or later required. Version found: #{$1}"; exit 1) unless Gem::Version.new($1) >= Gem::Version.new('1.0.31')
42
43
  android_home = ENV['ANDROID_HOME']
43
44
  if android_home.nil?
44
45
  if (adb_path = which('adb'))
@@ -52,10 +53,10 @@ else
52
53
  end
53
54
 
54
55
  # FIXME(uwe): Simplify when we stop supporting Android SDK < 22: Don't look in platform-tools for dx
55
- DX_FILENAME = Dir[File.join(android_home, '{build-tools/*,platform-tools}', ON_WINDOWS ? 'dx.bat' : 'dx')][-1]
56
+ DX_FILENAMES = Dir[File.join(android_home, '{build-tools/*,platform-tools}', ON_WINDOWS ? 'dx.bat' : 'dx')]
56
57
  # EMXIF
57
58
 
58
- unless DX_FILENAME
59
+ unless DX_FILENAMES.any?
59
60
  puts 'You need to install the Android SDK Build-tools!'
60
61
  exit 1
61
62
  end
@@ -72,16 +73,10 @@ def build_project_name
72
73
  @build_project_name ||= REXML::Document.new(File.read('build.xml')).elements['project'].attribute(:name).value
73
74
  end
74
75
 
75
- def scripts_path
76
- @sdcard_path ||= "/mnt/sdcard/Android/data/#{package}/files/scripts"
77
- end
78
-
79
76
  def app_files_path
80
77
  @app_files_path ||= "/data/data/#{package}/files"
81
78
  end
82
79
 
83
- PROJECT_DIR = File.expand_path('..', File.dirname(__FILE__))
84
- UPDATE_MARKER_FILE = File.join(PROJECT_DIR, 'bin', 'LAST_UPDATE')
85
80
  BUNDLE_JAR = File.expand_path 'libs/bundle.jar'
86
81
  BUNDLE_PATH = File.join(PROJECT_DIR, 'bin', 'bundle')
87
82
  MANIFEST_FILE = File.expand_path 'AndroidManifest.xml'
@@ -105,13 +100,12 @@ APK_DEPENDENCIES = [:patch_dex, MANIFEST_FILE, BUILD_XML_FILE, RUBOTO_CONFIG_FIL
105
100
  QUICK_APK_DEPENDENCIES = APK_DEPENDENCIES - RUBY_SOURCE_FILES
106
101
  KEYSTORE_FILE = (key_store = File.readlines('ant.properties').grep(/^key.store=/).first) ? File.expand_path(key_store.chomp.sub(/^key.store=/, '').sub('${user.home}', '~')) : "#{build_project_name}.keystore"
107
102
  KEYSTORE_ALIAS = (key_alias = File.readlines('ant.properties').grep(/^key.alias=/).first) ? key_alias.chomp.sub(/^key.alias=/, '') : build_project_name
108
- APK_FILE_REGEXP = /^-rw-r--r--\s+(?:system|\d+\s+\d+)\s+(?:system|\d+)\s+(\d+)\s+(\d{4}-\d{2}-\d{2} \d{2}:\d{2}|\w{3} \d{2}\s+(?:\d{4}|\d{2}:\d{2}))\s+(.*)$/
109
103
  JRUBY_ADAPTER_FILE = "#{PROJECT_DIR}/src/org/ruboto/JRubyAdapter.java"
110
104
  RUBOTO_ACTIVITY_FILE = "#{PROJECT_DIR}/src/org/ruboto/RubotoActivity.java"
111
105
 
112
106
  CLEAN.include('bin', 'gen', 'test/bin', 'test/gen')
113
107
 
114
- task :default => :debug
108
+ task default: :debug
115
109
 
116
110
  if File.exists?(CLASSES_CACHE)
117
111
  expected_jars = File.readlines(CLASSES_CACHE).grep(%r{#{PROJECT_DIR}/libs/(.*\.jar) \\}).map { |l| l =~ %r{#{PROJECT_DIR}/libs/(.*\.jar) \\}; $1 }
@@ -143,45 +137,45 @@ file JRUBY_JARS => RUBOTO_CONFIG_FILE do
143
137
  end
144
138
 
145
139
  desc 'build debug package'
146
- task :debug => APK_FILE
140
+ task debug: APK_FILE
147
141
 
148
142
  namespace :debug do
149
143
  desc 'build debug package if compiled files have changed'
150
- task :quick => QUICK_APK_DEPENDENCIES do |t|
144
+ task quick: QUICK_APK_DEPENDENCIES do |t|
151
145
  build_apk(t, false)
152
146
  end
153
147
  end
154
148
 
155
149
  desc 'build package and install it on the emulator or device'
156
- task :install => APK_FILE do
157
- install_apk
150
+ task install: APK_FILE do
151
+ install_apk(package, APK_FILE)
158
152
  end
159
153
 
160
154
  desc 'uninstall, build, and install the application'
161
- task :reinstall => [:uninstall, APK_FILE, :install]
155
+ task reinstall: [:uninstall, APK_FILE, :install]
162
156
 
163
157
  namespace :install do
164
158
  # FIXME(uwe): Remove December 2013
165
159
  desc 'Deprecated: use "reinstall" instead.'
166
- task :clean => :reinstall do
160
+ task clean: :reinstall do
167
161
  puts '"rake install:clean" is deprecated. Use "rake reinstall" instead.'
168
162
  end
169
163
 
170
164
  desc 'Install the application, but only if compiled files are changed.'
171
- task :quick => 'debug:quick' do
172
- install_apk
165
+ task quick: 'debug:quick' do
166
+ install_apk(package, APK_FILE)
173
167
  end
174
168
  end
175
169
 
176
170
  desc 'Build APK for release'
177
- task :release => [:tag, RELEASE_APK_FILE]
171
+ task release: [:tag, RELEASE_APK_FILE]
178
172
 
179
173
  file RELEASE_APK_FILE => [KEYSTORE_FILE] + APK_DEPENDENCIES do |t|
180
174
  build_apk(t, true)
181
175
  end
182
176
 
183
177
  desc 'Create a keystore for signing the release APK'
184
- task :keystore => KEYSTORE_FILE
178
+ task keystore: KEYSTORE_FILE
185
179
 
186
180
  file KEYSTORE_FILE do
187
181
  unless File.read('ant.properties') =~ /^key.store=/
@@ -226,10 +220,10 @@ task :stop do
226
220
  end
227
221
 
228
222
  desc 'Restart the application'
229
- task :restart => [:stop, :start]
223
+ task restart: [:stop, :start]
230
224
 
231
225
  task :uninstall do
232
- uninstall_apk
226
+ uninstall_apk(package, APK_FILE)
233
227
  end
234
228
 
235
229
  file PROJECT_PROPS_FILE
@@ -239,11 +233,11 @@ file MANIFEST_FILE => PROJECT_PROPS_FILE do
239
233
 
240
234
  # FIXME(uwe): Remove 'L' special case when Android L has been released.
241
235
  if sdk_level == 21
242
- manifest.sub!(/(android:minSdkVersion=').*?(')/) { "#$1L#$2" }
243
- manifest.sub!(/(android:targetSdkVersion=').*?(')/) { "#$1L#$2" }
236
+ manifest.sub!(/(android:minSdkVersion=').*?(')/) { "#{$1}L#{$2}" }
237
+ manifest.sub!(/(android:targetSdkVersion=').*?(')/) { "#{$1}L#{$2}" }
244
238
  else
245
- manifest.sub!(/(android:minSdkVersion=').*?(')/) { "#$1#{sdk_level}#$2" }
246
- manifest.sub!(/(android:targetSdkVersion=').*?(')/) { "#$1#{sdk_level}#$2" }
239
+ manifest.sub!(/(android:minSdkVersion=').*?(')/) { "#{$1}#{sdk_level}#{$2}" }
240
+ manifest.sub!(/(android:targetSdkVersion=').*?(')/) { "#{$1}#{sdk_level}#{$2}" }
247
241
  end
248
242
  # EMXIF
249
243
 
@@ -255,7 +249,7 @@ end
255
249
 
256
250
  file RUBOTO_CONFIG_FILE
257
251
 
258
- task :build_xml => BUILD_XML_FILE
252
+ task build_xml: BUILD_XML_FILE
259
253
  file BUILD_XML_FILE => RUBOTO_CONFIG_FILE do
260
254
  puts 'patching build.xml'
261
255
  ant_script = File.read(BUILD_XML_FILE)
@@ -374,7 +368,10 @@ file BUILD_XML_FILE => RUBOTO_CONFIG_FILE do
374
368
 
375
369
  <if>
376
370
  <condition>
377
- <contains string="${dex.merge.output}" substring="method ID not in [0, 0xffff]: 65536"/>
371
+ <or>
372
+ <contains string="${dex.merge.output}" substring="method ID not in [0, 0xffff]: 65536"/>
373
+ <contains string="${dex.merge.output}" substring="Too many method references"/>
374
+ </or>
378
375
  </condition>
379
376
  <then>
380
377
  <echo message="The package contains too many methods. Switching to multi-dex build." />
@@ -479,7 +476,7 @@ file BUILD_XML_FILE => RUBOTO_CONFIG_FILE do
479
476
  File.open(BUILD_XML_FILE, 'w') { |f| f << ant_script }
480
477
  end
481
478
 
482
- task :jruby_adapter => JRUBY_ADAPTER_FILE
479
+ task jruby_adapter: JRUBY_ADAPTER_FILE
483
480
  file JRUBY_ADAPTER_FILE => RUBOTO_CONFIG_FILE do
484
481
  require 'yaml'
485
482
 
@@ -532,7 +529,7 @@ EOF
532
529
  File.open(JRUBY_ADAPTER_FILE, 'w') { |f| f << source }
533
530
  end
534
531
 
535
- task :ruboto_activity => RUBOTO_ACTIVITY_FILE
532
+ task ruboto_activity: RUBOTO_ACTIVITY_FILE
536
533
  file RUBOTO_ACTIVITY_FILE => RUBY_ACTIVITY_SOURCE_FILES do |task|
537
534
  original_source = File.read(RUBOTO_ACTIVITY_FILE)
538
535
  next unless original_source =~ %r{\A(.*Generated Methods.*?\*/\n*)(.*)\B}m
@@ -555,55 +552,57 @@ file APK_FILE => APK_DEPENDENCIES do |t|
555
552
  build_apk(t, false)
556
553
  end
557
554
 
558
- MINIMUM_DX_HEAP_SIZE = 3072
555
+ MINIMUM_DX_HEAP_SIZE = (ENV['DX_HEAP_SIZE'] && ENV['DX_HEAP_SIZE'].to_i) || 4096
559
556
  task :patch_dex do
560
- new_dx_content = File.read(DX_FILENAME).dup
561
- xmx_pattern = ON_WINDOWS ? /^set defaultXmx=-Xmx(\d+)(M|m|G|g|T|t)/ : /^defaultMx="-Xmx(\d+)(M|m|G|g|T|t)"/
562
- if new_dx_content =~ xmx_pattern &&
563
- ($1.to_i * 1024 ** {'M' => 2, 'G' => 3, 'T' => 4}[$2.upcase]) < MINIMUM_DX_HEAP_SIZE*1024**2
564
- puts "Increasing max heap space from #$1#$2 to #{MINIMUM_DX_HEAP_SIZE}M in #{DX_FILENAME}"
565
- new_xmx_value = ON_WINDOWS ? %Q{set defaultXmx=-Xmx#{MINIMUM_DX_HEAP_SIZE}M} : %Q{defaultMx="-Xmx#{MINIMUM_DX_HEAP_SIZE}M"}
566
- new_dx_content.sub!(xmx_pattern, new_xmx_value)
567
- File.open(DX_FILENAME, 'w') { |f| f << new_dx_content } rescue puts "\n!!! Unable to increase dx heap size !!!\n\n"
557
+ DX_FILENAMES.each do |dx_filename|
558
+ new_dx_content = File.read(dx_filename).dup
559
+ xmx_pattern = ON_WINDOWS ? /^set defaultXmx=-Xmx(\d+)(M|m|G|g|T|t)/ : /^defaultMx="-Xmx(\d+)(M|m|G|g|T|t)"/
560
+ if new_dx_content =~ xmx_pattern &&
561
+ ($1.to_i * 1024 ** {M: 2, G: 3, T: 4}[$2.upcase.to_sym]) < MINIMUM_DX_HEAP_SIZE*1024**2
562
+ puts "Increasing max heap space from #{$1}#{$2} to #{MINIMUM_DX_HEAP_SIZE}M in #{dx_filename}"
563
+ new_xmx_value = ON_WINDOWS ? %Q{set defaultXmx=-Xmx#{MINIMUM_DX_HEAP_SIZE}M} : %Q{defaultMx="-Xmx#{MINIMUM_DX_HEAP_SIZE}M"}
564
+ new_dx_content.sub!(xmx_pattern, new_xmx_value)
565
+ File.open(dx_filename, 'w') { |f| f << new_dx_content } rescue puts "\n!!! Unable to increase dx heap size !!!\n\n"
566
+ end
568
567
  end
569
568
  end
570
569
 
571
570
  desc 'Copy scripts to emulator or device'
572
- task :update_scripts => %w(install:quick) do
573
- update_scripts
571
+ task update_scripts: %w(install:quick) do
572
+ update_scripts(package)
574
573
  end
575
574
 
576
575
  desc 'Copy scripts to emulator or device and reload'
577
- task :boing => %w(update_scripts:reload)
576
+ task boing: %w(update_scripts:reload)
578
577
 
579
578
  namespace :update_scripts do
580
579
  desc 'Copy scripts to emulator and restart the app'
581
- task :restart => QUICK_APK_DEPENDENCIES do |t|
580
+ task restart: QUICK_APK_DEPENDENCIES do |t|
582
581
  if build_apk(t, false) || !stop_app
583
- install_apk
582
+ install_apk(package, APK_FILE)
584
583
  else
585
- update_scripts
584
+ update_scripts(package)
586
585
  end
587
586
  start_app
588
587
  end
589
588
 
590
589
  desc 'Copy scripts to emulator and restart the app'
591
- task :start => QUICK_APK_DEPENDENCIES do |t|
590
+ task start: QUICK_APK_DEPENDENCIES do |t|
592
591
  if build_apk(t, false)
593
- install_apk
592
+ install_apk(package, APK_FILE)
594
593
  else
595
- update_scripts
594
+ update_scripts(package)
596
595
  end
597
596
  start_app
598
597
  end
599
598
 
600
599
  desc 'Copy scripts to emulator and reload'
601
- task :reload => QUICK_APK_DEPENDENCIES do |t|
600
+ task reload: QUICK_APK_DEPENDENCIES do |t|
602
601
  if build_apk(t, false)
603
- install_apk
602
+ install_apk(package, APK_FILE)
604
603
  start_app
605
604
  else
606
- scripts = update_scripts
605
+ scripts = update_scripts(package)
607
606
  if scripts && app_running?
608
607
  reload_scripts(scripts)
609
608
  else
@@ -613,7 +612,7 @@ namespace :update_scripts do
613
612
  end
614
613
  end
615
614
 
616
- task :test => APK_DEPENDENCIES + [:uninstall] do
615
+ task test: APK_DEPENDENCIES + [:uninstall] do
617
616
  Dir.chdir('test') do
618
617
  puts 'Running tests'
619
618
  sh "adb uninstall #{package}.tests"
@@ -622,7 +621,7 @@ task :test => APK_DEPENDENCIES + [:uninstall] do
622
621
  end
623
622
 
624
623
  namespace :test do
625
- task :quick => :update_scripts do
624
+ task quick: :update_scripts do
626
625
  Dir.chdir('test') do
627
626
  puts 'Running quick tests'
628
627
  install_retry_count = 0
@@ -649,7 +648,7 @@ file GEM_FILE
649
648
  file GEM_LOCK_FILE
650
649
 
651
650
  desc 'Generate bundle jar from Gemfile'
652
- task :bundle => BUNDLE_JAR
651
+ task bundle: BUNDLE_JAR
653
652
 
654
653
  file BUNDLE_JAR => [GEM_FILE, GEM_LOCK_FILE] do
655
654
  next unless File.exists? GEM_FILE
@@ -658,8 +657,9 @@ file BUNDLE_JAR => [GEM_FILE, GEM_LOCK_FILE] do
658
657
  if false
659
658
  # FIXME(uwe): Issue #547 https://github.com/ruboto/ruboto/issues/547
660
659
  # Bundler.settings[:platform] = Gem::Platform::DALVIK
661
- sh "bundle install --gemfile #{GEM_FILE} --path=#{BUNDLE_PATH} --platform=dalvik#{sdk_level}"
660
+ sh "bundle install --gemfile #{GEM_FILE} --path=#{BUNDLE_PATH} --platform=dalvik#{sdk_level} --without development test"
662
661
  else
662
+ # ENV["DEBUG"] = "true"
663
663
  require 'bundler/vendored_thor'
664
664
 
665
665
  # Store original RubyGems/Bundler environment
@@ -672,6 +672,8 @@ file BUNDLE_JAR => [GEM_FILE, GEM_LOCK_FILE] do
672
672
  Gem.platforms = [Gem::Platform::RUBY, Gem::Platform.new("universal-dalvik-#{sdk_level}"), Gem::Platform.new('universal-java')]
673
673
  ENV['GEM_HOME'] = BUNDLE_PATH
674
674
  ENV['GEM_PATH'] = BUNDLE_PATH
675
+ Gem.paths = BUNDLE_PATH
676
+ Gem.refresh
675
677
  old_verbose, $VERBOSE = $VERBOSE, nil
676
678
  begin
677
679
  Object.const_set('RUBY_ENGINE', 'jruby')
@@ -682,6 +684,7 @@ file BUNDLE_JAR => [GEM_FILE, GEM_LOCK_FILE] do
682
684
 
683
685
  Bundler.ui = Bundler::UI::Shell.new
684
686
  Bundler.bundle_path = Pathname.new BUNDLE_PATH
687
+ Bundler.settings.without = [:development, :test]
685
688
  definition = Bundler.definition
686
689
  definition.validate_ruby!
687
690
  Bundler::Installer.install(Bundler.root, definition)
@@ -702,6 +705,14 @@ file BUNDLE_JAR => [GEM_FILE, GEM_LOCK_FILE] do
702
705
  ENV['GEM_PATH'] = env_path
703
706
  end
704
707
 
708
+ GEM_PATH_PATTERN = /^PATH\s*remote:\s*(.*)$\s*specs:\s*(.*)\s+\(.+\)$/
709
+ File.read(GEM_LOCK_FILE).scan(GEM_PATH_PATTERN).each do |path, name|
710
+ FileUtils.mkpath "#{BUNDLE_PATH}/gems"
711
+ FileUtils.rm_rf "#{BUNDLE_PATH}/gems/#{name}"
712
+ FileUtils.cp_r File.expand_path(path, File.dirname(GEM_FILE)),
713
+ "#{BUNDLE_PATH}/gems"
714
+ end
715
+
705
716
  gem_paths = Dir["#{BUNDLE_PATH}/gems"]
706
717
  raise 'Gem path not found' if gem_paths.empty?
707
718
  raise "Found multiple gem paths: #{gem_paths}" if gem_paths.size > 1
@@ -731,28 +742,6 @@ file BUNDLE_JAR => [GEM_FILE, GEM_LOCK_FILE] do
731
742
  end
732
743
  end
733
744
 
734
- # Remove duplicate files
735
- Dir.chdir gem_path do
736
- scanned_files = []
737
- source_files = RUBY_SOURCE_FILES.map { |f| f.gsub("#{PROJECT_DIR}/src/", '') }
738
- Dir['*/lib/**/*'].each do |f|
739
- next if File.directory? f
740
- raise 'Malformed file name' unless f =~ %r{^(.*?)/lib/(.*)$}
741
- gem_name, lib_file = $1, $2
742
- if (existing_file = scanned_files.find { |sf| sf =~ %r{(.*?)/lib/#{lib_file}} })
743
- puts "Overwriting duplicate file #{lib_file} in gem #{$1} with file in #{gem_name}"
744
- FileUtils.rm existing_file
745
- scanned_files.delete existing_file
746
- elsif source_files.include? lib_file
747
- puts "Removing duplicate file #{lib_file} in gem #{gem_name}"
748
- puts "Already present in project source src/#{lib_file}"
749
- FileUtils.rm f
750
- next
751
- end
752
- scanned_files << f
753
- end
754
- end
755
-
756
745
  # Expand JARs
757
746
  Dir.chdir gem_path do
758
747
  Dir['*'].each do |gem_lib|
@@ -812,6 +801,20 @@ puts 'Starting JSON Parser Service'
812
801
  public
813
802
  Java::json.ext.ParserService.new.basicLoad(JRuby.runtime)
814
803
  END_CODE
804
+ elsif jar =~ %r{thread_safe/jruby_cache_backend.jar$}
805
+ jar_load_code = <<-END_CODE
806
+ require 'jruby'
807
+ puts 'Starting threadsafe JRubyCacheBackend Service'
808
+ public
809
+ begin
810
+ Java::thread_safe.JrubyCacheBackendService.new.basicLoad(JRuby.runtime)
811
+ rescue Exception
812
+ puts "Exception starting threadsafe JRubyCacheBackend Service"
813
+ puts $!
814
+ puts $!.backtrace.join("\n")
815
+ raise
816
+ end
817
+ END_CODE
815
818
  else
816
819
  jar_load_code = ''
817
820
  end
@@ -823,7 +826,45 @@ Java::json.ext.ParserService.new.basicLoad(JRuby.runtime)
823
826
  end
824
827
  FileUtils.rm_f(jar)
825
828
  end
829
+
830
+ # FIXME(uwe): Issue # 705 https://github.com/ruboto/ruboto/issues/705
831
+ # FIXME(uwe): Use the files from the bundle instead of stdlib.
832
+ if (stdlib_jar = Dir["#{PROJECT_DIR}/libs/jruby-stdlib-*.jar"].sort.last)
833
+ stdlib_files = `jar tf #{stdlib_jar}`.lines.map(&:chomp)
834
+ Dir['**/*'].each do |f|
835
+ if stdlib_files.include? f
836
+ puts "Removing duplicate file #{f} in gem #{gem_lib}."
837
+ puts 'Already present in the Ruby Standard Library.'
838
+ FileUtils.rm f
839
+ end
840
+ end
841
+ end
842
+ # EMXIF
843
+
844
+ end
845
+ end
846
+ end
847
+
848
+ # Remove duplicate files
849
+ Dir.chdir gem_path do
850
+ scanned_files = []
851
+ source_files = RUBY_SOURCE_FILES.map { |f| f.gsub("#{PROJECT_DIR}/src/", '') }
852
+ # FIXME(uwe): The gems should be loaded in the loading order defined by the Gemfile.apk(.lock)
853
+ Dir['*/lib/**/*'].sort.each do |f|
854
+ next if File.directory? f
855
+ raise 'Malformed file name' unless f =~ %r{^(.*?)/lib/(.*)$}
856
+ gem_name, lib_file = $1, $2
857
+ if (existing_file = scanned_files.find { |sf| sf =~ %r{(.*?)/lib/#{lib_file}} })
858
+ puts "Overwriting duplicate file #{lib_file} in gem #{$1} with file in #{gem_name}"
859
+ FileUtils.rm existing_file
860
+ scanned_files.delete existing_file
861
+ elsif source_files.include? lib_file
862
+ puts "Removing duplicate file #{lib_file} in gem #{gem_name}"
863
+ puts "Already present in project source src/#{lib_file}"
864
+ FileUtils.rm f
865
+ next
826
866
  end
867
+ scanned_files << f
827
868
  end
828
869
  end
829
870
 
@@ -850,6 +891,7 @@ task :log, [:filter] do |t, args|
850
891
  android_4_2_noise_regex = /Unexpected value from nativeGetEnabledTags/
851
892
  pid_regex = nil
852
893
  logcat.each_line do |line|
894
+ line.force_encoding(Encoding::BINARY)
853
895
  # FIXME(uwe): Remove when we stop supporting Ancdroid 4.2
854
896
  next if line =~ android_4_2_noise_regex
855
897
  # EMXIF
@@ -875,19 +917,6 @@ def sdk_level
875
917
  level == 0 ? 21 : level
876
918
  end
877
919
 
878
- def mark_update(time = Time.now)
879
- FileUtils.mkdir_p File.dirname(UPDATE_MARKER_FILE)
880
- File.open(UPDATE_MARKER_FILE, 'w') { |f| f << time.iso8601 }
881
- end
882
-
883
- def clear_update
884
- mark_update File.ctime APK_FILE
885
- if device_path_exists?(scripts_path)
886
- sh "adb shell rm -r #{scripts_path}"
887
- puts "Deleted scripts directory #{scripts_path}"
888
- end
889
- end
890
-
891
920
  def strings(name)
892
921
  @strings ||= REXML::Document.new(File.read('res/values/strings.xml'))
893
922
  value = @strings.elements["//string[@name='#{name.to_s}']"] or raise "string '#{name}' not found in strings.xml"
@@ -906,35 +935,6 @@ def main_activity
906
935
  manifest.root.elements['application'].elements["activity[@android:label='@string/app_name']"].attribute('android:name')
907
936
  end
908
937
 
909
- def device_path_exists?(path)
910
- path_output =`adb shell ls #{path}`
911
- path_output.chomp !~ /No such file or directory|opendir failed, Permission denied/
912
- end
913
-
914
- # Determine if the package is installed.
915
- # Return true if the package is installed and is identical to the local package.
916
- # Return false if the package is installed, but differs from the local package.
917
- # Return nil if the package is not installed.
918
- def package_installed?(test = false)
919
- package_name = "#{package}#{'.tests' if test}"
920
- loop do
921
- path_line = `adb shell pm path #{package_name}`.chomp
922
- path_line.gsub! /^WARNING:.*$/, ''
923
- return nil if $? == 0 && path_line.empty?
924
- break if $? == 0 && path_line =~ /^package:(.*)$/
925
- puts path_line
926
- sleep 0.5
927
- end
928
- path = $1
929
- o = `adb shell ls -l #{path}`.chomp
930
- raise "Unexpected ls output: #{o}" if o !~ APK_FILE_REGEXP
931
- installed_apk_size = $1.to_i
932
- installed_timestamp = Time.parse($2)
933
- apk_file = test ? TEST_APK_FILE : APK_FILE
934
- !File.exists?(apk_file) || (installed_apk_size == File.size(apk_file) &&
935
- installed_timestamp >= File.mtime(apk_file))
936
- end
937
-
938
938
  def replace_faulty_code(faulty_file, faulty_code)
939
939
  explicit_requires = Dir["#{faulty_file.chomp('.rb')}/*.rb"].sort.map { |f| File.basename(f) }.map do |filename|
940
940
  "require 'active_model/validations/#{filename}'"
@@ -968,124 +968,6 @@ def build_apk(t, release)
968
968
  true
969
969
  end
970
970
 
971
- def wait_for_valid_device
972
- while `adb shell echo "ping"`.strip != 'ping'
973
- `adb kill-server`
974
- `adb devices`
975
- sleep 5
976
- end
977
- end
978
-
979
- def install_apk
980
- wait_for_valid_device
981
-
982
- failure_pattern = /^Failure \[(.*)\]/
983
- success_pattern = /^Success/
984
- case package_installed?
985
- when true
986
- puts "Package #{package} already installed."
987
- return
988
- when false
989
- puts "Package #{package} already installed, but of different size or timestamp. Replacing package."
990
- sh "adb shell date -s #{Time.now.strftime '%Y%m%d.%H%M%S'}"
991
- output = nil
992
- install_retry_count = 0
993
- begin
994
- timeout 300 do
995
- output = `adb install -r "#{APK_FILE}" 2>&1`
996
- end
997
- rescue Timeout::Error
998
- puts "Installing package #{package} timed out."
999
- install_retry_count += 1
1000
- if install_retry_count <= 3
1001
- puts 'Retrying install...'
1002
- retry
1003
- end
1004
- puts 'Trying one final time to install the package:'
1005
- output = `adb install -r "#{APK_FILE}" 2>&1`
1006
- end
1007
- if $? == 0 && output !~ failure_pattern && output =~ success_pattern
1008
- clear_update
1009
- return
1010
- end
1011
- case $1
1012
- when 'INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES'
1013
- puts 'Found package signed with different certificate. Uninstalling it and retrying install.'
1014
- else
1015
- puts "'adb install' returned an unknown error: (#$?) #{$1 ? "[#$1}]" : output}."
1016
- puts "Uninstalling #{package} and retrying install."
1017
- end
1018
- uninstall_apk
1019
- else
1020
- # Package not installed.
1021
- sh "adb shell date -s #{Time.now.strftime '%Y%m%d.%H%M%S'}"
1022
- end
1023
- puts "Installing package #{package}"
1024
- output = nil
1025
- install_retry_count = 0
1026
- begin
1027
- timeout 300 do
1028
- output = `adb install "#{APK_FILE}" 2>&1`
1029
- end
1030
- rescue Timeout::Error
1031
- puts "Installing package #{package} timed out."
1032
- install_retry_count += 1
1033
- if install_retry_count <= 3
1034
- puts 'Retrying install...'
1035
- retry
1036
- end
1037
- puts 'Trying one final time to install the package:'
1038
- install_start = Time.now
1039
- output = `adb install "#{APK_FILE}" 2>&1`
1040
- puts "Install took #{(Time.now - install_start).to_i}s."
1041
- end
1042
- puts output
1043
- raise "Install failed (#{$?}) #{$1 ? "[#$1}]" : output}" if $? != 0 || output =~ failure_pattern || output !~ success_pattern
1044
- clear_update
1045
- end
1046
-
1047
- def uninstall_apk
1048
- return if package_installed?.nil?
1049
- puts "Uninstalling package #{package}"
1050
- system "adb uninstall #{package}"
1051
- if $? != 0 && package_installed?
1052
- puts "Uninstall failed exit code #{$?}"
1053
- exit $?
1054
- end
1055
- end
1056
-
1057
- def update_scripts
1058
- # FIXME(uwe): Simplify when we stop supporting Android 2.3
1059
- if sdk_level < 15
1060
- scripts_path.split('/').tap do |parts|
1061
- parts.size.times do |i|
1062
- path = parts[0..i].join('/')
1063
- puts(`adb shell mkdir #{path}`) unless device_path_exists?(path)
1064
- end
1065
- end
1066
- else
1067
- puts(`adb shell mkdir -p #{scripts_path}`) unless device_path_exists?(scripts_path)
1068
- end
1069
- # EMXIF
1070
-
1071
- raise "Unable to create device scripts dir: #{scripts_path}" unless device_path_exists?(scripts_path)
1072
- last_update = File.exists?(UPDATE_MARKER_FILE) ? Time.parse(File.read(UPDATE_MARKER_FILE)) : Time.parse('1970-01-01T00:00:00')
1073
- Dir.chdir('src') do
1074
- source_files = Dir['**/*.rb']
1075
- changed_files = source_files.select { |f| !File.directory?(f) && File.mtime(f) >= last_update && f !~ /~$/ }
1076
- unless changed_files.empty?
1077
- puts 'Pushing files to apk public file area:'
1078
- changed_files.each do |script_file|
1079
- print "#{script_file}: "; $stdout.flush
1080
- system "adb push #{script_file} #{scripts_path}/#{script_file}"
1081
- end
1082
- mark_update
1083
- return changed_files
1084
- end
1085
- end
1086
- return nil
1087
- end
1088
-
1089
971
  def app_running?
1090
972
  `adb shell ps | egrep -e " #{package}\r$"`.size > 0
1091
973
  end