ruboto 0.10.1 → 0.10.2.rc.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/Gemfile +1 -1
  2. data/Gemfile.lock +1 -1
  3. data/Rakefile +110 -34
  4. data/assets/rakelib/ruboto.rake +181 -76
  5. data/assets/src/org/ruboto/JRubyAdapter.java +7 -3
  6. data/assets/src/org/ruboto/ScriptLoader.java +12 -4
  7. data/assets/src/ruboto/widget.rb +43 -34
  8. data/bin/ruboto +9 -4
  9. data/lib/ruboto/sdk_versions.rb +11 -2
  10. data/lib/ruboto/util/build.rb +1 -1
  11. data/lib/ruboto/util/update.rb +104 -32
  12. data/lib/ruboto/version.rb +1 -1
  13. data/test/activity/call_super_activity.rb +2 -3
  14. data/test/activity/dir_and_file_activity.rb +18 -0
  15. data/test/activity/dir_and_file_activity_test.rb +20 -0
  16. data/test/activity/image_button_and_button_activity.rb +4 -5
  17. data/test/activity/json_activity.rb +21 -0
  18. data/test/activity/json_activity_test.rb +17 -0
  19. data/test/activity/location_activity.rb +30 -0
  20. data/test/activity/location_activity_test.rb +17 -0
  21. data/test/activity/margins_activity.rb +0 -1
  22. data/test/activity/option_menu_activity.rb +0 -1
  23. data/test/activity/psych_activity.rb +8 -2
  24. data/test/activity/ssl_activity.rb +31 -0
  25. data/test/activity/ssl_activity_test.rb +22 -0
  26. data/test/activity/stack_activity.rb +0 -1
  27. data/test/activity/stack_activity_test.rb +4 -5
  28. data/test/activity/subclass_activity.rb +0 -1
  29. data/test/activity/view_constants_activity.rb +0 -1
  30. data/test/app_test_methods.rb +19 -6
  31. data/test/minimal_app_test.rb +10 -10
  32. data/test/rake_test.rb +8 -8
  33. data/test/ruboto_gen_test.rb +18 -12
  34. data/test/ruboto_update_test.rb +16 -10
  35. data/test/test_helper.rb +16 -35
  36. metadata +21 -9
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source :rubygems
1
+ source 'https://rubygems.org'
2
2
 
3
3
  gem 'rake'
4
4
  gem 'main'
data/Gemfile.lock CHANGED
@@ -1,5 +1,5 @@
1
1
  GEM
2
- remote: http://rubygems.org/
2
+ remote: https://rubygems.org/
3
3
  specs:
4
4
  arrayfields (4.7.4)
5
5
  chronic (0.6.7)
data/Rakefile CHANGED
@@ -11,7 +11,7 @@ PLATFORM_PROJECT = File.expand_path('tmp/RubotoCore', File.dirname(__FILE__))
11
11
  PLATFORM_DEBUG_APK = "#{PLATFORM_PROJECT}/bin/RubotoCore-debug.apk"
12
12
  PLATFORM_DEBUG_APK_BAK = "#{PLATFORM_PROJECT}/bin/RubotoCore-debug.apk.bak"
13
13
  PLATFORM_RELEASE_APK = "#{PLATFORM_PROJECT}/bin/RubotoCore-release.apk"
14
- PLATFORM_CURRENT_RELEASE_APK = "#{PLATFORM_PROJECT}/bin/RubotoCore-release.apk.current"
14
+ PLATFORM_CURRENT_RELEASE_APK = File.expand_path('tmp/RubotoCore-release.apk', File.dirname(__FILE__))
15
15
  MANIFEST_FILE = "AndroidManifest.xml"
16
16
  GEM_FILE = "ruboto-#{Ruboto::VERSION}.gem"
17
17
  GEM_SPEC_FILE = 'ruboto.gemspec'
@@ -87,8 +87,8 @@ task :release_docs do
87
87
  user = ask('login : ') { |q| q.echo = true }
88
88
  pass = ask('password: ') { |q| q.echo = '*' }
89
89
  rescue
90
- print 'user name: ' ; user = STDIN.gets.chomp
91
- print ' password: ' ; pass = STDIN.gets.chomp
90
+ print 'user name: '; user = STDIN.gets.chomp
91
+ print ' password: '; pass = STDIN.gets.chomp
92
92
  end
93
93
  require 'uri'
94
94
  require 'net/http'
@@ -106,12 +106,12 @@ task :release_docs do
106
106
  req.basic_auth(user, pass)
107
107
  res = https.start { |http| http.request(req) }
108
108
  milestones = YAML.load(res.body).sort_by { |i| Date.parse(i['due_on']) }
109
- puts milestones.map{|m| "#{'%2d' % m['number']} #{m['title']}"}.join("\n")
109
+ puts milestones.map { |m| "#{'%2d' % m['number']} #{m['title']}" }.join("\n")
110
110
 
111
111
  if defined? ask
112
112
  milestone = ask('milestone: ', Integer) { |q| q.echo = true }
113
113
  else
114
- print 'milestone: ' ; milestone = STDIN.gets.chomp
114
+ print 'milestone: '; milestone = STDIN.gets.chomp
115
115
  end
