Author: boisvert
Date: Fri Oct 1 06:18:10 2010
New Revision: 1003400
URL: http://svn.apache.org/viewvc?rev=1003400&view=rev
Log:
BUILDR-514 New 'run' local task.
Added:
buildr/trunk/lib/buildr/core/run.rb
buildr/trunk/lib/buildr/run.rb
buildr/trunk/spec/core/run_spec.rb
buildr/trunk/spec/java/run_spec.rb
Modified:
buildr/trunk/CHANGELOG
buildr/trunk/doc/more_stuff.textile
buildr/trunk/lib/buildr.rb
buildr/trunk/lib/buildr/core.rb
Modified: buildr/trunk/CHANGELOG
URL:
http://svn.apache.org/viewvc/buildr/trunk/CHANGELOG?rev=1003400&r1=1003399&r2=1003400&view=diff
==============================================================================
--- buildr/trunk/CHANGELOG (original)
+++ buildr/trunk/CHANGELOG Fri Oct 1 06:18:10 2010
@@ -1,4 +1,5 @@
1.4.3 (Pending)
+* Added: BUILDR-514 New 'run' local task.
http://buildr.apache.org/more_stuff.html#run
* Added: BUILDR-518 Load _buildr.rb or .buildr.rb from same directory as
Buildfile if they exist (Peter Donald)
* Added: BUILDR-519 Load repositories.release_to from build settings (Peter
Donald)
* Fixed: BUILDR-520 Scaladoc 2.8 no longer support -windowtitle, use
-doc-title instead.
@@ -6,7 +7,7 @@
* Fixed: BUILDR-513 --trace fails with NoMethodError : undefined method
`include?' for nil:NilClass
* Fixed: BUILDR-515 -update-snapshot doesn't work as expected
-* Fixed: JavaRebel was previously not correctly detected
+* Fixed: JavaRebel was previously not correctly detected.
1.4.2 (2010-09-18)
* Added: BUILDR-415 Ability to exclude tests from command line
Modified: buildr/trunk/doc/more_stuff.textile
URL:
http://svn.apache.org/viewvc/buildr/trunk/doc/more_stuff.textile?rev=1003400&r1=1003399&r2=1003400&view=diff
==============================================================================
--- buildr/trunk/doc/more_stuff.textile (original)
+++ buildr/trunk/doc/more_stuff.textile Fri Oct 1 06:18:10 2010
@@ -108,7 +108,7 @@ If you don't know which tracing category
$ buildr --trace=all
{% endhighlight %}
-h3. JavaRebel Integration
+h3(#javarebel). JavaRebel Integration
"JavaRebel":http://www.zeroturnaround.com/javarebel is a live bytecode
reloading solution by Zero Turnaround. It's a lot like the hot code reload
feature found in many Java IDE debuggers (like Eclipse and IntelliJ), but
capable of handling things like member addition or removal and new class
definition. The tool itself is commercial and works with any JVM language, but
they do offer a free license for use with Scala classes only.
@@ -146,6 +146,59 @@ scala> </pre>
Note that Buildr does *not* check to make sure that you have a valid JavaRebel
license, so you may end up launching with JavaRebel configured but without the
ability to use it (in which case, JavaRebel will print a notification).
+h2(#run). Running Your Application
+
+The @run@ task lets you easily run programs from your buildfile, such as
launching your own application.
+
+In its simplest form, you simply define the main class of your Java
application,
+
+{% highlight ruby %}
+define 'my-project' do
+ compile.with COMMONS_IO, HTTPCLIENT
+ run.using :main => "org.example.Main"
+end
+{% endhighlight %}
+
+And then run,
+
+{% highlight ruby %}
+~/my-project$ buildr run
+{% endhighlight %}
+
+which would launch your application using the project's compile classpath.
+
+It's also possible to pass arguments to the JVM using the @:java_args@ option:
+
+{% highlight ruby %}
+ run.using :main => "org.example.Main",
+ :java_args => ["-server"]
+{% endhighlight %}
+
+If your application requires arguments, you can pass in an array of values for
the @:main@ option, or provide a set of system properties using @:propert...@.
+
+{% highlight ruby %}
+ run.using :main => ["org.example.Main", "-t", "input.txt"],
+ :properties => { :debug => "true" }
+{% endhighlight %}
+
+The @run@ task is a local task, which means that Buildr will automatically
pick the @run@ task matching the project in the current directory. Executing
the following command:
+
+{% highlight ruby %}
+~/my-project/subproject$ buildr run
+{% endhighlight %}
+
+will run the @my-project:subproject:run@ task, assuming @my-project@ is your
top-level project.
+
+Here is a summary of @run.using@ options,
+
+|_. Option |_. Description ... |
+| @:main@ | The java main class, e.g. "com.example.Main". Can also be an
array if the main class requires arguments. |
+| @:properties@ | A hash of system properties to be passed to java. |
+| @:java_args@ | An array of additional parameters to pass to java |
+| @:classpath@ | An array of additional classpath elements (i.e. artifacts,
files, etc.). By default, the @run@ task automatically uses the
@compile.dependencies@, @test.dependencies@ and @test.compile.target@ of your
project. |
+
+p(note). The @run@ task also detects and uses JavaRebel if it's available.
See the "JavaRebel":#javarebel section for details.
+
h2(#gems). Using Gems
The purpose of the buildfile is to define your projects, and the various tasks
and functions used for building them. Some of these are specific to your
projects, others are more general in nature, and you may want to share them
across projects.
Modified: buildr/trunk/lib/buildr.rb
URL:
http://svn.apache.org/viewvc/buildr/trunk/lib/buildr.rb?rev=1003400&r1=1003399&r2=1003400&view=diff
==============================================================================
--- buildr/trunk/lib/buildr.rb (original)
+++ buildr/trunk/lib/buildr.rb Fri Oct 1 06:18:10 2010
@@ -22,6 +22,7 @@ require 'buildr/packaging'
require 'buildr/java'
require 'buildr/ide'
require 'buildr/shell'
+require 'buildr/run'
# Methods defined in Buildr are both instance methods (e.g. when included in
Project)
# and class methods when invoked like Buildr.artifacts().
Modified: buildr/trunk/lib/buildr/core.rb
URL:
http://svn.apache.org/viewvc/buildr/trunk/lib/buildr/core.rb?rev=1003400&r1=1003399&r2=1003400&view=diff
==============================================================================
--- buildr/trunk/lib/buildr/core.rb (original)
+++ buildr/trunk/lib/buildr/core.rb Fri Oct 1 06:18:10 2010
@@ -23,6 +23,7 @@ require 'buildr/core/filter'
require 'buildr/core/compile'
require 'buildr/core/test'
require 'buildr/core/shell'
+require 'buildr/core/run'
require 'buildr/core/checks'
require 'buildr/core/transports'
require 'buildr/core/generate'
Added: buildr/trunk/lib/buildr/core/run.rb
URL:
http://svn.apache.org/viewvc/buildr/trunk/lib/buildr/core/run.rb?rev=1003400&view=auto
==============================================================================
--- buildr/trunk/lib/buildr/core/run.rb (added)
+++ buildr/trunk/lib/buildr/core/run.rb Fri Oct 1 06:18:10 2010
@@ -0,0 +1,43 @@
+# 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 'buildr/run'
+require 'buildr/java/commands'
+require 'buildr/core/util'
+
+module Buildr
+ module Run
+
+ class JavaRunner < Base
+ include Shell::JavaRebel
+
+ specify :name => :java, :languages => [:java, :scala, :groovy, :clojure]
+
+ def run(task)
+ fail "Missing :main option" unless task.options[:main]
+ cp = project.compile.dependencies + [project.path_to(:target,
:classes)] + task.classpath
+ Java::Commands.java(task.options[:main], {
+ :properties => rebel_props(project).merge (task.options[:properties]
|| {}),
+ :classpath => cp,
+ :java_args => rebel_args + (task.options[:java_args] || [])
+ })
+ end
+ end # JavaRunnner
+
+ end
+end
+
+Buildr::Run.runners << Buildr::Run::JavaRunner
+
Added: buildr/trunk/lib/buildr/run.rb
URL:
http://svn.apache.org/viewvc/buildr/trunk/lib/buildr/run.rb?rev=1003400&view=auto
==============================================================================
--- buildr/trunk/lib/buildr/run.rb (added)
+++ buildr/trunk/lib/buildr/run.rb Fri Oct 1 06:18:10 2010
@@ -0,0 +1,202 @@
+# 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.
+
+
+module Buildr
+ module Run
+ include Extension
+
+ class << self
+ def runners
+ @runners ||= []
+ end
+
+ def select_by_lang(lang)
+ fail 'Unable to define run task for nil language' if lang.nil?
+ runners.detect { |e| e.languages.nil? ? false :
e.languages.include?(lang.to_sym) }
+ end
+
+ alias_method :select, :select_by_lang
+
+ def select_by_name(name)
+ fail 'Unable to define run task for nil' if name.nil?
+ runners.detect { |e| e.to_sym == name.to_sym }
+ end
+
+ end
+
+ # Base class for any run provider. Defines most
+ # common functionality (things like @lang@, @build?@ and friends).
+ class Base
+ attr_reader :project
+
+ class << self
+ attr_accessor :name, :languages
+
+ def specify(options)
+ @name ||= options[:name]
+ @languages ||= options[:languages]
+ end
+
+ def to_sym
+ @name ||= name.split('::').last.downcase.to_sym
+ end
+ end
+
+ def initialize(project)
+ @project = project
+ end
+
+ def build?
+ true
+ end
+
+ def launch
+ fail 'Not implemented'
+ end
+ end
+
+ class RunTask < Rake::Task
+ # Classpath dependencies.
+ attr_accessor :classpath
+
+ # Returns the run options.
+ attr_reader :options
+
+ # Returns file dependencies
+ attr_reader :files
+
+ attr_reader :project # :nodoc:
+
+ def initialize(*args) # :nodoc:
+ super
+ @options = {}
+ @classpath = []
+ @files = FileList[]
+ end
+
+ # :call-seq:
+ # with(*artifacts) => self
+ #
+ # Adds files and artifacts as classpath dependencies, and returns self.
+ def with(*specs)
+ @classpath |= Buildr.artifacts(specs.flatten).uniq
+ self
+ end
+
+ # :call-seq:
+ # using(options) => self
+ #
+ # Sets the run options from a hash and returns self.
+ #
+ # For example:
+ # run.using :main=>'org.example.Main'
+ def using(*args)
+ args.pop.each { |key, value| @options[key.to_sym] = value } if Hash
=== args.last
+
+ until args.empty?
+ new_runner = Run.select_by_name(args.pop)
+ @runner = new_runner.new(project) unless new_runner.nil?
+ end
+
+ self
+ end
+
+ # :call-seq:
+ # requires(*files) => self
+ #
+ # Adds additional files and directories as dependencies to the task and
returns self.
+ # When specifying a directory, includes all files in that directory.
+ def requires(*files)
+ @files.include *files.flatten.compact
+ self
+ end
+
+ def runner
+ @runner ||= guess_runner
+ end
+
+ # :call-seq:
+ # runner?(clazz) => boolean
+ #
+ # Check if the underlying runner is an instance of the given class.
+ # If no class is supplied, simply check if runner is defined.
+ def runner?(clazz = nil)
+ begin
+ @runner ||= guess_runner if project.compile.language
+ rescue
+ return false
+ end
+ return [email protected]? unless clazz
+ @runner.is_a?(clazz) if @runner
+ end
+
+ def run
+ runner.run(self) if runner?
+ end
+
+ def prerequisites #:nodoc:
+ super + @files + classpath
+ end
+
+ private
+
+ def guess_runner
+ runner = Run.select project.compile.language
+ fail 'Unable to guess runner for project.' unless runner
+ runner.new project
+ end
+
+ def associate_with(project)
+ @project ||= project
+ end
+ end
+
+ first_time do
+ Project.local_task 'run'
+ end
+
+ before_define(:run => :test) do |project|
+ RunTask.define_task('run').tap do |run|
+ run.send(:associate_with, project)
+ run.enhance([project.compile, project.test]) do |t|
+ # double-enhance to execute the runner last
+ run.enhance { |t| t.run }
+ end
+ end
+ end
+
+ after_define(:run => :test) do |project|
+ project.run.with project.test.compile.dependencies
+ project.run.with project.test.compile.target if
project.test.compile.target
+ end
+
+ # :call-seq:
+ # run(&block) => RunTask
+ #
+ # This method returns the project's run task. It also accepts a block to
be executed
+ # when the run task is invoked.
+ def run(&block)
+ task('run').tap do |t|
+ t.enhance &block if block
+ end
+ end
+
+ end
+
+ class Project
+ include Run
+ end
+end
Added: buildr/trunk/spec/core/run_spec.rb
URL:
http://svn.apache.org/viewvc/buildr/trunk/spec/core/run_spec.rb?rev=1003400&view=auto
==============================================================================
--- buildr/trunk/spec/core/run_spec.rb (added)
+++ buildr/trunk/spec/core/run_spec.rb Fri Oct 1 06:18:10 2010
@@ -0,0 +1,92 @@
+# 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 File.expand_path(File.join(File.dirname(__FILE__), '..',
'spec_helpers'))
+
+describe Project, :run do
+
+ it 'should return the project\'s run task' do
+ define('foo')
+ project('foo').run.name.should eql('foo:run')
+ end
+
+ it 'should return a RunTask' do
+ define('foo')
+ project('foo').run.should be_kind_of(Run::RunTask)
+ end
+
+ it 'should include compile and test.compile dependencies' do
+ define('foo') do
+ compile.using(:javac).with 'group:compile:jar:1.0'
+ test.compile.using(:javac).with 'group:test:jar:1.0'
+ end
+ project('foo').run.classpath.should
include(artifact('group:compile:jar:1.0'))
+ project('foo').run.classpath.should include(artifact('group:test:jar:1.0'))
+ end
+
+ it 'should respond to using() and return self' do
+ define 'foo' do
+ run.using(:foo=>'Fooing').should be(run)
+ end
+ end
+
+ it 'should respond to using() and accept options' do
+ define 'foo' do
+ run.using :foo=>'Fooing'
+ end
+ project('foo').run.options[:foo].should eql('Fooing')
+ end
+
+ it 'should select runner using run.using' do
+ define 'foo' do
+ run.using :java
+ end
+ project('foo').run.runner.should be_a(Run::JavaRunner)
+ end
+
+ it 'should select runner based on compile language' do
+ write 'src/main/java/Test.java', 'class Test {}'
+ define 'foo' do
+ # compile language detected as :java
+ end
+ project('foo').run.runner.should be_a(Run::JavaRunner)
+ end
+
+ it 'should depend on project''s compile and test.compile task' do
+ define 'foo'
+ project('foo').run.prerequisites.should include(project('foo').compile)
+ end
+
+ it 'should be local task' do
+ define 'foo' do
+ define('bar')
+ end
+ project('foo:bar').run.should_receive(:invoke_prerequisites)
+ project('foo:bar').run.should_receive(:run)
+ in_original_dir(project('foo:bar').base_dir) { task('run').invoke }
+ end
+
+ it 'should not recurse' do
+ define 'foo' do
+ define('bar') { run.using :java, :main => 'foo' }
+ end
+ project('foo:bar').run.should_not_receive(:invoke_prerequisites)
+ project('foo:bar').run.should_not_receive(:run)
+ project('foo').run.should_receive(:run)
+ project('foo').run.invoke
+ end
+
+end
+
Added: buildr/trunk/spec/java/run_spec.rb
URL:
http://svn.apache.org/viewvc/buildr/trunk/spec/java/run_spec.rb?rev=1003400&view=auto
==============================================================================
--- buildr/trunk/spec/java/run_spec.rb (added)
+++ buildr/trunk/spec/java/run_spec.rb Fri Oct 1 06:18:10 2010
@@ -0,0 +1,78 @@
+# 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 File.expand_path(File.join(File.dirname(__FILE__), '..',
'spec_helpers'))
+
+
+describe Run::JavaRunner do
+
+ it 'should fail on error' do
+ define 'foo' do
+ run.using :java, :main => 'org.example.NonExistentMain' # class doesn't
exist
+ end
+ lambda { project('foo').run.invoke }.should raise_error(RuntimeError,
/Failed to execute java/)
+ end
+
+ it 'should execute main class' do
+ write 'src/main/java/org/example/Main.java', <<-JAVA
+ package org.example;
+ public class Main {
+ public static void main(String[] args) {
+ System.out.println("Hello, world!");
+ }
+ }
+ JAVA
+ define 'foo' do
+ run.using :main => 'org.example.Main'
+ end
+ project('foo').run.prerequisites.should include(task("foo:compile"))
+ end
+
+ it 'should accept :main option as an array including parameters for the main
class' do
+ define 'foo' do
+ run.using :java, :main => ['org.example.Main', '-t', 'input.txt']
+ end
+ Java::Commands.should_receive(:java).once.with do |*args|
+ args[0].should == ['org.example.Main', '-t', 'input.txt']
+ end
+ project('foo').run.invoke
+ end
+
+ it 'should accept :java_args and pass them to java' do
+ define 'foo' do
+ run.using :java, :main => 'foo', :java_args => ['-server']
+ end
+ Java::Commands.should_receive(:java).once.with do |*args|
+ args[0].should == 'foo'
+ args[1][:java_args].should include('-server')
+ end
+ project('foo').run.invoke
+ end
+
+ it 'should accept :properties and pass them as -Dproperty=value to java' do
+ define 'foo' do
+ run.using :java, :main => 'foo', :properties => { :foo => 'one', :bar =>
'two' }
+ end
+ Java::Commands.should_receive(:java).once.with do |*args|
+ args[0].should == 'foo'
+ args[1][:properties][:foo].should == 'one'
+ args[1][:properties][:bar].should == 'two'
+ end
+ project('foo').run.invoke
+ end
+
+end
+