Author: boisvert
Date: Sun Sep 13 23:58:31 2009
New Revision: 814442
URL: http://svn.apache.org/viewvc?rev=814442&view=rev
Log:
BUILDR-300: Make Eclipse task more configurable; thanks to Antoine Toulme for
base contribution
Modified:
buildr/trunk/CHANGELOG
buildr/trunk/lib/buildr/ide/eclipse.rb
buildr/trunk/spec/ide/eclipse_spec.rb
Modified: buildr/trunk/CHANGELOG
URL:
http://svn.apache.org/viewvc/buildr/trunk/CHANGELOG?rev=814442&r1=814441&r2=814442&view=diff
==============================================================================
--- buildr/trunk/CHANGELOG (original)
+++ buildr/trunk/CHANGELOG Sun Sep 13 23:58:31 2009
@@ -1,4 +1,5 @@
1.3.5 (Pending)
+* Added: BUILDR-300: Make Eclipse task more configurable (Antoine Toulme,
Alex Boisvert)
* Fixed: BUILDR-307 Failures are not reported correctly for ScalaTest
(Jeremie Lenfant-Engelmann)
* Fixed: BUILDR-278 tasks/*.rake files are loaded after the buildfile (Rhett
Sutphin)
* Fixed: BUILDR-304 Referencing an existing package task using the package
Modified: buildr/trunk/lib/buildr/ide/eclipse.rb
URL:
http://svn.apache.org/viewvc/buildr/trunk/lib/buildr/ide/eclipse.rb?rev=814442&r1=814441&r2=814442&view=diff
==============================================================================
--- buildr/trunk/lib/buildr/ide/eclipse.rb (original)
+++ buildr/trunk/lib/buildr/ide/eclipse.rb Sun Sep 13 23:58:31 2009
@@ -22,28 +22,121 @@
module Eclipse #:nodoc:
include Extension
- def eclipse
- Eclipse.instance
- end
-
class Eclipse
- include Singleton
-
+
attr_reader :options
-
- def initialize
- @options = Options.new
+
+ def initialize(project)
+ @project = project
+ @options = Options.new(project)
+ end
+
+ # :call-seq:
+ # natures=(natures)
+ # Sets the Eclipse project natures on the project.
+ #
+ def natures=(var)
+ @natures = arrayfy(var)
+ end
+
+ # :call-seq:
+ # natures() => [n1, n2]
+ # Returns the Eclipse project natures on the project.
+ # They may be derived from the parent project if no specific natures
have been set
+ # on the project.
+ #
+ # An Eclipse project nature is used internally by Eclipse to determine
the aspects of a project.
+ def natures(*values)
+ if values.size > 0
+ @natures ||= []
+ @natures += values
+ else
+ @natures || (@project.parent ? @project.parent.eclipse.natures : [])
+ end
+ end
+
+ # :call-seq:
+ # classpath_containers=(cc)
+ # Sets the Eclipse project classpath containers on the project.
+ #
+ def classpath_containers=(var)
+ @classpath_containers = arrayfy(var)
+ end
+
+ # :call-seq:
+ # classpath_containers() => [con1, con2]
+ # Returns the Eclipse project classpath containers on the project.
+ # They may be derived from the parent project if no specific classpath
containers have been set
+ # on the project.
+ #
+ # A classpath container is an Eclipse pre-determined ensemble of
dependencies made available to
+ # the project classpath.
+ def classpath_containers(*values)
+ if values.size > 0
+ @classpath_containers ||= []
+ @classpath_containers += values
+ else
+ @classpath_containers || (@project.parent ?
@project.parent.eclipse.classpath_containers : [])
+ end
+ end
+
+ # :call-seq:
+ # builders=(builders)
+ # Sets the Eclipse project builders on the project.
+ #
+ def builders=(var)
+ @builders = arrayfy(var)
+ end
+
+ # :call-seq:
+ # builders() => [b1, b2]
+ # Returns the Eclipse project builders on the project.
+ # They may be derived from the parent project if no specific builders
have been set
+ # on the project.
+ #
+ # A builder is an Eclipse background job that parses the source code to
produce built artifacts.
+ def builders(*values)
+ if values.size > 0
+ @builders ||= []
+ @builders += values
+ else
+ @builders || (@project.parent ? @project.parent.eclipse.builders :
[])
+ end
+ end
+
+ private
+
+ def arrayfy(obj)
+ obj.is_a?(Array) ? obj : [obj]
end
end
-
+
class Options
- attr_accessor :m2_repo_var
- def initialize
- @m2_repo_var = 'M2_REPO'
+ attr_writer :m2_repo_var
+
+ def initialize(project)
+ @project = project
+ end
+
+ # The classpath variable used to point at the local maven2 repository.
+ # Example:
+ # eclipse.options.m2_repo_var = 'M2_REPO'
+ def m2_repo_var(*values)
+ fail "m2_repo_var can only accept one value: #{values}" if values.size
> 1
+ if values.size > 0
+ @m2_repo_var = values[0]
+ else
+ @m2_repo_var || (@project.parent ?
@project.parent.eclipse.options.m2_repo_var : 'M2_REPO')
+ end
end
end
-
+
+ def eclipse
+ @eclipse ||= Eclipse.new(self)
+ @eclipse
+ end
+
first_time do
# Global task "eclipse" generates artifacts for all projects.
desc 'Generate Eclipse artifacts for all projects'
@@ -57,19 +150,11 @@
after_define do |project|
eclipse = project.task('eclipse')
- # Check if project has scala facet
- scala = project.compile.language == :scala
-
- # Only for projects that we support
- supported_languages = [:java, :scala]
- supported_packaging = %w(jar war rar mar aar)
- if (supported_languages.include?(project.compile.language) ||
- supported_languages.include?(project.test.compile.language) ||
- project.packages.detect { |pkg|
supported_packaging.include?(pkg.type.to_s) })
- eclipse.enhance [ file(project.path_to('.classpath')),
file(project.path_to('.project')) ]
+ eclipse.enhance [ file(project.path_to('.classpath')),
file(project.path_to('.project')) ]
- # The only thing we need to look for is a change in the Buildfile.
- file(project.path_to('.classpath')=>Buildr.application.buildfile) do
|task|
+ # The only thing we need to look for is a change in the Buildfile.
+ file(project.path_to('.classpath')=>Buildr.application.buildfile) do
|task|
+ if (project.eclipse.natures.reject { |x| x.is_a?(Symbol) }.size > 0)
info "Writing #{task.name}"
m2repo = Buildr::Repositories.instance.local
@@ -106,16 +191,19 @@
classpathentry.output project.compile.target if
project.compile.target
classpathentry.lib libs
- classpathentry.var m2_libs,
Eclipse.instance.options.m2_repo_var, m2repo
+ classpathentry.var m2_libs, project.eclipse.options.m2_repo_var,
m2repo
- classpathentry.con 'ch.epfl.lamp.sdt.launching.SCALA_CONTAINER'
if scala
- classpathentry.con 'org.eclipse.jdt.launching.JRE_CONTAINER'
+ project.eclipse.classpath_containers.each { |container|
+ classpathentry.con container
+ }
end
end
end
+ end
- # The only thing we need to look for is a change in the Buildfile.
- file(project.path_to('.project')=>Buildr.application.buildfile) do
|task|
+ # The only thing we need to look for is a change in the Buildfile.
+ file(project.path_to('.project')=>Buildr.application.buildfile) do |task|
+ if (project.eclipse.natures.reject { |x| x.is_a?(Symbol) }.size > 0)
info "Writing #{task.name}"
File.open(task.name, 'w') do |file|
xml = Builder::XmlMarkup.new(:target=>file, :indent=>2)
@@ -123,25 +211,21 @@
xml.name project.id
xml.projects
xml.buildSpec do
- if scala
+ project.eclipse.builders.each { |builder|
xml.buildCommand do
- xml.name 'ch.epfl.lamp.sdt.core.scalabuilder'
+ xml.name builder
end
- else
- xml.buildCommand do
- xml.name 'org.eclipse.jdt.core.javabuilder'
- end
- end
+ }
end
xml.natures do
- xml.nature 'ch.epfl.lamp.sdt.core.scalanature' if scala
- xml.nature 'org.eclipse.jdt.core.javanature'
+ project.eclipse.natures.each { |nature|
+ xml.nature nature unless nature.is_a? Symbol
+ }
end
end
end
end
end
-
end
@@ -156,11 +240,11 @@
@excludes = [ '**/.svn/', '**/CVS/' ].join('|')
@paths_written = []
end
-
+
def write &block
@xml.classpath &block
end
-
+
def con path
@xml.classpathentry :kind=>'con', :path=>path
end
@@ -188,7 +272,7 @@
@xml.classpathentry :kind=>'src', :combineaccessrules=>'false',
:path=>"/#{project_id}"
end
end
-
+
def output target
@xml.classpathentry :kind=>'output', :path=>relative(target)
end
@@ -207,7 +291,7 @@
@xml.classpathentry :kind=>'var', :path=>relative_lib_path,
:sourcepath=>relative_source_path
end
end
-
+
private
# Find a path relative to the project's root directory.
@@ -236,10 +320,15 @@
end
end
-
-end # module Buildr
+end # module Buildr
class Buildr::Project
include Buildr::Eclipse
end
+
+# Order is significant for auto-detection, from most specific to least
+require 'buildr/ide/eclipse/plugin'
+require 'buildr/ide/eclipse/scala'
+require 'buildr/ide/eclipse/java'
+
Modified: buildr/trunk/spec/ide/eclipse_spec.rb
URL:
http://svn.apache.org/viewvc/buildr/trunk/spec/ide/eclipse_spec.rb?rev=814442&r1=814441&r2=814442&view=diff
==============================================================================
--- buildr/trunk/spec/ide/eclipse_spec.rb (original)
+++ buildr/trunk/spec/ide/eclipse_spec.rb Sun Sep 13 23:58:31 2009
@@ -17,14 +17,17 @@
require File.join(File.dirname(__FILE__), '../spec_helpers')
-JAVA_CONTAINER = 'org.eclipse.jdt.launching.JRE_CONTAINER'
-SCALA_CONTAINER = 'ch.epfl.lamp.sdt.launching.SCALA_CONTAINER'
-
-SCALA_NATURE = 'ch.epfl.lamp.sdt.core.scalanature'
-JAVA_NATURE = 'org.eclipse.jdt.core.javanature'
-
-SCALA_BUILDER = 'ch.epfl.lamp.sdt.core.scalabuilder'
-JAVA_BUILDER = 'org.eclipse.jdt.core.javabuilder'
+JAVA_CONTAINER = Buildr::Eclipse::Java::CONTAINER
+SCALA_CONTAINER = Buildr::Eclipse::Scala::CONTAINER
+PLUGIN_CONTAINER = Buildr::Eclipse::Plugin::CONTAINER
+
+JAVA_NATURE = Buildr::Eclipse::Java::NATURE
+SCALA_NATURE = Buildr::Eclipse::Scala::NATURE
+PLUGIN_NATURE = Buildr::Eclipse::Plugin::NATURE
+
+JAVA_BUILDER = Buildr::Eclipse::Java::BUILDER
+SCALA_BUILDER = Buildr::Eclipse::Scala::BUILDER
+PLUGIN_BUILDERS = Buildr::Eclipse::Plugin::BUILDERS
module EclipseHelper
@@ -32,72 +35,75 @@
task('eclipse').invoke
REXML::Document.new(File.open('.classpath')).root.elements
end
-
- def classpath_sources attribute='path'
+
+ def classpath_sources(attribute='path')
classpath_xml_elements.collect("classpathent...@kind='src']") { |n|
n.attributes[attribute] }
end
-
+
# <classpathentry path="PATH" output="RETURNED_VALUE"/>
- def classpath_specific_output path
+ def classpath_specific_output(path)
specific_output =
classpath_xml_elements.collect("classpathent...@path='#{path}']") { |n|
n.attributes['output'] }
raise "expected: one output attribute for path '#{path}, got:
#{specific_output.inspect}" if specific_output.length > 1
specific_output[0]
end
-
+
# <classpathentry path="RETURNED_VALUE" kind="output"/>
def classpath_default_output
default_output =
classpath_xml_elements.collect("classpathent...@kind='output']") { |n|
n.attributes['path'] }
raise "expected: one path attribute for kind='output', got:
#{default_output.inspect}" if default_output.length > 1
default_output[0]
end
-
+
# <classpathentry path="PATH" sourcepath="RETURNED_VALUE" kind="var"/>
- def sourcepath_for_path path
+ def sourcepath_for_path(path)
classpath_xml_elements.collect("classpathent...@kind='var',@path='#{path}']")
do |n|
n.attributes['sourcepath'] || 'no source artifact'
end
end
-
+
def project_xml_elements
task('eclipse').invoke
REXML::Document.new(File.open('.project')).root.elements
end
+ def project_natures
+ project_xml_elements.collect("natures/nature") { |n| n.text }
+ end
+
+ def build_commands
+ project_xml_elements.collect("buildSpec/buildCommand/name") { |n| n.text }
+ end
+
+ def classpath_containers(attribute='path')
+ classpath_xml_elements.collect("classpathent...@kind='con']") { |n|
n.attributes[attribute] }
+ end
end
describe Buildr::Eclipse do
include EclipseHelper
-
+
describe "eclipse's .project file" do
- def project_natures
- project_xml_elements.collect("natures/nature") { |n| n.text }
- end
-
- def build_commands
- project_xml_elements.collect("buildSpec/buildCommand/name") { |n| n.text
}
- end
-
describe 'java project' do
before do
write 'buildfile'
write 'src/main/java/Main.java'
end
-
+
it 'should have Java nature' do
define('foo')
project_natures.should include(JAVA_NATURE)
end
-
+
it 'should have Java build command' do
define('foo')
build_commands.should include(JAVA_BUILDER)
end
end
-
+
describe 'nested java project' do
-
+
it 'should have name corresponding to its project definition' do
mkdir 'foo'
define('myproject') {
@@ -110,42 +116,102 @@
end
end
-
+
describe 'scala project' do
-
+
+ before do
+ define 'foo' do
+ eclipse.natures :scala
+ end
+ end
+
+ it 'should have Scala nature before Java nature' do
+ project_natures.should include(SCALA_NATURE)
+ project_natures.should include(JAVA_NATURE)
+ project_natures.index(SCALA_NATURE).should <
project_natures.index(JAVA_NATURE)
+ end
+
+ it 'should have Scala build command and no Java build command' do
+ build_commands.should include(SCALA_BUILDER)
+ build_commands.should_not include(JAVA_BUILDER)
+ end
+ end
+
+ describe 'standard scala project' do
+
before do
write 'buildfile'
write 'src/main/scala/Main.scala'
+ define 'foo'
end
-
+
it 'should have Scala nature before Java nature' do
- define('foo')
project_natures.should include(SCALA_NATURE)
project_natures.should include(JAVA_NATURE)
project_natures.index(SCALA_NATURE).should <
project_natures.index(JAVA_NATURE)
end
-
+
+ it 'should have Scala build command and no Java build command' do
+ build_commands.should include(SCALA_BUILDER)
+ build_commands.should_not include(JAVA_BUILDER)
+ end
+ end
+
+ describe 'non-standard scala project' do
+
+ before do
+ write 'buildfile'
+ write 'src/main/foo/Main.scala'
+ define 'foo' do
+ eclipse.natures = :scala
+ end
+ end
+
+ it 'should have Scala nature before Java nature' do
+ project_natures.should include(SCALA_NATURE)
+ project_natures.should include(JAVA_NATURE)
+ project_natures.index(SCALA_NATURE).should <
project_natures.index(JAVA_NATURE)
+ end
+
it 'should have Scala build command and no Java build command' do
- define('foo')
build_commands.should include(SCALA_BUILDER)
build_commands.should_not include(JAVA_BUILDER)
end
end
+
+ describe 'Plugin project' do
+
+ before do
+ write 'buildfile'
+ write 'src/main/java/Activator.java'
+ write 'plugin.xml'
+ end
+
+ it 'should have plugin nature before Java nature' do
+ define('foo')
+ project_natures.should include(PLUGIN_NATURE)
+ project_natures.should include(JAVA_NATURE)
+ project_natures.index(PLUGIN_NATURE).should <
project_natures.index(JAVA_NATURE)
+ end
+
+ it 'should have plugin build commands and the Java build command' do
+ define('foo')
+ build_commands.should include(PLUGIN_BUILDERS[0])
+ build_commands.should include(PLUGIN_BUILDERS[1])
+ build_commands.should include(JAVA_BUILDER)
+ end
+ end
end
-
+
describe "eclipse's .classpath file" do
-
+
describe 'scala project' do
- def classpath_containers attribute='path'
- classpath_xml_elements.collect("classpathent...@kind='con']") { |n|
n.attributes[attribute] }
- end
-
before do
write 'buildfile'
write 'src/main/scala/Main.scala'
end
-
+
it 'should have SCALA_CONTAINER before JAVA_CONTAINER' do
define('foo')
classpath_containers.should include(SCALA_CONTAINER)
@@ -153,15 +219,15 @@
classpath_containers.index(SCALA_CONTAINER).should <
classpath_containers.index(JAVA_CONTAINER)
end
end
-
+
describe 'source folders' do
-
+
before do
write 'buildfile'
write 'src/main/java/Main.java'
write 'src/test/java/Test.java'
end
-
+
describe 'source', :shared=>true do
it 'should ignore CVS and SVN files' do
define('foo')
@@ -172,106 +238,106 @@
end
end
end
-
+
describe 'main code' do
it_should_behave_like 'source'
-
+
it 'should accept to come from the default directory' do
define('foo')
classpath_sources.should include('src/main/java')
end
-
+
it 'should accept to come from a user-defined directory' do
define('foo') { compile path_to('src/java') }
classpath_sources.should include('src/java')
end
-
+
it 'should accept a file task as a main source folder' do
define('foo') { compile apt }
classpath_sources.should include('target/generated/apt')
end
-
+
it 'should go to the default target directory' do
define('foo')
classpath_specific_output('src/main/java').should be(nil)
classpath_default_output.should == 'target/classes'
end
end
-
+
describe 'test code' do
it_should_behave_like 'source'
-
+
it 'should accept to come from the default directory' do
define('foo')
classpath_sources.should include('src/test/java')
end
-
+
it 'should accept to come from a user-defined directory' do
define('foo') { test.compile path_to('src/test') }
classpath_sources.should include('src/test')
end
-
+
it 'should go to the default target directory' do
define('foo')
classpath_specific_output('src/test/java').should ==
'target/test/classes'
end
-
+
it 'should accept to be the only code in the project' do
rm 'src/main/java/Main.java'
define('foo')
classpath_sources.should include('src/test/java')
end
end
-
+
describe 'main resources' do
it_should_behave_like 'source'
-
+
before do
write 'src/main/resources/config.xml'
end
-
+
it 'should accept to come from the default directory' do
define('foo')
classpath_sources.should include('src/main/resources')
end
-
+
it 'should share a classpath entry if it comes from a directory with
code' do
write 'src/main/java/config.properties'
define('foo') { resources.from('src/main/java').exclude('**/*.java')
}
classpath_sources.select { |path| path ==
'src/main/java'}.length.should == 1
end
-
+
it 'should go to the default target directory' do
define('foo')
classpath_specific_output('src/main/resources').should ==
'target/resources'
end
end
-
+
describe 'test resources' do
it_should_behave_like 'source'
-
+
before do
write 'src/test/resources/config-test.xml'
end
-
+
it 'should accept to come from the default directory' do
define('foo')
classpath_sources.should include('src/test/resources')
end
-
+
it 'should share a classpath entry if it comes from a directory with
code' do
write 'src/test/java/config-test.properties'
define('foo') {
test.resources.from('src/test/java').exclude('**/*.java') }
classpath_sources.select { |path| path ==
'src/test/java'}.length.should == 1
end
-
+
it 'should go to the default target directory' do
define('foo')
classpath_specific_output('src/test/resources').should ==
'target/test/resources'
end
end
end
-
+
describe 'project depending on another project' do
it 'should have the underlying project in its classpath' do
mkdir 'foo'
@@ -287,34 +353,34 @@
end
end
end
-
+
describe 'maven2 artifact dependency' do
before do
define('foo') {
compile.using(:javac).with('com.example:library:jar:2.0') }
artifact('com.example:library:jar:2.0') { |task| write task.name }
task('eclipse').invoke
end
-
+
it 'should have a reference in the .classpath file relative to the local
M2 repo' do
classpath_xml_elements.collect("classpathent...@kind='var']") { |n|
n.attributes['path'] }.
should include('M2_REPO/com/example/library/2.0/library-2.0.jar')
end
-
+
it 'should be downloaded' do
file(artifact('com.example:library:jar:2.0').name).should exist
end
-
+
it 'should have a source artifact reference in the .classpath file' do
sourcepath_for_path('M2_REPO/com/example/library/2.0/library-2.0.jar').
should == ['M2_REPO/com/example/library/2.0/library-2.0-sources.jar']
end
end
-
+
describe 'maven2 repository variable' do
it 'should be configurable' do
define('foo') do
eclipse.options.m2_repo_var = 'PROJ_REPO'
- compile.using(:javac).with('com.example:library:jar:2.0')
+ compile.using(:javac).with('com.example:library:jar:2.0')
end
artifact('com.example:library:jar:2.0') { |task| write task.name }
@@ -322,5 +388,90 @@
classpath_xml_elements.collect("classpathent...@kind='var']") { |n|
n.attributes['path'] }.
should include('PROJ_REPO/com/example/library/2.0/library-2.0.jar')
end
+
+ it 'should pick the parent value by default' do
+ define('foo') do
+ eclipse.options.m2_repo_var = 'FOO_REPO'
+ define('bar')
+
+ define('bar2') do
+ eclipse.options.m2_repo_var = 'BAR2_REPO'
+ end
+ end
+ project('foo:bar').eclipse.options.m2_repo_var.should eql('FOO_REPO')
+ project('foo:bar2').eclipse.options.m2_repo_var.should eql('BAR2_REPO')
+ end
+ end
+
+ describe 'natures variable' do
+ it 'should be configurable' do
+ define('foo') do
+ eclipse.natures = 'dummyNature'
+ compile.using(:javac).with('com.example:library:jar:2.0')
+ end
+ artifact('com.example:library:jar:2.0') { |task| write task.name }
+ project_natures.should include('dummyNature')
+ end
+
+ it 'should pick the parent value by default' do
+ define('foo') do
+ eclipse.natures = 'foo_nature'
+ define('bar')
+
+ define('bar2') do
+ eclipse.natures = 'bar2_nature'
+ end
+ end
+ project('foo:bar').eclipse.natures.should include('foo_nature')
+ project('foo:bar2').eclipse.natures.should include('bar2_nature')
+ end
+ end
+
+ describe 'builders variable' do
+ it 'should be configurable' do
+ define('foo') do
+ eclipse.builders 'dummyBuilder'
+ compile.using(:javac).with('com.example:library:jar:2.0')
+ end
+ artifact('com.example:library:jar:2.0') { |task| write task.name }
+ build_commands.should include('dummyBuilder')
+ end
+
+ it 'should pick the parent value by default' do
+ define('foo') do
+ eclipse.builders = 'foo_builder'
+ define('bar')
+
+ define('bar2') do
+ eclipse.builders = 'bar2_builder'
+ end
+ end
+ project('foo:bar').eclipse.builders.should include('foo_builder')
+ project('foo:bar2').eclipse.builders.should include('bar2_builder')
+ end
+ end
+
+ describe 'classpath_containers variable' do
+ it 'should be configurable' do
+ define('foo') do
+ eclipse.classpath_containers = 'myOlGoodContainer'
+ compile.using(:javac).with('com.example:library:jar:2.0')
+ end
+ artifact('com.example:library:jar:2.0') { |task| write task.name }
+ classpath_containers.should include('myOlGoodContainer')
+ end
+
+ it 'should pick the parent value by default' do
+ define('foo') do
+ eclipse.classpath_containers = 'foo_classpath_containers'
+ define('bar')
+
+ define('bar2') do
+ eclipse.classpath_containers = 'bar2_classpath_containers'
+ end
+ end
+ project('foo:bar').eclipse.classpath_containers.should
include('foo_classpath_containers')
+ project('foo:bar2').eclipse.classpath_containers.should
include('bar2_classpath_containers')
+ end
end
end