116
116
 
117
117
  uri = URI("#{base_uri}/issues?milestone=#{milestone}&state=closed&per_page=1000")
@@ -123,9 +123,9 @@ task :release_docs do
123
123
  milestone_description = issues[0] ? issues[0]['milestone']['description'] : "No issues for milestone #{milestone}"
124
124
  categories = {'Features' => 'feature', 'Bugfixes' => 'bug', 'Internal' => 'internal', 'Support' => 'support', 'Documentation' => 'documentation', 'Pull requests' => nil, 'Other' => nil}
125
125
  grouped_issues = issues.group_by do |i|
126
- labels = i['labels'].map { |l| l['name']}
126
+ labels = i['labels'].map { |l| l['name'] }
127
127
  cat = nil
128
- categories.each do |k,v|
128
+ categories.each do |k, v|
129
129
  if labels.include? v
130
130
  cat = k
131
131
  break
@@ -198,7 +198,7 @@ task :stats do
198
198
  https.use_ssl = true
199
199
  https.verify_mode = OpenSSL::SSL::VERIFY_NONE
200
200
 
201
- counts_per_month = Hash.new{|h, k| h[k] = Hash.new{|mh,mk| mh[mk] = 0 }}
201
+ counts_per_month = Hash.new { |h, k| h[k] = Hash.new { |mh, mk| mh[mk] = 0 } }
202
202
  total = 0
203
203
 
204
204
  %w{ruboto-core ruboto}.each do |gem|
@@ -213,20 +213,20 @@ task :stats do
213
213
  req = Net::HTTP::Get.new(downloads_uri.request_uri)
214
214
  res = https.start { |http| http.request(req) }
215
215
  counts = YAML.load(res.body)
216
- counts.delete_if{|date_str,count| count == 0}
216
+ counts.delete_if { |date_str, count| count == 0 }
217
217
  counts.each do |date_str, count|
218
218
  date = Date.parse(date_str)
219
219
  counts_per_month[date.year][date.month] += count
220
220
  total += count
221
221
  end
222
- print '.' ; STDOUT.flush
222
+ print '.'; STDOUT.flush
223
223
  end
224
224
  puts
225
225
  end
226
226
 
227
227
  puts "\nDownloads statistics per month:"
228
228
  years = counts_per_month.keys
229
- puts "\n #{years.map{|year| '%6s:' % year}.join(' ')}"
229
+ puts "\n #{years.map { |year| '%6s:' % year }.join(' ')}"
230
230
  (1..12).each do |month|
231
231
  print "#{'%2d' % month}:"
232
232
  years.each do |year|
@@ -240,7 +240,7 @@ task :stats do
240
240
 
241
241
  puts "\nRubyGems download statistics per month:"
242
242
  years = counts_per_month.keys
243
- puts ' ' + years.map{|year| '%-12s' % year}.join
243
+ puts ' ' + years.map { |year| '%-12s' % year }.join
244
244
  (0..20).each do |l|
245
245
  print (l % 10 == 0) ? '%4d' % ((20-l) * 100) : ' '
246
246
  years.each do |year|
@@ -254,7 +254,7 @@ task :stats do
254
254
  end
255
255
  puts
256
256
  end
257
- puts ' ' + years.map{|year| '%-12s' % year}.join
257
+ puts ' ' + years.map { |year| '%-12s' % year }.join
258
258
 
259
259
  puts "\nTotal: #{total}\n\n"
260
260
  end
@@ -275,11 +275,15 @@ task :release => [:clean, :gem] do
275
275
  sh "git push"
276
276
  end
277
277
 
278
- desc "Run the tests"
278
+ desc "Run the tests. Select which test files to load with 'rake test TEST=test_file_pattern'"
279
279
  task :test do
280
280
  FileUtils.rm_rf Dir['tmp/RubotoTestApp_template*']
281
- Dir['./test/*_test.rb'].each do |f|
282
- require f.chomp('.rb')
281
+ test_pattern = ARGV.grep(/^TEST=.*$/)
282
+ ARGV.delete_if { |a| test_pattern.include? a }
283
+ test_pattern.map! { |t| t[5..-1] }
284
+ $: << File.expand_path('test', File.dirname(__FILE__))
285
+ (test_pattern.any? ? test_pattern : ['test/*_test.rb']).map { |d| Dir[d] }.flatten.each do |f|
286
+ require f.chomp('.rb')[5..-1]
283
287
  end
284
288
  end
285
289
 
@@ -305,13 +309,10 @@ namespace :platform do
305
309
  task PLATFORM_DEBUG_APK do
306
310
  Rake::Task[PLATFORM_PROJECT].invoke
307
311
  Dir.chdir(PLATFORM_PROJECT) do
308
- if File.exists?(PLATFORM_CURRENT_RELEASE_APK) && File.exists?(PLATFORM_DEBUG_APK) &&
309
- File.size(PLATFORM_CURRENT_RELEASE_APK) == File.size(PLATFORM_DEBUG_APK)
310
- if File.exists?(PLATFORM_DEBUG_APK_BAK)
311
- FileUtils.cp PLATFORM_DEBUG_APK_BAK, PLATFORM_DEBUG_APK
312
- else
313
- FileUtils.rm PLATFORM_DEBUG_APK
314
- end
312
+ if File.exists?(PLATFORM_DEBUG_APK_BAK)
313
+ FileUtils.cp PLATFORM_DEBUG_APK_BAK, PLATFORM_DEBUG_APK
314
+ else
315
+ FileUtils.rm PLATFORM_DEBUG_APK
315
316
  end
