ruboto 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/COPYING +19 -0
  2. data/Gemfile +4 -0
  3. data/Gemfile.lock +21 -0
  4. data/README.md +293 -0
  5. data/Rakefile +114 -0
  6. data/assets/Rakefile +386 -0
  7. data/assets/res/drawable-hdpi/icon.png +0 -0
  8. data/assets/res/drawable-ldpi/icon.png +0 -0
  9. data/assets/res/drawable-mdpi/icon.png +0 -0
  10. data/assets/res/layout/get_ruboto_core.xml +25 -0
  11. data/assets/samples/sample_activity.rb +21 -0
  12. data/assets/samples/sample_activity_test.rb +21 -0
  13. data/assets/samples/sample_broadcast_receiver.rb +6 -0
  14. data/assets/samples/sample_broadcast_receiver_test.rb +1 -0
  15. data/assets/samples/sample_service.rb +14 -0
  16. data/assets/samples/sample_service_test.rb +1 -0
  17. data/assets/src/InheritingActivity.java +195 -0
  18. data/assets/src/InheritingBroadcastReceiver.java +27 -0
  19. data/assets/src/InheritingClass.java +19 -0
  20. data/assets/src/InheritingService.java +9 -0
  21. data/assets/src/RubotoActivity.java +111 -0
  22. data/assets/src/RubotoBroadcastReceiver.java +51 -0
  23. data/assets/src/RubotoService.java +61 -0
  24. data/assets/src/org/ruboto/RubotoDialog.java +11 -0
  25. data/assets/src/org/ruboto/Script.java +545 -0
  26. data/assets/src/org/ruboto/test/ActivityTest.java +63 -0
  27. data/assets/src/org/ruboto/test/InstrumentationTestRunner.java +124 -0
  28. data/assets/src/ruboto.rb +621 -0
  29. data/assets/test/assets/scripts/test_helper.rb +13 -0
  30. data/bin/ruboto +5 -0
  31. data/lib/java_class_gen/InheritingClass.java.erb +10 -0
  32. data/lib/java_class_gen/android_api.xml +1 -0
  33. data/lib/ruboto.rb +16 -0
  34. data/lib/ruboto/api.rb +21 -0
  35. data/lib/ruboto/commands/base.rb +392 -0
  36. data/lib/ruboto/core_ext/array.rb +6 -0
  37. data/lib/ruboto/core_ext/object.rb +10 -0
  38. data/lib/ruboto/util/asset_copier.rb +27 -0
  39. data/lib/ruboto/util/build.rb +201 -0
  40. data/lib/ruboto/util/code_formatting.rb +22 -0
  41. data/lib/ruboto/util/log_action.rb +20 -0
  42. data/lib/ruboto/util/main_fix.rb +13 -0
  43. data/lib/ruboto/util/objectspace.rb +8 -0
  44. data/lib/ruboto/util/scan_in_api.rb +40 -0
  45. data/lib/ruboto/util/update.rb +420 -0
  46. data/lib/ruboto/util/verify.rb +87 -0
  47. data/lib/ruboto/util/xml_element.rb +200 -0
  48. data/lib/ruboto/version.rb +3 -0
  49. data/test/activity/image_button_activity.rb +21 -0
  50. data/test/activity/image_button_activity_test.rb +21 -0
  51. data/test/activity/image_button_and_button_activity.rb +24 -0
  52. data/test/activity/image_button_and_button_activity_test.rb +27 -0
  53. data/test/activity/option_menu_activity.rb +21 -0
  54. data/test/activity/option_menu_activity_test.rb +20 -0
  55. data/test/activity/stack_activity.rb +21 -0
  56. data/test/activity/stack_activity_test.rb +23 -0
  57. data/test/app_test_methods.rb +41 -0
  58. data/test/minimal_app_test.rb +23 -0
  59. data/test/rake_test.rb +40 -0
  60. data/test/ruboto_gen_test.rb +32 -0
  61. data/test/ruboto_gen_with_psych_test.rb +16 -0
  62. data/test/ruboto_update_test.rb +5 -0
  63. data/test/ruboto_update_with_psych_test.rb +18 -0
  64. data/test/service_test.rb +49 -0
  65. data/test/test_helper.rb +177 -0
  66. data/test/update_test_methods.rb +33 -0
  67. metadata +157 -0
