ruboto 0.5.2

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