org.gradle.buildinit.plugins.internal.maven.Maven2Gradle.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-api Show documentation
Show all versions of gradle-api Show documentation
Gradle 6.9.1 API redistribution.
/*
* Copyright 2012 the original author or authors.
*
* Licensed 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.
*/
package org.gradle.buildinit.plugins.internal.maven
import groovy.util.slurpersupport.GPathResult
import org.apache.maven.project.MavenProject
import org.gradle.api.artifacts.ModuleIdentifier
import org.gradle.api.internal.artifacts.DefaultModuleIdentifier
import org.gradle.api.logging.Logger
import org.gradle.api.logging.Logging
import org.gradle.util.RelativePathUtil
/**
* This script obtains the effective POM of the current project, reads its dependencies
* and generates build.gradle scripts. It also generates settings.gradle for multimodule builds.
*
* It currently supports both single-module and multi-module POMs, inheritance, dependency management, properties - everything.
*/
class Maven2Gradle {
def dependentWars = []
def qualifiedNames
def workingDir
def effectivePom
Logger logger = Logging.getLogger(getClass())
private Set mavenProjects
Maven2Gradle(Set mavenProjects, File workingDir) {
assert !mavenProjects.empty: "No Maven projects provided."
this.mavenProjects = mavenProjects
this.workingDir = workingDir.canonicalFile;
}
def convert() {
//For now we're building the effective POM XML from the model
//and then we parse the XML using slurper.
//This way we don't have to rewrite the Maven2Gradle just yet.
//Maven2Gradle should be rewritten (with coverage) so that feeds of the maven object model, not XML.
def effectivePom = new MavenProjectXmlWriter().toXml(mavenProjects)
//use the Groovy XmlSlurper library to parse the text string
this.effectivePom = new XmlSlurper().parseText(effectivePom)
String build
def multimodule = this.effectivePom.name() == "projects"
if (multimodule) {
def allProjects = this.effectivePom.project
qualifiedNames = generateSettings(workingDir.getName(), allProjects[0].artifactId, allProjects);
def dependencies = [:];
allProjects.each { project ->
dependencies[project.artifactId.text()] = getDependencies(project, allProjects)
}
def commonDeps = dependencies.get(allProjects[0].artifactId.text())
build = """allprojects {
apply plugin: 'maven'
${getArtifactData(allProjects[0])}
}
subprojects {
apply plugin: 'java'
${compilerSettings(allProjects[0], " ")}
${packageSources(allProjects[0])}
${getRepositoriesForProjects(allProjects)}
${globalExclusions(allProjects[0])}
${commonDeps}
${testNg(commonDeps)}
}
"""
modules(allProjects, false).each { module ->
def id = module.artifactId.text()
String moduleDependencies = dependencies.get(id)
boolean warPack = module.packaging.text().equals("war")
def hasDependencies = !(moduleDependencies == null || moduleDependencies.length() == 0)
File submoduleBuildFile = new File(projectDir(module), 'build.gradle')
def group = ''
if (module.groupId != allProjects[0].groupId) {
group = "group = '${module.groupId}'"
}
String moduleBuild = "${group}\n"
if (warPack) {
moduleBuild += """apply plugin: 'war'
"""
if (dependentWars.any { project ->
project.groupId.text() == module.groupId.text() &&
project.artifactId.text() == id
}) {
moduleBuild += """jar.enabled = true
"""
}
}
if (module.name) {
moduleBuild += "description = '${module.name}'\n"
}
if (hasDependencies) {
moduleBuild += moduleDependencies
}
moduleBuild += testNg(moduleDependencies)
if (submoduleBuildFile.exists()) {
submoduleBuildFile.renameTo(new File(projectDir(module), "build.gradle.bak"))
}
def packageTests = packageTests(module);
if (packageTests) {
moduleBuild += packageTests;
}
logger.debug("writing build.gradle file at ${submoduleBuildFile.absolutePath}");
submoduleBuildFile.text = moduleBuild
}
//TODO deployment
} else {//simple
build = """apply plugin: 'java'
apply plugin: 'maven'
${getArtifactData(this.effectivePom)}
description = \"""${this.effectivePom.name}\"""
${compilerSettings(this.effectivePom, "")}
${globalExclusions(this.effectivePom)}
"""
Set repoSet = new LinkedHashSet();
getRepositoriesForModule(this.effectivePom, repoSet)
String repos = """repositories {
$localRepoUri
"""
repoSet.each {
repos = "${repos} ${it}\n"
}
build += "${repos}}\n"
String dependencies = getDependencies(this.effectivePom, null)
build += dependencies
String packageTests = packageTests(this.effectivePom);
if (packageTests) {
build += '//packaging tests'
build += packageTests;
}
generateSettings(workingDir.getName(), this.effectivePom.artifactId, null);
}
def buildFile = new File(workingDir, "build.gradle")
if (buildFile.exists()) {
buildFile.renameTo(new File(workingDir, "build.gradle.bak"))
}
logger.debug("writing build.gradle file at ${buildFile.absolutePath}");
buildFile.text = build
}
def globalExclusions = { project ->
def exclusions = ''
def enforcerPlugin = plugin('maven-enforcer-plugin', project)
def enforceGoal = pluginGoal('enforce', enforcerPlugin)
if (enforceGoal) {
exclusions += 'configurations.all {\n'
enforceGoal.configuration.rules.bannedDependencies.excludes.childNodes().each {
def tokens = it.text().tokenize(':')
exclusions += "it.exclude group: '${tokens[0]}'"
if (tokens.size() > 1 && tokens[1] != '*') {
exclusions += ", module: '${tokens[1]}'"
}
exclusions += '\n'
}
}
exclusions = exclusions ? exclusions += '}' : exclusions
exclusions
}
def testNg = { moduleDependencies ->
if (moduleDependencies.contains('testng')) {
"""test.useTestNG()
"""
} else {
''
}
}
def modules = { allProjects, incReactors ->
return allProjects.findAll { project ->
def parentIsPartOfThisBuild = allProjects.find { proj ->
proj.artifactId == project.parent.artifactId && proj.groupId == project.parent.groupId
}
project.parent.text().length() > 0 && parentIsPartOfThisBuild && (incReactors || project.packaging.text() != 'pom')
}
}
def fqn = { project, allProjects ->
def buffer = new StringBuilder()
generateFqn(project, allProjects, buffer)
return buffer.toString()
}
private generateFqn(GPathResult project, GPathResult allProjects, StringBuilder buffer) {
def artifactId = project.artifactId.text()
buffer.insert(0, ":${artifactId}")
//we don't need the top-level parent in gradle, so we stop on it
if (getModuleIdentifier(project.parent) != getModuleIdentifier(allProjects[0])) {
def parentInBuild = allProjects.find { proj ->
getModuleIdentifier(proj) == getModuleIdentifier(project.parent)
}
if (parentInBuild) {
generateFqn(parentInBuild, allProjects, buffer)
}
}
}
private ModuleIdentifier getModuleIdentifier(GPathResult project) {
def artifactId = project.artifactId.text()
def groupId = project.groupId ? project.groupId.text() : project.parent.groupId.text()
return new DefaultModuleIdentifier(groupId, artifactId)
}
def localRepoUri = {
"""mavenLocal()
"""
}
private String getArtifactData(project) {
return """group = '$project.groupId'
version = '$project.version'""";
}
private String getRepositoriesForProjects(projects) {
String repos = """repositories {
${localRepoUri()}
"""
def repoSet = new LinkedHashSet();
projects.each {
getRepositoriesForModule(it, repoSet)
}
repoSet.each {
repos = "${repos}${it}\n"
}
repos = "${repos} }\n"
return repos
}
private void getRepositoriesForModule(module, repoSet) {
module.repositories.repository.each {
repoSet.add(" maven { url \"${it.url}\" }")
}
//No need to include plugin repos - who cares about maven plugins?
}
private String getDependencies(project, allProjects) {
// use GPath to navigate the object hierarchy and retrieve the collection of dependency nodes.
def dependencies = project.dependencies.dependency
def war = project.packaging == "war"
def compileTimeScope = []
def runTimeScope = []
def testScope = []
def providedScope = []
def systemScope = []
//cleanup duplicates from parent
// using Groovy Looping and mapping a Groovy Closure to each element, we collect together all
// the dependency nodes into corresponding collections depending on their scope value.
dependencies.each() {
if (!duplicateDependency(it, project, allProjects)) {
def scope = (elementHasText(it.scope)) ? it.scope : "compile"
switch (scope) {
case "compile":
compileTimeScope.add(it)
break
case "test":
testScope.add(it)
break
case "provided":
providedScope.add(it)
break
case "runtime":
runTimeScope.add(it)
break
case "system":
systemScope.add(it)
break
}
}
}
/**
* print function then checks the exclusions node to see if it exists, if
* so it branches off, otherwise we call our simple print function
*/
def createGradleDep = { String scope, StringBuilder sb, mavenDependency ->
def projectDep = allProjects.find { prj ->
return prj.artifactId.text() == mavenDependency.artifactId.text() && prj.groupId.text() == mavenDependency.groupId.text()
}
if (projectDep) {
createProjectDependency(projectDep, sb, scope, allProjects)
} else {
if (!war && scope == 'providedCompile') {
scope = 'compileOnly'
}
def exclusions = mavenDependency.exclusions.exclusion
if (exclusions.size() > 0) {
createComplexDependency(mavenDependency, sb, scope)
} else {
createBasicDependency(mavenDependency, sb, scope)
}
}
}
StringBuilder build = new StringBuilder()
if (!compileTimeScope.isEmpty() || !runTimeScope.isEmpty() || !testScope.isEmpty() || !providedScope.isEmpty() || !systemScope.isEmpty()) {
build.append("dependencies {").append("\n")
// for each collection, one at a time, we take each element and call our print function
if (!compileTimeScope.isEmpty()) {
compileTimeScope.each() { createGradleDep("compile", build, it) }
}
if (!runTimeScope.isEmpty()) {
runTimeScope.each() { createGradleDep("runtime", build, it) }
}
if (!testScope.isEmpty()) {
testScope.each() { createGradleDep("testCompile", build, it) }
}
if (!providedScope.isEmpty()) {
providedScope.each() { createGradleDep("providedCompile", build, it) }
}
if (!systemScope.isEmpty()) {
systemScope.each() { createGradleDep("system", build, it) }
}
build.append("}\n")
}
return build.toString();
}
def compilerSettings = { project, indent ->
def configuration = plugin('maven-compiler-plugin', project).configuration
def settings = new StringBuilder()
settings.append "sourceCompatibility = ${configuration.source.text() ?: '1.5'}\n"
settings.append "${indent}targetCompatibility = ${configuration.target.text() ?: '1.5'}\n"
def encoding = project.properties.'project.build.sourceEncoding'.text()
if (encoding) {
settings.append "${indent}tasks.withType(JavaCompile) {\n"
settings.append "${indent}\toptions.encoding = '${encoding}'\n"
settings.append "${indent}}\n"
}
return settings
}
def plugin = { artifactId, project ->
project.build.plugins.plugin.find { pluginTag ->
pluginTag.artifactId.text() == artifactId
}
}
def pluginGoal = { goalName, plugin ->
plugin.executions.execution.find { exec ->
exec.goals.goal.find { gl ->
gl.text().startsWith(goalName)
}
}
}
def packSources = { sourceSets ->
def sourceSetStr = ''
if (!sourceSets.empty) {
sourceSetStr = """task packageSources(type: Jar) {
classifier = 'sources'
"""
sourceSets.each { sourceSet ->
sourceSetStr += """from sourceSets.${sourceSet}.allSource
"""
}
sourceSetStr += """
}
artifacts.archives packageSources"""
}
sourceSetStr
}
def packageTests = { project ->
def jarPlugin = plugin('maven-jar-plugin', project)
pluginGoal('test-jar', jarPlugin) ? """
task packageTests(type: Jar) {
from sourceSets.test.output
classifier = 'tests'
}
artifacts.archives packageTests
""" : ''
}
def packageSources = { project ->
def sourcePlugin = plugin('maven-source-plugin', project)
def sourceSets = []
if (sourcePlugin) {
if (pluginGoal('jar', sourcePlugin)) {
sourceSets += 'main'
} else if (pluginGoal('test-jar', sourcePlugin)) {
sourceSets += 'test'
}
}
packSources(sourceSets)
}
private boolean duplicateDependency(dependency, project, allProjects) {
def parentTag = project.parent
if (allProjects == null || parentTag.isEmpty()) {//simple project or no parent
return false;
} else {
def parent = allProjects.find {
it.groupId.equals(parentTag.groupId) && it.artifactId.equals(parentTag.artifactId)
}
def duplicate = parent.dependencies.dependency.any {
it.groupId.equals(dependency.groupId) && it.artifactId.equals(dependency.artifactId)
}
if (duplicate) {
return true;
} else {
duplicateDependency(dependency, parent, allProjects)
}
}
}
def artifactId = { File dir ->
return new XmlSlurper().parse(new File(dir, 'pom.xml')).artifactId.text()
}
def projectDir = { project ->
return new File(project.build.directory.text()).parentFile
}
private def generateSettings(def dirName, def mvnProjectName, def projects) {
def qualifiedNames = [:]
def projectName = "";
if (dirName != mvnProjectName) {
projectName = """rootProject.name = '${mvnProjectName}'
"""
}
def modulePoms = modules(projects, true)
List moduleNames = new ArrayList();
def artifactIdToDir = [:]
if (projects) {
modulePoms.each { project ->
def fqn = fqn(project, projects)
File projectDirectory = projectDir(project)
// don't add project if it's the rootproject
if (!workingDir.equals(projectDirectory)) {
artifactIdToDir[fqn] = RelativePathUtil.relativePath(workingDir, projectDirectory)
moduleNames.add(fqn)
}
}
}
File settingsFile = new File(workingDir, "settings.gradle")
if (settingsFile.exists()) {
settingsFile.renameTo(new File(workingDir, "settings.gradle.bak"))
}
StringBuffer settingsText = new StringBuffer(projectName)
if (moduleNames.size() > 0) {
moduleNames.each {
settingsText.append("include '$it'\n")
}
}
artifactIdToDir.each { entry ->
settingsText.append("""
project('$entry.key').projectDir = """ + '"$rootDir/' + "${entry.value}" + '" as File')
}
settingsFile.text = settingsText.toString()
return qualifiedNames
}
/**
* complex print statement does one extra task which is
* iterate over each node and print out the artifact id.
* It also provides review comments for the user.
*/
private def createComplexDependency(it, build, scope) {
build.append(" ${scope}(${contructSignature(it)}) {\n")
it.exclusions.exclusion.each() {
build.append("exclude(module: '${it.artifactId}')\n")
}
build.append(" }\n")
}
/**
* Print out the basic form og gradle dependency
*/
private def createBasicDependency(mavenDependency, build, String scope) {
def classifier = contructSignature(mavenDependency)
build.append(" ${scope} ${classifier}\n")
}
/**
* Print out the basic form of gradle dependency
*/
private def createProjectDependency(projectDep, build, String scope, allProjects) {
if (projectDep.packaging.text() == 'war') {
dependentWars += projectDep
}
build.append(" ${scope} project('${fqn(projectDep, allProjects)}')\n")
}
/**
* Construct and return the signature of a dependency, including its version and
* classifier if it exists
*/
private def contructSignature(mavenDependency) {
def gradelDep = "group: '${mavenDependency.groupId.text()}', name: '${mavenDependency.artifactId.text()}', version:'${mavenDependency?.version?.text()}'"
def classifier = elementHasText(mavenDependency.classifier) ? gradelDep + ", classifier:'" + mavenDependency.classifier.text().trim() + "'" : gradelDep
return classifier
}
/**
* Check to see if the selected node has content
*/
private boolean elementHasText(it) {
return it.text().length() != 0
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy