Issue Details (XML | Word | Printable)

Key: GRADLE-154
Type: Wish Wish
Status: Open Open
Priority: Major Major
Assignee: Hans Dockter
Reporter: Antony Stubbs
Votes: 1
Watchers: 5
Operations

If you were logged in you would be able to see more operations.
Gradle

Create a utility to easily translate Maven dependency lists to Gradle dependency lists - XSLT?

Created: 09/Jul/08 08:28 PM   Updated: 30/Nov/09 01:54 PM
Return to search
Component/s: dependencies
Affects Version/s: None
Fix Version/s: 0.9

Time Tracking:
Original Estimate: 2 hours
Original Estimate - 2 hours
Remaining Estimate: 2 hours
Remaining Estimate - 2 hours
Time Spent: Not Specified
Time Spent - Not Specified

File Attachments: 1. File dExtractor.groovy (4 kB)
2. File maven dependency translator.groovy (1.0 kB)
3. File MavenDependencyExtractor.groovy (6 kB)
4. XML File pom.xml (12 kB)



 Description  « Hide

Perhaps this could initially easily be done with an XSLT sheet?
It would do two things:
speed up migration from larger Maven projects to Gradle
More easily allow people to try out Gradle on their existing projects



Antony Stubbs added a comment - 10/Jul/08 06:31 AM

ha! who needs XSLT when you've got Groovy!

A simple Groovy script to start you off with the Gradle formatting of dependencies. Just paste in your dependecies section into the script and run. I recommend the Groovy console.

translates:
<dependencies>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>1.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.4.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.4.3</version>
</dependency>
<!-- work around for jetty commons logging issue -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl104-over-slf4j</artifactId>
<version>1.4.3</version>
</dependency>
</dependencies>

to:
compile: "joda-time:joda-time:1.5"
compile: "org.slf4j:slf4j-api:1.4.3"
compile: "org.slf4j:slf4j-log4j12:1.4.3"
compile: "org.slf4j:jcl104-over-slf4j:1.4.3"


Hans Dockter added a comment - 10/Jul/08 06:44 AM

Very cool.

If we add two things to this we can ship it with 0.3.

  • Mapping the Maven scope to a Gradle configuration
  • Taking the Maven classifier into account. For example "org:testng:testng:1.0:jdk15"

If this could also be wrapped in a unix and windows script which runs against a pom.xml in the current dir that would be awesome.

End of the wishlist


Antony Stubbs added a comment - 10/Jul/08 06:57 AM

Also need to support exclusions? Or is the dep management too different?


Hans Dockter added a comment - 10/Jul/08 07:32 AM

Exclusions would be important. See user's guide: 12.2.3


Antony Stubbs added a comment - 10/Jul/08 09:01 AM

done!

ok - getting more complicated here

This one groups together scopes and adds on classifiers if they are found
It also runs from the command lie and analyses a pom.xml in the same directory

The layout of the scopes could be tweeked-but i'm not yet familiar with how gradle handles them anyway - or what the various scope equivalents are.

excludes are just a test and slightly more complicated formatting away!

I have also included a pretty messed up pom.xml to show it is pretty tolerant.

usage is - put it in your project root ( same as your pom.xml ) and type:
groovy dExtractor.groovy
you'll then get a dump of your deps, grouped into scopes.


Hans Dockter added a comment - 10/Jul/08 09:21 AM

Great. I gonna have a look the code soon.

Scope Mapping:

Maven:Gradle
compile:compile
runtime:runtime
test:testCompile
provided:provided (not implemented yet in Gradle but soon)


Antony Stubbs added a comment - 10/Jul/08 04:42 PM

Done!

Added exclusion support and corrected scope mapping.

I'm getting faster with this groovy stuff

