Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
80993fc
commit b0b05dc
Showing
1,046 changed files
with
220,794 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,5 @@ | |
/.settings/ | ||
/.classpath | ||
/build/ | ||
/.DS_Store | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
require 'java' | ||
begin | ||
require 'ant/element' | ||
rescue NameError => ne | ||
# uncaught, we should get a NameError, such as: | ||
# NameError: uppercase package names not accessible this way (`org.apache.tools.ant.IntrospectionHelper') | ||
# this probably means $ANT_HOME is not set properly | ||
raise RuntimeError, "Caught NameError; examine $ANT_HOME" | ||
end | ||
require 'ant/target' | ||
|
||
class Ant | ||
java_import org.apache.tools.ant.DefaultLogger | ||
java_import org.apache.tools.ant.Location | ||
java_import org.apache.tools.ant.Project | ||
java_import org.apache.tools.ant.ProjectHelper | ||
|
||
attr_reader :project, :log, :location | ||
attr_accessor :current_target | ||
|
||
def initialize(options={}, &block) | ||
@options = options | ||
@location = Ant.location_from_caller | ||
@project = create_project options | ||
@current_target = nil | ||
generate_methods @project.data_type_definitions | ||
generate_methods @project.task_definitions | ||
process_arguments unless options[:run] == false || Ant.run || @location.file_name != $0 | ||
define_tasks(&block) | ||
end | ||
|
||
def properties | ||
@project.properties | ||
end | ||
|
||
def define_tasks(&code) | ||
code.arity == 1 ? code[self] : instance_eval(&code) if code | ||
end | ||
|
||
# Add a target (two forms) | ||
# 1. Execute a block as a target: add_target "foo-target" { echo :message => "I am cool" } | ||
# 2. Execute a rake task as a target: add_target Rake.application["default"] | ||
def add_target(*options, &block) | ||
target = options.first.respond_to?(:name) ? RakeTarget.new(self, options.first) : BlockTarget.new(self, *options, &block) | ||
@project.add_target target | ||
end | ||
alias target add_target | ||
|
||
def [](name) | ||
if @project.targets.containsKey(name.to_s) | ||
TargetWrapper.new(@project, name) | ||
else | ||
MissingWrapper.new(@project, name) | ||
end | ||
end | ||
|
||
def execute_target(name) | ||
self[name].execute | ||
end | ||
|
||
def execute_default | ||
@project.execute_target(@project.default_target) | ||
end | ||
|
||
def project_help | ||
max_width = @project.targets.keys.max {|a,b| a.length <=> b.length}.length | ||
@project.targets.values.select {|t| | ||
t.description | ||
}.sort{|a,b| | ||
a.name <=> b.name | ||
}.map {|t| | ||
"%-#{max_width}s - %s" % [t.name, t.description] | ||
}.join("\n") | ||
end | ||
|
||
def ant(*args) | ||
raise "ant is known to be broken and is unsupported in the ant library" | ||
end | ||
|
||
def antcall(*args) | ||
raise "antcall is known to be broken and is unsupported in the ant library" | ||
end | ||
|
||
def _element(name, args = {}, &block) | ||
Element.new(self, name).call(@current_target, args, &block) | ||
end | ||
|
||
def method_missing(name, *args, &block) | ||
project.log "invoking method_missing: #{name} on Ant instance", 5 | ||
_element(name, *args, &block) | ||
end | ||
|
||
def run(*targets) | ||
if targets.length > 0 | ||
targets.each {|t| execute_target(t) } | ||
else | ||
execute_default | ||
end | ||
end | ||
|
||
def process_arguments(argv = ARGV, run_at_exit = true) | ||
properties = [] | ||
targets = [] | ||
argv.each {|a| a =~ /^-D/ ? properties << a[2..-1] : targets << a } | ||
properties.each do |p| | ||
key, value = p.split('=', 2) | ||
value ||= "true" | ||
@project.set_user_property(key, value) | ||
end | ||
at_exit do | ||
begin | ||
run(*targets) if (!targets.empty? || @project.default_target) && !Ant.run | ||
rescue => e | ||
warn e.message | ||
puts e.backtrace.join("\n") if $DEBUG | ||
exit 1 | ||
end | ||
end if run_at_exit | ||
end | ||
|
||
private | ||
def create_project(options) | ||
# If we are calling into a rakefile from ant then we already have a project to use | ||
return $project if defined?($project) && $project | ||
|
||
options[:basedir] ||= '.' | ||
output_level = options.delete(:output_level) || 2 | ||
|
||
Project.new.tap do |p| | ||
p.init | ||
p.add_build_listener(DefaultLogger.new.tap do |log| | ||
log.output_print_stream = Java::java.lang.System.out | ||
log.error_print_stream = Java::java.lang.System.err | ||
log.emacs_mode = true | ||
log.message_output_level = output_level | ||
@log = log | ||
end) | ||
helper = ProjectHelper.getProjectHelper | ||
helper.import_stack.add(Java::java.io.File.new(@location.file_name)) | ||
p.addReference(ProjectHelper::PROJECTHELPER_REFERENCE, helper) | ||
options.each_pair {|k,v| p.send("set_#{k}", v) if p.respond_to?("set_#{k}") } | ||
end | ||
end | ||
|
||
def generate_methods(collection) | ||
existing_methods = Ant.instance_methods(false) | ||
collection.each do |name, clazz| | ||
element = Element.new(self, name, clazz) | ||
method_name = Ant.safe_method_name(name) | ||
(class << self; self; end).send(:define_method, method_name) do |*a, &b| | ||
element.call(@current_target, *a, &b) | ||
end unless existing_methods.include?(method_name) | ||
end | ||
end | ||
|
||
class << self | ||
attr_accessor :run | ||
|
||
def safe_method_name(element_name) | ||
if element_name =~ /\A(and|or|not|do|end|if|else)\z/m | ||
"_#{element_name}" | ||
else | ||
element_name | ||
end | ||
end | ||
|
||
def location_from_caller | ||
file, line = caller.detect{|el| el !~ /^#{File.dirname(__FILE__)}/ && el !~ /\.java:/}.split(/:(\d+):?/) | ||
Location.new(file, line.to_i, 1) | ||
end | ||
|
||
def ant(options={}, &code) | ||
if options.respond_to? :to_hash | ||
@ant ||= Ant.new options.to_hash | ||
@ant.define_tasks(&code) | ||
@ant | ||
else | ||
options = options.join(" ") if options.respond_to? :to_ary | ||
ant_bin = ENV['ANT_HOME'] ? File.join(ENV['ANT_HOME'], 'bin', 'ant') : 'ant' # find one on $PATH | ||
system "#{ant_bin} #{options.to_s}" # FIXME: Make this more secure if using array form | ||
end | ||
rescue Exception => e | ||
warn e.message | ||
warn e.backtrace.join("\n") | ||
end | ||
end | ||
end | ||
|
||
# This method has three different uses: | ||
# | ||
# 1. Call an ant task or type directly: | ||
# task :compile do # Rake task | ||
# ant.javac { } # Look I am calling an ant task | ||
# end | ||
# 2. Provide a block to provide an impromptu ant session | ||
# ant do | ||
# javac {} # Everything executes as if in an executing ant target | ||
# end | ||
# 3. Provide arguments to execute ant as it's own build | ||
# ant '-f my_build.xml my_target1' | ||
# | ||
# Additionally this may be passed in array format if you are worried about injection: | ||
# | ||
# args = ['-f', 'my_build.xml', 'my_target1'] | ||
# ant args | ||
# | ||
def ant(*args, &block) | ||
Ant.ant(*args, &block) | ||
end | ||
|
||
def ant_import(filename = 'build.xml') | ||
ant = Ant.ant | ||
|
||
abs_name = File.expand_path(filename) | ||
Ant::ProjectHelper.configure_project ant.project, java.io.File.new(abs_name) | ||
|
||
ant.project.targets.each do |target_name, target| | ||
name = Rake.application.lookup(target_name) ? "ant_" + target_name : target_name | ||
|
||
task(name) { target.project.execute_target(target_name) } | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
require 'java' | ||
|
||
class Ant | ||
java_import org.apache.tools.ant.IntrospectionHelper | ||
java_import org.apache.tools.ant.RuntimeConfigurable | ||
java_import org.apache.tools.ant.UnknownElement | ||
|
||
# preserve idempotence of Ruby wrapper as much as possible | ||
UnknownElement.__persistent__ = true | ||
|
||
class UnknownElement | ||
attr_accessor :ant, :nesting | ||
# undef some method names that might collide with ant task/type names | ||
%w(test fail abort raise exec trap).each {|m| undef_method(m)} | ||
Object.instance_methods.grep(/java/).each {|m| undef_method(m)} | ||
|
||
def _element(name, args = {}, &block) | ||
Element.new(ant, name).call(self, args, &block) | ||
end | ||
|
||
def method_missing(name, *args, &block) | ||
ant.project.log "#{location.to_s}: #{' ' * nesting}#{task_name} -> #{name}", 5 | ||
_element(name, *args, &block) | ||
end | ||
end | ||
|
||
# This is really the metadata of the element coupled with the logic for | ||
# instantiating an instance of an element and evaluating it. My intention | ||
# is to decouple these two pieces. This has extra value since we can then | ||
# also make two types of instances for both top-level tasks and for targets | ||
# since we have some conditionals which would then be eliminated | ||
class Element | ||
attr_reader :name | ||
|
||
def initialize(ant, name, clazz = nil) | ||
@ant, @name, @clazz = ant, name, clazz | ||
end | ||
|
||
def call(parent, args={}, &code) | ||
element = create_element(parent) | ||
assign_attributes element, args | ||
define_nested_elements element if @clazz | ||
code.arity==1 ? code[element] : element.instance_eval(&code) if block_given? | ||
if parent.respond_to? :add_child # Task | ||
parent.add_child element | ||
parent.runtime_configurable_wrapper.add_child element.runtime_configurable_wrapper | ||
elsif parent.respond_to? :add_task # Target | ||
parent.add_task element | ||
else # Just run it now | ||
@ant.project.log "#{element.location.to_s}: Executing #{name}", 5 | ||
element.owning_target = Target.new.tap {|t| t.name = ""} | ||
element.maybe_configure | ||
element.execute | ||
end | ||
end | ||
|
||
private | ||
def create_element(parent) # See ProjectHelper2.ElementHandler | ||
UnknownElement.new(@name).tap do |e| | ||
if parent.respond_to?(:nesting) | ||
e.nesting = parent.nesting + 1 | ||
else | ||
e.nesting = 1 | ||
end | ||
e.ant = @ant | ||
e.project = @ant.project | ||
e.task_name = @name | ||
e.location = Ant.location_from_caller | ||
e.owning_target = @ant.current_target | ||
end | ||
end | ||
|
||
# This also subsumes configureId to only have to traverse args once | ||
def assign_attributes(instance, args) | ||
wrapper = RuntimeConfigurable.new instance, instance.task_name | ||
args.each do |key, value| | ||
wrapper.set_attribute to_string(key), @ant.project.replace_properties(to_string(value)) | ||
end | ||
end | ||
|
||
def define_nested_elements(instance) | ||
meta_class = class << instance; self; end | ||
@helper = IntrospectionHelper.get_helper(@ant.project, @clazz) | ||
@helper.get_nested_element_map.each do |element_name, clazz| | ||
element = Element.new(@ant, element_name, clazz) | ||
meta_class.send(:define_method, Ant.safe_method_name(element_name)) do |*args, &block| | ||
instance.ant.project.log "#{instance.location.to_s}: #{' ' * instance.nesting}#{instance.task_name} . #{element_name}", 5 | ||
element.call(instance, *args, &block) | ||
end | ||
end | ||
end | ||
|
||
def to_string(value) | ||
if String === value | ||
value | ||
elsif value.respond_to?(:to_str) | ||
value.to_str | ||
else | ||
value.to_s | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.