ruboto 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|