ruboto 1.2.0 → 1.3.0

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 (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