The test pom.xml included produces this output (please let me know if it's wrong):

output
Working path:C:\workspaces\mavenDepConvert\src\.
compile: "c3p0:c3p0:0.9.1.2"
compile: "com.fonterra.tams:msg-classes:1.0.0"
compile: "oracle.jdbc.driver:OracleDriver:10.2.0.3"
addDependency(['compile'], "org.apache.struts:struts-core:1.3.8") {
   exclude(module: 'commons-logging')
}
addDependency(['compile'], "org.apache.struts:struts-extras:1.3.8") {
   exclude(module: 'commons-logging')
}
addDependency(['compile'], "org.apache.struts:struts-taglib:1.3.8") {
   exclude(module: 'commons-logging')
}
addDependency(['compile'], "org.apache.ibatis:ibatis-sqlmap:2.3.0") {
   exclude(module: 'commons-logging')
}
addDependency(['compile'], "org.springframework:spring-web:2.5") {
   exclude(module: 'commons-logging')
}
addDependency(['compile'], "org.springframework:spring-beans:2.5") {
   exclude(module: 'commons-logging')
}
addDependency(['compile'], "org.springframework:spring-jdbc:2.5") {
   exclude(module: 'commons-logging')
}
addDependency(['compile'], "org.springframework:spring-orm:2.5") {
   exclude(module: 'commons-logging')
}
addDependency(['compile'], "org.hibernate:hibernate:3.2.5.ga") {
   exclude(module: 'commons-logging')
}
compile: "commons-lang:commons-lang:2.3"
compile: "javax.xml.bind:jaxb-api:2.1"
compile: "opensymphony:sitemesh:2.3"
addDependency(['compile'], "displaytag:displaytag:1.1") {
   exclude(module: 'commons-logging')
}
compile: "javax.jms:jms:1.1"
compile: "joda-time:joda-time:1.5"
compile: "org.slf4j:slf4j-api:1.4.3"
compile: "org.slf4j:slf4j-log4j12:1.4.3"
compile: "org.slf4j:jcl104-over-slf4j:1.4.3"
compile: "log4j:log4j:1.2.14"
compile: "org.apache.commons:commons-io:1.3.2"
compile: "jscience:jscience:4.3.1"
compile: "org.google:google-collect:0.20071022-BETA"
compile: "taglibs:standard:1.1.2"
runtime: "com.sun.xml.bind:jaxb-impl:2.0.3"
runtime: "cglib:cglib:2.1_3"
testCompile: "org.easymock:easymock:2.3"
testCompile: "org.easymock:easymockclassextension:2.2.2:jdk14"
addDependency(['testCompile'], "org.dbunit:dbunit:2.2") {
   exclude(module: 'commons-logging')
}
testCompile: "junit:junit:4.4"
addDependency(['testCompile'], "org.openqa.selenium.client-drivers:selenium-java-client-driver:${selenium-version}") {
   exclude(module: 'commons-logging')
   exclude(module: 'selenium-server')
   exclude(module: 'selenium-server-coreless')
}
addDependency(['testCompile'], "org.openqa.selenium.server:selenium-server:${selenium-version}") {
   exclude(module: 'commons-logging')
}
provided: "javax.servlet:jstl:1.1.2"
provided: "javax.servlet:servlet-api:2.5"
provided: "javax.servlet:jsp-api:2.0"
system: "com.ibm:WebSphere-Runtime:6.1.0.13"}}

Antony Stubbs added a comment - 11/Jul/08 08:23 PM

Added license (correct one?) and comments.


Antony Stubbs added a comment - 11/Jul/08 09:09 PM

Added gradle formated project group and version (what else can we add? - where is a reference similar to the maven pom reference with all the things we can optionally conifgure?)
updated test pom.xml


Antony Stubbs added a comment - 11/Jul/08 09:11 PM
$ groovy ../../../mavenDepConvert/src/converter.groovy
Working path:c:\workspaces\jbossMavenPlugin\jboss\jboss-server-manager\.

Project settings:
project.group = 'org.jboss.jbossas'
project.version = 'jboss-server-manager

Dependency information:
compile: "org.apache.commons:commons-io:1.3.2"

Antony Stubbs added a comment - 11/Jul/08 09:12 PM

typo


Antony Stubbs added a comment - 12/Jul/08 08:48 AM

omg - did i have my eyes shut when i wrote that?
bug fix - project.version = .., now uses version not artifactId


Hans Dockter added a comment - 12/Jul/08 11:21 AM

version = 'jboss-server-manager' will do. Any assignment gets automatically delegated to the project object.

To provide the user a better out of the box experience it would be cool to have start scripts for this, which adds the groovy jar which is shipped with Gradle to the classpath. That way the user does not need to have Gradle installed. And we have a defined Groovy version we run against.

Could you imagine to do this? If not I'm also happy to do this.


Hans Dockter added a comment - 12/Jul/08 11:22 AM

We use launch4j to provide windows start scripts. This is for example used in the build.gradle file of Gradle.


Hans Dockter added a comment - 12/Jul/08 02:31 PM

Some more details:

Your transformer code would live in a new package in the gradle-core src called for example org.gradle.mvn2gradle. Our build would generate a jar just out of this package. Our build would also generate two scripts, mvn2gradle and mvn2gradle.exe for starting the command under *nix and windows. Those scripts would be part of the Gradle bin directory. For this your script would need to move into a class. This class might be wrapped by a Mvn2GradleMain class for argument processing (I'm sure eventually we will have some). Last but not least it would be important to have a test.

Does this makes sense?


Antony Stubbs added a comment - 13/Jul/08 06:09 AM

Yup - sweet as. Is this already done anywhere yet, that I could use as an example?


Hans Dockter added a comment - 13/Jul/08 06:49 AM

We do the same for the Gradle start scripts. Have a look in the build.gradle of Gradle.

StartScriptsGenerator.generate("$archivesBaseName-${version}.jar", explodedDistBinDir, archivesBaseName) This is were we generate the *nix start script. StartScriptsGenerator is a class from buildSrc.

This is were we create the windows exe:

logger.info('Generate launch4j windows exe.')
        String launch4jDistName = "launch4j-" + launch4jVersion
        createLaunch4j(explodedDistLaunch4jLibDir, launch4jDistName)
        try {
            ant.taskdef(
                name: "launch4j",
                    classname: "net.sf.launch4j.ant.Launch4jTask",
                    classpath: "$buildDir/$launch4jDistName/launch4j.jar:$buildDir/$launch4jDistName/lib/xstream.jar")
            ant.launch4j() {
                config(headerType: "console", outfile: "$explodedDistBinDir/gradle.exe",
                        dontWrapJar: "true", jarPath: "../lib/" + archive_jar.archiveName) {
                    jre(minVersion: "1.5.0", jdkPreference: 'jdkOnly')
                }
            }
        } catch (Exception e) {
            logger.warning("The windows start exe could not be generated. Possibly you run the build on a machine with an OS which is not Linux, Mac OS X or Windows.")
            logger.warning(e.getMessage());
        }

Baruch Sadogursky added a comment - 23/Nov/09 02:02 PM - edited

New version - MavenDependencyExtractor.groovy

Added support for multi-module POMs, inheritance, dependency management, properties - everything.

Uses maven-help-plugin, so have it in local repo or have an Internet connection

Enjoy.

P.S. "-verbose" (w/o quotes) to see the output of maven-help-plugin execution


Hans Dockter added a comment - 30/Nov/09 08:26 AM

Thanks Baruch, this is excellent stuff, Baruch. That script should be either shipped with Gradle 0.9 or made available in a prominent way. I will start a discussion on the dev list on that soon and put you in cc. Maven 3 should provide additional means of integrating Maven projects into Gradle, Maven 3 is supposed to be very easy to embedd. What would be very nice, is to include a pom.xml at runtime. Either just for the dependencies or as a complete project. The latter could wrap Maven goals and lifecycle phases as Gradle tasks. Have you had a look at Maven 3?


Baruch Sadogursky added a comment - 30/Nov/09 08:44 AM

Hans, I am not sure I understood what do you mean by "include a pom.xml at runtime either just for the dependencies or as a complete project".
Considering Maven3 - yap, looks like it will be very simple to embed it and to get all the information about build from it.

Anyway, we just had the JavaEdge09 conference (biggest annual Java conference in Israel) and I made a talk about modern build tools, featuring Gradle, of course. It included a demo on migrating from Maven2 to Gradle (that's what I needed the script for).
This is the presentation - http://prezi.com/ngwwf1wcfn7n/
I am planing to record the whole talk, or at least to blog about the demo details, but I don't know when I'll get into it.


Hans Dockter added a comment - 30/Nov/09 10:24 AM

Hi Baruch,

just reading my very cryptic comment (I have written that in a rush). Apologies for that.

With your script you can transform a maven pom.xml in a build.gradle file. Which is very helpful and might be exactly what people want if they want to migrate to Gradle.

But there are other scenarios where people want to stick with the pom.xml. For example if you want to integrate an active Maven project in your multi-project Gradle build. Our vision for Gradle is also to be a build integration tool. I have seen a couple of situations where people had a mix of Maven and Ant builds and they wanted to have a single multi-project build for them. They ended up using CI tools for that. Our idea is that you can use Gradle to orchestrate any kind of build. With Ant builds this is already possible.

For Ant projects you can already say in build.gradle.

ant.import('build.xml')

It would be very handy if you could do:

maven.importDependencies('pom.xml') or maven.import('pom.xml')

The first would add dynamically the dependencies of the pom.xml to the Gradle project object. The latter would to the same plus creating a number of Gradle tasks that wrap Maven lifecycle phases and goals. Have a look at the Ant import described in the user's guide. That way you can not just integrate Maven projects but also add functionality to them from Gradle.

Does that make sense?


Baruch Sadogursky added a comment - 30/Nov/09 01:54 PM

Oh, yeah. Lot's of sense. Frankly, I have expected this functionality to exist in a first place, and turned to this script only as a hack when didn't find one. If such functionality will be present in Gradle that would be a huge selling point.

Meanwhile, I hacked the other direction too - in order to maintain pom.xml dependencies (for IntelliJ) I use the Gradle's Maven plugin to generate pom and then copy it (inside the build) to the root directory. Then I have my build in Gradle, and my IntelliJ happy with up-to-date dependencies in pom.xml