org.gradle.buildinit.plugins.internal.maven.Maven2Gradle 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 org.apache.commons.lang.StringUtils;
import org.apache.maven.model.Exclusion;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginExecution;
import org.apache.maven.model.Repository;
import org.apache.maven.project.MavenProject;
import org.apache.maven.repository.RepositorySystem;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.gradle.api.JavaVersion;
import org.gradle.api.artifacts.ModuleIdentifier;
import org.gradle.api.file.Directory;
import org.gradle.api.artifacts.dsl.RepositoryHandler;
import org.gradle.api.internal.artifacts.DefaultModuleIdentifier;
import org.gradle.buildinit.plugins.internal.BuildScriptBuilder;
import org.gradle.buildinit.plugins.internal.BuildScriptBuilderFactory;
import org.gradle.buildinit.plugins.internal.DependenciesBuilder;
import org.gradle.buildinit.plugins.internal.ScriptBlockBuilder;
import org.gradle.buildinit.plugins.internal.modifiers.BuildInitDsl;
import org.gradle.util.RelativePathUtil;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
/**
* This script obtains the effective POM of the current project, reads its dependencies
* and generates build.gradle scripts. It also generates settings.gradle for multi-module builds.
*
* It currently supports both single-module and multi-module POMs, inheritance, dependency management and properties.
*/
public class Maven2Gradle {
private final BuildScriptBuilderFactory scriptBuilderFactory;
private final Set allProjects;
private final MavenProject rootProject;
private final List dependentWars = new ArrayList<>();
private final Directory workingDir;
private final BuildInitDsl dsl;
public Maven2Gradle(Set mavenProjects, Directory workingDir, BuildInitDsl dsl, BuildScriptBuilderFactory scriptBuilderFactory) {
assert !mavenProjects.isEmpty(): "No Maven projects provided.";
this.allProjects = mavenProjects;
this.rootProject = mavenProjects.iterator().next();
this.workingDir = workingDir;
this.dsl = dsl;
this.scriptBuilderFactory = scriptBuilderFactory;
}
public void convert() {
boolean multimodule = !rootProject.getModules().isEmpty();
if (multimodule) {
String groupId = rootProject.getGroupId();
BuildScriptBuilder buildSrcScriptBuilder = scriptBuilderFactory.script(dsl, "buildSrc/build");
buildSrcScriptBuilder.conventionPluginSupport("Support convention plugins written in " + dsl.toString() + ". Convention plugins are build scripts in 'src/main' that automatically become available as plugins in the main build.");
buildSrcScriptBuilder.create(workingDir).generate();
BuildScriptBuilder conventionPluginBuilder = scriptBuilderFactory.script(dsl, "buildSrc/src/main/" + dsl.name().toLowerCase() + "/" + groupId + ".java-conventions");
generateSettings(rootProject.getArtifactId(), allProjects);
Map> dependencies = new LinkedHashMap<>();
for (MavenProject project : allProjects) {
dependencies.put(project.getArtifactId(), getDependencies(project, allProjects));
}
coordinatesForProject(rootProject, conventionPluginBuilder);
conventionPluginBuilder.plugin(null, "java-library");
conventionPluginBuilder.plugin(null, "maven-publish");
compilerSettings(rootProject, conventionPluginBuilder);
repositoriesForProjects(allProjects, conventionPluginBuilder);
globalExclusions(rootProject, conventionPluginBuilder);
List commonDeps = dependencies.get(rootProject.getArtifactId());
declareDependencies(commonDeps, conventionPluginBuilder);
testNg(commonDeps, conventionPluginBuilder);
configurePublishing(conventionPluginBuilder, packagesSources(rootProject), false, false);
conventionPluginBuilder.create(workingDir).generate();
for (MavenProject module : modules(allProjects, false)) {
String id = module.getArtifactId();
List moduleDependencies = dependencies.get(id);
boolean warPack = module.getPackaging().equals("war");
BuildScriptBuilder moduleScriptBuilder = scriptBuilderFactory.script(dsl, projectDir(module).getPath() + "/build");
moduleScriptBuilder.plugin(null, groupId + ".java-conventions");
if (!module.getGroupId().equals(rootProject.getGroupId())) {
moduleScriptBuilder.propertyAssignment(null, "group", module.getGroupId());
}
if (warPack) {
moduleScriptBuilder.plugin(null, "war");
if (dependentWars.stream().anyMatch(project -> project.getGroupId().equals(module.getGroupId()) && project.getArtifactId().equals(id))) {
moduleScriptBuilder.taskPropertyAssignment(null, "jar", "Jar", "enabled", true);
}
}
descriptionForProject(module, moduleScriptBuilder);
declareDependencies(moduleDependencies, moduleScriptBuilder);
testNg(moduleDependencies, moduleScriptBuilder);
if (packageTests(module, moduleScriptBuilder)) {
if (dsl == BuildInitDsl.GROOVY) {
moduleScriptBuilder.methodInvocation(null, "publishing.publications.maven.artifact", moduleScriptBuilder.propertyExpression("testsJar"));
} else {
moduleScriptBuilder.methodInvocation(null, "(publishing.publications[\"maven\"] as MavenPublication).artifact", moduleScriptBuilder.propertyExpression("testsJar"));
}
}
if (packagesJavadocs(module)) {
ScriptBlockBuilder javaExtension = moduleScriptBuilder.block(null, "java");
javaExtension.methodInvocation(null, "withJavadocJar");
}
moduleScriptBuilder.create(workingDir).generate();
}
} else {
BuildScriptBuilder scriptBuilder = scriptBuilderFactory.script(dsl, "build");
generateSettings(this.rootProject.getArtifactId(), Collections.emptySet());
scriptBuilder.plugin(null, "java");
scriptBuilder.plugin(null, "maven-publish");
coordinatesForProject(this.rootProject, scriptBuilder);
descriptionForProject(this.rootProject, scriptBuilder);
compilerSettings(this.rootProject, scriptBuilder);
globalExclusions(this.rootProject, scriptBuilder);
boolean testsJarTaskGenerated = packageTests(this.rootProject, scriptBuilder);
configurePublishing(scriptBuilder, packagesSources(this.rootProject), testsJarTaskGenerated, packagesJavadocs(this.rootProject));
scriptBuilder.repositories().mavenLocal(null);
Set repoSet = new LinkedHashSet<>();
getRepositoriesForModule(this.rootProject, repoSet);
for (String repo : repoSet) {
scriptBuilder.repositories().maven(null, repo);
}
List dependencies = getDependencies(this.rootProject, null);
declareDependencies(dependencies, scriptBuilder);
testNg(dependencies, scriptBuilder);
scriptBuilder.create(workingDir).generate();
}
}
private void configurePublishing(BuildScriptBuilder builder, boolean publishesSources, boolean testsJarTaskGenerated, boolean publishesJavadoc) {
if (publishesSources || publishesJavadoc) {
ScriptBlockBuilder javaExtension = builder.block(null, "java");
if (publishesSources) {
javaExtension.methodInvocation(null, "withSourcesJar");
}
if (publishesJavadoc) {
javaExtension.methodInvocation(null, "withJavadocJar");
}
}
ScriptBlockBuilder publishing = builder.block(null, "publishing");
publishing.containerElement(null, "publications", "maven", "MavenPublication", p -> {
p.methodInvocation(null, "from", builder.containerElementExpression("components", "java"));
if (testsJarTaskGenerated) {
p.methodInvocation(null, "artifact", builder.propertyExpression("testsJar"));
}
});
}
private void declareDependencies(List dependencies, BuildScriptBuilder builder) {
DependenciesBuilder dependenciesBuilder = builder.dependencies();
for (Dependency dep : dependencies) {
if (dep instanceof ProjectDependency) {
dependenciesBuilder.projectDependency(dep.getConfiguration(), null, ((ProjectDependency) dep).getProjectPath());
} else {
ExternalDependency extDep = (ExternalDependency) dep;
dependenciesBuilder.dependency(dep.getConfiguration(), null, extDep.getGroupId() + ":" + extDep.getModule() + ":" + extDep.getVersion());
}
}
}
private void globalExclusions(MavenProject project, BuildScriptBuilder builder) {
Plugin enforcerPlugin = plugin("maven-enforcer-plugin", project);
PluginExecution enforceGoal = pluginGoal("enforce", enforcerPlugin);
if (enforceGoal != null) {
Xpp3Dom configuration = (Xpp3Dom) enforceGoal.getConfiguration();
Xpp3Dom bannedDependencies = configuration.getChild("rules").getChild("bannedDependencies");
if (bannedDependencies!=null) {
Xpp3Dom[] children = bannedDependencies.getChild("excludes").getChildren();
ScriptBlockBuilder block = builder.block(null, "configurations.all");
if (children != null) {
for (Xpp3Dom exclude : children) {
String[] tokens = exclude.getValue().split(":");
Map params = new LinkedHashMap<>();
params.put("group", tokens[0]);
if (tokens.length > 1 && !tokens[1].equals("*")) {
params.put("module", tokens[1]);
}
block.methodInvocation(null, "exclude", params);
}
}
}
}
}
private void testNg(List moduleDependencies, BuildScriptBuilder builder) {
boolean testng = moduleDependencies.stream().anyMatch(dep ->
dep instanceof ExternalDependency && "org.testng".equals(((ExternalDependency) dep).getGroupId()) && "testng".equals(((ExternalDependency) dep).getModule())
);
if (testng) {
builder.taskMethodInvocation(null, "test", "Test", "useTestNG");
}
}
private Set modules(Set projects, boolean incReactors) {
return projects.stream().filter(project -> {
Optional parentIsPartOfThisBuild = projects.stream().filter(proj ->
project.getParent() != null && proj.getArtifactId().equals(project.getParent().getArtifactId()) && proj.getGroupId().equals(project.getParent().getGroupId())
).findFirst();
return parentIsPartOfThisBuild.isPresent() && (incReactors || !"pom".equals(project.getPackaging()));
}).collect(Collectors.toSet());
}
private String fqn(MavenProject project, Set allProjects) {
StringBuilder buffer = new StringBuilder();
generateFqn(project, allProjects, buffer);
return buffer.toString();
}
private void generateFqn(MavenProject project, Set allProjects, StringBuilder buffer) {
String artifactId = project.getArtifactId();
buffer.insert(0, ":" + artifactId);
//we don't need the top-level parent in gradle, so we stop on it
if (!getModuleIdentifier(rootProject).equals(getModuleIdentifier(project.getParent()))) {
allProjects.stream().filter(proj ->
getModuleIdentifier(proj) == getModuleIdentifier(project.getParent())
).findFirst().ifPresent(parentInBuild -> generateFqn(parentInBuild, allProjects, buffer));
}
}
private ModuleIdentifier getModuleIdentifier(MavenProject project) {
if (project == null) {
return null;
}
String artifactId = project.getArtifactId();
String groupId = StringUtils.isNotEmpty(project.getGroupId()) ? project.getGroupId() : project.getParent().getGroupId();
return DefaultModuleIdentifier.newId(groupId, artifactId);
}
private void coordinatesForProject(MavenProject project, BuildScriptBuilder builder) {
builder.propertyAssignment(null, "group", project.getGroupId());
builder.propertyAssignment(null, "version", project.getVersion());
}
private void descriptionForProject(MavenProject project, BuildScriptBuilder builder) {
if (StringUtils.isNotEmpty(project.getName())) {
builder.propertyAssignment(null, "description", project.getName());
}
}
private void repositoriesForProjects(Set projects, BuildScriptBuilder builder) {
builder.repositories().mavenLocal(null);
Set repoSet = new LinkedHashSet<>();
for(MavenProject project : projects) {
getRepositoriesForModule(project, repoSet);
}
for(String repo : repoSet) {
builder.repositories().maven(null, repo);
}
}
private void getRepositoriesForModule(MavenProject module, Set repoSet) {
for(Repository repo : module.getRepositories()) {
if (repo.getId().equals(RepositorySystem.DEFAULT_REMOTE_REPO_ID)) {
repoSet.add(RepositoryHandler.MAVEN_CENTRAL_URL);
} else {
repoSet.add(repo.getUrl());
}
}
// No need to include plugin repos, as they won't be used by Gradle
}
private List getDependencies(MavenProject project, Set allProjects) {
List dependencies = new ArrayList<>();
collectAllDependencies(project, dependencies);
boolean war = "war".equals(project.getPackaging());
List compileTimeScope = new ArrayList<>();
List runtimeScope = new ArrayList<>();
List testScope = new ArrayList<>();
List providedScope = new ArrayList<>();
List systemScope = new ArrayList<>();
//cleanup duplicates from parent
for(org.apache.maven.model.Dependency mavenDependency : dependencies) {
if (!duplicateDependency(mavenDependency, project, allProjects)) {
String scope = StringUtils.isNotEmpty(mavenDependency.getScope()) ? mavenDependency.getScope() : "compile";
switch (scope) {
case "compile":
compileTimeScope.add(mavenDependency);
break;
case "test":
testScope.add(mavenDependency);
break;
case "provided":
providedScope.add(mavenDependency);
break;
case "runtime":
runtimeScope.add(mavenDependency);
break;
case "system":
systemScope.add(mavenDependency);
break;
}
}
}
List result = new ArrayList<>();
if (!compileTimeScope.isEmpty() || !runtimeScope.isEmpty() || !testScope.isEmpty() || !providedScope.isEmpty() || !systemScope.isEmpty()) {
if (!compileTimeScope.isEmpty()) {
for (org.apache.maven.model.Dependency dep : compileTimeScope) {
createGradleDep("implementation", result, dep, war);
}
}
if (!runtimeScope.isEmpty()) {
for (org.apache.maven.model.Dependency dep : runtimeScope) {
createGradleDep("runtimeOnly", result, dep, war);
}
}
if (!testScope.isEmpty()) {
for (org.apache.maven.model.Dependency dep : testScope) {
createGradleDep("testImplementation", result, dep, war);
}
}
if (!providedScope.isEmpty()) {
for (org.apache.maven.model.Dependency dep : providedScope) {
createGradleDep("providedCompile", result, dep, war);
}
}
if (!systemScope.isEmpty()) {
for (org.apache.maven.model.Dependency dep : systemScope) {
createGradleDep("system", result, dep, war);
}
}
}
return result;
}
private void collectAllDependencies(MavenProject mavenProject, List dependencies) {
if (mavenProject.getParent() != null) {
collectAllDependencies(mavenProject.getParent(), dependencies);
}
dependencies.addAll(mavenProject.getDependencies());
}
/**
* print function then checks the exclusions node to see if it exists, if
* so it branches off, otherwise we call our simple print function
*/
private void createGradleDep(String scope, List result, org.apache.maven.model.Dependency mavenDependency, boolean war) {
Optional projectDep = allProjects.stream().filter(prj ->
prj.getArtifactId().equals(mavenDependency.getArtifactId()) && prj.getGroupId().equals(mavenDependency.getGroupId())
).findFirst();
if (projectDep.isPresent()) {
createProjectDependency(projectDep.get(), result, scope, allProjects);
} else {
if (!war && "providedCompile".equals(scope)) {
scope = "compileOnly";
}
createExternalDependency(mavenDependency, result, scope);
}
}
private void compilerSettings(MavenProject project, BuildScriptBuilder builder) {
String source = "1.8";
String target = "1.8";
Plugin compilerPlugin = plugin("maven-compiler-plugin", project);
if (compilerPlugin != null) {
Xpp3Dom configuration = (Xpp3Dom) compilerPlugin.getConfiguration();
if (configuration != null) {
Xpp3Dom configuredSource = configuration.getChild("source");
Xpp3Dom configuredTarget = configuration.getChild("target");
if (configuredSource != null && !configuredSource.getValue().trim().isEmpty()) {
source = configuredSource.getValue();
}
if (configuredTarget != null && !configuredTarget.getValue().trim().isEmpty()) {
target = configuredTarget.getValue();
}
}
}
builder.propertyAssignment(null, "java.sourceCompatibility", JavaVersion.toVersion(source));
if (!target.equals(source)) {
builder.propertyAssignment(null, "java.targetCompatibility", JavaVersion.toVersion(target));
}
String encoding = (String) project.getProperties().get("project.build.sourceEncoding");
if (StringUtils.isNotEmpty(encoding)) {
builder.taskPropertyAssignment(null, "JavaCompile", "options.encoding", encoding);
}
}
private Plugin plugin(String artifactId, MavenProject project) {
return project.getBuild().getPlugins().stream().filter(pluginTag ->
pluginTag.getArtifactId().equals(artifactId)
).findFirst().orElse(null);
}
private PluginExecution pluginGoal(String goalName, Plugin plugin) {
if (plugin == null) {
return null;
}
return plugin.getExecutions().stream().filter(exec ->
exec.getGoals().stream().anyMatch(gl -> gl.startsWith(goalName))
).findFirst().orElse(null);
}
boolean packagesSources(MavenProject project) {
Plugin sourcePlugin = plugin("maven-source-plugin", project);
return sourcePlugin != null && pluginGoal("jar", sourcePlugin) != null;
}
boolean packageTests(MavenProject project, BuildScriptBuilder builder) {
Plugin jarPlugin = plugin("maven-jar-plugin", project);
if (pluginGoal("test-jar", jarPlugin) != null) {
builder.taskRegistration(null, "testsJar", "Jar", task -> {
task.propertyAssignment(null, "archiveClassifier", "tests", false);
task.methodInvocation(null, "from", builder.propertyExpression(builder.containerElementExpression("sourceSets", "test"), "output"));
});
return true;
}
return false;
}
boolean packagesJavadocs(MavenProject project) {
Plugin jarPlugin = plugin("maven-javadoc-plugin", project);
return jarPlugin != null && pluginGoal("jar", jarPlugin) != null;
}
private boolean duplicateDependency(org.apache.maven.model.Dependency dependency, MavenProject project, Set allProjects) {
MavenProject parent = project.getParent();
if (allProjects == null || !allProjects.contains(parent)) { // simple project or no parent in the build
return false;
} else {
boolean duplicate = parent.getDependencies().stream().anyMatch(dep ->
dep.getGroupId().equals(dependency.getGroupId()) && dep.getArtifactId().equals(dependency.getArtifactId())
);
if (duplicate) {
return true;
} else {
return duplicateDependency(dependency, parent, allProjects);
}
}
}
private File projectDir(MavenProject project) {
return new File(project.getBuild().getDirectory()).getParentFile();
}
private void generateSettings(String mvnProjectName, Set projects) {
BuildScriptBuilder scriptBuilder = scriptBuilderFactory.script(dsl, "settings");
scriptBuilder.propertyAssignment(null, "rootProject.name", mvnProjectName);
Set modules = modules(projects, true);
List moduleNames = new ArrayList<>();
Map artifactIdToDir = new LinkedHashMap<>();
for (MavenProject project : modules) {
String fqn = fqn(project, projects);
File projectDirectory = projectDir(project);
// don't add project if it's the rootproject
if (!workingDir.getAsFile().equals(projectDirectory)) {
moduleNames.add(fqn);
// Calculate the path to the project, ignore this path if it's the default value
String relativePath = RelativePathUtil.relativePath(workingDir.getAsFile(), projectDirectory);
if (!fqn.equals(":" + relativePath)) {
artifactIdToDir.put(fqn, relativePath);
}
}
}
for (String name : moduleNames) {
scriptBuilder.methodInvocation(null, "include", name);
}
for (Map.Entry entry : artifactIdToDir.entrySet()) {
BuildScriptBuilder.Expression dirExpression = scriptBuilder.methodInvocationExpression("file", entry.getValue());
scriptBuilder.propertyAssignment(null, "project(\"" + entry.getKey() + "\").projectDir", dirExpression);
}
scriptBuilder.create(workingDir).generate();
}
private void createExternalDependency(org.apache.maven.model.Dependency mavenDependency, List result, String scope) {
String classifier = mavenDependency.getClassifier();
List exclusions = mavenDependency.getExclusions().stream().map(Exclusion::getArtifactId).collect(Collectors.toList());
result.add(new ExternalDependency(scope, mavenDependency.getGroupId(), mavenDependency.getArtifactId(), mavenDependency.getVersion(), classifier, exclusions));
}
private void createProjectDependency(MavenProject projectDep, List result, String scope, Set allProjects) {
if ("war".equals(projectDep.getPackaging())) {
dependentWars.add(projectDep);
}
result.add(new ProjectDependency(scope, fqn(projectDep, allProjects)));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy