You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@buildr.apache.org by do...@apache.org on 2012/09/24 06:08:23 UTC
svn commit: r1389201 - in /buildr/trunk: CHANGELOG
lib/buildr/core/application.rb lib/buildr/core/generate.rb
spec/core/generate_from_eclipse_spec.rb
Author: donaldp
Date: Mon Sep 24 04:08:22 2012
New Revision: 1389201
URL: http://svn.apache.org/viewvc?rev=1389201&view=rev
Log:
BUILDR-652 Generate buildfile from Eclipse workspace. (Niklaus Giger)
Added:
buildr/trunk/spec/core/generate_from_eclipse_spec.rb
Modified:
buildr/trunk/CHANGELOG
buildr/trunk/lib/buildr/core/application.rb
buildr/trunk/lib/buildr/core/generate.rb
Modified: buildr/trunk/CHANGELOG
URL: http://svn.apache.org/viewvc/buildr/trunk/CHANGELOG?rev=1389201&r1=1389200&r2=1389201&view=diff
==============================================================================
--- buildr/trunk/CHANGELOG (original)
+++ buildr/trunk/CHANGELOG Mon Sep 24 04:08:22 2012
@@ -1,4 +1,5 @@
1.4.8 (Pending)
+* Added: BUILDR-652 Generate buildfile from Eclipse workspace. (Niklaus Giger)
* Fixed: BUILDR-627 Support explicitly listed source files in buildr cc task. (Christopher Tiwald)
* Fixed: BUILDR-606 Transitive artifact resolution should not include artifacts in 'provided' scope in poms to
match maven behaviour. (Julio Arias)
Modified: buildr/trunk/lib/buildr/core/application.rb
URL: http://svn.apache.org/viewvc/buildr/trunk/lib/buildr/core/application.rb?rev=1389201&r1=1389200&r2=1389201&view=diff
==============================================================================
--- buildr/trunk/lib/buildr/core/application.rb (original)
+++ buildr/trunk/lib/buildr/core/application.rb Mon Sep 24 04:08:22 2012
@@ -387,23 +387,31 @@ module Buildr
end
def ask_generate_buildfile
- source = choose do |menu|
- menu.header = "To use Buildr you need a buildfile. Do you want me to create one?"
- menu.choice("From Maven2 POM file") { 'pom.xml' } if File.exist?('pom.xml')
- menu.choice("From directory structure") { Dir.pwd }
- menu.choice("Cancel") { }
+ source, fromEclipse = choose do |menu|
+ menu.header = "ngng: To use Buildr you need a buildfile. Do you want me to create one?"
+ menu.choice("From eclipse .project files") { [Dir.pwd, true] } if Generate.hasEclipseProject
+ menu.choice("From Maven2 POM file") { ['pom.xml', false] } if File.exist?('pom.xml')
+ menu.choice("From directory structure") { [Dir.pwd, false] }
+ menu.choice("Cancel") {}
end
if source
- buildfile = raw_generate_buildfile(source)
+ buildfile = raw_generate_buildfile(source, fromEclipse)
[buildfile, File.dirname(buildfile)]
end
end
- def raw_generate_buildfile(source)
+ def raw_generate_buildfile(source, fromEclipse)
# We need rakefile to be known, for settings.build to be accessible.
@rakefile = File.expand_path(DEFAULT_BUILDFILES.first)
fail "Buildfile already exists" if File.exist?(@rakefile) && !(tty_output? && agree('Buildfile exists, overwrite?'))
- script = File.directory?(source) ? Generate.from_directory(source) : Generate.from_maven2_pom(source)
+ script = nil
+ if fromEclipse
+ script = Generate.from_eclipse(source)
+ elsif File.directory?(source)
+ script = Generate.from_directory(source)
+ else
+ script = Generate.from_maven2_pom(source)
+ end
File.open @rakefile, 'w' do |file|
file.puts script
end
Modified: buildr/trunk/lib/buildr/core/generate.rb
URL: http://svn.apache.org/viewvc/buildr/trunk/lib/buildr/core/generate.rb?rev=1389201&r1=1389200&r2=1389201&view=diff
==============================================================================
--- buildr/trunk/lib/buildr/core/generate.rb (original)
+++ buildr/trunk/lib/buildr/core/generate.rb Mon Sep 24 04:08:22 2012
@@ -20,7 +20,7 @@ module Buildr
script = nil
choose do |menu|
menu.header = "To use Buildr you need a buildfile. Do you want me to create one?"
-
+ menu.choice("From eclipse .project files") { script = Generate.from_eclipse(Dir.pwd).join("\n") } if has_eclipse_project?
menu.choice("From maven2 pom file") { script = Generate.from_maven2_pom('pom.xml').join("\n") } if File.exists?("pom.xml")
menu.choice("From directory structure") { script = Generate.from_directory(Dir.pwd).join("\n") }
menu.choice("Skip") { }
@@ -35,14 +35,40 @@ module Buildr
class << self
+ def compatibility_option(path)
+ # compile.options.target = '1.5'
+ end
+
+ def get_project_natures(projectFile)
+ return nil unless File.exists?(projectFile)
+ File.open(projectFile) do |f|
+ root = REXML::Document.new(f).root
+ return nil if root == nil
+ natures = root.elements.collect("natures/nature") { |n| n.text }
+ return natures if natures
+ end
+ return nil
+ end
+
+ def get_build_property(path, propertyName)
+ propertiesFile = File.join(path, 'build.properties')
+ return nil unless File.exists?(propertiesFile)
+ inhalt = Hash.from_java_properties(File.read(propertiesFile))
+ binDef = inhalt[propertyName]
+ end
+
+ def has_eclipse_project?
+ candidates = Dir.glob("**/.project")
+ return false if candidates.size == 0
+ candidates.find { |x| get_project_natures(x) }
+ return false
+ end
+
+
HEADER = "# Generated by Buildr #{Buildr::VERSION}, change to your liking\n\n"
- def from_directory(path = Dir.pwd, root = true)
- Dir.chdir(path) do
- name = File.basename(path)
- if root
- script = HEADER.split("\n")
- header = <<-EOF
+ def getEclipseBuildfileHeader(path, name)
+ x = <<-EOF
#{"require 'buildr/scala'\n" if Dir.glob(path + "/**/*.scala").size > 0}
#{"require 'buildr/groovy'\n" if Dir.glob(path + "/**/*.groovy").size > 0}
# Version number for this release
@@ -61,6 +87,121 @@ define "#{name}" do
project.group = GROUP
manifest["Implementation-Vendor"] = COPYRIGHT
EOF
+ return x
+ end
+
+ def setLayout(source=nil, output = nil)
+ script = ""
+ if source
+ source = source.sub(/\/$/, '') # remove trailing /
+ script += <<-EOF
+ layout[:source, :main, :java] = "#{source}"
+ layout[:source, :main, :scala] = "#{source}"
+EOF
+ end
+ if output
+ output = output.sub(/\/$/, '') # remove trailing /
+ script += <<-EOF
+ layout[:target, :main] = "#{output}"
+ layout[:target, :main, :java] = "#{output}"
+ layout[:target, :main, :scala] = "#{output}"
+EOF
+ end
+ return script
+ end
+
+ # tries to read as much information as needed at the moment from an existing Eclipse workspace
+ # Here are some links to the relevant information
+ # * http://help.eclipse.org/juno/index.jsp?topic=/org.eclipse.pde.doc.user/reference/pde_feature_generating_build.htm
+ # * http://wiki.eclipse.org/FAQ_What_is_the_plug-in_manifest_file_%28plugin.xml%29%3F
+ # * http://help.eclipse.org/juno/index.jsp?topic=/org.eclipse.platform.doc.isv/reference/misc/bundle_manifest.html
+ # * http://help.eclipse.org/juno/index.jsp?topic=/org.eclipse.platform.doc.isv/reference/misc/plugin_manifest.html
+ # * http://help.eclipse.org/juno/index.jsp?topic=/org.eclipse.pde.doc.user/tasks/pde_compilation_env.htm
+ def from_eclipse(path = Dir.pwd, root = true)
+ # We need two passes to be able to determine the dependencies correctly
+ Dir.chdir(path) do
+ name = File.basename(path)
+ dot_projects = []
+ mf = nil # avoid reloading manifest
+ if root
+ @@allProjects = Hash.new
+ @@topDir = File.expand_path(Dir.pwd)
+ script = HEADER.split("\n")
+ script << "require 'buildr/ide/eclipse'"
+ header = getEclipseBuildfileHeader(path, name)
+ script += header.split("\n")
+ script << " # you may see hints about which jars are missing and should resolve them correctly"
+ script << " # dependencies << 'junit should be commented out and replace by correct ARTIFACT definition. Eg"
+ script << " # dependencies << 'junit:junit:jar:3.8.2'"
+ script << setLayout('src', 'bin') # default values for eclipse
+ dot_projects = Dir.glob('**/.project').find_all { |dot_project| get_project_natures(dot_project) }
+ dot_projects.sort.each { |dot_project| from_eclipse(File.dirname(dot_project), false) } if dot_projects
+ else
+ # Skip fragments. Buildr cannot handle it without the help of buildr4osgi
+ return [""] if File.exists?('fragment.xml')
+ projectName = name
+ version = ""
+ mfName = File.join('META-INF', 'MANIFEST.MF')
+ if File.exists?(mfName)
+ mf = Packaging::Java::Manifest.parse(IO.readlines(mfName).join(''))
+ if mf.main['Bundle-SymbolicName']
+ projectName = mf.main['Bundle-SymbolicName'].split(';')[0]
+ bundleVersion = mf.main['Bundle-Version']
+ version = ", :version => \"#{bundleVersion}\"" unless "1.0.0".eql?(bundleVersion)
+ end
+ end
+ # in the first run we just want to know that we exist
+ unless @@allProjects[projectName]
+ @@allProjects[projectName] = Dir.pwd
+ return
+ end
+ base_dir = ""
+ unless File.join(@@topDir, projectName).eql?(File.expand_path(Dir.pwd))
+ base_dir = ", :base_dir => \"#{File.expand_path(Dir.pwd).sub(@@topDir+File::SEPARATOR, '')}\""
+ end
+ script = [%{define "#{projectName}"#{version}#{base_dir} do}]
+ end
+ natures = get_project_natures('.project')
+ if natures && natures.index('org.eclipse.pde.PluginNature')
+ script << " package(:jar)"
+ end
+ if mf && mf.main['Require-Bundle']
+ mf.main['Require-Bundle'].split(',').each do
+ |bundle|
+ requiredName = bundle.split(';')[0]
+ if @@allProjects.has_key?(requiredName)
+ script << " dependencies << projects(\"#{requiredName}\")"
+ else
+ script << " # dependencies << '#{requiredName}'"
+ end
+ end
+ end
+ script << " compile.with dependencies # Add more classpath dependencies" if Dir.glob(File.join('src', '**', '*.java')).size > 0
+ script << " resources" if File.exist?("rsc")
+ sourceProp = get_build_property('.', 'source..')
+ outputProp = get_build_property('.', 'output..')
+ if (sourceProp && !/src\/+/.match(sourceProp)) or (outputProp && !/bin\/+/.match(outputProp))
+ setLayout(sourceProp, outputProp) # default values are overridden in this project
+ end
+ unless dot_projects.empty?
+ script << ""
+ dot_projects.sort.each do |dot_project|
+ next if File.dirname(File.expand_path(dot_project)).eql?(File.expand_path(Dir.pwd))
+ next unless get_project_natures(dot_project)
+ script << from_eclipse(File.dirname(dot_project), false).flatten.map { |line| " " + line } << ""
+ end
+ end
+ script << "end\n\n"
+ script.flatten
+ end
+ end
+
+ def from_directory(path = Dir.pwd, root = true)
+ Dir.chdir(path) do
+ name = File.basename(path)
+ if root
+ script = HEADER.split("\n")
+ header = getEclipseBuildfileHeader(path, name)
script += header.split("\n")
else
script = [ %{define "#{name}" do} ]
Added: buildr/trunk/spec/core/generate_from_eclipse_spec.rb
URL: http://svn.apache.org/viewvc/buildr/trunk/spec/core/generate_from_eclipse_spec.rb?rev=1389201&view=auto
==============================================================================
--- buildr/trunk/spec/core/generate_from_eclipse_spec.rb (added)
+++ buildr/trunk/spec/core/generate_from_eclipse_spec.rb Mon Sep 24 04:08:22 2012
@@ -0,0 +1,280 @@
+# 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'))
+
+module EclipseHelper
+
+ def setupExample(group, projectName, options = {})
+ options[:symName] ? symName = options[:symName] :symName = File.basename(projectName)
+ requiredPlugins = nil
+ if options[:requires]
+ requiredPlugins = "Require-Bundle: #{options[:requires]};bundle-version=\"1.1.0\",\n"
+ end
+ write "#{group}/#{projectName}/META-INF/MANIFEST.MF", <<-MANIFEST
+Manifest-Version: 1.0
+Name: #{projectName}
+Bundle-Version: 1.1
+Specification-Title: "Examples for #{File.basename(projectName)}"
+Specification-Version: "1.0"
+Specification-Vendor: "Acme Corp.".
+Implementation-Title: "#{File.basename(projectName)}"
+Implementation-Version: "build57"
+Implementation-Vendor: "Acme Corp."
+Bundle-SymbolicName: #{symName}
+#{requiredPlugins}
+MANIFEST
+ write "#{group}/#{projectName}/.project", <<-DOT_PROJECT
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>#{File.basename(projectName)}</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
+DOT_PROJECT
+
+write "#{group}/#{projectName}/.classpath", <<-DOT_CLASSPATH
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/another.plugin"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
+DOT_CLASSPATH
+
+write "#{group}/#{projectName}/plugin.xml", <<-PLUGIN_XML
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.0"?>
+<plugin>
+<!--some comment
+-->
+</plugin>
+PLUGIN_XML
+ write "#{group}/#{projectName}/build.properties", <<-BUILD_PROPERTIES
+source.. = src/
+output.. = bin/
+javacDefaultEncoding.. = UTF-8
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ rsc/,
+BUILD_PROPERTIES
+ end
+end
+
+describe Buildr::Generate do
+ include EclipseHelper
+ describe 'it should find a single eclipse project' do
+ top = "top_#{__LINE__}"
+
+ before do
+ setupExample(top, 'single')
+ File.open(File.join(top, 'buildfile'), 'w') { |file| file.write Generate.from_eclipse(File.join(Dir.pwd, top)).join("\n") }
+ end
+
+ it 'should create a valid buildfile' do
+ define('first')
+ File.exists?(File.join(top, 'single', '.project')).should be_true
+ File.exists?(File.join(top, '.project')).should be_false
+ File.exists?('.project').should be_false
+ buildFile = File.join(top, 'buildfile')
+ file(buildFile).should exist
+ file(buildFile).should contain("GROUP = \"#{top}\"")
+ lambda { Buildr.application.run }.should_not raise_error
+ end
+
+ it "should not add project if the corresponding .project file is not an eclipse project" do
+ buildFile = File.join(top, 'buildfile')
+ FileUtils.rm(buildFile)
+ write File.join(top, 'myproject', '.project'), '# Dummy file'
+ File.open(File.join(top, 'buildfile'), 'w') { |file| file.write Generate.from_eclipse(File.join(Dir.pwd, top)).join("\n") }
+ file(buildFile).should exist
+ file(buildFile).should contain('define "single"')
+ file(buildFile).should_not contain('define "myproject"')
+ lambda { Buildr.application.run }.should_not raise_error
+ end
+
+ it 'should honour Bundle-Version in MANIFEST.MF' do
+ define('bundle_version')
+ buildFile = File.join(top, 'buildfile')
+ file(buildFile).should exist
+ file(buildFile).should contain('define "single"')
+ file(buildFile).should contain('define "single", :version => "1.1"')
+ lambda { Buildr.application.run }.should_not raise_error
+ end
+
+ it "should pass source in build.properties to layout[:source, :main, :java] and layout[:source, :main, :scala]" do
+ define('layout_source')
+ buildFile = File.join(top, 'buildfile')
+ file(buildFile).should exist
+ file(buildFile).should contain('define')
+ file(buildFile).should contain('define "single"')
+ file(buildFile).should contain('layout[:source, :main, :java]')
+ file(buildFile).should contain('layout[:source, :main, :scala]')
+ lambda { Buildr.application.run }.should_not raise_error
+ end
+
+ it "should pass output in build.properties to layout[:target, :main], etc" do
+ define('layout_target')
+ buildFile = File.join(top, 'buildfile')
+ file(buildFile).should exist
+ file(buildFile).should contain('define')
+ file(buildFile).should contain('define "single"')
+ file(buildFile).should contain('layout[:target, :main]')
+ file(buildFile).should contain('layout[:target, :main, :java]')
+ file(buildFile).should contain('layout[:target, :main, :scala]')
+ lambda { Buildr.application.run }.should_not raise_error
+ end
+
+ it "should package an eclipse plugin" do
+ define('layout_target')
+ buildFile = File.join(top, 'buildfile')
+ file(buildFile).should exist
+ file(buildFile).should contain('define')
+ file(buildFile).should contain('package(:jar)')
+ lambda { Buildr.application.run }.should_not raise_error
+ end
+
+ end
+
+ describe 'it should check for a SymbolicName in MANIFEST.MF' do
+ top = "top_#{__LINE__}"
+ before do
+ setupExample(top, 'single', { :symName => 'singleSymbolicName'} )
+ File.open(File.join(top, 'buildfile'), 'w') { |file| file.write Generate.from_eclipse(File.join(Dir.pwd, top)).join("\n") }
+ end
+ it "should set the project name to the SymbolicName from the MANIFEST.MF" do
+ buildFile = File.join(top, 'buildfile')
+ file(buildFile).should exist
+ file(buildFile).should contain('define "singleSymbolicName"')
+ lambda { Buildr.application.run }.should_not raise_error
+ end
+ end
+
+ describe 'it should accecpt singleton SymbolicName in MANIFEST.MF' do
+ top = "top_#{__LINE__}"
+ before do
+ setupExample(top, 'single', { :symName => 'singleSymbolicName;singleton:=true'})
+ File.open(File.join(top, 'buildfile'), 'w') { |file| file.write Generate.from_eclipse(File.join(Dir.pwd, top)).join("\n") }
+ end
+
+ it "should not get confused if SymbolicName in MANIFEST.MF is a singleton:=true" do
+ buildFile = File.join(top, 'buildfile')
+ file(buildFile).should exist
+ file(buildFile).should contain('define "singleSymbolicName"')
+ lambda { Buildr.application.run }.should_not raise_error
+ end
+ end
+
+ describe 'it should find an eclipse project deep' do
+ top = "top_#{__LINE__}"
+ before do
+ setupExample(top, 'nested/single')
+ File.open(File.join(top, 'buildfile'), 'w') { |file| file.write Generate.from_eclipse(File.join(Dir.pwd, top)).join("\n") }
+ end
+
+ it 'should create a valid buildfile for a nested project' do
+ setupExample(top, 'single')
+ define('nested/second')
+ File.exists?(File.join(top, 'single', '.project')).should be_true
+ File.exists?(File.join(top, '.project')).should be_false
+ File.exists?('.project').should be_false
+ buildFile = File.join(top, 'buildfile')
+ file(buildFile).should contain("GROUP = \"#{top}\"")
+ file(buildFile).should contain('define "single"')
+ lambda { Buildr.application.run }.should_not raise_error
+ end
+
+ it "should correct the path for a nested plugin" do
+ define('base_dir')
+ buildFile = File.join(top, 'buildfile')
+ file(buildFile).should exist
+ file(buildFile).should contain('define "single"')
+ file(buildFile).should contain('define "single", :version => "1.1", :base_dir => "nested/single"')
+ lambda { Buildr.application.run }.should_not raise_error
+ end
+
+ end
+
+ describe 'it should detect dependencies between projects' do
+ top = "top_#{__LINE__}"
+ before do
+ setupExample(top, 'first')
+ write(File.join(top, 'first', 'src','org','demo','Demo.java'))
+ write(File.join(top, 'first', 'rsc','aResource.txt'))
+ setupExample(top, 'second', { :requires => 'first'} )
+ write(File.join(top, 'second', 'src','org','second','Demo.java'))
+ setupExample(top, 'aFragment', { :fragment_host => 'second'})
+ write(File.join(top, 'aFragment', 'fragment.xml'))
+ File.open(File.join(top, 'buildfile'), 'w') { |file| file.write Generate.from_eclipse(File.join(Dir.pwd, top)).join("\n") }
+ end
+
+ it 'should add "compile.with dependencies" in MANIFEST.MF' do
+ define('base_dir')
+ buildFile = File.join(top, 'buildfile')
+ file(buildFile).should exist
+ file(buildFile).should contain('compile.with dependencies')
+ file(buildFile).should contain('resources')
+ lambda { Buildr.application.run }.should_not raise_error
+ end
+ #dependencies << projects("first")
+
+ it 'should honour Require-Bundle in MANIFEST.MF' do
+ define('base_dir')
+ buildFile = File.join(top, 'buildfile')
+ file(buildFile).should exist
+ file(buildFile).should contain(/define "second"/)
+ file(buildFile).should contain( /dependencies << projects\("first"\)/)
+ file(buildFile).should contain(/define "second".*do.*dependencies << projects\("first"\).* end/m)
+ lambda { Buildr.application.run }.should_not raise_error
+ end
+
+ # Fragments are only supported with buildr4osi which is not (yet?) part of buildr
+ it 'should skip fragments.' do
+ define('base_dir')
+ buildFile = File.join(top, 'buildfile')
+ file(buildFile).should exist
+# system("cat #{buildFile}") # if $VERBOSE
+ file(buildFile).should contain('define "first"')
+ lambda { Buildr.application.run }.should_not raise_error
+ end
+
+ end
+
+end