316
317
  sh 'rake debug'
317
318
  end
@@ -342,14 +343,9 @@ namespace :platform do
342
343
  end
343
344
  end
344
345
 
345
- desc 'Use the current RubotoCore platform release apk'
346
- task :current => [:debug, PLATFORM_CURRENT_RELEASE_APK] do
347
- Dir.chdir PLATFORM_PROJECT do
348
- if File.size(PLATFORM_CURRENT_RELEASE_APK) != File.size(PLATFORM_DEBUG_APK)
349
- FileUtils.cp PLATFORM_DEBUG_APK, PLATFORM_DEBUG_APK_BAK
350
- FileUtils.cp PLATFORM_CURRENT_RELEASE_APK, PLATFORM_DEBUG_APK
351
- end
352
- end
346
+ desc 'Install the current RubotoCore platform release apk'
347
+ task :current => PLATFORM_CURRENT_RELEASE_APK do
348
+ install_apk
353
349
  end
354
350
 
355
351
  desc 'Install the Ruboto Core platform debug apk'
@@ -360,9 +356,89 @@ namespace :platform do
360
356
  end
361
357
 
362
358
  desc 'Uninstall the Ruboto Core platform debug apk'
363
- task :uninstall => PLATFORM_PROJECT do
364
- Dir.chdir(PLATFORM_PROJECT) do
365
- sh 'rake uninstall'
359
+ task :uninstall do
360
+ uninstall_apk
361
+ end
362
+
363
+ private
364
+
365
+ def package
366
+ 'org.ruboto.core'
367
+ end
368
+
369
+ def install_apk
370
+ failure_pattern = /^Failure \[(.*)\]/
371
+ success_pattern = /^Success/
372
+ case package_installed?
373
+ when true
374
+ puts "Package #{package} already installed."
375
+ return
376
+ when false
377
+ puts "Package #{package} already installed, but of different size. Replacing package."
378
+ output = `adb install -r #{PLATFORM_CURRENT_RELEASE_APK} 2>&1`
379
+ if $? == 0 && output !~ failure_pattern && output =~ success_pattern
380
+ clear_update
381
+ return
382
+ end
383
+ case $1
384
+ when 'INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES'
385
+ puts 'Found package signed with different certificate. Uninstalling it and retrying install.'
386
+ else
387
+ puts "'adb install' returned an unknown error: (#$?) #{$1 ? "[#$1}]" : output}."
388
+ puts "Uninstalling #{package} and retrying install."
389
+ end
390
+ uninstall_apk
391
+ end
392
+ puts "Installing package #{package}"
393
+ begin
394
+ output = nil
395
+ timeout 180 do
396
+ output = `adb install #{PLATFORM_CURRENT_RELEASE_APK} 2>&1`
397
+ end
398
+ rescue TimeoutError
399
+ puts 'Install of current RubotoCore timed out. Retrying.'
400
+ retry
401
+ end
402
+ puts output
403
+ raise "Install failed (#{$?}) #{$1 ? "[#$1}]" : output}" if $? != 0 || output =~ failure_pattern || output !~ success_pattern
404
+ end
405
+
406
+ def uninstall_apk
407
+ return if package_installed?.nil?
408
+ puts "Uninstalling package #{package}"
409
+ system "adb uninstall #{package}"
410
+ if $? != 0 && package_installed?
411
+ puts "Uninstall failed exit code #{$?}"
412
+ exit $?
366
413
  end
367
414
  end
415
+
416
+ def package_installed?
417
+ package_name = package
418
+ ['', '-0', '-1', '-2'].each do |i|
419
+ path = "/data/app/#{package_name}#{i}.apk"
420
+ o = `adb shell ls -l #{path}`.chomp
421
+ if o =~ /^-rw-r--r-- system\s+system\s+(\d+) \d{4}-\d{2}-\d{2} \d{2}:\d{2} #{File.basename(path)}$/
422
+ apk_file = PLATFORM_CURRENT_RELEASE_APK
423
+ if !File.exists?(apk_file) || $1.to_i == File.size(apk_file)
424
+ return true
425
+ else
426
+ return false
427
+ end
428
+ end
429
+
430
+ sdcard_path = "/mnt/asec/#{package_name}#{i}/pkg.apk"
431
+ o = `adb shell ls -l #{sdcard_path}`.chomp
432
+ if o =~ /^-r-xr-xr-x system\s+root\s+(\d+) \d{4}-\d{2}-\d{2} \d{2}:\d{2} #{File.basename(sdcard_path)}$/
433
+ apk_file = PLATFORM_CURRENT_RELEASE_APK
434
+ if !File.exists?(apk_file) || $1.to_i == File.size(apk_file)
435
+ return true
436
+ else
437
+ return false
438
+ end
439
+ end
440
+ end
441
+ return nil
442
+ end
443
+
368
444
  end
@@ -3,8 +3,11 @@ require 'rubygems'
3
3
  require 'time'
4
4
  require 'rake/clean'
5
5
  require 'rexml/document'
6
+ require 'timeout'
6
7
 
7
- ANT_CMD = (RbConfig::CONFIG['host_os'] =~ /mswin|mingw/i) ? "ant.bat" : "ant"
8
+ ON_WINDOWS = (RbConfig::CONFIG['host_os'] =~ /mswin|mingw/i)
9
+
10
+ ANT_CMD = ON_WINDOWS ? 'ant.bat' : 'ant'
8
11
 
9
12
  if `#{ANT_CMD} -version` !~ /version (\d+)\.(\d+)\.(\d+)/ || $1.to_i < 1 || ($1.to_i == 1 && $2.to_i < 8)
10
13
  puts "ANT version 1.8.0 or later required. Version found: #{$1}.#{$2}.#{$3}"
@@ -12,48 +15,64 @@ if `#{ANT_CMD} -version` !~ /version (\d+)\.(\d+)\.(\d+)/ || $1.to_i < 1 || ($1.
12
15
  end
13
16
 
14
17
  adb_version_str = `adb version`
15
- (puts "Android SDK platform tools not in PATH (adb command not found).";exit 1) unless $? == 0
16
- (puts "Unrecognized adb version: #$1";exit 1) unless adb_version_str =~ /Android Debug Bridge version (\d+\.\d+\.\d+)/
17
- (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')
18
- adb_path = `which adb`
19
- ENV['ANDROID_HOME'] ||= File.dirname(File.dirname(adb_path)) if $? == 0
20
-
21
- dx_filename = "#{ENV['ANDROID_HOME']}/platform-tools/dx"
22
- old_dx_content = File.read(dx_filename)
23
- new_dx_content = old_dx_content.dup
24
- if new_dx_content =~ /^defaultMx="-Xmx(\d+)(M|G)"/ &&
25
- ($1.to_i * 1024 ** {'M' => 2, 'G' => 3, 'T' => 4}[$2]) < 3*1024**3
26
- new_dx_content.sub(/^defaultMx="-Xmx\d+(M|G)"/, 'defaultMx="-Xmx3G"')
27
- File.open(dx_filename, 'w') { |f| f << new_dx_content }
28
- end
29
-
30
- def manifest() @manifest ||= REXML::Document.new(File.read(MANIFEST_FILE)) end
31
- def package() manifest.root.attribute('package') end
32
- def build_project_name() @build_project_name ||= REXML::Document.new(File.read('build.xml')).elements['project'].attribute(:name).value end
33
- def scripts_path() @sdcard_path ||= "/mnt/sdcard/Android/data/#{package}/files/scripts" end
34
- def app_files_path() @app_files_path ||= "/data/data/#{package}/files" end
35
-
36
- PROJECT_DIR = File.expand_path('..', File.dirname(__FILE__))
18
+ (puts 'Android SDK platform tools not in PATH (adb command not found).'; exit 1) unless $? == 0
19
+ (puts "Unrecognized adb version: #$1"; exit 1) unless adb_version_str =~ /Android Debug Bridge version (\d+\.\d+\.\d+)/
20
+ (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')
21
+ unless ENV['ANDROID_HOME']
22
+ unless ON_WINDOWS
23
+ begin
24
+ adb_path = `which adb`
25
+ ENV['ANDROID_HOME'] = File.dirname(File.dirname(adb_path)) if $? == 0
26
+ rescue Errno::ENOENT
27
+ puts "Unable to detect adb location: #$!"
28
+ end
29
+ end
30
+ end
31
+ (puts 'You need to set the ANDROID_HOME environment variable.'; exit 1) unless ENV['ANDROID_HOME']
32
+
33
+ # FIXME(uwe): On windows the file is called dx.bat
34
+ dx_filename = File.join(ENV['ANDROID_HOME'], 'platform-tools', ON_WINDOWS ? 'dx.bat' : 'dx')
35
+ unless File.exists? dx_filename
36
+ puts 'You need to install the Android SDK Platform-tools!'
37
+ exit 1
38
+ end
39
+ new_dx_content = File.read(dx_filename).dup
40
+ # set defaultXmx=-Xmx1024M
41
+ xmx_pattern = /^defaultMx="-Xmx(\d+)(M|m|G|g|T|t)"/
42
+ if new_dx_content =~ xmx_pattern &&
43
+ ($1.to_i * 1024 ** {'M' => 2, 'G' => 3, 'T' => 4}[$2.upcase]) < 2560*1024**2
44
+ puts "Increasing max heap space from #$1#$2 to 2560M in #{dx_filename}"
45
+ new_dx_content.sub!(xmx_pattern, 'defaultMx="-Xmx2560M"')
46
+ File.open(dx_filename, 'w') { |f| f << new_dx_content } rescue puts "\n!!! Unable to increase dx heap size !!!\n\n"
47
+ end
48
+
49
+ def manifest; @manifest ||= REXML::Document.new(File.read(MANIFEST_FILE)) end
50
+ def package; manifest.root.attribute('package') end
51
+ def build_project_name; @build_project_name ||= REXML::Document.new(File.read('build.xml')).elements['project'].attribute(:name).value end
52
+ def scripts_path; @sdcard_path ||= "/mnt/sdcard/Android/data/#{package}/files/scripts" end
53
+ def app_files_path; @app_files_path ||= "/data/data/#{package}/files" end
54
+
55
+ PROJECT_DIR = File.expand_path('..', File.dirname(__FILE__))
37
56
  UPDATE_MARKER_FILE = File.join(PROJECT_DIR, 'bin', 'LAST_UPDATE')
38
- BUNDLE_JAR = File.expand_path 'libs/bundle.jar'
39
- BUNDLE_PATH = File.expand_path 'bin/bundle'
40
- MANIFEST_FILE = File.expand_path 'AndroidManifest.xml'
57
+ BUNDLE_JAR = File.expand_path 'libs/bundle.jar'
58
+ BUNDLE_PATH = File.expand_path 'bin/bundle'
59
+ MANIFEST_FILE = File.expand_path 'AndroidManifest.xml'
41
60
  PROJECT_PROPS_FILE = File.expand_path 'project.properties'
42
61
  RUBOTO_CONFIG_FILE = File.expand_path 'ruboto.yml'
43
- GEM_FILE = File.expand_path('Gemfile.apk')
44
- GEM_LOCK_FILE = File.expand_path('Gemfile.apk.lock')
45
- RELEASE_APK_FILE = File.expand_path "bin/#{build_project_name}-release.apk"
46
- APK_FILE = File.expand_path "bin/#{build_project_name}-debug.apk"
47
- TEST_APK_FILE = File.expand_path "test/bin/#{build_project_name}Test-debug.apk"
48
- JRUBY_JARS = Dir[File.expand_path 'libs/jruby-*.jar']
49
- RESOURCE_FILES = Dir[File.expand_path 'res/**/*']
50
- JAVA_SOURCE_FILES = Dir[File.expand_path 'src/**/*.java']
51
- RUBY_SOURCE_FILES = Dir[File.expand_path 'src/**/*.rb']
52
- APK_DEPENDENCIES = [MANIFEST_FILE, RUBOTO_CONFIG_FILE, BUNDLE_JAR] + JRUBY_JARS + JAVA_SOURCE_FILES + RESOURCE_FILES + RUBY_SOURCE_FILES
53
- 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"
54
- KEYSTORE_ALIAS = (key_alias = File.readlines('ant.properties').grep(/^key.alias=/).first) ? key_alias.chomp.sub(/^key.alias=/, '') : build_project_name
55
-
56
- CLEAN.include('bin', 'gen')
62
+ GEM_FILE = File.expand_path 'Gemfile.apk'
63
+ GEM_LOCK_FILE = File.expand_path 'Gemfile.apk.lock'
64
+ RELEASE_APK_FILE = File.expand_path "bin/#{build_project_name}-release.apk"
65
+ APK_FILE = File.expand_path "bin/#{build_project_name}-debug.apk"
66
+ TEST_APK_FILE = File.expand_path "test/bin/#{build_project_name}Test-debug.apk"
67
+ JRUBY_JARS = Dir[File.expand_path 'libs/jruby-*.jar']
68
+ RESOURCE_FILES = Dir[File.expand_path 'res/**/*']
69
+ JAVA_SOURCE_FILES = Dir[File.expand_path 'src/**/*.java']
70
+ RUBY_SOURCE_FILES = Dir[File.expand_path 'src/**/*.rb']
71
+ APK_DEPENDENCIES = [MANIFEST_FILE, RUBOTO_CONFIG_FILE, BUNDLE_JAR] + JRUBY_JARS + JAVA_SOURCE_FILES + RESOURCE_FILES + RUBY_SOURCE_FILES
72
+ 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"
73
+ KEYSTORE_ALIAS = (key_alias = File.readlines('ant.properties').grep(/^key.alias=/).first) ? key_alias.chomp.sub(/^key.alias=/, '') : build_project_name
74
+
75
+ CLEAN.include('bin', 'gen', 'test/bin', 'test/gen')
57
76
 
58
77
  task :default => :debug
59
78
 
@@ -84,7 +103,7 @@ namespace :debug do
84
103
  end
85
104
  end
86
105
 
87
- desc "build package and install it on the emulator or device"
106
+ desc 'build package and install it on the emulator or device'
88
107
  task :install => APK_FILE do
89
108
  install_apk
90
109
  end
@@ -117,10 +136,10 @@ task :keystore => KEYSTORE_FILE
117
136
 
118
137
  file KEYSTORE_FILE do
119
138
  unless File.read('ant.properties') =~ /^key.store=/
120
- File.open('ant.properties', 'a'){|f| f << "\nkey.store=#{KEYSTORE_FILE}\n"}
139
+ File.open('ant.properties', 'a') { |f| f << "\nkey.store=#{KEYSTORE_FILE}\n" }
121
140
  end
122
141
  unless File.read('ant.properties') =~ /^key.alias=/
123
- File.open('ant.properties', 'a'){|f| f << "\nkey.alias=#{KEYSTORE_ALIAS}\n"}
142
+ File.open('ant.properties', 'a') { |f| f << "\nkey.alias=#{KEYSTORE_ALIAS}\n" }
124
143
  end
125
144
  sh "keytool -genkey -v -keystore #{KEYSTORE_FILE} -alias #{KEYSTORE_ALIAS} -keyalg RSA -keysize 2048 -validity 10000"
126
145
  end
@@ -129,14 +148,14 @@ desc 'Tag this working copy with the current version'
129
148
  task :tag do
130
149
  next unless File.exists?('.git') && `git --version` =~ /git version /
131
150
  unless `git branch` =~ /^\* master$/
132
- puts "You must be on the master branch to release!"
151
+ puts 'You must be on the master branch to release!'
133
152
  exit!
134
153
  end
135
154
  # sh "git commit --allow-empty -a -m 'Release #{version}'"
136
155
  output = `git status --porcelain`
137
156
  raise "\nWorkspace not clean!\n#{output}" unless output.empty?
138
157
  sh "git tag #{version}"
139
- sh "git push origin master --tags"
158
+ sh 'git push origin master --tags'
140
159
  end
141
160
 
142
161
  desc 'Start the emulator with larger disk'
@@ -151,7 +170,7 @@ end
151
170
 
152
171
  desc 'Stop the application on the device/emulator (requires emulator or rooted device).'
153
172
  task :stop do
154
- raise "Unable to stop app. Only available on emulator." unless stop_app
173
+ raise 'Unable to stop app. Only available on emulator.' unless stop_app
155
174
  end
156
175
 
157
176
  desc 'Restart the application'
@@ -166,9 +185,9 @@ file MANIFEST_FILE => PROJECT_PROPS_FILE do
166
185
  sdk_level = File.read(PROJECT_PROPS_FILE).scan(/(?:target=android-)(\d+)/)[0][0].to_i
167
186
  old_manifest = File.read(MANIFEST_FILE)
168
187
  manifest = old_manifest.dup
169
- manifest.sub!(/(android:minSdkVersion=').*?(')/){|m| "#$1#{sdk_level}#$2"}
170
- manifest.sub!(/(android:targetSdkVersion=').*?(')/){|m| "#$1#{sdk_level}#$2"}
171
- File.open(MANIFEST_FILE, 'w'){|f| f << manifest} if manifest != old_manifest
188
+ manifest.sub!(/(android:minSdkVersion=').*?(')/) { "#$1#{sdk_level}#$2" }
189
+ manifest.sub!(/(android:targetSdkVersion=').*?(')/) { "#$1#{sdk_level}#$2" }
190
+ File.open(MANIFEST_FILE, 'w') { |f| f << manifest } if manifest != old_manifest
172
191
  end
173
192
 
174
193
  file RUBOTO_CONFIG_FILE
@@ -178,7 +197,7 @@ file APK_FILE => APK_DEPENDENCIES do |t|
178
197
  end
179
198
 
180
199
  desc 'Copy scripts to emulator or device'
181
- task :update_scripts => ['install:quick'] do
200
+ task :update_scripts => %w(install:quick) do
182
201
  update_scripts
183
202
  end
184
203
 
@@ -206,7 +225,23 @@ namespace :test do
206
225
  task :quick => :update_scripts do
207
226
  Dir.chdir('test') do
208
227
  puts 'Running quick tests'
209
- sh "#{ANT_CMD} instrument install run-tests-quick"
228
+ sh "#{ANT_CMD} instrument"
229
+ install_retry_count = 0
230
+ begin
231
+ timeout 120 do
232
+ sh "#{ANT_CMD} installi"
233
+ end
234
+ rescue TimeoutError
235
+ puts 'Installing package timed out.'
236
+ install_retry_count += 1
237
+ if install_retry_count > 3
238
+ puts 'Retrying install...'
239
+ retry
240
+ end
241
+ puts 'Trying one final time to install the package:'
242
+ sh "#{ANT_CMD} installi"
243
+ end
244
+ sh "#{ANT_CMD} run-tests-quick"
210
245
  end
211
246
  end
212
247
  end
@@ -221,11 +256,26 @@ file BUNDLE_JAR => [GEM_FILE, GEM_LOCK_FILE] do
221
256
  next unless File.exists? GEM_FILE
222
257
  puts "Generating #{BUNDLE_JAR}"
223
258
 
224
- FileUtils.mkdir_p BUNDLE_PATH
225
- sh "bundle install --gemfile #{GEM_FILE} --path=#{BUNDLE_PATH}"
259
+ # Override RUBY_ENGINE (we can bundle from MRI for JRuby)
260
+ platforms = Gem.platforms
261
+ ruby_engine = defined?(RUBY_ENGINE) && RUBY_ENGINE
262
+ Gem.platforms = [Gem::Platform::RUBY, Gem::Platform.new('universal-java')]
263
+ Object.const_set('RUBY_ENGINE', 'jruby')
264
+
265
+ ENV['BUNDLE_GEMFILE'] = GEM_FILE
266
+ require 'bundler'
267
+ Bundler.bundle_path = Pathname.new BUNDLE_PATH
268
+
269
+ definition = Bundler.definition
270
+ definition.validate_ruby!
271
+ Bundler::Installer.install(Bundler.root, definition)
272
+
273
+ # Restore RUBY_ENGINE (limit the scope of this hack)
274
+ Object.const_set('RUBY_ENGINE', ruby_engine) if ruby_engine
275
+ Gem.platforms = platforms
226
276
 
227
- gem_paths = Dir["#{BUNDLE_PATH}/{{,j}ruby,rbx}/{1.8,1.9{,.1},shared}/gems"]
228
- raise "Gem path not found" if gem_paths.empty?
277
+ gem_paths = Dir["#{BUNDLE_PATH}/gems"]
278
+ raise 'Gem path not found' if gem_paths.empty?
229
279
  raise "Found multiple gem paths: #{gem_paths}" if gem_paths.size > 1
230
280
  gem_path = gem_paths[0]
231
281
  puts "Found gems in #{gem_path}"
@@ -257,11 +307,11 @@ file BUNDLE_JAR => [GEM_FILE, GEM_LOCK_FILE] do
257
307
  Dir.chdir gem_path do
258
308
  scanned_files = []
259
309
  source_files = RUBY_SOURCE_FILES.map { |f| f.gsub("#{PROJECT_DIR}/src/", '') }
260
- Dir["*/lib/**/*"].each do |f|
310
+ Dir['*/lib/**/*'].each do |f|
261
311
  next if File.directory? f
262
- raise "Malformed file name" unless f =~ %r{^(.*?)/lib/(.*)$}
312
+ raise 'Malformed file name' unless f =~ %r{^(.*?)/lib/(.*)$}
263
313
  gem_name, lib_file = $1, $2
264
- if existing_file = scanned_files.find { |sf| sf =~ %r{(.*?)/lib/#{lib_file}} }
314
+ if (existing_file = scanned_files.find { |sf| sf =~ %r{(.*?)/lib/#{lib_file}} })
265
315
  puts "Overwriting duplicate file #{lib_file} in gem #{$1} with file in #{gem_name}"
266
316
  FileUtils.rm existing_file
267
317
  scanned_files.delete existing_file
@@ -300,6 +350,20 @@ puts 'Starting JRuby OpenSSL Service'
300
350
  public
301
351
  Java::JopensslService.new.basicLoad(JRuby.runtime)
302
352
  END_CODE
353
+ elsif jar =~ %r{json/ext/generator.jar$}
354
+ jar_load_code = <<-END_CODE
355
+ require 'jruby'
356
+ puts 'Starting JSON Generator Service'
357
+ public
358
+ Java::json.ext.GeneratorService.new.basicLoad(JRuby.runtime)
359
+ END_CODE
360
+ elsif jar =~ %r{json/ext/parser.jar$}
361
+ jar_load_code = <<-END_CODE
362
+ require 'jruby'
363
+ puts 'Starting JSON Parser Service'
364
+ public
365
+ Java::json.ext.ParserService.new.basicLoad(JRuby.runtime)
366
+ END_CODE
303
367
  else
304
368
  jar_load_code = ''
305
369
  end
@@ -345,7 +409,7 @@ def strings(name)
345
409
  end
346
410
 
347
411
  def version
348
- strings :version_name
412
+ manifest.root.attribute('versionName')
349
413
  end
350
414
 
351
415
  def app_name
@@ -358,18 +422,24 @@ end
358
422
 
359
423
  def device_path_exists?(path)
360
424
  path_output =`adb shell ls #{path}`
361
- result = path_output.chomp !~ /No such file or directory|opendir failed, Permission denied/
362
- result
425
+ path_output.chomp !~ /No such file or directory|opendir failed, Permission denied/
363
426
  end
364
427
 
365
- def package_installed? test = false
428
+ # Determine if the package is installed.
429
+ # Return true if the package is installed and is identical to the local package.
430
+ # Return false if the package is installed, but differs from the local package.
431
+ # Return nil if the package is not installed.
432
+ def package_installed?(test = false)
366
433
  package_name = "#{package}#{'.tests' if test}"
367
- ['', '-0', '-1', '-2'].each do |i|
434
+ %w( -0 -1 -2).each do |i|
368
435
  path = "/data/app/#{package_name}#{i}.apk"
369
436
  o = `adb shell ls -l #{path}`.chomp
370
- if o =~ /^-rw-r--r-- system\s+system\s+(\d+) \d{4}-\d{2}-\d{2} \d{2}:\d{2} #{File.basename(path)}$/
437
+ if o =~ /^-rw-r--r-- system\s+system\s+(\d+)\s+(\d{4}-\d{2}-\d{2} \d{2}:\d{2})\s+#{File.basename(path)}$/
438
+ installed_apk_size = $1.to_i
439
+ installed_timestamp = Time.parse($2)
371
440
  apk_file = test ? TEST_APK_FILE : APK_FILE
372
- if !File.exists?(apk_file) || $1.to_i == File.size(apk_file)
441
+ if !File.exists?(apk_file) || (installed_apk_size == File.size(apk_file) &&
442
+ installed_timestamp >= File.mtime(apk_file))
373
443
  return true
374
444
  else
375
445
  return false
@@ -378,16 +448,19 @@ def package_installed? test = false
378
448
 
379
449
  sdcard_path = "/mnt/asec/#{package_name}#{i}/pkg.apk"
380
450
  o = `adb shell ls -l #{sdcard_path}`.chomp
381
- if o =~ /^-r-xr-xr-x system\s+root\s+(\d+) \d{4}-\d{2}-\d{2} \d{2}:\d{2} #{File.basename(sdcard_path)}$/
451
+ if o =~ /^-r-xr-xr-x system\s+root\s+(\d+)\s+(\d{4}-\d{2}-\d{2} \d{2}:\d{2})\s+#{File.basename(sdcard_path)}$/
452
+ installed_apk_size = $1.to_i
453
+ installed_timestamp = Time.parse($2)
382
454
  apk_file = test ? TEST_APK_FILE : APK_FILE
383
- if !File.exists?(apk_file) || $1.to_i == File.size(apk_file)
455
+ if !File.exists?(apk_file) || (installed_apk_size == File.size(apk_file) &&
456
+ installed_timestamp >= File.mtime(apk_file))
384
457
  return true
385
458
  else
386
459
  return false
387
460
  end
388
461
  end
389
462
  end
390
- return nil
463
+ nil
391
464
  end
392
465
 
393
466
  def replace_faulty_code(faulty_file, faulty_code)
@@ -420,7 +493,7 @@ def build_apk(t, release)
420
493
  else
421
494
  sh "#{ANT_CMD} debug"
422
495
  end
423
- return true
496
+ true
424
497
  end
425
498
 
426
499
  def install_apk
@@ -431,23 +504,55 @@ def install_apk
431
504
  puts "Package #{package} already installed."
432
505
  return
433
506
  when false
434
- puts "Package #{package} already installed, but of different size. Replacing package."
435
- output = `adb install -r #{APK_FILE} 2>&1`
507
+ puts "Package #{package} already installed, but of different size or timestamp. Replacing package."
508
+ output = nil
509
+ install_retry_count = 0
510
+ begin
511
+ timeout 120 do
512
+ output = `adb install -r #{APK_FILE} 2>&1`
513
+ end
514
+ rescue Timeout::Error
515
+ puts "Installing package #{package} timed out."
516
+ install_retry_count += 1
517
+ if install_retry_count > 3
518
+ puts 'Retrying install...'
519
+ retry
520
+ end
521
+ puts 'Trying one final time to install the package:'
522
+ output = `adb install -r #{APK_FILE} 2>&1`
523
+ end
436
524
  if $? == 0 && output !~ failure_pattern && output =~ success_pattern
437
525
  clear_update
438
526
  return
439
527
  end
440
528
  case $1
441
529
  when 'INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES'
442
- puts "Found package signed with different certificate. Uninstalling it and retrying install."
530
+ puts 'Found package signed with different certificate. Uninstalling it and retrying install.'
443
531
  else
444
532
  puts "'adb install' returned an unknown error: (#$?) #{$1 ? "[#$1}]" : output}."
445
533
  puts "Uninstalling #{package} and retrying install."
446
534
  end
447
535
  uninstall_apk
536
+ else
537
+ # Package not installed.
448
538
  end
449
539
  puts "Installing package #{package}"
450
- output = `adb install #{APK_FILE} 2>&1`
540
+ output = nil
541
+ install_retry_count = 0
542
+ begin
543
+ timeout 120 do
544
+ output = `adb install #{APK_FILE} 2>&1`
545
+ end
546
+ rescue Timeout::Error
547
+ puts "Installing package #{package} timed out."
548
+ install_retry_count += 1
549
+ if install_retry_count > 3
550
+ puts 'Retrying install...'
551
+ retry
552
+ end
553
+ puts 'Trying one final time to install the package:'
554
+ output = `adb install #{APK_FILE} 2>&1`
555
+ end
451
556
  puts output
452
557
  raise "Install failed (#{$?}) #{$1 ? "[#$1}]" : output}" if $? != 0 || output =~ failure_pattern || output !~ success_pattern
453
558
  clear_update
@@ -465,10 +570,10 @@ end
465
570
 
466
571
  def update_scripts
467
572
  `adb shell mkdir -p #{scripts_path}` if !device_path_exists?(scripts_path)
468
- puts "Pushing files to apk public file area."
573
+ puts 'Pushing files to apk public file area.'
469
574
  last_update = File.exists?(UPDATE_MARKER_FILE) ? Time.parse(File.read(UPDATE_MARKER_FILE)) : Time.parse('1970-01-01T00:00:00')
470
575
  Dir.chdir('src') do
471
- Dir["**/*.rb"].each do |script_file|
576
+ Dir['**/*.rb'].each do |script_file|
472
577
  next if File.directory? script_file
473
578
  next if File.mtime(script_file) < last_update
474
579
  next if script_file =~ /~$/
@@ -485,5 +590,5 @@ end
485
590
 
486
591
  def stop_app
487
592
  output = `adb shell ps | grep #{package} | awk '{print $2}' | xargs adb shell kill`
488
- return output !~ /Operation not permitted/
593
+ output !~ /Operation not permitted/
489
594
  end