Author: vborja
Date: Tue Sep 2 20:33:06 2008
New Revision: 691494
URL: http://svn.apache.org/viewvc?rev=691494&view=rev
Log:
Nailgun running on jruby 1.1.4, using BuildfileTask
Added:
incubator/buildr/trunk/addon/buildr/org/apache/buildr/BuildrNail$Main.class
incubator/buildr/trunk/addon/buildr/org/apache/buildr/BuildrNail.class
incubator/buildr/trunk/addon/buildr/org/apache/buildr/BuildrNail.java
Modified:
incubator/buildr/trunk/addon/buildr/nailgun.rb
Modified: incubator/buildr/trunk/addon/buildr/nailgun.rb
URL:
http://svn.apache.org/viewvc/incubator/buildr/trunk/addon/buildr/nailgun.rb?rev=691494&r1=691493&r2=691494&view=diff
==============================================================================
--- incubator/buildr/trunk/addon/buildr/nailgun.rb (original)
+++ incubator/buildr/trunk/addon/buildr/nailgun.rb Tue Sep 2 20:33:06 2008
@@ -13,7 +13,6 @@
# License for the specific language governing permissions and limitations under
# the License.
-
require 'benchmark'
require 'jruby'
require 'monitor'
@@ -24,310 +23,136 @@
module Buildr
- # See the nailgun_help method for documentation.
- module Nailgun # :nodoc:
+ module Nailgun
+
extend self
+ attr_reader :ng
+ @ng ||= OpenStruct.new
+
VERSION = '0.7.1'
NAME = "nailgun-#{VERSION}"
URL = "http://downloads.sourceforge.net/nailgun/#{NAME}.zip"
ARTIFACT_SPEC = "com.martiansoftware:nailgun:jar:#{VERSION}"
+
+ # Paths used to initialize a buildr runtime
BUILDR_PATHS = [File.expand_path('../', File.dirname(__FILE__)),
File.expand_path('../../lib', File.dirname(__FILE__))]
+
+ private
- attr_accessor :artifact
- attr_accessor :server, :port, :jruby_queue_size, :buildr_queue_size
- attr_accessor :jruby_home, :home
-
- self.jruby_home = if RUBY_PLATFORM =~ /java/
- Config::CONFIG['prefix']
- else
- ENV['JRUBY_HOME'] || File.join(ENV['HOME'], '.jruby')
- end
+ # Returns the path to JRUBY_HOME.
+ def jruby_home
+ ENV['JRUBY_HOME'] || Config::CONFIG['prefix']
+ end
- self.home = ENV['NAILGUN_HOME'] || File.join(jruby_home, 'tool', 'nailgun')
- self.server = 'localhost'
- self.port = 2113
- self.jruby_queue_size = 3
- self.buildr_queue_size = 3
-
- def namespace(&block)
- if Object.const_defined?(:Rake)
- Rake.application.in_namespace(:nailgun, &block)
- end
+ # Returns the path to NAILGUN_HOME.
+ def nailgun_home
+ ENV['NAILGUN_HOME'] || File.expand_path('tool/nailgun', jruby_home)
end
- def boot(&block)
- if block
- @boot = block
- else
- @boot.call
- end
+ def tmp_path(*paths)
+ File.join(Dir.tmpdir, 'nailgun', *paths)
end
- module Application
- def nailgun_help
- " " + <<-DESC.strip.gsub(/ *\n +/, "\n ")
- NailGun is a client, protocol, and server for running Java
- programs from the command line without incurring the JVM
- startup overhead. Nailgun integration is currently available
- only when running Buildr with JRuby.
-
- Buildr provides a custom nailgun server, allowing you to
- start a single JVM and let buildr create a queue of runtimes.
- These JRuby runtimes can be cached (indexed by buildfile path)
- and are automatically reloaded when the buildfile has been modified.
- Runtime caching allows you to execute tasks without
- spending time creating the buildr environment. Some nailgun
- tasks have been provided to manage the cached runtimes.
-
- To start the buildr server execute the following task:
-
- nailgun:start
-
- Server output will display a message when it becomes ready, you
- will also see messages when the JRuby runtimes are being created,
- or when a new buildr environment is being loaded on them.
- After the runtime queues have been populated, you can start calling
- buildr as you normally do, by invoking the $NAILGUN_HOME/ng binary:
-
- # on another terminal, change directory to a project.
- # if this project is the same nailgun:start was invoked on, it's
- # runtime has been cached, so no loading is performed unless
- # the buildfile has been modified. otherwise the buildfile
- # will be loaded on a previously loaded fresh-buildr runtime
- # and it will be cached.
- cd /some/buildr/project
- ng nailgun:help # display nailgun help
- ng nailgun:tasks # display overview of ng
tasks
- ng clean compile # just invoke those two tasks
-
- Configuration and Environment Variables.
-
- Before starting the server, buildr will check if you have
- nailgun already installed by seeking the nailgun jar under
-
- $NAILGUN_HOME
-
- You can override this environment variable to tell buildr where
- to find or where to install nailgun. If missing, NAILGUN_HOME
- defaults to the $JRUBY_HOME/tool/nailgun directory. You can
- also specify the nailgun_home on your buildfile with the following
- code:
-
- require 'buildr/nailgun'
- Buildr::Nailgun.home = File.expand_path('~/.jruby/tool/nailgun')
-
- Buildr will also check that the nailgun client binary (ng.exe for
- Windows systems, ng otherwise) is installed on NAILGUN_HOME.
- If no binary is found, buildr will download nailgun and
- compile+install it.
-
-
- The buildr server binds itself to localhost, port 2113. You can
- override this on your buildfile, by placing the following code:
-
- require 'buildr/nailgun'
- Buildr::Nailgun.server = '127.0.0.1'
- Buildr::Nailgun.port = 2233
-
- If you provided custom host/port settings you need
- to tell the nailgun client where to connect to:
-
- ng --nailgun-server 127.0.0.1 --nailgun-port 2233 nailgun:tasks
-
- The buildr server starts a BuildrFactory responsible for providing
- a pool of JRuby runtimes configured and ready for task execution.
- This BuildrFactory consists of two queues: One of pure JRuby runtimes
- with almost nothing loaded, and another of Buildr runtimes (consumed
- from the first queue) with the Buildr runtime preloaded but without
- any project definition. The jruby queue is used for sandboxing code
- like running GetoptLong, but most importantly its the place where
- buildr runtimes begin life, to be later added on the buildr queue.
- By default both queues are of size 3, you can customize this with:
-
- require 'buildr/nailgun'
- Buildr::Nailgun.jruby_queue_size = 4 # JRuby creation is fast!
- Buildr::Nailgun.buildr_queue_size = 5 # loading buildr takes
longer
-
- The buildr_queue_size is of particular importance if you expect to
- reload lots of buildfiles.
-
- Execute nailgun:tasks get an overview of available nailgun tasks.
-
- DESC
- end
+ file_tasks = lambda do
- def nailgun_tasks
- tasks = {}
- tasks['nailgun:help'] = 'Display nailgun help'
- tasks['nailgun:start'] = 'Start the Nailgun server.'
- tasks['nailgun:stop'] = 'Stop the Nailgun server.'
- tasks['nailgun:tasks'] = 'Display this message'
- tasks['nailgun:list'] = <<-DESC
- Display a list of builfile paths having an associated
- buildr runtime. Having a cached runtime reduces buidlr
- execution time.
-
- If buildr finds the current buildfile on this list,
- no file loading will be performed, only execution of
- specified tasks on the previously loaded environment.
- However if the cached runtime is out of date (buildfile
- has been modified) the runtime will be reloaded.
-
- This feature becomes handy when performing development
- cycle: edit -> compile -> test -> report.
-
- This task exits inmediatly after printing the file list.
- DESC
- tasks['nailgun:clear'] = <<-DESC
- Remove all cached buildr runtimes and exit
- DESC
- tasks['nailgun:load'] = <<-DESC
- Add or update a cached runtime.
-
- Use this task to create a cached buildr runtime for a
- buildfile.
- DESC
- tasks['nailgun:delete'] = <<-DESC
- Delete cached runtime for a buildfile and exit.
- DESC
- tasks['nailgun:once [tasks]'] = <<-DESC
- Ignore cached runtime and perform tasks on a newly
- created environment. This new runtime is dropped right
- after buildr completion.
- DESC
-
- out = ""
- out << "\nNailgun tasks:\n"
- tasks.each_pair do |task, desc|
- out << "\n"
- out << sprintf(" %20-s\n", [task].flatten.join(' | '))
- out << sprintf(" %s\n", desc.strip.gsub(/ *\n +/, "\n "))
- end
- out
- end
-
- def buildfile(dir = nil, candidates = nil)
- dir ||= Dir.pwd
- candidates ||= @rakefiles.dup
- Util.find_buildfile(dir, candidates, options.nosearch)
- end
-
- def clear_invoked
- tasks.each do |task|
- is_project =
Project.instance_variable_get(:@projects).key?(task.name)
- task.instance_variable_set(:@already_invoked, false) unless
is_project
- end
- end
-
- if Buildr.const_defined?(:Application)
- class Buildr::Application
- include Nailgun::Application
- public :requires
- end
+ dist_zip = Buildr.download(tmp_path(NAME + '.zip') => URL)
+ dist_dir = Buildr.unzip(tmp_path(NAME) => dist_zip)
+
+ nailgun_jar = file(File.expand_path(NAME + '.jar', nailgun_home))
+ ng.artifact = Buildr.artifact(ARTIFACT_SPEC).from(nailgun_jar)
+ unless File.exist?(nailgun_jar.to_s)
+ nailgun_jar.enhance [dist_dir]
end
- end
-
- module ContextRunner
- extend self
- def parse_options(ctx, opts)
- opts.requires = []
- Buildr.const_set(:VERSION,
ctx.server.runtime.object.const_get(:Buildr)::VERSION)
-
- obj = OpenStruct.new(:ctx => ctx, :opts => opts)
- class << obj
- include Buildr::CommandLineInterface
-
- def help
- super
- puts
- puts 'To get a summary of Nailgun features use'
- puts ' nailgun:help'
- end
-
- def do_option(opt, value)
- case opt
- when '--help'
- help
- opts.exit = true
- when '--version'
- puts version
- opts.exit = true
- when '--environment'
- ctx.env['BUILDR_ENV'] = value
- when '--buildfile'
- opts.buildfile = value
- when '--require'
- opts.requires << value
- when '--nosearch'
- opts.nosearch = true
- end
+ compiled_bin = file(tmp_path(NAME, NAME, 'ng' +
Config::CONFIG['EXEEXT']) => dist_dir.target) do |task|
+ unless task.to_s.pathmap('%x') == '.exe'
+ Dir.chdir(task.to_s.pathmap('%d')) do
+ info "Compiling #{task.to_s}"
+ system('make', task.to_s.pathmap('%f')) or
+ fail "Nailgun binary compilation failed."
end
end
-
- ARGV.replace(ctx.argv)
- obj.parse_options
end
- def run(ctx)
- ARGV.replace(ctx.argv)
- Dir.chdir(ctx.pwd)
- ctx.env.each { |k, v| ENV[k.to_s] = v.to_s }
- Buildr::Application.module_eval do
- include Nailgun::Application
- end
- task 'nailgun:load' do
- puts "Buildfile #{Rake.application.buildfile} loaded"
+ ng.installed_bin =
file(File.expand_path(compiled_bin.to_s.pathmap('%f'), nailgun_home) =>
compiled_bin) do |task|
+ mkpath task.to_s.pathmap('%d'), :verbose => false
+ cp compiled_bin.to_s, task.to_s, :verbose => false
+ end
+
+ end # file_tasks
+
+ server_tasks = lambda do
+
+ task('start', :port, :iface, :queue_size => [ng.artifact,
ng.installed_bin]) do |task, args|
+
+ iface = args[:iface].to_s.empty? ? '127.0.0.1' : args[:iface]
+ port = args[:port].to_s.empty? ? 2113 : args[:port].to_i
+ queue_size = args[:queue_size].to_s.empty? ? 1 : args[:queue_size].to_i
+
+ if ng.server || ng.nail
+ fail "Already running on Nailgun server: #{ng.server || ng.nail}"
end
- if ctx.fresh
- run_fresh(ctx)
- else
- run_local(ctx)
+ info 'Booting Buildr nailgun server...'
+ top_level = Buildr.application.instance_eval { @top_level_tasks.dup }
+ top_level.delete_if { |t| t[/nailgun/] }
+ unless top_level.empty?
+ raise 'Don\'t specify more targets when starting Nailgun server'
end
+ ng.server_setup.call
+
+ factory = RuntimeFactory.new(queue_size, queue_size)
+ ng.server = NGServer.new(iface, port, factory)
+
+ ng.server.start
+ end
+
+ task('help') do
+ info "HELP"
end
- private
-
- def run_fresh(ctx)
- Project.clear
- old_app = Rake.application
- Rake.application = Buildr::Application.new
- Rake.application.instance_eval do
- @tasks = old_app.instance_variable_get(:@tasks)
- @rules = old_app.instance_variable_get(:@rules)
- run
- end
+ end # server_tasks
+
+ client_tasks = lambda do
+
+ task('list') do
+ info "HELLO"
end
- def run_local(ctx)
- Rake.application.instance_eval do
- verbose(nil)
- options.trace = false
- parse_options
- collect_tasks
- clear_invoked
- top_level_tasks.delete('buildr:initialize')
- Util.benchmark { top_level }
- end
+ end # client_tasks
+
+ # Load java classes on server side.
+ ng.server_setup = lambda do
+
+ module Util
+ include Buildr::Util
end
- end
- module Util
- extend Buildr::Util
- extend self
+ Util.add_to_sysloader ng.artifact.to_s
+ Util.add_to_sysloader File.dirname(__FILE__)
- def find_buildfile(pwd, candidates, nosearch=false)
- candidates = [candidates].flatten
- buildfile = candidates.find { |c| File.file?(File.expand_path(c, pwd))
}
- return File.expand_path(buildfile, pwd) if buildfile
- return nil if nosearch
- updir = File.dirname(pwd)
- return nil if File.expand_path(updir) == File.expand_path(pwd)
- find_buildfile(updir, candidates)
+ class Client
+ include org.apache.buildr.BuildrNail
+ end
+
+ class NGServer < com.martiansoftware.nailgun.NGServer
+ include Server
end
+
+ end # server_setup
+
+ module Util
+ extend self
+ def add_to_sysloader(path)
+ sysloader = java.lang.ClassLoader.getSystemClassLoader
+ add_url_method = java.lang.Class.forName('java.net.URLClassLoader').
+ getDeclaredMethod('addURL',
[java.net.URL.java_class].to_java(java.lang.Class))
+ add_url_method.setAccessible(true)
+ add_url_method.invoke(sysloader,
[java.io.File.new(path).toURI.toURL].to_java(java.net.URL))
+ end
+
def benchmark(action = ['Completed'], verbose = true)
result = nil
times = Benchmark.measure do
@@ -338,11 +163,56 @@
real << ("%ih" % (times.real / 3600)) if times.real >= 3600
real << ("%im" % ((times.real / 60) % 60)) if times.real >= 60
real << ("%.3fs" % (times.real % 60))
- puts "#{[action].flatten.join(' ')} in #{real.join}"
+ trace "#{[action].flatten.join(' ')} in #{real.join}"
end
result
end
+ def find_buildfile(pwd, candidates, nosearch=false)
+ candidates = [candidates].flatten
+ buildfile = candidates.find { |c| File.file?(File.expand_path(c, pwd))
}
+ return File.expand_path(buildfile, pwd) if buildfile
+ return nil if nosearch
+ updir = File.dirname(pwd)
+ return nil if File.expand_path(updir) == File.expand_path(pwd)
+ find_buildfile(updir, candidates)
+ end
+
+ def exception_handling(raise_again = true)
+ begin
+ yield
+ rescue => e
+ error "#{e.backtrace.shift}: #{e.message}"
+ e.backtrace.each { |i| error "\tfrom #{i}" }
+ raise e if raise_again
+ end
+ end
+
+ # invoke a java constructor
+ def ctor(on_class, *args)
+ parameters = []
+ classes = []
+ args.each do |obj|
+ case obj
+ when nil
+ classes.push(nil)
+ parameters.push(nil)
+ when Hash
+ vclass = obj.keys.first
+ value = obj[vclass]
+ classes.push(vclass.java_class)
+ parameters.push(value)
+ else
+ parameters.push obj
+ classes.push obj.java_class
+ end
+ end
+ on_class = [on_class.java_class].to_java(java.lang.Class)[0]
+ ctor =
on_class.getDeclaredConstructor(classes.to_java(java.lang.Class))
+ ctor.setAccessible(true)
+ ctor.newInstance(parameters.to_java(java.lang.Object))
+ end
+
def on_runtime(runtime, *args, &block)
raise_error = lambda do |cls, msg, trace|
raise RuntimeError.new(cls + ": "+ msg.to_s).tap { |e|
e.set_backtrace(trace.map(&:to_s)) }
@@ -360,534 +230,444 @@
raise_error.call(*result[1..-1]) if result.kind_of?(Array) &&
result.first == :error
result
end
+
+ def set_stdio(runtime, dev)
+ set_global = lambda do |global, constant, stream|
+ runtime.global_variables.set(global, stream)
+ runtime.object.send(:remove_const, constant)
+ runtime.object.send(:const_set, constant, stream)
+ end
+ stdin = runtime.global_variables.get('$stdin')
+ stdout = runtime.global_variables.get('$stdout')
+ stderr = runtime.global_variables.get('$stderr')
+ #stdin.close; stdout.close; stderr.close;
+ output = Util.ctor(org.jruby.RubyIO, runtime, java.io.OutputStream =>
dev.out)
+ error = Util.ctor(org.jruby.RubyIO, runtime, java.io.OutputStream =>
dev.err)
+ input = Util.ctor(org.jruby.RubyIO, runtime, java.io.InputStream =>
dev.in)
+ #stdin.reopen(input, 'r') # not working on jruby, :(
+ #stdout.reopen(output, 'w')
+ #stderr.reopen(error, 'w')
+ set_global.call('$stdin', 'STDIN', input)
+ set_global.call('$stdout', 'STDOUT', output)
+ set_global.call('$stderr', 'STDERR', error)
+ end
+
end # module Util
- boot do
+ class FieldAccessor
+ def initialize(obj, clazz = nil)
+ @obj = obj
+ clazz ||= obj.class
+ @cls = [clazz.java_class].to_java(java.lang.Class)[0]
+ end
+
+ def [](name)
+ field = @cls.getDeclaredField(name.to_s)
+ field.setAccessible(true)
+ field.get(@obj)
+ end
- class ::ConcreteJavaProxy
- def self.jclass(name = nil)
- name ||= self.java_class.name
- Nailgun::Util.class_for_name(name)
- end
-
- def self.jnew(*args)
- objs = []
- classes = args.map do |a|
- case a
- when nil
- obj << nil
- nil
- when Hash
- objs << a.keys.first
- cls = a.values.first
- cls = Nailgun::Util.proxy_class(cls) if String == cls
- cls
- else
- objs << a
- a.java_class
- end
- end
- classes = classes.to_java(java.lang.Class)
- ctor = jclass.getDeclaredConstructor(classes)
- ctor.setAccessible(true)
- ctor.newInstance(objs.to_java(java.lang.Object))
+ def []=(name, value)
+ field = @cls.getDeclaredField(name.to_s)
+ field.setAccessible(true)
+ field.set(@obj, value)
+ end
+
+ def method_missing(name, value =nil)
+ if name.to_s =~ /=$/
+ self[name.to_s.chomp('=')] = value
+ else
+ self[name]
end
end
+ end
- module Util
- def class_for_name(name)
- java.lang.Class.forName(name)
- end
+ class Client
+
+ module NailMethods
- def add_to_sysloader(path)
- sysloader = java.lang.ClassLoader.system_class_loader
- add_url_method = class_for_name('java.net.URLClassLoader').
- getDeclaredMethod('addURL',
[java.net.URL].to_java(java.lang.Class))
- add_url_method.accessible = true
- add_url_method.invoke(sysloader, [java.io.File.new(path.to_s).
- toURL].to_java(java.net.URL))
+ def self.extend_object(obj)
+ super
+ (class << obj; self; end).module_eval do
+ alias_method :pwd, :getWorkingDirectory
+ alias_method :server, :getNGServer
+ end
end
- add_to_sysloader Nailgun.artifact
-
- def proxy_class(name)
- JavaUtilities.get_proxy_class(name)
+
+ def argv
+ [command] + args
end
- import org.jruby.RubyIO
- def set_stdio(runtime, dev)
- set_global = lambda do |global, constant, stream|
- runtime.global_variables.set(global, stream)
- runtime.object.send(:remove_const, constant)
- runtime.object.send(:const_set, constant, stream)
- end
- stdin = runtime.global_variables.get('$stdin')
- stdout = runtime.global_variables.get('$stdout')
- stderr = runtime.global_variables.get('$stderr')
- input = RubyIO.jnew(runtime, dev.in => java.io.InputStream)
- output = RubyIO.jnew(runtime, dev.out => java.io.OutputStream)
- error = RubyIO.jnew(runtime, dev.err => java.io.OutputStream)
- # stdin.reopen(input, 'r') # not working on jruby, :(
- set_global.call('$stdin', 'STDIN', input)
- stdout.reopen(output, 'w')
- stderr.reopen(error, 'w')
+ def attach_runtime(runtime)
+ runtime.evalScriptlet %q{
+ require 'ostruct'
+ module Buildr
+ module Nailgun
+ extend self
+ attr_reader :ng
+ @ng = OpenStruct.new
+ end
+ end
+ }
+ runtime.object.const_get(:Buildr)::Nailgun.ng.nail = self
+ runtime.load_service.require __FILE__
+ runtime
end
+ private :attach_runtime
- def redirect_stdio(runtime, nail)
- result = nil
- begin
- set_stdio(runtime, nail)
- result = yield
- ensure
- set_stdio(runtime, java.lang.System)
- end
- result
+ def jruby
+ @jruby ||= attach_runtime(server.runtime_factory.new_jruby)
end
- end
- class Buildfile
- attr_reader :path, :requires, :loaded_time
- attr_accessor :runtime
-
- def initialize(path, *requires)
- @path = File.expand_path(path)
- @requires = requires.dup
+ def buildr
+ @buildr ||= server.runtime_factory.new_buildr
end
- def loaded!
- @loaded_time = Time.now
+ def options
+ @options ||= OpenStruct.new
end
- def last_modification
- Util.timestamp(path)
+ end # NailMethods
+
+ class << self
+ include Buildr::CommandLineInterface
+
+ def options
+ Nailgun.ng.nail.options
end
-
- def should_be_loaded?
- (loaded_time || Rake::EARLY) < last_modification
+
+ def rakefiles
+ Nailgun.ng.nail.options.rakefiles
+ end
+
+ def requires
+ Nailgun.ng.nail.options.requires
end
- def to_s
- buff = path.dup
- buff << sprintf("\n %-25s %s", "Last Modified:", last_modification)
- unless requires.empty?
- buff << sprintf("\n %-25s %s", "Requires:", requires.join(" "))
- end
- if should_be_loaded?
- buff << sprintf("\n %-25s %s", "Needs reload, last was:",
loaded_time)
+ def help
+ super
+ puts
+ puts 'To get a summary of Nailgun features use'
+ puts ' nailgun:help'
+ end
+
+ def version
+ puts super
+ end
+
+ def do_option(opt, value)
+ case opt
+ when '--help'
+ options.exit = :help
+ when '--version'
+ options.exit = :version
+ when '--nosearch'
+ options.nosearch = true
else
- buff << sprintf("\n %-25s %s", "Loaded at:", loaded_time)
+ super
end
- buff << sprintf("\n %-25s %s", "Runtime:", runtime)
- buff
- end
- end
-
- class BuildrNail
- include org.apache.buildr.BuildrNail
- Main = Util.proxy_class 'org.apache.buildr.BuildrNail$Main'
+ end
- attr_reader :buildfile
+ def sBuildr
+ Nailgun.ng.nail.server.runtime.object.const_get(:Buildr)
+ end
- def initialize
- buildfile = Buildfile.new(Rake.application.buildfile,
- *Rake.application.requires)
- buildfile.loaded!
- buildfile.runtime = JRuby.runtime
- @buildfiles = { buildfile.path => buildfile }
+ def attach_runtime
+ nail = Nailgun.ng.nail
+ ARGV.replace nail.argv
+ Dir.chdir nail.pwd
+ nail.env.each { |k, v| ENV[k.to_s] = v.to_s }
+
+ Buildr.const_set(:VERSION, sBuildr::VERSION) unless
Buildr.const_defined?(:VERSION)
+ nail.options.rakefiles = sBuildr::Application::DEFAULT_BUILDFILES.dup
+ nail.options.requires = []
+ end
+
+ def client(runtime, nail, &block)
+ runtime.object.const_get(:Buildr)::Nailgun.ng.nail = nail
+ runtime.object.const_get(:Buildr)::Nailgun::Client.attach_runtime
+ if block_given?
+ Util.on_runtime(runtime) do
+
runtime.object.const_get(:Buildr)::Nailgun::Client.instance_eval(&block)
+ end
+ end
end
+ end
- def main(nail)
- Thread.exclusive { Thread.current.priority = 100; run(nail) }
+ module AppMixin
+
+ def load_tasks
+ trace "Not loading tasks again"
end
+
+ def load_buildfile
+ trace "Not loading buildfile again"
+ end
+
+ end
+
+ def main(nail)
+ nail.extend NailMethods
+ info "Got connection from #{nail.pwd}"
- private
- def run(nail)
- nail.assert_loopback_client
- nail.out.println "Using #{nail.getNGServer}"
- ctx = context_from_nail(nail)
+ Client.client(nail.jruby, nail) do
- case ctx.action
- when :start
- nail.out.println "Cannot start nailgun when running as client"
- return nail.exit(0)
- when :stop
- puts "Stopping #{nail.getNGServer}"
- nail.out.println "Stopping #{nail.getNGServer}"
- return nail.getNGServer.shutdown(true)
- when :list
- if @buildfiles.empty?
- nail.out.println "No defined runtimes"
- else
- nail.out.println "Defined runtimes:"
- @buildfiles.each_value { |f| nail.out.println "- #{f}" }
- end
- return nail.exit(0)
- when :clear
- @buildfiles.clear
- nail.out.println "Cleared all runtimes"
- return nail.exit(0)
- when :tasks
- nail.out.println ""
- nail.out.println Rake.application.nailgun_tasks
- return nail.exit(0)
- when :help
- nail.out.println ""
- nail.out.println Rake.application.nailgun_help
- return nail.exit(0)
+ parse_options
+ if options.exit
+ send(options.exit)
+ nail.exit(0)
end
-
- opts = OpenStruct.new
-
- runtime = ctx.runtime
- #Util.set_stdio(runtime, nail)
-
runtime.object.const_get(:Buildr)::Nailgun::ContextRunner.parse_options(ctx,
opts)
- return nail.exit(0) if opts.exit
- candidates = Buildr::Application::DEFAULT_BUILDFILES
- candidates = [opts.buildfile] if opts.buildfile
-
- path = Util.find_buildfile(ctx.pwd, candidates, opts.nosearch) ||
- File.expand_path(candidates.first, ctx.pwd)
+ if options.project && File.directory?(options.project)
+ Dir.chdir(options.project)
+ end
- if ctx.action == :delete
- nail.out.println "Deleting runtime for #{path}"
- @buildfiles.delete(path)
- return nail.exit(0)
+ bf = Util.find_buildfile(Dir.pwd, options.rakefiles,
options.nosearch)
+ unless bf
+ nail.out.println "No buildfile found at #{Dir.pwd}"
+ nail.exit(0)
end
-
- puts "Getting buildr runtime for #{path}"
- buildfile = @buildfiles[path] || Buildfile.new(path, *opts.requires)
- save = buildfile.should_be_loaded? || ctx.action == :load
+ rt = nail.server.cached_runtimes[bf]
+ old_stamp = nail.server.cached_stamps[bf] || Rake::EARLY
+ new_stamp = rt ?
rt.object.const_get(:Buildr).application.buildfile.timestamp : Rake::EARLY
- runtime = buildfile.runtime
-
- if save || ctx.action == :once
- ctx.argv.unshift 'nailgun:load'
- ctx.fresh = true
- runtime = ctx.buildr
- if save
- buildfile.runtime = runtime
- buildfile.loaded!
- @buildfiles[buildfile.path] = buildfile
+ if rt.nil? || new_stamp > old_stamp
+ rt = nail.buildr
+ nail.server.cached_runtimes[bf] = rt
+ Client.client(rt, nail) do
+ bldr = rt.object.const_get(:Buildr)
+ bldr.application.run
+ nail.server.cache(rt, bldr.application.buildfile)
+ end
+ else
+ Client.client(rt, nail) do
+ buildr = rt.object.const_get(:Buildr)
+ app = buildr.application.extend AppMixin
+ app.lookup('buildr:initialize').instance_eval do
+ @already_invoked = false
+ @actions = []
+ end
+ app.instance_variable_get(:@tasks).values.each do |task|
+ task.instance_variable_set(:@already_invoked, false)
+ end
+ app.instance_variable_set(:@original_dir, nail.pwd)
+ app.parse_options
+ app.collect_tasks
+ app.run
end
end
-
- Util.redirect_stdio(runtime, nail) do
- runtime.object.send :puts
- runtime.object.const_get(:Buildr)::Nailgun::ContextRunner.run(ctx)
- end
- end
-
- def context_from_nail(nail)
- ctx = OpenStruct.new
- ctx.pwd = nail.getWorkingDirectory
- ctx.env = nail.env
- ctx.argv = [nail.command] + nail.args.map(&:to_s)
- ctx.server = nail.getNGServer
- def ctx.runtime; @runtime ||= server.buildr_factory.runtime; end
- def ctx.buildr; @buildr ||= server.buildr_factory.obtain; end
- actions = {
- :load => %w{ nailgun:load },
- :delete => %w{ nailgun:delete },
- :clear => %w{ nailgun:clear },
- :list => %w{ nailgun:list },
- :start => %w{ nailgun:boot nailgun:start },
- :stop => %w{ nailgun:stop },
- :once => %w{ nailgun:once },
- :tasks => %w{ nailgun:tasks },
- :help => %w{ nailgun:help help:nailgun },
- }
- action = actions.find { |k,v| k if v.any? { |t| ctx.argv.delete(t) }
}
- ctx.action = action.first if action
- ctx
+
end
-
- end # class BuildrNail
+ end
+
+ end # class Client
+
+ module Server
+
+ attr_reader :runtime_factory
+ attr_reader :cached_runtimes
+ attr_reader :cached_stamps
+
+ def initialize(host = 'localhost', port = 2113, buildr_factory = nil)
+ super(java.net.InetAddress.get_by_name(host), port)
+ @cached_runtimes = {}
+ @cached_stamps = {}
+ cache(runtime, Buildr.application.buildfile)
+ @runtime_factory = buildr_factory
+ @host, @port = host, port
+ end
+
+ def cache(runtime, buildfile)
+ cached_runtimes[buildfile.to_s] = runtime
+ cached_stamps[buildfile.to_s] = buildfile.timestamp
+ end
+
+ def runtime
+ JRuby.runtime
+ end
- class BuildrFactory
+ def start
+ self.allow_nails_by_class_name = false
- attr_accessor :buildrs_size, :runtimes_size
+ Client::Main.nail = Client.new
+ self.default_nail_class = Client::Main
+ runtime_factory.start
- def initialize(buildrs_size = 1, runtimes_size = nil)
- runtimes_size ||= buildrs_size
- @buildrs_size = buildrs_size < 1 ? 1 : buildrs_size
- @runtimes_size = runtimes_size < 1 ? 1 : runtimes_size
+ @thread = java.lang.Thread.new(self)
+ @thread.setName(to_s)
+ @thread.start
+
+ sleep 1 while getPort == 0
+ info "#{self} Started."
+ end
+
+ def stop
+ runtime_factory.stop
+ @thread.kill
+ end
- @buildrs = [].extend(MonitorMixin)
- @buildrs_ready = @buildrs.new_cond
- @buildrs_needed = @buildrs.new_cond
-
- @buildrs_creators = [].extend(MonitorMixin)
+ def to_s
+ self.class.name+'('+[Buildr.application.version, @host, @port].join(',
')+')'
+ end
+ end # module Server
+
+ class RuntimeFactory
+
+ attr_accessor :buildrs_size, :jrubys_size
+
+ def initialize(buildrs_size = 1, jrubys_size = nil)
+ jrubys_size ||= buildrs_size
+ @buildrs_size = buildrs_size < 1 ? 1 : buildrs_size
+ @jrubys_size = jrubys_size < 1 ? 1 : jrubys_size
- @runtimes = [].extend(MonitorMixin)
- @runtimes_ready = @runtimes.new_cond
- @runtimes_needed = @runtimes.new_cond
-
- @runtimes_creators = [].extend(MonitorMixin)
- end
+ @buildrs = [].extend(MonitorMixin)
+ @buildrs_ready = @buildrs.new_cond
+ @buildrs_needed = @buildrs.new_cond
- def obtain
- get(:buildr)
- end
+ @buildrs_creators = [].extend(MonitorMixin)
- def runtime
- get(:runtime)
- end
+ @jrubys = [].extend(MonitorMixin)
+ @jrubys_ready = @jrubys.new_cond
+ @jrubys_needed = @jrubys.new_cond
+
+ @jrubys_creators = [].extend(MonitorMixin)
+ end
+
+ def new_buildr
+ get(:buildr)
+ end
- def start
- debug "Starting Buildr runtime factory"
- @runtime_creator = Thread.new { loop { create :runtime } }
- @runtime_creator.priority = -2
- @buildr_creator = Thread.new { loop { create :buildr } }
- @buildr_creator.priority = 1
- end
+ def new_jruby(&block)
+ # get(:jruby)
+ create_jruby(0, &block)
+ end
- def stop
- @buildr_creator.kill if @buildr_creator
- @runtime_creator.kill if @runtime_creator
- end
+ def start
+ trace "Starting Buildr runtime factory"
+ # @jruby_creator = Thread.new { loop { create :jruby } }
+ # @jruby_creator.priority = -2
+ @buildr_creator = Thread.new { loop { create :buildr } }
+ @buildr_creator.priority = 1
+ end
- private
- def debug(*msg)
- puts *msg if Rake.application.options.trace
- end
+ def stop
+ @buildr_creator.kill if @buildr_creator
+ # @jruby_creator.kill if @jruby_creator
+ end
- def get(thing)
- collection = instance_variable_get("@#{thing}s")
- needs = instance_variable_get("@#{thing}s_needed")
- ready = instance_variable_get("@#{thing}s_ready")
- result = nil
- collection.synchronize do
- if collection.empty?
- debug "no #{thing} available, ask to create more"
- needs.broadcast
- debug "should be creating #{thing}"
- ready.wait_while { collection.empty? }
- end
- debug "Getting my #{thing}"
- result = collection.shift
- debug "would need more #{thing}s"
+ private
+ def get(thing)
+ collection = instance_variable_get("@#{thing}s")
+ needs = instance_variable_get("@#{thing}s_needed")
+ ready = instance_variable_get("@#{thing}s_ready")
+ result = nil
+ collection.synchronize do
+ if collection.empty?
+ trace "no #{thing} available, ask to create more"
needs.broadcast
- debug "got my #{thing}: #{result.inspect}"
- Thread.pass
+ trace "should be creating #{thing}"
+ ready.wait_while { collection.empty? }
end
- debug "returning #{result.inspect}"
- result
+ trace "Getting my #{thing}"
+ result = collection.shift
+ trace "would need more #{thing}s"
+ needs.broadcast
+ trace "got my #{thing}: #{result.inspect}"
+ Thread.pass
end
+ trace "returning #{result.inspect}"
+ result
+ end
- def create(thing, *args, &prc)
+ def create(thing, *args, &block)
+ Util.exception_handling do
creator = needed(thing)
collection = instance_variable_get("@#{thing}s")
ready = instance_variable_get("@#{thing}s_ready")
needs = instance_variable_get("@#{thing}s_needed")
unless creator
collection.synchronize do
- debug "awake those wanting a #{thing}"
+ trace "awake those wanting a #{thing}"
ready.broadcast
Thread.pass
- debug "wait until more #{thing}s are needed"
+ trace "wait until more #{thing}s are needed"
# needs.wait(1); return
needs.wait_until { creator = needed(thing) }
end
end
- debug "About to create #{thing} # #{creator}"
+ trace "About to create #{thing} # #{creator}"
method = "create_#{thing}"
creators = instance_variable_get("@#{thing}s_creators")
- debug "registering creator for #{thing} #{creator}"
+ trace "registering creator for #{thing} #{creator}"
creators.synchronize { creators << creator }
- result = send(method, creator, *args, &prc)
- debug "created #{thing}[#{creator}] => #{result.inspect}"
+ result = send(method, creator, *args, &block)
+ trace "created #{thing}[#{creator}] => #{result.inspect}"
creators.synchronize do
- debug "unregistering creator for #{thing} #{creator}"
+ trace "unregistering creator for #{thing} #{creator}"
creators.delete(creator)
collection.synchronize do
- debug "adding object on queue for #{thing} #{creator}"
+ trace "adding object on queue for #{thing} #{creator}"
collection << result
end
end
- rescue => e
- puts "#{e.backtrace.shift}: #{e.message}"
- e.backtrace.each { |i| puts "\tfrom #{i}" }
end
-
- def needed(thing)
- collection = instance_variable_get("@#{thing}s")
- creators = instance_variable_get("@#{thing}s_creators")
- size = instance_variable_get("@#{thing}s_size")
- collection.synchronize do
- count = collection.size
- if count < size
- count += creators.synchronize { creators.size }
- end
- count if count < size
- end
+ end
+
+ def needed(thing)
+ collection = instance_variable_get("@#{thing}s")
+ creators = instance_variable_get("@#{thing}s_creators")
+ size = instance_variable_get("@#{thing}s_size")
+ collection.synchronize do
+ count = collection.size
+ if count < size
+ count += creators.synchronize { creators.size }
+ end
+ count if count < size
end
-
- def create_runtime(creator)
- debug "Creating runtime[#{creator}]"
+ end
+
+ def create_jruby(creator, &block)
+ Util.exception_handling do
+ trace "Creating jruby[#{creator}]"
Util.benchmark do |header|
- runtime = org.jruby.Ruby.newInstance
- runtime.global_variables.set('$nailgun_server',
JRuby.reference($nailgun_server))
- BUILDR_PATHS.each { |path| runtime.load_service.load_path.unshift
path }
- runtime.load_service.require 'buildr/nailgun'
- header.replace ["Created runtime[#{creator}]", runtime]
- runtime
+ cfg = org.jruby.RubyInstanceConfig.new
+ cfg.setOutput(java.io.PrintStream.new(java.lang.System.out))
+ cfg.setError(java.io.PrintStream.new(java.lang.System.err))
+ cfg.setInput(java.io.BufferedInputStream.new(java.lang.System.in))
+ yield cfg if block_given?
+ jruby = org.jruby.Ruby.newInstance(cfg)
+ jruby.load_service.load_path.concat BUILDR_PATHS
+ header.replace ["Created jruby[#{creator}]", jruby]
+ jruby
end
end
+ end
- def create_buildr(creator)
- debug "Obtaining runtime to load buildr[#{creator}] on it"
- runtime = get(:runtime)
- debug "Loading buildr[#{creator}] on #{runtime} ..."
- Util.benchmark ["Loaded buildr[#{creator}] on #{runtime}"] do
- load_service = runtime.load_service
+ def create_buildr(creator)
+ Util.exception_handling do
+ trace "Obtaining jruby to load buildr[#{creator}] on it"
+ jruby = new_jruby
+ trace "Loading buildr[#{creator}] on #{jruby} ..."
+ Util.benchmark ["Loaded buildr[#{creator}] on #{jruby}"] do
+ load_service = jruby.load_service
load_service.require 'rubygems'
load_service.require 'buildr'
end
- runtime
+ jruby
end
-
- end # BuildrFactory
-
- class BuildrServer < com.martiansoftware.nailgun.NGServer
-
- attr_reader :buildr_factory
-
- def initialize(host = 'localhost', port = 2113, buildr_factory = nil)
- super(java.net.InetAddress.get_by_name(host), port)
- @buildr_factory = buildr_factory
- @host, @port = host, port
- end
-
- def runtime
- JRuby.runtime
- end
-
- def start_server
- self.allow_nails_by_class_name = false
-
- BuildrNail::Main.nail = BuildrNail.new
- self.default_nail_class = BuildrNail::Main
- buildr_factory.start
-
- @thread = java.lang.Thread.new(self)
- @thread.setName(to_s)
- @thread.start
-
- sleep 1 while getPort == 0
- puts "#{self} Started."
- end
-
- def stop_server
- buildr_factory.stop
- @thread.kill
- end
-
- def to_s
- "BuildrServer(" <<
- [Rake.application.version, @host, @port].join(", ") <<
- ")"
- end
- end # class BuildrServer
-
- end # Nailgun boot
-
- namespace do
- tmp = lambda { |*files| File.join(Dir.tmpdir, "nailgun", *files) }
- dist_zip = Buildr.download(tmp[NAME + ".zip"] => URL)
- dist_dir = Buildr.unzip(tmp[NAME] => dist_zip)
-
- if File.exist?(File.join(home, NAME + ".jar"))
- ng_jar = file(File.join(home, NAME + ".jar"))
- else
- ng_jar = file(tmp[NAME, NAME, NAME+".jar"] => dist_dir)
end
- self.artifact = Buildr.artifact(ARTIFACT_SPEC).from(ng_jar)
-
- compiled_bin = tmp[NAME, NAME, "ng"+Config::CONFIG['EXEEXT']]
- compiled_bin = file(compiled_bin => dist_dir.target) do |task|
- unless task.to_s.pathmap('%x') == '.exe'
- Dir.chdir(task.to_s.pathmap('%d')) do
- puts "Compiling #{task.to_s}"
- system('make', task.to_s.pathmap('%f')) or
- fail "Nailgun binary compilation failed."
- end
- end
- end
+ end # RuntimeFactory
- installed_bin = file(File.join(home,
- compiled_bin.to_s.pathmap('%f')) => compiled_bin) do |task|
- mkpath task.to_s.pathmap('%d'), :verbose => false
- cp compiled_bin.to_s, task.to_s, :verbose => false
- end
-
- task :boot => artifact do |task|
- if $nailgun_server
- raise "Already nunning on Nailgun server: #{$nailgun_server}"
- end
- tasks = Rake.application.instance_eval { @top_level_tasks.dup }
- tasks.delete_if do |t|
- t =~ /^(buildr:initialize|(ng|nailgun):.+)$/
- end
- unless tasks.empty?
- raise "Don't specify more targets when starting Nailgun server"
- end
- boot
- end
+ if Buildr.respond_to?(:application) && ng.nail.nil?
+ Buildr.application.in_namespace(:nailgun, &file_tasks)
+ Buildr.application.in_namespace(:nailgun, &server_tasks)
+ elsif ng.nail
- task :start => [installed_bin, :boot] do
- factory = BuildrFactory.new(buildr_queue_size, jruby_queue_size)
- $nailgun_server = BuildrServer.new(server, port, factory)
- puts "Starting #{$nailgun_server}"
- $nailgun_server.start_server
-
- is_win = Util.win_os?
- bin_path = File.expand_path(installed_bin.to_s.pathmap("%d"))
- bin_name = installed_bin.to_s.pathmap("%f")
-
- puts <<-NOTICE
-
- Buildr server has been started, you may need to update your PATH
- variable in order to execute the #{bin_name} binary.
-
- #{ is_win ?
- "> set NAILGUN_HOME=#{bin_path}" :
- "$ export NAILGUN_HOME=#{bin_path}"
- }
- #{ is_win ?
- "> set PATH=%NAILGUN_HOME%;%PATH%" :
- "$ export PATH=${NAILGUN_HOME}:${PATH}"
- }
-
- Runtime for #{Rake.application.buildfile} has been cached, this
- means you can open a terminal inside
-
- #{Rake.application.buildfile.pathmap("%d")}
-
- Invoke tasks by executing the #{bin_name} program, it takes the
- same parameters you normally use for ``buildr''.
-
- To display Nailgun related help, execute the command:
- ``#{bin_name} nailgun:help''
-
- To get an overview of Nailgun tasks, execute the command:
- ``#{bin_name} nailgun:tasks''
-
- NOTICE
- end
-
- task :help do
- puts Rake.application.nailgun_help
- end
+ end
- task :tasks do
- puts Rake.application.nailgun_tasks
- end
-
- end # namespace :nailgun
-
end # module Nailgun
-
+
end
Added:
incubator/buildr/trunk/addon/buildr/org/apache/buildr/BuildrNail$Main.class
URL:
http://svn.apache.org/viewvc/incubator/buildr/trunk/addon/buildr/org/apache/buildr/BuildrNail%24Main.class?rev=691494&view=auto
==============================================================================
Files
incubator/buildr/trunk/addon/buildr/org/apache/buildr/BuildrNail$Main.class
(added) and
incubator/buildr/trunk/addon/buildr/org/apache/buildr/BuildrNail$Main.class Tue
Sep 2 20:33:06 2008 differ
Added: incubator/buildr/trunk/addon/buildr/org/apache/buildr/BuildrNail.class
URL:
http://svn.apache.org/viewvc/incubator/buildr/trunk/addon/buildr/org/apache/buildr/BuildrNail.class?rev=691494&view=auto
==============================================================================
Files incubator/buildr/trunk/addon/buildr/org/apache/buildr/BuildrNail.class
(added) and
incubator/buildr/trunk/addon/buildr/org/apache/buildr/BuildrNail.class Tue Sep
2 20:33:06 2008 differ
Added: incubator/buildr/trunk/addon/buildr/org/apache/buildr/BuildrNail.java
URL:
http://svn.apache.org/viewvc/incubator/buildr/trunk/addon/buildr/org/apache/buildr/BuildrNail.java?rev=691494&view=auto
==============================================================================
--- incubator/buildr/trunk/addon/buildr/org/apache/buildr/BuildrNail.java
(added)
+++ incubator/buildr/trunk/addon/buildr/org/apache/buildr/BuildrNail.java Tue
Sep 2 20:33:06 2008
@@ -0,0 +1,41 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package org.apache.buildr;
+
+import com.martiansoftware.nailgun.NGContext;
+
+public interface BuildrNail {
+
+ public void main(NGContext ctx);
+
+ public static class Main {
+ private static BuildrNail nail;
+ public static void setNail(BuildrNail _nail) { nail = _nail; }
+ public static void nailMain(NGContext ctx) {
+ nail.main(ctx);
+ }
+ }
+
+}
+
+/*
+ * Local Variables:
+ * indent-tabs-mode: nil
+ * c-basic-offset: 2
+ * End:
+ */