@@ -0,0 +1,6 @@
1
+ # Add an "indent" method to Array
2
+ class Array
3
+ def indent
4
+ flatten.compact.map{|i| " " + i}
5
+ end
6
+ end
@@ -0,0 +1,10 @@
1
+ class Object
2
+ # active_support/inflector.rb
3
+ def underscore(camel_cased_word)
4
+ camel_cased_word.to_s.gsub(/::/, '/').
5
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
6
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
7
+ tr("-", "_").
8
+ downcase
9
+ end
10
+ end
@@ -0,0 +1,27 @@
1
+ module Ruboto
2
+ module Util
3
+ class AssetCopier
4
+ def initialize(from, to, force = true)
5
+ @from = from
6
+ @to = to
7
+ @force = force
8
+ end
9
+
10
+ def copy(from, to='')
11
+ target_dir = File.join(@to, to)
12
+ file_pattern = File.directory?(File.join(@from, from)) ? File.join(from, '**/*') : from
13
+ existing_files = @force ? [] : Dir.chdir(target_dir){Dir[file_pattern].select{|f| !File.directory?(f)}}
14
+ files_to_copy = Dir.chdir(@from){Dir[file_pattern].select{|f| !File.directory?(f)}} - existing_files
15
+ files_to_copy.each do |f|
16
+ FileUtils.mkdir_p(File.join(target_dir, File.dirname(f)))
17
+ FileUtils.cp(File.join(@from, f), File.join(target_dir, f))
18
+ end
19
+ end
20
+
21
+ def copy_from_absolute_path(from, to='')
22
+ FileUtils.mkdir_p(File.join(@to, to))
23
+ FileUtils.cp_r(Dir[from], File.join(@to, to))
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,201 @@
1
+ module Ruboto
2
+ module Util
3
+ module Build
4
+ include Verify
5
+ SCRIPTS_DIR = 'src'
6
+
7
+ ###########################################################################
8
+ #
9
+ # Build Subclass or Interface:
10
+ #
11
+
12
+ #
13
+ # build_file: Reads the src from the appropriate location,
14
+ # uses the substitutions hash to modify the contents,
15
+ # and writes to the new location
16
+ #
17
+ def build_file(src, package, name, substitutions, dest='.')
18
+ to = File.join(dest, "src/#{package.gsub('.', '/')}")
19
+ Dir.mkdir(to) unless File.directory?(to)
20
+
21
+ text = File.read(File.expand_path(Ruboto::GEM_ROOT + "/assets/src/#{src}.java"))
22
+ substitutions.each {|k,v| text.gsub!(k, v)}
23
+
24
+ File.open(File.join(to, "#{name}.java"), 'w') {|f| f << text}
25
+ end
26
+
27
+ #
28
+ # get_class_or_interface: Opens the xml file and locates the specified class.
29
+ # Aborts if the class is not found or if it is not available for
30
+ # all api levels
31
+ #
32
+ def get_class_or_interface(klass, force=nil)
33
+ element = verify_api.find_class_or_interface(klass, "either")
34
+
35
+ abort "ERROR: #{klass} not found" unless element
36
+
37
+ unless force == "include"
38
+ abort "#{klass} not available in minSdkVersion, added in #{element.attribute('api_added')}; use '--force include' to create it" if
39
+ element.attribute('api_added') and element.attribute('api_added').to_i > verify_min_sdk.to_i
40
+ abort "#{klass} deprecated for targetSdkVersion, deprecatrd in #{element.attribute('deprecated')}; use '--force include' to create it" if
41
+ element.attribute('deprecated') and element.attribute('deprecated').to_i <= verify_target_sdk.to_i
42
+ end
43
+
44
+ abort "#{klass} removed for targetSdkVersion, removed in #{element.attribute('api_removed')}" if
45
+ element.attribute('api_removed') and element.attribute('api_removed').to_i <= verify_target_sdk.to_i
46
+
47
+ element
48
+ end
49
+
50
+ #
51
+ # check_methods: Checks the methods to see if they are available for all api levels
52
+ #
53
+ def check_methods(methods, force=nil)
54
+ min_api = verify_min_sdk.to_i
55
+ target_api = verify_target_sdk.to_i
56
+
57
+ # Remove methods changed outside of the scope of the sdk versions
58
+ methods = methods.select{|i| not i.attribute('api_added') or i.attribute('api_added').to_i <= target_api}
59
+ methods = methods.select{|i| not i.attribute('deprecated') or i.attribute('deprecated').to_i > min_api}
60
+ methods = methods.select{|i| not i.attribute('api_removed') or i.attribute('api_removed').to_i > min_api}
61
+
62
+ # Inform and remove methods that do not exist in one of the sdk versions
63
+ methods = methods.select do |i|
64
+ if i.attribute('api_removed') and i.attribute('api_removed').to_i <= target_api
65
+ puts "Can't create #{i.method_signature} -- removed in #{i.attribute('api_removed')}"
66
+ false
67
+ else
68
+ true
69
+ end
70
+ end
71
+
72
+ abort = false
73
+ new_methods = methods
74
+ unless force == "include"
75
+ # Inform and remove methods changed inside the scope of the sdk versions
76
+ new_methods = methods.select do |i|
77
+ if i.attribute('api_added') and i.attribute('api_added').to_i > min_api and force == "exclude"
78
+ false
79
+ elsif i.attribute('api_added') and i.attribute('api_added').to_i > min_api
80
+ puts "Can't create #{i.method_signature} -- added in #{i.attribute('api_added')} -- use method_exclude or force exclude"
81
+ abort = true
82
+ false
83
+ elsif i.attribute('deprecated') and i.attribute('deprecated').to_i <= target_api and force == "exclude"
84
+ false
85
+ elsif i.attribute('deprecated') and i.attribute('deprecated').to_i <= target_api
86
+ puts "Can't create #{i.method_signature} -- deprecated in #{i.attribute('deprecated')} -- use method_exclude or force exclude"
87
+ abort = true
88
+ false
89
+ else
90
+ true
91
+ end
92
+ end
93
+
94
+ abort("Aborting!") if abort
95
+ end
96
+
97
+ new_methods
98
+ end
99
+
100
+ #
101
+ # generate_subclass_or_interface: Creates a subclass or interface based on the specifications.
102
+ #
103
+ def generate_subclass_or_interface(params)
104
+ defaults = {:template => "InheritingClass", :method_base => "all", :method_include => "", :method_exclude => "", :force => nil, :implements => ""}
105
+ params = defaults.merge(params)
106
+ params[:package] ||= verify_package
107
+
108
+ class_desc = get_class_or_interface(params[:class] || params[:interface], params[:force])
109
+
110
+ print "Generating methods for #{params[:name]}..."
111
+ methods = class_desc.all_methods(params[:method_base], params[:method_include], params[:method_exclude], params[:implements])
112
+ methods = check_methods(methods, params[:force])
113
+ puts "Done. Methods created: #{methods.count}"
114
+
115
+ # Remove any duplicate constants (use *args handle multiple parameter lists)
116
+ constants = methods.map(&:constant_string).uniq
117
+
118
+ build_file params[:template], params[:package], params[:name], {
119
+ "THE_PACKAGE" => params[:package],
120
+ "THE_ACTION" => class_desc.name == "class" ? "extends" : "implements",
121
+ "THE_ANDROID_CLASS" => (params[:class] || params[:interface]) +
122
+ (params[:implements] == "" ? "" : (" implements " + params[:implements].split(",").join(", "))),
123
+ "THE_RUBOTO_CLASS" => params[:name],
124
+ "THE_CONSTANTS" => constants.map {|i| "public static final int #{i} = #{constants.index(i)};"}.indent.join("\n"),
125
+ "CONSTANTS_COUNT" => methods.count.to_s,
126
+ "THE_CONSTRUCTORS" => class_desc.name == "class" ?
127
+ class_desc.get_elements("constructor").map{|i| i.constructor_definition(params[:name])}.join("\n\n") : "",
128
+ "THE_METHODS" => methods.map{|i| i.method_definition}.join("\n\n")
129
+ }
130
+ end
131
+
132
+ #
133
+ # generate_core_classe: generates RubotoActivity, RubotoService, etc. based
134
+ # on the API specifications.
135
+ #
136
+ def generate_core_classes(params)
137
+ %w(android.view.View.OnClickListener android.widget.AdapterView.OnItemClickListener android.widget.AdapterView.OnItemSelectedListener).each do |i|
138
+ name = i.split(".")[-1]
139
+ if(params[:class] == name or params[:class] == "all")
140
+ generate_subclass_or_interface({:package => "org.ruboto.callbacks", :class => i, :name => "Ruboto#{name}", :force => params[:force]})
141
+ end
142
+ end
143
+
144
+ hash = {:package => "org.ruboto"}
145
+ %w(method_base method_include implements force).inject(hash) {|h, i| h[i.to_sym] = params[i.to_sym]; h}
146
+ hash[:method_exclude] = params[:method_exclude].split(",").push("onCreate").join(",")
147
+
148
+ %w(android.app.Activity android.app.Service android.content.BroadcastReceiver android.view.View).each do |i|
149
+ name = i.split(".")[-1]
150
+ if(params[:class] == name or params[:class] == "all")
151
+ generate_subclass_or_interface(hash.merge({:template => name == "View" ? "InheritingClass" : "Ruboto#{name}", :class => i, :name => "Ruboto#{name}"}))
152
+ end
153
+ end
154
+
155
+ # Activities that can be created, but only directly (i.e., not included in all)
156
+ %w(android.preference.PreferenceActivity android.app.TabActivity).each do |i|
157
+ name = i.split(".")[-1]
158
+ if params[:class] == name
159
+ generate_subclass_or_interface(hash.merge({:template => "RubotoActivity", :class => i, :name => "Ruboto#{name}"}))
160
+ end
161
+ end
162
+ end
163
+
164
+ ###########################################################################
165
+ #
166
+ # generate_inheriting_file:
167
+ # Builds a script based subclass of Activity, Service, or BroadcastReceiver
168
+ #
169
+ def generate_inheriting_file(klass, name, package, script_name = "#{underscore(name)}.rb")
170
+ dest = '.'
171
+ file = File.expand_path File.join(dest, "src/#{package.gsub('.', '/')}", "#{name}.java")
172
+ text = File.read(File.join(Ruboto::ASSETS, "src/Inheriting#{klass}.java"))
173
+ file_existed = File.exists?(file)
174
+ File.open(file, 'w') do |f|
175
+ f << text.gsub("THE_PACKAGE", package).gsub("Inheriting#{klass}", name).gsub("start.rb", script_name)
176
+ end
177
+ puts "#{file_existed ? 'Updated' : 'Added'} file #{file}."
178
+
179
+ script_file = File.expand_path("#{SCRIPTS_DIR}/#{script_name}", dest)
180
+ if !File.exists? script_file
181
+ sample_source = File.read(File.join(Ruboto::ASSETS, "samples/sample_#{underscore klass}.rb")).gsub("THE_PACKAGE", package).gsub("Sample#{klass}", name).gsub("start.rb", script_name)
182
+ FileUtils.mkdir_p File.join(dest, SCRIPTS_DIR)
183
+ File.open script_file, "a" do |f|
184
+ f << sample_source
185
+ end
186
+ puts "Added file #{script_file}."
187
+ end
188
+
189
+ test_file = File.expand_path("test/assets/scripts/#{script_name.chomp('.rb')}_test.rb", dest)
190
+ if !File.exists? test_file
191
+ sample_test_source = File.read(File.join(Ruboto::ASSETS, "samples/sample_#{underscore klass}_test.rb")).gsub("THE_PACKAGE", package).gsub("Sample#{klass}", name)
192
+ FileUtils.mkdir_p File.join(dest, 'test/assets/scripts')
193
+ File.open test_file, "a" do |f|
194
+ f << sample_test_source
195
+ end
196
+ puts "Added file #{test_file}."
197
+ end
198
+ end
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,22 @@
1
+ module Ruboto
2
+ module Util
3
+ module CodeFormatting
4
+ ###########################################################################
5
+ #
6
+ # Methods for formatting code
7
+ #
8
+ def method_call(return_type=nil, method_name="", parameters=[], body_clause=[])
9
+ ["public #{return_type || ""} #{method_name}(" + parameters.map{|i| "#{i[1]} #{i[0]}"}.join(", ") + ") {",
10
+ body_clause.indent, "}"]
11
+ end
12
+
13
+ def if_else(condition, if_clause, else_clause)
14
+ ["if (#{condition}) {", if_clause.indent, else_clause.compact.empty? ? nil : "} else {", else_clause.indent, "}"]
15
+ end
16
+
17
+ def try_catch(try_clause, catch_clause)
18
+ ["try {", try_clause.indent, "} catch (RaiseException re) {", catch_clause.indent, "}"]
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,20 @@
1
+ module Ruboto
2
+ module Util
3
+ module LogAction
4
+ ###########################################################################
5
+ #
6
+ # log_action: put text to stdout around the execution of a block
7
+ #
8
+
9
+ def log_action(initial_text, final_text="Done.", &block)
10
+ $stdout.sync = true
11
+
12
+ print initial_text, "..."
13
+ result = yield
14
+ puts final_text
15
+
16
+ result
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,13 @@
1
+ # fix main (to an extent)
2
+ module Main
3
+ class Program
4
+ module InstanceMethods
5
+ def setup_finalizers
6
+ @finalizers ||= []
7
+ ObjectSpace.define_finalizer(self) do
8
+ while((f = @finalizers.pop)); f.call; end
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ module Ruboto
2
+ # Enable ObjectSpace if running in JRuby, for the "main" lib
3
+ def self.enable_objectspace
4
+ require 'jruby'
5
+ JRuby.objectspace = true
6
+ rescue LoadError
7
+ end
8
+ end
@@ -0,0 +1,40 @@
1
+ module Ruboto
2
+ module Util
3
+ module ScanInAPI
4
+ ###########################################################################
5
+ #
6
+ # Scan the XML file. Much faster than using REXML.
7
+ #
8
+
9
+ def scan_in_api(file)
10
+ require 'strscan'
11
+ doc = StringScanner.new(file)
12
+ Thread.current[:api] = XMLElement.new
13
+ parents = [Thread.current[:api]]
14
+
15
+ while not doc.eos?
16
+ doc.scan(/</)
17
+ if doc.scan(/\/\w+>/)
18
+ parents.pop
19
+ else
20
+ name = doc.scan(/\w+/)
21
+ doc.scan(/\s+/)
22
+ values = {}
23
+ while not (term = doc.scan(/[\/>]/))
24
+ key = doc.scan(/\w+/)
25
+ doc.scan(/='/)
26
+ value = doc.scan(/[^']*/)
27
+ doc.scan(/'\s*/)
28
+ values[key] = value.include?("&") ? value.gsub('&lt;', '<').gsub('&gt;', '>').gsub('&quot;', "\"") : value
29
+ end
30
+ element = parents[-1].add_element(name, values)
31
+ parents.push(element) if term == ">"
32
+ doc.scan(/>/) if term == "/"
33
+ end
34
+ end
35
+
36
+ Thread.current[:api]
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,420 @@
1
+ module Ruboto
2
+ module Util
3
+ module Update
4
+ include Build
5
+ ###########################################################################
6
+ #
7
+ # Updating components
8
+ #
9
+
10
+ def update_android
11
+ root = Dir.getwd
12
+
13
+ # FIXME(uwe): Remove build.xml file to force regeneration.
14
+ # FIXME(uwe): Needed when updating from Android SDK <=13 to 14
15
+ name = REXML::Document.new(File.read("#{root}/build.xml")).root.attributes['name']
16
+ FileUtils.rm_f "#{root}/build.xml"
17
+ # FIXME end
18
+
19
+ system "android update project -p #{root} -n #{name}"
20
+ end
21
+
22
+ def update_test(force = nil)
23
+ root = Dir.getwd
24
+ if !File.exists?("#{root}/test")
25
+ name = verify_strings.root.elements['string'].text.gsub(' ', '')
26
+ puts "\nGenerating Android test project #{name} in #{root}..."
27
+ system %Q{android create test-project -m "#{root.gsub('"', '\"')}" -n "#{name}Test" -p "#{root.gsub('"', '\"')}/test"}
28
+ FileUtils.rm_rf File.join(root, 'test', 'src', verify_package.split('.'))
29
+ puts "Done"
30
+ else
31
+ # FIXME(uwe): Remove build.xml file to force regeneration.
32
+ # FIXME(uwe): Needed when updating from Android SDK <=13 to 14
33
+ FileUtils.rm_f "#{root}/test/build.xml"
34
+ # FIXME end
35
+
36
+ puts "\nUpdating Android test project #{name} in #{root}/test..."
37
+ system "android update test-project -m #{root} -p #{root}/test"
38
+ end
39
+
40
+ Dir.chdir File.join(root, 'test') do
41
+ test_manifest = REXML::Document.new(File.read('AndroidManifest.xml')).root
42
+ test_manifest.elements['application'].attributes['android:icon'] = '@drawable/icon'
43
+ test_manifest.elements['instrumentation'].attributes['android:name'] = 'org.ruboto.test.InstrumentationTestRunner'
44
+
45
+ # TODO(uwe): Trying to push test scripts for faster test cycle, but failing...
46
+ # if test_manifest.elements["uses-permission[@android:name='android.permission.WRITE_INTERNAL_STORAGE']"]
47
+ # puts 'Found permission tag'
48
+ # else
49
+ # test_manifest.add_element 'uses-permission', {"android:name" => "android.permission.WRITE_INTERNAL_STORAGE"}
50
+ # puts 'Added permission tag'
51
+ # end
52
+ # if test_manifest.elements["uses-permission[@android:name='android.permission.WRITE_EXTERNAL_STORAGE']"]
53
+ # puts 'Found external permission tag'
54
+ # else
55
+ # test_manifest.add_element 'uses-permission', {"android:name" => "android.permission.WRITE_EXTERNAL_STORAGE"}
56
+ # puts 'Added external permission tag'
57
+ # end
58
+
59
+ File.open("AndroidManifest.xml", 'w'){|f| test_manifest.document.write(f, 4)}
60
+ instrumentation_property = "test.runner=org.ruboto.test.InstrumentationTestRunner\n"
61
+
62
+ # FIXME(uwe): Cleanup when we stop supporting Android SDK <= 13
63
+ prop_file = %w{ant.properties build.properties}.find{|f| File.exists?(f)}
64
+ prop_lines = File.readlines(prop_file)
65
+ File.open(prop_file, 'a'){|f| f << instrumentation_property} unless prop_lines.include?(instrumentation_property)
66
+ # FIXME end
67
+
68
+ ant_setup_line = /^(\s*<\/project>)/
69
+ run_tests_override = <<-EOF
70
+ <!-- BEGIN added by ruboto -->
71
+
72
+ <macrodef name="run-tests-helper">
73
+ <attribute name="emma.enabled" default="false"/>
74
+ <element name="extra-instrument-args" optional="yes"/>
75
+
76
+ <sequential>
77
+ <xpath input="AndroidManifest.xml" expression="/manifest/@package"
78
+ output="manifest.package" />
79
+ <echo>Running tests with failure detection...</echo>
80
+ <exec executable="${adb}" failonerror="true" outputproperty="tests.output">
81
+ <arg line="${adb.device.arg}"/>
82
+ <arg value="shell"/>
83
+ <arg value="am"/>
84
+ <arg value="instrument"/>
85
+ <arg value="-w"/>
86
+ <arg value="-e"/>
87
+ <arg value="coverage"/>
88
+ <arg value="@{emma.enabled}"/>
89
+ <extra-instrument-args/>
90
+ <arg value="${manifest.package}/${test.runner}"/>
91
+ </exec>
92
+ <echo message="${tests.output}"/>
93
+ <fail message="Tests failed!!!">
94
+ <condition>
95
+ <or>
96
+ <contains string="${tests.output}" substring="INSTRUMENTATION_RESULT"/>
97
+ <contains string="${tests.output}" substring="INSTRUMENTATION_FAILED"/>
98
+ <contains string="${tests.output}" substring="FAILURES"/>
99
+ <not>
100
+ <matches string="${tests.output}" pattern="OK \\(\\d+ tests\\)" multiline="true"/>
101
+ </not>
102
+ </or>
103
+ </condition>
104
+ </fail>
105
+ </sequential>
106
+ </macrodef>
107
+
108
+ <target name="run-tests-quick" description="Runs tests with previously installed packages">
109
+ <run-tests-helper />
110
+ </target>
111
+ <!-- END added by ruboto -->
112
+
113
+ EOF
114
+ ant_script = File.read('build.xml')
115
+ # TODO(uwe): Old patches without delimiter. Remove when we stop supporting upgrading from ruboto-core 0.2.0 and older.
116
+ ant_script.gsub!(/\s*<macrodef name="run-tests-helper">.*?<\/macrodef>\s*/m, '')
117
+ ant_script.gsub!(/\s*<target name="run-tests-quick".*?<\/target>\s*/m, '')
118
+ # TODO end
119
+ ant_script.gsub!(/\s*<!-- BEGIN added by ruboto(?:-core)? -->.*?<!-- END added by ruboto(?:-core)? -->\s*/m, '')
120
+ raise "Bad ANT script" unless ant_script.gsub!(ant_setup_line, "#{run_tests_override}\n\n\\1")
121
+ File.open('build.xml', 'w'){|f| f << ant_script}
122
+ end
123
+ end
124
+
125
+ def update_jruby(force=nil, with_psych=nil)
126
+ jruby_core = Dir.glob("libs/jruby-core-*.jar")[0]
127
+ jruby_stdlib = Dir.glob("libs/jruby-stdlib-*.jar")[0]
128
+ new_jruby_version = JRubyJars::VERSION
129
+
130
+ unless force
131
+ if !jruby_core || !jruby_stdlib
132
+ puts "Cannot find existing jruby jars in libs. Make sure you're in the root directory of your app."
133
+ return false
134
+ end
135
+
136
+ current_jruby_version = jruby_core ? jruby_core[16..-5] : "None"
137
+ if current_jruby_version == new_jruby_version
138
+ puts "JRuby is up to date at version #{new_jruby_version}. Make sure you 'gem update jruby-jars' if there is a new version."
139
+ return false
140
+ end
141
+
142
+ puts "Current jruby version: #{current_jruby_version}"
143
+ puts "New jruby version: #{new_jruby_version}"
144
+ end
145
+
146
+ copier = AssetCopier.new Ruboto::ASSETS, File.expand_path(".")
147
+ log_action("Removing #{jruby_core}") {File.delete *Dir.glob("libs/jruby-core-*.jar")} if jruby_core
148
+ log_action("Removing #{jruby_stdlib}") {File.delete *Dir.glob("libs/jruby-stdlib-*.jar")} if jruby_stdlib
149
+ log_action("Copying #{JRubyJars::core_jar_path} to libs") {copier.copy_from_absolute_path JRubyJars::core_jar_path, "libs"}
150
+ log_action("Copying #{JRubyJars::stdlib_jar_path} to libs") {copier.copy_from_absolute_path JRubyJars::stdlib_jar_path, "libs"}
151
+
152
+ reconfigure_jruby_libs(new_jruby_version, with_psych)
153
+
154
+ puts "JRuby version is now: #{new_jruby_version}"
155
+ true
156
+ end
157
+
158
+ def update_assets
159
+ puts "\nCopying files:"
160
+ copier = Ruboto::Util::AssetCopier.new Ruboto::ASSETS, '.'
161
+
162
+ %w{.gitignore Rakefile assets res/layout test}.each do |f|
163
+ log_action(f) {copier.copy f}
164
+ end
165
+
166
+ # FIXME(uwe): Remove when we stop supporting upgrades from ruboto-core 0.3.3 and older
167
+ old_scripts_dir = 'assets/scripts'
168
+ if File.exists? old_scripts_dir
169
+ FileUtils.mv Dir["#{old_scripts_dir}/*"], SCRIPTS_DIR
170
+ FileUtils.rm_rf old_scripts_dir
171
+ end
172
+ # FIXME end
173
+
174
+ end
175
+
176
+ def update_icons(force = nil)
177
+ copier = Ruboto::Util::AssetCopier.new Ruboto::ASSETS, '.', force
178
+ log_action('icons') do
179
+ copier.copy 'res/drawable*/icon.png'
180
+ copier.copy 'res/drawable*/icon.png', 'test'
181
+ end
182
+ end
183
+
184
+ def update_classes(force = nil)
185
+ copier = Ruboto::Util::AssetCopier.new Ruboto::ASSETS, '.'
186
+ log_action("Ruboto java classes"){copier.copy "src/org/ruboto/*.java"}
187
+ log_action("Ruboto java test classes"){copier.copy "src/org/ruboto/test/*.java", "test"}
188
+ Dir["src/#{verify_package.gsub('.', '/')}/*.java"].each do |f|
189
+ if File.read(f) =~ /public class (.*?) extends org.ruboto.Ruboto(Activity|BroadcastReceiver|Service) \{/
190
+ subclass_name, class_name = $1, $2
191
+ puts "Regenerating #{subclass_name}"
192
+ generate_inheriting_file(class_name, subclass_name, verify_package)
193
+
194
+ # FIXME(uwe): Remove when we stop supporting upgrading from ruboto-core 0.3.3 and older
195
+ if class_name == 'BroadcastReceiver'
196
+ script_file = File.expand_path("#{SCRIPTS_DIR}/#{underscore(subclass_name)}.rb")
197
+ script_content = File.read(script_file)
198
+ if script_content !~ /\$broadcast_receiver.handle_receive do \|context, intent\|/
199
+ puts "Putting receiver script in a block in #{script_file}"
200
+ script_content.gsub! '$broadcast_context', 'context'
201
+ File.open(script_file, 'w') do |of|
202
+ of.puts '$broadcast_receiver.handle_receive do |context, intent|'
203
+ of << script_content
204
+ of.puts 'end'
205
+ end
206
+ end
207
+ end
208
+ # FIXME end
209
+
210
+ end
211
+ end
212
+ end
213
+
214
+ def update_manifest(min_sdk, target, force = false)
215
+ log_action("\nAdding activities (RubotoActivity and RubotoDialog) and SDK versions to the manifest") do
216
+ if sdk_element = verify_manifest.elements['uses-sdk']
217
+ min_sdk ||= sdk_element.attributes["android:minSdkVersion"]
218
+ target ||= sdk_element.attributes["android:targetSdkVersion"]
219
+ else
220
+ min_sdk ||= MINIMUM_SUPPORTED_SDK
221
+ target ||= MINIMUM_SUPPORTED_SDK
222
+ end
223
+ app_element = verify_manifest.elements['application']
224
+ app_element.attributes['android:icon'] ||= '@drawable/icon'
225
+ if min_sdk.to_i >= 11
226
+ app_element.attributes['android:hardwareAccelerated'] ||= 'true'
227
+ app_element.attributes['android:largeHeap'] ||= 'true'
228
+ end
229
+ if app_element.elements["activity[@android:name='org.ruboto.RubotoActivity']"]
230
+ puts 'found activity tag'
231
+ else
232
+ app_element.add_element 'activity', {"android:name" => "org.ruboto.RubotoActivity", 'android:exported' => 'false'}
233
+ end
234
+ if app_element.elements["activity[@android:name='org.ruboto.RubotoDialog']"]
235
+ puts 'found dialog tag'
236
+ else
237
+ app_element.add_element 'activity', {"android:name" => "org.ruboto.RubotoDialog", 'android:exported' => 'false', "android:theme" => "@android:style/Theme.Dialog"}
238
+ end
239
+ if sdk_element
240
+ sdk_element.attributes["android:minSdkVersion"] = min_sdk
241
+ sdk_element.attributes["android:targetSdkVersion"] = target
242
+ else
243
+ verify_manifest.add_element 'uses-sdk', {"android:minSdkVersion" => min_sdk, "android:targetSdkVersion" => target}
244
+ end
245
+ save_manifest
246
+ end
247
+ end
248
+
249
+ def update_core_classes(force = nil)
250
+ generate_core_classes(:class => "all", :method_base => "on", :method_include => "", :method_exclude => "", :force => force, :implements => "")
251
+ end
252
+
253
+ def update_ruboto(force=nil)
254
+ log_action("Copying ruboto.rb") do
255
+ from = File.expand_path(Ruboto::GEM_ROOT + "/assets/#{SCRIPTS_DIR}/ruboto.rb")
256
+ to = File.expand_path("./#{SCRIPTS_DIR}/ruboto.rb")
257
+ FileUtils.cp from, to
258
+ end
259
+ log_action("Copying ruboto/version.rb") do
260
+ from = File.expand_path(Ruboto::GEM_ROOT + "/lib/ruboto/version.rb")
261
+ to = File.expand_path("./#{SCRIPTS_DIR}/ruboto/version.rb")
262
+ FileUtils.mkdir_p File.dirname(to)
263
+ FileUtils.cp from, to
264
+ end
265
+ end
266
+
267
+ def reconfigure_jruby_libs(jruby_core_version, with_psych=nil)
268
+ reconfigure_jruby_core(jruby_core_version)
269
+ reconfigure_jruby_stdlib(with_psych)
270
+ end
271
+
272
+ # - Removes unneeded code from jruby-core
273
+ # - Split into smaller jars that can be used separately
274
+ def reconfigure_jruby_core(jruby_core_version)
275
+ jruby_core = JRubyJars::core_jar_path.split('/')[-1]
276
+ Dir.chdir 'libs' do
277
+ log_action("Removing unneeded classes from #{jruby_core}") do
278
+ FileUtils.rm_rf 'tmp'
279
+ Dir.mkdir 'tmp'
280
+ Dir.chdir 'tmp' do
281
+ FileUtils.move "../#{jruby_core}", "."
282
+ `jar -xf #{jruby_core}`
283
+ File.delete jruby_core
284
+ excluded_core_packages = [
285
+ 'META-INF', 'cext', 'com/kenai/constantine', 'com/kenai/jffi', 'com/martiansoftware', 'ext', 'java',
286
+ 'jline', 'jni',
287
+ 'jnr/constants/platform/darwin', 'jnr/constants/platform/fake', 'jnr/constants/platform/freebsd',
288
+ 'jnr/constants/platform/openbsd', 'jnr/constants/platform/sunos', 'jnr/constants/platform/windows',
289
+ 'jnr/ffi/annotations', 'jnr/ffi/byref', 'jnr/ffi/provider', 'jnr/ffi/util',
290
+ 'jnr/netdb', 'jnr/ffi/posix/util',
291
+ 'org/apache', 'org/jruby/ant',
292
+ 'org/jruby/compiler/util',
293
+ 'org/jruby/demo', 'org/jruby/embed/bsf',
294
+ 'org/jruby/embed/jsr223', 'org/jruby/embed/osgi', 'org/jruby/ext/ffi', 'org/jruby/javasupport/bsf',
295
+ 'org/jruby/runtime/invokedynamic',
296
+ ]
297
+
298
+ # FIXME(uwe): Add one of these when IR is moved to org.jruby.ir
299
+ # excluded_core_packages << 'org/jruby/compiler'
300
+ # excluded_core_packages << 'org/jruby/compiler/ir'
301
+
302
+ # TODO(uwe): Remove when we stop supporting jruby-jars < 1.7.0
303
+ if jruby_core_version < '1.7.0'
304
+ excluded_core_packages << 'org/jruby/compiler/ir'
305
+ print 'Retaining com.kenai.constantine and removing jnr for JRuby < 1.7.0...'
306
+ excluded_core_packages << 'jnr'
307
+ excluded_core_packages.delete 'com/kenai/constantine'
308
+ end
309
+ # TODO end
310
+
311
+ # TODO(uwe): Remove when we stop supporting jruby-jars-1.6.2
312
+ if jruby_core_version == '1.6.2'
313
+ print 'Retaining FFI for JRuby 1.6.2...'
314
+ excluded_core_packages.delete('org/jruby/ext/ffi')
315
+ end
316
+ # TODO end
317
+
318
+ excluded_core_packages.each {|i| FileUtils.remove_dir i, true}
319
+
320
+ # Uncomment this section to get a jar for each top level package in the core
321
+ #Dir['**/*'].select{|f| !File.directory?(f)}.map{|f| File.dirname(f)}.uniq.sort.reverse.each do |dir|
322
+ # `jar -cf ../jruby-core-#{dir.gsub('/', '.')}-#{jruby_core_version}.jar #{dir}`
323
+ # FileUtils.rm_rf dir
324
+ #end
325
+
326
+ `jar -cf ../#{jruby_core} .`
327
+ end
328
+ FileUtils.remove_dir "tmp", true
329
+ end
330
+ end
331
+ end
332
+
333
+ # - Moves ruby stdlib to the root of the jruby-stdlib jar
334
+ # FIXME(uwe): Place stdlib and psych source in lib/ruby/site_ruby/1.8 since that is first in the load path generated by JRuby.
335
+ def reconfigure_jruby_stdlib(with_psych=nil)
336
+ excluded_stdlibs = %w{} + (verify_ruboto_config[:excluded_stdlibs] || [])
337
+ Dir.chdir 'libs' do
338
+ jruby_stdlib = JRubyJars::stdlib_jar_path.split('/')[-1]
339
+ stdlib_1_8_files = nil
340
+ log_action("Reformatting #{jruby_stdlib}") do
341
+ FileUtils.mkdir_p "tmp/old"
342
+ FileUtils.mkdir_p "tmp/new/lib/ruby"
343
+ Dir.chdir "tmp/old" do
344
+ # FileUtils.move "../#{jruby_stdlib}", "."
345
+ `jar -xf ../../#{jruby_stdlib}`
346
+ # File.delete jruby_stdlib
347
+
348
+ FileUtils.move "META-INF/jruby.home/lib/ruby/1.8", "../new/lib/ruby"
349
+ Dir["META-INF/jruby.home/lib/ruby/site_ruby/1.8/*"].each do |f|
350
+ next if File.basename(f) =~ /^..?$/
351
+ FileUtils.move f, "../new/lib/ruby/1.8/" + File.basename(f)
352
+ end
353
+ Dir["META-INF/jruby.home/lib/ruby/site_ruby/shared/*"].each do |f|
354
+ next if File.basename(f) =~ /^..?$/
355
+ FileUtils.move f, "../new/lib/ruby/1.8/" + File.basename(f)
356
+ end
357
+ end
358
+ Dir.chdir "tmp/new/lib/ruby/1.8" do
359
+ if excluded_stdlibs.any?
360
+ excluded_stdlibs.each { |d| FileUtils.rm_rf d }
361
+ print "excluded #{excluded_stdlibs.join(' ')}..."
362
+ end
363
+ stdlib_1_8_files = Dir['**/*']
364
+ end
365
+ Dir.chdir "tmp/new" do
366
+ # Uncomment this part to split the stdlib into one jar per directory
367
+ # Dir['*'].select{|f| File.directory? f}.each do |d|
368
+ # `jar -cf ../jruby-stdlib-#{d}-#{JRubyJars::VERSION}.jar #{d}`
369
+ # FileUtils.rm_rf d
370
+ # end
371
+
372
+ `jar -cf ../../#{jruby_stdlib} .`
373
+ end
374
+ end
375
+
376
+ psych_jar = "psych.jar"
377
+ psych_already_present = File.exists? psych_jar
378
+ FileUtils.rm_f psych_jar
379
+
380
+ if with_psych || with_psych.nil? && psych_already_present
381
+ log_action("Adding psych #{File.basename psych_jar}") do
382
+ psych_dir = 'tmp/psych/lib/ruby/1.8'
383
+ FileUtils.mkdir_p File.dirname(psych_dir)
384
+ FileUtils.move "tmp/old/META-INF/jruby.home/lib/ruby/1.9", psych_dir
385
+ Dir.chdir psych_dir do
386
+ if excluded_stdlibs.any?
387
+ excluded_stdlibs.each { |d| FileUtils.rm_rf d }
388
+ print "excluded #{excluded_stdlibs.join(' ')}..."
389
+ end
390
+ psych_files = Dir["**/*"]
391
+ puts if psych_files.any?
392
+ psych_files.each do |f|
393
+ next if File.basename(f) =~ /^..?$/
394
+ if stdlib_1_8_files.include? f
395
+ puts "Removing duplicate #{f}"
396
+ FileUtils.rm_f f
397
+ end
398
+ end
399
+ end
400
+ Dir.chdir 'tmp/psych' do
401
+ `jar -cf ../../#{psych_jar} .`
402
+ end
403
+ FileUtils.remove_dir psych_dir, true
404
+ end
405
+ end
406
+
407
+ FileUtils.remove_dir "tmp", true
408
+ end
409
+ end
410
+
411
+ def update_bundle
412
+ if File.exist?('Gemfile.apk') && File.exists?('libs/bundle.jar')
413
+ FileUtils.rm 'libs/bundle.jar'
414
+ system 'rake bundle'
415
+ end
416
+ end
417
+
418
+ end
419
+ end
420
+ end