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.
- data/COPYING +19 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +21 -0
- data/README.md +293 -0
- data/Rakefile +114 -0
- data/assets/Rakefile +386 -0
- data/assets/res/drawable-hdpi/icon.png +0 -0
- data/assets/res/drawable-ldpi/icon.png +0 -0
- data/assets/res/drawable-mdpi/icon.png +0 -0
- data/assets/res/layout/get_ruboto_core.xml +25 -0
- data/assets/samples/sample_activity.rb +21 -0
- data/assets/samples/sample_activity_test.rb +21 -0
- data/assets/samples/sample_broadcast_receiver.rb +6 -0
- data/assets/samples/sample_broadcast_receiver_test.rb +1 -0
- data/assets/samples/sample_service.rb +14 -0
- data/assets/samples/sample_service_test.rb +1 -0
- data/assets/src/InheritingActivity.java +195 -0
- data/assets/src/InheritingBroadcastReceiver.java +27 -0
- data/assets/src/InheritingClass.java +19 -0
- data/assets/src/InheritingService.java +9 -0
- data/assets/src/RubotoActivity.java +111 -0
- data/assets/src/RubotoBroadcastReceiver.java +51 -0
- data/assets/src/RubotoService.java +61 -0
- data/assets/src/org/ruboto/RubotoDialog.java +11 -0
- data/assets/src/org/ruboto/Script.java +545 -0
- data/assets/src/org/ruboto/test/ActivityTest.java +63 -0
- data/assets/src/org/ruboto/test/InstrumentationTestRunner.java +124 -0
- data/assets/src/ruboto.rb +621 -0
- data/assets/test/assets/scripts/test_helper.rb +13 -0
- data/bin/ruboto +5 -0
- data/lib/java_class_gen/InheritingClass.java.erb +10 -0
- data/lib/java_class_gen/android_api.xml +1 -0
- data/lib/ruboto.rb +16 -0
- data/lib/ruboto/api.rb +21 -0
- data/lib/ruboto/commands/base.rb +392 -0
- data/lib/ruboto/core_ext/array.rb +6 -0
- data/lib/ruboto/core_ext/object.rb +10 -0
- data/lib/ruboto/util/asset_copier.rb +27 -0
- data/lib/ruboto/util/build.rb +201 -0
- data/lib/ruboto/util/code_formatting.rb +22 -0
- data/lib/ruboto/util/log_action.rb +20 -0
- data/lib/ruboto/util/main_fix.rb +13 -0
- data/lib/ruboto/util/objectspace.rb +8 -0
- data/lib/ruboto/util/scan_in_api.rb +40 -0
- data/lib/ruboto/util/update.rb +420 -0
- data/lib/ruboto/util/verify.rb +87 -0
- data/lib/ruboto/util/xml_element.rb +200 -0
- data/lib/ruboto/version.rb +3 -0
- data/test/activity/image_button_activity.rb +21 -0
- data/test/activity/image_button_activity_test.rb +21 -0
- data/test/activity/image_button_and_button_activity.rb +24 -0
- data/test/activity/image_button_and_button_activity_test.rb +27 -0
- data/test/activity/option_menu_activity.rb +21 -0
- data/test/activity/option_menu_activity_test.rb +20 -0
- data/test/activity/stack_activity.rb +21 -0
- data/test/activity/stack_activity_test.rb +23 -0
- data/test/app_test_methods.rb +41 -0
- data/test/minimal_app_test.rb +23 -0
- data/test/rake_test.rb +40 -0
- data/test/ruboto_gen_test.rb +32 -0
- data/test/ruboto_gen_with_psych_test.rb +16 -0
- data/test/ruboto_update_test.rb +5 -0
- data/test/ruboto_update_with_psych_test.rb +18 -0
- data/test/service_test.rb +49 -0
- data/test/test_helper.rb +177 -0
- data/test/update_test_methods.rb +33 -0
- metadata +157 -0
@@ -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,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('<', '<').gsub('>', '>').gsub('"', "\"") : 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
|