# 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')) 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 def classpath_xml_elements task('eclipse').invoke File.open('.classpath') { |f| REXML::Document.new(f).root.elements } end def classpath_sources(attribute='path') classpath_xml_elements.collect("classpathentry[@kind='src']") { |n| n.attributes[attribute] } end # def classpath_specific_output(path) specific_output = classpath_xml_elements.collect("classpathentry[@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 # def classpath_default_output default_output = classpath_xml_elements.collect("classpathentry[@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 # def sourcepath_for_path(path) classpath_xml_elements.collect("classpathentry[@kind='var',@path='#{path}']") do |n| n.attributes['sourcepath'] || 'no source artifact' end end # def javadocpath_for_path(path) classpath_xml_elements.collect("classpathentry[@kind='var',@path='#{path}']") do |n| n.attributes['javadocpath'] || 'no javadoc artifact' end end def project_xml_elements task('eclipse').invoke File.open('.project') { |f| REXML::Document.new(f).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("classpathentry[@kind='con']") { |n| n.attributes[attribute] } end end describe Buildr::Eclipse do include EclipseHelper describe "eclipse's .project file" do describe 'default project' do before do write 'buildfile' write 'src/main/nono/Main.nono' end it 'should not have natures' do define('foo') project_natures.should be_empty end it 'should not have build commands' do define('foo') build_commands.should be_empty end it 'should generate a .project file' do define('foo') task('eclipse').invoke File.open('.project') do |f| REXML::Document.new(f).root. elements.collect("name") { |e| e.text }.should == ['foo'] end end it 'should use eclipse project name if specified' do define('foo') { eclipse.name = 'bar' } task('eclipse').invoke File.open('.project') do |f| REXML::Document.new(f).root. elements.collect("name") { |e| e.text }.should == ['bar'] end end it 'should not generate a .classpath file' do define('foo') task('eclipse').invoke File.exists?('.classpath').should be_false end end describe 'parent project' do before do write 'buildfile' mkpath 'bar' end it 'should not generate a .project for the parent project' do define('foo') do define('bar') end task('eclipse').invoke File.exists?('.project').should be_false File.exists?(File.join('bar','.project')).should be_true end 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') { project.version = '1.0' define('foo') { compile.using(:javac); package :jar } } task('eclipse').invoke File.open(File.join('foo', '.project')) do |f| REXML::Document.new(f).root. elements.collect("name") { |e| e.text }.should == ['myproject-foo'] end end it 'should use eclipse name for child project if set' do mkdir 'foo' define('myproject') { project.version = '1.0' define('foo') { eclipse.name = 'bar'; compile.using(:javac); package :jar } } task('eclipse').invoke File.open(File.join('foo', '.project')) do |f| REXML::Document.new(f).root. elements.collect("name") { |e| e.text }.should == ['bar'] end end it 'should use short name for child project if eclipse.options.short_names = true' do mkdir 'foo' define('myproject') { project.version = '1.0' eclipse.options.short_names = true define('foo') { compile.using(:javac); package :jar } } task('eclipse').invoke File.open(File.join('foo', '.project')) do |f| REXML::Document.new(f).root. elements.collect("name") { |e| e.text }.should == ['foo'] end 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 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 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 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 describe 'Plugin project with META-INF/MANIFEST.MF' do before do write 'buildfile' write 'src/main/java/Activator.java' end it 'should have plugin nature by default if MANIFEST.MF contains "Bundle-SymbolicName:"' do write 'META-INF/MANIFEST.MF', <<-MANIFEST Manifest-Version: 1.0 Name: example/ Specification-Title: "Examples" Specification-Version: "1.0" Specification-Vendor: "Acme Corp.". Implementation-Title: "example" Implementation-Version: "build57" Implementation-Vendor: "Acme Corp." Bundle-SymbolicName: acme.plugin.example MANIFEST define('foo') project_natures.should include(PLUGIN_NATURE) end it 'should not have plugin nature if MANIFEST.MF exists but doesn\'t contain "Bundle-SymbolicName:"' do write 'META-INF/MANIFEST.MF', <<-MANIFEST Manifest-Version: 1.0 Name: example/ Specification-Title: "Examples" Specification-Version: "1.0" Specification-Vendor: "Acme Corp.". Implementation-Title: "example" Implementation-Version: "build57" Implementation-Vendor: "Acme Corp." MANIFEST define('foo') project_natures.should_not include(PLUGIN_NATURE) end end end describe "eclipse's .classpath file" do describe 'scala project' do 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) classpath_containers.should include(JAVA_CONTAINER) 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 RSpec.shared_examples 'source' do it 'should ignore CVS and SVN files' do define('foo') classpath_sources('excluding').each do |excluding_attribute| excluding = excluding_attribute.split('|') excluding.should include('**/.svn/') excluding.should include('**/CVS/') 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' mkdir 'bar' define('myproject') { project.version = '1.0' define('foo') { package :jar } define('bar') { compile.using(:javac).with project('foo'); } } task('eclipse').invoke File.open(File.join('bar', '.classpath')) do |f| REXML::Document.new(f).root. elements.collect("classpathentry[@kind='src']") { |n| n.attributes['path'] }.should include('/myproject-foo') end end it 'should use eclipse name in its classpath if set' do mkdir 'foo' mkdir 'bar' define('myproject') { project.version = '1.0' define('foo') { eclipse.name = 'eclipsefoo'; package :jar } define('bar') { eclipse.name = 'eclipsebar'; compile.using(:javac).with project('foo'); } } task('eclipse').invoke File.open(File.join('bar', '.classpath')) do |f| REXML::Document.new(f).root. elements.collect("classpathentry[@kind='src']") { |n| n.attributes['path'] }.should include('/eclipsefoo') end end end end describe 'local dependency' do before do write 'lib/some-local.jar' define('foo') { compile.using(:javac).with(_('lib/some-local.jar')) } end it 'should have a lib artifact reference in the .classpath file' do classpath_xml_elements.collect("classpathentry[@kind='lib']") { |n| n.attributes['path'] }. should include('lib/some-local.jar') end end describe 'project .classpath' do before do mkdir_p '../libs' write '../libs/some-local.jar' define('foo') do eclipse.classpath_variables :LIBS => '../libs', :LIBS2 => '../libs2' compile.using(:javac).with(_('../libs/some-local.jar')) end end after do rm_rf '../libs' end it 'supports generating library paths with classpath variables' do classpath_xml_elements.collect("classpathentry[@kind='var']") { |n| n.attributes['path'] }. should include('LIBS/some-local.jar') end end describe 'generated .classes' do before do write 'lib/some.class' define('foo') { compile.using(:javac).with(_('lib')) } end it 'should have src reference in the .classpath file' do classpath_xml_elements.collect("classpathentry[@kind='src']") { |n| n.attributes['path'] }. should include('lib') 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("classpathentry[@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 it 'should have a javadoc artifact reference in the .classpath file' do javadocpath_for_path('M2_REPO/com/example/library/2.0/library-2.0.jar'). should == ['M2_REPO/com/example/library/2.0/library-2.0-javadoc.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') end artifact('com.example:library:jar:2.0') { |task| write task.name } task('eclipse').invoke classpath_xml_elements.collect("classpathentry[@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 it 'should handle arrays correctly' do define('foo') do eclipse.natures ['foo_nature', 'bar_nature'] end project('foo').eclipse.natures.should == ['foo_nature', 'bar_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 it 'should handle arrays correctly' do define('foo') do eclipse.builders ['foo_builder', 'bar_builder'] end project('foo').eclipse.builders.should == ['foo_builder', 'bar_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 it 'should handle arrays correctly' do define('foo') do eclipse.classpath_containers ['foo_cc', 'bar_cc'] end project('foo').eclipse.classpath_containers.should == ['foo_cc', 'bar_cc'] end end describe 'exclude_libs' do it 'should support artifacts' do define('foo') do compile.using(:javac).with('com.example:library:jar:2.0') eclipse.exclude_libs += [ artifact('com.example:library:jar:2.0') ] end artifact('com.example:library:jar:2.0') { |task| write task.name } task('eclipse').invoke classpath_xml_elements.collect("classpathentry[@kind='var']") { |n| n.attributes['path'] }. should_not include('M2_REPO/com/example/library/2.0/library-2.0.jar') end it 'should support string paths' do define('foo') do compile.using(:javac).with _('path/to/library.jar') eclipse.exclude_libs += [ _('path/to/library.jar') ] end write project('foo').path_to('path/to/library.jar') task('eclipse').invoke classpath_xml_elements.collect("classpathentry[@kind='lib']") { |n| n.attributes['path'] }. should_not include('path/to/library.jar') end end end