buildr-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From vbo...@apache.org
Subject svn commit: r633992 - in /incubator/buildr/trunk: Rakefile buildfile lib/core/application.rb lib/core/application_cli.rb lib/java/jruby.rb lib/java/nailgun.rb lib/java/org/apache/buildr/BuildrNail.java
Date Wed, 05 Mar 2008 19:29:40 GMT
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:
+ */



Mime
View raw message