Author: vborja
Date: Wed Mar 5 11:29:38 2008
New Revision: 633992
URL: http://svn.apache.org/viewvc?rev=633992&view=rev
Log:
First stable nailgun integration
Added:
incubator/buildr/trunk/lib/core/application_cli.rb
incubator/buildr/trunk/lib/java/org/apache/buildr/BuildrNail.java
Modified:
incubator/buildr/trunk/Rakefile
incubator/buildr/trunk/buildfile
incubator/buildr/trunk/lib/core/application.rb
incubator/buildr/trunk/lib/java/jruby.rb
incubator/buildr/trunk/lib/java/nailgun.rb
Modified: incubator/buildr/trunk/Rakefile
URL:
http://svn.apache.org/viewvc/incubator/buildr/trunk/Rakefile?rev=633992&r1=633991&r2=633992&view=diff
==============================================================================
--- incubator/buildr/trunk/Rakefile (original)
+++ incubator/buildr/trunk/Rakefile Wed Mar 5 11:29:38 2008
@@ -58,7 +58,7 @@
gems = Gem::SourceIndex.from_installed_gems
dependencies = specify(RUBY_PLATFORM).dependencies
dependencies << Gem::Dependency.new('docter', '~>1.1')
- dependencies << Gem::Dependency.new('ultraviolet', '~>0.10')
+ dependencies << Gem::Dependency.new('ultraviolet', '~>0.10') unless
RUBY_PLATFORM =~ /java/
dependencies << Gem::Dependency.new('rcov', '~>0.8') unless RUBY_PLATFORM =~
/java/
dependencies.each do |dep|
if gems.search(dep.name, dep.version_requirements).empty?
Modified: incubator/buildr/trunk/buildfile
URL:
http://svn.apache.org/viewvc/incubator/buildr/trunk/buildfile?rev=633992&r1=633991&r2=633992&view=diff
==============================================================================
--- incubator/buildr/trunk/buildfile (original)
+++ incubator/buildr/trunk/buildfile Wed Mar 5 11:29:38 2008
@@ -4,7 +4,8 @@
options = :javac, { :source=>'1.4', :target=>'1.4', :debug=>false }
define 'java' do
- compile.from(FileList['lib/java/**/*.java']).into('lib/java').using(*options)
+ require 'java/nailgun'
+
compile.from(FileList['lib/java/**/*.java']).into('lib/java').using(*options).with
Buildr::Nailgun.artifact
end
define 'buildr' do
compile.from(FileList['lib/buildr/**/*.java']).into('lib/buildr').using(*options).with(Buildr::Jetty::REQUIRES)
Modified: incubator/buildr/trunk/lib/core/application.rb
URL:
http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/core/application.rb?rev=633992&r1=633991&r2=633992&view=diff
==============================================================================
--- incubator/buildr/trunk/lib/core/application.rb (original)
+++ incubator/buildr/trunk/lib/core/application.rb Wed Mar 5 11:29:38 2008
@@ -55,33 +55,20 @@
class Application < Rake::Application #:nodoc:
DEFAULT_BUILDFILES = ['buildfile', 'Buildfile'] + DEFAULT_RAKEFILES
+
+ require 'core/application_cli'
+ include CommandLineInterface
- OPTIONS = [ # :nodoc:
- ['--help', '-h', GetoptLong::NO_ARGUMENT,
- 'Display this help message.'],
- ['--nosearch', '-n', GetoptLong::NO_ARGUMENT,
- 'Do not search parent directories for the buildfile.'],
- ['--quiet', '-q', GetoptLong::NO_ARGUMENT,
- 'Do not log messages to standard output.'],
- ['--buildfile', '-f', GetoptLong::REQUIRED_ARGUMENT,
- 'Use FILE as the buildfile.'],
- ['--require', '-r', GetoptLong::REQUIRED_ARGUMENT,
- 'Require MODULE before executing buildfile.'],
- ['--trace', '-t', GetoptLong::NO_ARGUMENT,
- 'Turn on invoke/execute tracing, enable full backtrace.'],
- ['--version', '-v', GetoptLong::NO_ARGUMENT,
- 'Display the program version.'],
- ['--environment', '-e', GetoptLong::REQUIRED_ARGUMENT,
- 'Environment name (e.g. development, test, production).']
- ]
+ attr_reader :rakefiles, :requires
+ private :rakefiles, :requires
def initialize()
super
@rakefiles = DEFAULT_BUILDFILES
@name = 'Buildr'
@requires = []
- opts = GetoptLong.new(*command_line_options)
- opts.each { |opt, value| do_option(opt, value) }
+ @top_level_tasks = []
+ parse_options
collect_tasks
top_level_tasks.unshift 'buildr:initialize'
end
@@ -103,26 +90,6 @@
end
end
- def do_option(opt, value)
- case opt
- when '--help'
- help
- exit
- when '--buildfile'
- @rakefiles.clear
- @rakefiles << value
- when '--version'
- puts "Buildr #{Buildr::VERSION} #{RUBY_PLATFORM[/java/] && '(JRuby
'+JRUBY_VERSION+')'}"
- exit
- when '--environment'
- ENV['BUILDR_ENV'] = value
- when '--require'
- @requires << value
- when '--nosearch', '--quiet', '--trace'
- super
- end
- end
-
def find_buildfile()
here = Dir.pwd
while ! have_rakefile
@@ -147,46 +114,6 @@
load_imports
end
- def collect_tasks
- @top_level_tasks = []
- ARGV.each do |arg|
- if arg =~ /^(\w+)=(.*)$/
- ENV[$1.upcase] = $2
- else
- @top_level_tasks << arg
- end
- end
- @top_level_tasks.push("default") if @top_level_tasks.size == 0
- end
-
- def usage()
- puts "Buildr #{Buildr::VERSION} #{RUBY_PLATFORM[/java/] && '(JRuby
'+JRUBY_VERSION+')'}"
- puts
- puts 'Usage:'
- puts ' buildr [options] [tasks] [name=value]'
- end
-
- def help()
- usage
- puts
- puts 'Options:'
- OPTIONS.sort.each do |long, short, mode, desc|
- if mode == GetoptLong::REQUIRED_ARGUMENT
- if desc =~ /\b([A-Z]{2,})\b/
- long = long + "=#{$1}"
- end
- end
- printf " %-20s (%s)\n", long, short
- printf " %s\n", desc
- end
- puts
- puts 'For help with your buildfile:'
- puts ' buildr help'
- end
-
- def command_line_options
- OPTIONS.collect { |lst| lst[0..-2] }
- end
end
Rake.application = Buildr::Application.new
Added: incubator/buildr/trunk/lib/core/application_cli.rb
URL:
http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/core/application_cli.rb?rev=633992&view=auto
==============================================================================
--- incubator/buildr/trunk/lib/core/application_cli.rb (added)
+++ incubator/buildr/trunk/lib/core/application_cli.rb Wed Mar 5 11:29:38 2008
@@ -0,0 +1,131 @@
+# 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.
+
+# Portion of this file derived from Rake.
+# Copyright (c) 2003, 2004 Jim Weirich
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+module Buildr
+ module CommandLineInterface
+
+ require 'getoptlong'
+ OPTIONS = [ # :nodoc:
+ ['--help', '-h', GetoptLong::NO_ARGUMENT,
+ 'Display this help message.'],
+ ['--nosearch', '-n', GetoptLong::NO_ARGUMENT,
+ 'Do not search parent directories for the buildfile.'],
+ ['--quiet', '-q', GetoptLong::NO_ARGUMENT,
+ 'Do not log messages to standard output.'],
+ ['--buildfile', '-f', GetoptLong::REQUIRED_ARGUMENT,
+ 'Use FILE as the buildfile.'],
+ ['--require', '-r', GetoptLong::REQUIRED_ARGUMENT,
+ 'Require MODULE before executing buildfile.'],
+ ['--trace', '-t', GetoptLong::NO_ARGUMENT,
+ 'Turn on invoke/execute tracing, enable full backtrace.'],
+ ['--version', '-v', GetoptLong::NO_ARGUMENT,
+ 'Display the program version.'],
+ ['--environment', '-e', GetoptLong::REQUIRED_ARGUMENT,
+ 'Environment name (e.g. development, test, production).']
+ ]
+
+ def collect_tasks
+ top_level_tasks.clear
+ ARGV.each do |arg|
+ if arg =~ /^(\w+)=(.*)$/
+ ENV[$1.upcase] = $2
+ else
+ top_level_tasks << arg
+ end
+ end
+ top_level_tasks.push("default") if top_level_tasks.size == 0
+ end
+
+ def parse_options
+ opts = GetoptLong.new(*command_line_options)
+ opts.each { |opt, value| do_option(opt, value) }
+ end
+
+ def do_option(opt, value)
+ case opt
+ when '--help'
+ help
+ exit
+ when '--buildfile'
+ rakefiles.clear
+ rakefiles << value
+ when '--version'
+ puts version
+ exit
+ when '--environment'
+ ENV['BUILDR_ENV'] = value
+ when '--require'
+ requires << value
+ when '--nosearch', '--quiet', '--trace'
+ super
+ end
+ end
+
+ def command_line_options
+ OPTIONS.collect { |lst| lst[0..-2] }
+ end
+
+ def version
+ "Buildr #{Buildr::VERSION} #{RUBY_PLATFORM[/java/] && '(JRuby
'+JRUBY_VERSION+')'}"
+ end
+
+ def usage
+ puts version
+ puts
+ puts 'Usage:'
+ puts ' buildr [options] [tasks] [name=value]'
+ end
+
+ def help
+ usage
+ puts
+ puts 'Options:'
+ OPTIONS.sort.each do |long, short, mode, desc|
+ if mode == GetoptLong::REQUIRED_ARGUMENT
+ if desc =~ /\b([A-Z]{2,})\b/
+ long = long + "=#{$1}"
+ end
+ end
+ printf " %-20s (%s)\n", long, short
+ printf " %s\n", desc
+ end
+ puts
+ puts 'For help with your buildfile:'
+ puts ' buildr help'
+ end
+
+ end
+end
Modified: incubator/buildr/trunk/lib/java/jruby.rb
URL:
http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/java/jruby.rb?rev=633992&r1=633991&r2=633992&view=diff
==============================================================================
--- incubator/buildr/trunk/lib/java/jruby.rb (original)
+++ incubator/buildr/trunk/lib/java/jruby.rb Wed Mar 5 11:29:38 2008
@@ -96,4 +96,26 @@
end
+ task 'ng:start' do |t|
+ require 'java/nailgun'
+ Rake.application.invoke_task('nailgun:start')
+ end
+
end
+
+
+# File.fnmatch bug on JRuby1.1RC2.
+# This issue has been fixed on jruby's trunk, so delete this monkey patch
+# when we upgrade to a new JRuby release.
+# http://jira.codehaus.org/browse/JRUBY-2196
+class File
+ class << self
+ def fnmatch_with_workaround2196(pattern, file, *flags)
+ return true if pattern == '**/*' && flags.include?(FNM_PATHNAME)
+ fnmatch_without_workaround2196(pattern, file, *flags)
+ end
+
+ alias_method_chain :fnmatch, :workaround2196
+ end
+end
+
Modified: incubator/buildr/trunk/lib/java/nailgun.rb
URL:
http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/java/nailgun.rb?rev=633992&r1=633991&r2=633992&view=diff
==============================================================================
--- incubator/buildr/trunk/lib/java/nailgun.rb (original)
+++ incubator/buildr/trunk/lib/java/nailgun.rb Wed Mar 5 11:29:38 2008
@@ -1,26 +1,39 @@
+# 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.
+
+require 'rbconfig'
+
module Buildr
-
- # To start the nailgun server run the ng:start task, this will
- # download, compile and installed nailgun if needed, afterwards
- # it will start the nailgun server.
- #
+
# Issues:
# JRuby 1.1RC2 fails at reopening STDIN, so the workaround is
# to redefine the $stdin global and STDIN constant.
# Kernel#gets, readline, etc, must be avoided and you should use
# $stdin#gets
- module Nailgun
+ module Nailgun # :nodoc:
+ extend self
+
VERSION = '0.7.1'
NAME = "nailgun-#{VERSION}"
URL = "http://downloads.sourceforge.net/nailgun/#{NAME}.zip"
ARTIFACT_SPEC = "com.martiansoftware:nailgun:jar:#{VERSION}"
-
- class << self
- attr_accessor :artifact
- attr_accessor :iface, :port, :runtime_pool_size
- attr_accessor :jruby_home, :home
- end
-
+
+ attr_accessor :artifact
+ attr_accessor :iface, :port, :runtime_pool_size
+ attr_accessor :jruby_home, :home
+
self.jruby_home = if PLATFORM =~ /java/
Config::CONFIG['prefix']
else
@@ -29,112 +42,253 @@
self.home = ENV['NAILGUN_HOME'] || File.join(jruby_home, 'tool', 'nailgun')
self.iface = 'localhost'
self.port = 2113
- self.runtime_pool_size = 0
-
- namespace :nailgun 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"))
+ self.runtime_pool_size = 3
+
+ def namespace(&block)
+ if Object.const_defined?(:Rake)
+ Rake.application.in_namespace(:nailgun, &block)
+ end
+ end
+
+ def boot(&block)
+ if block
+ @boot = block
else
- ng_jar = file(tmp[NAME, NAME, NAME+".jar"] => dist_dir)
+ @boot.call
end
-
- self.artifact = Buildr.artifact(ARTIFACT_SPEC).from(ng_jar)
-
- compiled_bin = tmp[NAME, NAME, 'ng']
- compiled_bin << '.exe' if Config::CONFIG['host_os'] =~ /mswin/i
- 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
+
+ module Application
+ def nailgun_help
+ tasks = {}
+ tasks['ng:stop'] = 'Start the Nailgun server.'
+ tasks['ng:stop'] = 'Stop the Nailgun server.'
+ tasks['ng: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.
+
+ This feature becomes handy when performing development
+ cycle: edit -> compile -> test -> report.
+
+ This task exits inmediatly after printing the file list.
+ DESC
+ tasks['ng:clear'] = <<-DESC
+ Remove all cached buildr runtimes and exit
+ DESC
+ tasks[['ng:add [tasks]', 'ng:put [tasks]']] = <<-DESC
+ Add or reload a cached runtime.
+
+ Use this task to create a cached buildr runtime for a
+ buildfile.
+ DESC
+ tasks[['ng:del', 'ng:delete']] = <<-DESC
+ Delete cached runtime for a buildfile and exit.
+ DESC
+ tasks['ng: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 << <<-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.
+ Buildr provides nailgun integration, allowing you to start
+ a single JVM and let buildr create a pool of JRuby instances.
+ DESC
+ out << "\n\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
-
- 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
+
+ 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 { |t| t.instance_variable_set(:@already_invoked, false) }
end
- task :boot => artifact do |task|
- if $nailgun_server
- raise "Already nunning on Nailgun server: #{$nailgun_server}"
+ if Buildr.const_defined?(:Application)
+ class Buildr::Application
+ include Nailgun::Application
end
- tasks = Rake.application.instance_eval { @top_level_tasks.dup }
- tasks.delete_if do |t|
- t =~ /^(buildr:initialize|(ng|nailgun):.+)$/
+ end
+ end
+
+ module ContextRunner
+ extend self
+
+ def parse_options(ctx, opts)
+
+ Buildr.const_set(:VERSION, ctx.server.runtime.getObject.
+ const_get(:Buildr)::VERSION)
+
+ require 'ostruct'
+ obj = OpenStruct.new(:ctx => ctx, :opts => opts)
+ class << obj
+ require 'core/application_cli'
+ include Buildr::CommandLineInterface
+
+ def help
+ super
+ puts
+ puts 'To get a summary of Nailgun features use'
+ puts ' help:nailgun'
+ end
+
+ def do_option(opt, value)
+ case opt
+ when '--help'
+ help
+ opts.exit = true
+ when '--version'
+ puts version
+ opts.exit = true
+ when '--environment'
+ opts.environment = value
+ when '--buildfile'
+ opts.buildfile = value
+ when '--nosearch'
+ opts.nosearch = true
+ end
+ end
end
- unless tasks.empty?
- raise "Don't specify more targets when starting Nailgun server"
+
+ 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.help do
+ "\nTo get a summary of Nailgun features use" <<
+ "\n help:nailgun"
+ end
+ if ctx.fresh
+ run_fresh(ctx)
+ else
+ run_local(ctx)
end
- BOOT.call
end
- task :start => [installed_bin, :boot] do
- factory = BuildrFactory.new(runtime_pool_size)
- $nailgun_server = BuildrServer.new(iface, port, factory)
- puts "Starting #{$nailgun_server}"
- $nailgun_server.start_server
+ 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
- end # namespace :nailgun
-
- end # module Nailgun
-
- Nailgun::BOOT = lambda do
- require 'jruby'
-
- 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 run_local(ctx)
+ Rake.application.instance_eval do
+ parse_options
+ collect_tasks
+ clear_invoked
+ top_level_tasks.delete('buildr:initialize')
+ Util.benchmark { top_level }
+ end
end
end
-
- class Application
- def buildfile(dir = nil, candidates = nil)
- Nailgun::Util.find_buildfile(dir || Dir.pwd, candidates || @rakefiles)
+
+ module Util
+ extend self
+
+ 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 benchmark(action = ['Completed'], verbose = true)
+ result = nil
+ require 'benchmark'
+ times = Benchmark.measure do
+ result = yield(action)
+ end
+ if verbose
+ real = []
+ 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}"
+ end
+ result
end
- def clear_invoked
- tasks.each { |t| t.instance_variable_set(:@already_invoked, false) }
+ def on_runtime(runtime, *args, &block)
+ code = %q{
+ obj = Object.new
+ def obj.runtime_exec(*args, &block)
+ (class << self; self; end).
+ send(:define_method, :runtime_exec, &block)
+ runtime_exec(*args)
+ end
+ obj
+ }
+ executor = runtime.evalScriptlet(code)
+ executor.runtime_exec(*args, &block)
end
- end
+ end # module Util
- module Nailgun
+ boot do
+ require 'jruby'
- module Util
- extend self
+ 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))
+ end
+ end
+ module Util
def class_for_name(name)
java.lang.Class.forName(name)
end
@@ -148,34 +302,11 @@
toURL].to_java(java.net.URL))
end
add_to_sysloader Nailgun.artifact
-
+
def proxy_class(name)
JavaUtilities.get_proxy_class(name)
end
- def find_buildfile(pwd, candidates)
- buildfile = candidates.find { |c| File.file?(File.join(pwd, c)) }
- return File.expand_path(buildfile, pwd) if buildfile
- updir = File.dirname(pwd)
- return nil if File.expand_path(updir) == File.expand_path(pwd)
- find_buildfile(updir, candidates)
- end
-
- def benchmark(action = 'Completed', verbose = true)
- result = nil
- times = Benchmark.measure do
- result = yield
- end
- if verbose
- real = []
- 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} in #{real.join}"
- end
- result
- end
-
import org.jruby.RubyIO
def redirect_stdio(runtime, nail)
result = nil
@@ -208,9 +339,8 @@
end
result
end
-
end
-
+
class BuildrNail
include org.apache.buildr.BuildrNail
Main = Util.proxy_class 'org.apache.buildr.BuildrNail$Main'
@@ -222,117 +352,237 @@
@runtimes = { @buildfile => JRuby.runtime }
end
+ def main(nail)
+ Thread.exclusive { Thread.current.priority = 100; run(nail) }
+ end
+
+ private
def run(nail)
nail.assert_loopback_client
- nail.out.println "Obtaining Buildr runtime from #{nail.getNGServer}"
- pwd = nail.working_directory
- env = nail.env
- argv = [nail.command] + nail.args.map(&:to_s)
-
- ARGV.replace(argv)
- Util.redirect_stdio(JRuby.runtime, nail) do
- Util.benchmark 'Local Buildr completed' do
- Rake.application.instance_eval do
- clear_invoked
- opts = GetoptLong.new(*command_line_options)
- opts.each { |opt, value| do_option(opt, value) }
- collect_tasks
- @top_level_tasks.delete('buildr:initialize')
- top_level
- end
- end
+ nail.out.println "Connected to #{nail.getNGServer}"
+ ctx = context_from_nail(nail)
+ 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
+ nail.out.println "Defined runtimes:"
+ @runtimes.each_key { |f| nail.out.println f }
+ return nail.exit(0)
+ when :clear
+ @runtimes.clear
+ nail.out.println "Cleared all runtimes"
+ return nail.exit(0)
+ when :help
+ nail.out.println ""
+ nail.out.println Rake.application.nailgun_help
+ return nail.exit(0)
end
- end
+ opts = OpenStruct.new
+
+ Util.on_runtime(ctx.runtime) do
+ ::Buildr::Nailgun::ContextRunner.parse_options(ctx, opts)
+ end
+ return nail.exit(0) if opts.exit
- private
+ candidates = Buildr::Application::DEFAULT_BUILDFILES
+ candidates = [opts.buildfile] if opts.buildfile
+
+ buildfile = Util.find_buildfile(ctx.pwd, candidates, opts.nosearch)
+ if ctx.action == :delete
+ buildfile ||= File.expand_path(candidates.first, ctx.pwd)
+ nail.out.println "Deleting runtime for #{buildfile}"
+ @runtimes.delete(buildfile)
+ return nail.exit(0)
+ end
+ puts "Obtaining Buildr for #{buildfile}"
+ runtime = @runtimes[buildfile]
+ if runtime.nil? || [:put, :once].include?(ctx.action)
+ runtime = ctx.buildr
+ @runtimes[buildfile] = runtime if ctx.action == :put
+ ctx.fresh = true
+ end
+
+ Util.on_runtime(runtime) do
+ Util.redirect_stdio(runtime, nail) do
+ ::Buildr::Nailgun::ContextRunner.run(ctx)
+ end
+ 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 = {
+ :put => %w{ng:add ng:put nailgun:add nailgun:put},
+ :delete => %w{ng:del ng:delete nailgun:del nailgun:delete},
+ :clear => %w{ng:clear nailgun:clear},
+ :list => %w{ng:list nailgun:list},
+ :start => %w{ng:boot ng:start nailgun:boot nailgun:start},
+ :stop => %w{ng:stop nailgun:stop},
+ :once => %w{ng:once nailgun:once},
+ :help => %w{ng:help nailgun:help ng:tasks nailgun:tasks
+ help:ng 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
class BuildrFactory
require 'thread'
require 'monitor'
- attr_reader :work_queue_size
-
- def initialize(size)
- @work_queue = [].extend(MonitorMixin)
- @work_queue_size = size
- @ready_cond = @work_queue.new_cond
- @workers = [].extend(MonitorMixin)
+ attr_accessor :buildrs_size, :runtimes_size
+
+ 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
+
+ @buildrs = [].extend(MonitorMixin)
+ @buildrs_ready = @buildrs.new_cond
+ @buildrs_create = @buildrs.new_cond
+
+ @buildrs_creators = [].extend(MonitorMixin)
+ @runtimes_creators = [].extend(MonitorMixin)
+
+ @runtimes = [].extend(MonitorMixin)
+ @runtimes_ready = @runtimes.new_cond
+ @runtimes_create = @runtimes.new_cond
end
-
+
def obtain
- @work_queue.synchronize do
- @ready_cond.wait_while { @work_queue.empty? }
- @work_queue.shift
+ @buildrs.synchronize do
+ @buildrs_ready.wait_while { @buildrs.empty? }
+ @buildrs_create.signal
+ @buildrs.shift
end
end
- def start
- puts "Starting Buildr runtime queue"
- @thread = Thread.new do
- create_if_needed
- sleep 10
- loop { create_if_needed }
+ def runtime
+ @runtimes.synchronize do
+ @runtimes_ready.wait_while { @runtimes.empty? }
+ @runtimes_create.signal
+ @runtimes.shift
end
end
+ def start
+ puts "Starting Buildr runtime factory"
+ @runtime_creator = Thread.new { loop { create_runtime_when_needed } }
+ @buildr_creator = Thread.new { loop { create_buildr_when_needed } }
+ @runtime_creator.priority = -2
+ @buildr_creator.priority = 1
+ end
+
def stop
- @thread.kill if @thread
+ @buildr_creator.kill if @buildr_creator
+ @runtime_creator.kill if @runtime_creator
end
private
- def configure_runtime(runtime)
- load_service = runtime.getLoadService
- load_service.add_path File.expand_path('..', File.dirname(__FILE__))
- load_service.require 'rubygems'
- load_service.require 'buildr'
+ def may_create_runtime?
+ @runtimes.synchronize do
+ count = @runtimes.size
+ if count < runtimes_size
+ count += @runtimes_creators.synchronize {
@runtimes_creators.size }
+ end
+ count if count < runtimes_size
+ end
end
-
+
+ def create_runtime_when_needed
+ @runtimes.synchronize do
+ @runtimes_create.wait_until { may_create_runtime? }
+ end
+ create_runtime
+ Thread.pass
+ end
+
def create_runtime
- @workers.synchronize { @workers << Thread.current }
- puts "Creating new Buildr runtime"
- cfg = org.jruby.RubyInstanceConfig.new
- cfg.input = java.lang.System.in
- cfg.output = java.lang.System.out
- cfg.error = java.lang.System.err
- cfg.current_directory Dir.pwd
- runtime = nil
- times = Benchmark.measure do
- runtime = org.jruby.Ruby.new_instance(cfg)
- configure_runtime(runtime)
+ creator = may_create_runtime?
+ return unless creator
+ @runtimes_creators.synchronize { @runtimes_creators << creator }
+ puts "Creating runtime[#{creator}]"
+ runtime = Util.benchmark do |header|
+ runtime = org.jruby.Ruby.newInstance
+ load_service = runtime.getLoadService
+ load_service.getLoadPath.
+ unshift File.expand_path('..', File.dirname(__FILE__))
+ load_service.require 'java/nailgun'
+ header.replace ["Created runtime[#{creator}]", runtime]
+ runtime
+ end
+ @runtimes_creators.synchronize do
+ @runtimes_creators.delete(creator)
+ @runtimes.synchronize do
+ @runtimes << runtime
+ @runtimes_ready.signal
+ end
end
- real = []
- 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 "Buildr runtime #{runtime} created in #{real.join}"
+ rescue => e
+ p e
+ end
- @workers.synchronize do
- @workers.delete(Thread.current)
- @work_queue.synchronize { @work_queue << runtime }
+ def may_create_buildr?
+ @buildrs.synchronize do
+ count = @buildrs.size
+ if count < buildrs_size
+ count += @buildrs_creators.synchronize { @buildrs_creators.size }
+ end
+ count if count < buildrs_size
end
-
- create_if_needed
- @ready_cond.signal
end
- def create_if_needed
- return unless may_create?
- Thread.new { create_runtime }
- end
-
- def may_create?
- @workers.synchronize do
- workers = @workers.size
- worked = @work_queue.synchronize { @work_queue.size }
- (workers + worked) < work_queue_size
+ def create_buildr_when_needed
+ @buildrs.synchronize do
+ @buildrs_create.wait_until { may_create_buildr? }
+ end
+ Thread.pass while @runtime_creator.status == 'run'
+ create_buildr
+ Thread.pass
+ rescue => e
+ p e
+ end
+
+ def create_buildr
+ creator = may_create_buildr?
+ return unless creator
+ @buildrs_creators.synchronize { @buildrs_creators << creator }
+ runtime = self.runtime
+ puts "Loading buildr[#{creator}] on #{runtime} ..."
+ Util.benchmark ["Loaded buildr[#{creator}] on #{runtime}"] do
+ load_service = runtime.getLoadService
+ load_service.require 'rubygems'
+ load_service.require 'buildr'
+ end
+ @buildrs_creators.synchronize do
+ @buildrs_creators.delete(creator)
+ @buildrs.synchronize do
+ @buildrs << runtime
+ @buildrs_ready.signal
+ end
end
end
+
end # BuildrFactory
-
+
class BuildrServer < com.martiansoftware.nailgun.NGServer
+
attr_reader :buildr_factory
def initialize(host = 'localhost', port = 2113, buildr_factory = nil)
@@ -340,7 +590,15 @@
@buildr_factory = buildr_factory
@host, @port = host, port
end
-
+
+ def runtime
+ JRuby.runtime
+ end
+
+ def to_ruby
+ org.jruby.javasupport.JavaEmbedUtils.javaToRuby(runtime, java_object)
+ end
+
def start_server
self.allow_nails_by_class_name = false
@@ -348,21 +606,81 @@
self.default_nail_class = BuildrNail::Main
buildr_factory.start
- t = java.lang.Thread.new(self)
- t.setName(to_s)
- t.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.buildfile, @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)
- end # module Nailgun
- end # Nailgun::Boot
+ 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']
+ compiled_bin << '.exe' if Config::CONFIG['host_os'] =~ /mswin/i
+ 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
+
+ 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
+
+ task :start => [installed_bin, :boot] do
+ factory = BuildrFactory.new(runtime_pool_size)
+ $nailgun_server = BuildrServer.new(iface, port, factory)
+ puts "Starting #{$nailgun_server}"
+ $nailgun_server.start_server
+ end
+ end # namespace :nailgun
+
+ end # module Nailgun
+
end
Added: incubator/buildr/trunk/lib/java/org/apache/buildr/BuildrNail.java
URL:
http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/java/org/apache/buildr/BuildrNail.java?rev=633992&view=auto
==============================================================================
--- incubator/buildr/trunk/lib/java/org/apache/buildr/BuildrNail.java (added)
+++ incubator/buildr/trunk/lib/java/org/apache/buildr/BuildrNail.java Wed Mar
5 11:29:38 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:
+ */