org.wildfly.plugins.componentmatrix.BuildBomMojo Maven / Gradle / Ivy
The newest version!
/*
* JBoss, Home of Professional Open Source.
* Copyright 2018, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*
*/
package org.wildfly.plugins.componentmatrix;
import static org.codehaus.plexus.util.StringUtils.defaultString;
import static org.codehaus.plexus.util.StringUtils.trim;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DefaultArtifact;
import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.DependencyManagement;
import org.apache.maven.model.Exclusion;
import org.apache.maven.model.Model;
import org.apache.maven.model.Parent;
import org.apache.maven.model.Profile;
import org.apache.maven.model.building.ModelBuilder;
import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectHelper;
import org.apache.maven.project.ProjectBuilder;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.util.StringUtils;
/**
* Build a BOM based on the dependencies in a GAV
*/
@Mojo(name = "build-bom", defaultPhase = LifecyclePhase.GENERATE_RESOURCES, requiresDependencyResolution = ResolutionScope.COMPILE)
public class BuildBomMojo
extends AbstractMojo {
private static final String VERSION_PROPERTY_PREFIX = "version.";
/**
* Set the parent of the generated bom
*/
@Parameter
private Parent parent;
/**
* BOM groupId
*/
@Parameter(required = true)
private String bomGroupId;
/**
* BOM artifactId
*/
@Parameter(required = true)
private String bomArtifactId;
/**
* BOM version
*/
@Parameter(required = true)
private String bomVersion;
/**
* BOM name
*/
@Parameter(defaultValue = "")
private String bomName;
/**
* BOM description
*/
@Parameter(defaultValue = "")
private String bomDescription;
/**
* Set to {@code true} to generate the licenses
*/
@Parameter
private boolean licenses = false;
/**
* BOM output file
*/
@Parameter(defaultValue = "bom-pom.xml")
String outputFilename;
/**
* Whether the BOM should include the dependency exclusions that
* are present in the source POM. By default the exclusions
* will not be copied to the new BOM.
*/
@Parameter
private List exclusions;
/**
* List of dependencies which should not be added to BOM
*/
@Parameter
private List dependencyExclusions;
/**
* Whether or not to inherit exclusions
*/
@Parameter
private boolean inheritExclusions;
@Parameter
private Set includeProfiles;
/**
* The current project
*/
@Component
MavenProject mavenProject;
@Component
private ArtifactHandlerManager artifactHandlerManager;
private final PomDependencyVersionsTransformer versionsTransformer;
private final ModelWriter modelWriter;
public BuildBomMojo() {
this(new ModelWriter(), new PomDependencyVersionsTransformer());
}
public BuildBomMojo(ModelWriter modelWriter, PomDependencyVersionsTransformer versionsTransformer) {
this.versionsTransformer = versionsTransformer;
this.modelWriter = modelWriter;
}
public void execute()
throws MojoExecutionException {
getLog().debug("Generating BOM");
Model model = initializeModel();
addDependencyManagement(model);
model = versionsTransformer.transformPomModel(model);
getLog().debug("Dependencies versions converted to properties");
final File file = new File(mavenProject.getBuild().getDirectory(), outputFilename);
modelWriter.writeModel(model, file);
// Add the artifact
Artifact projectArtifact = mavenProject.getArtifact();
final Artifact pomArtifact =
new DefaultArtifact(
bomGroupId, bomArtifactId, bomVersion,
null, "pom", null, artifactHandlerManager.getArtifactHandler("pom"));
pomArtifact.setFile(file);
mavenProject.addAttachedArtifact( pomArtifact );
}
private Model initializeModel() {
Model pomModel = new Model();
pomModel.setModelVersion("4.0.0");
pomModel.setGroupId(bomGroupId);
pomModel.setArtifactId(bomArtifactId);
pomModel.setVersion(bomVersion);
pomModel.setPackaging("pom");
pomModel.setName(bomName);
pomModel.setDescription(bomDescription);
pomModel.setProperties(new OrderedProperties());
pomModel.getProperties().setProperty("project.build.sourceEncoding", "UTF-8");
if (licenses) {
pomModel.setLicenses(mavenProject.getLicenses());
}
if (parent != null) {
if (parent.getGroupId() == null) {
throw new IllegalArgumentException("No groupId was set for the parent");
}
if (parent.getArtifactId() == null) {
throw new IllegalArgumentException("No artifactId was set for the parent");
}
if (parent.getVersion() == null) {
MavenProject current = mavenProject;
while (current != null) {
if (current.getGroupId().equals(parent.getGroupId()) && current.getArtifactId().equals(parent.getArtifactId())) {
parent.setVersion(current.getVersion());
break;
}
current = current.getParent();
}
if (parent.getVersion() == null) {
throw new IllegalArgumentException("No version was set for the parent " + parent.getGroupId() + ":" + parent.getArtifactId() +
" and it cannot be determined from the parents of the consuming pom");
}
}
pomModel.setParent(parent);
}
Set addedProfiles = new HashSet<>();
List profiles = new ArrayList<>();
MavenProject current = mavenProject;
while (current != null) {
Model currModel = current.getModel();
if (includeProfiles != null && currModel != null) {
for ( Profile profile : currModel.getProfiles() ) {
if (includeProfiles.contains(profile.getId()) && !addedProfiles.contains(profile.getId())) {
profiles.add(profile);
addedProfiles.add(profile.getId());
}
}
}
current = current.getParent();
}
if (profiles.size() > 0) {
pomModel.setProfiles(profiles);
}
return pomModel;
}
private void addDependencyManagement(Model pomModel) {
// Map originalDeps = createDependencyMap(mavenProject.getDependencyManagement());
Properties versionProperties = new Properties();
DependencyManagement depMgmt = new DependencyManagement();
for (Dependency originalDependency : mavenProject.getDependencyManagement().getDependencies()) {
if (isExcludedDependency(originalDependency)) {
continue;
}
String versionPropertyName = VERSION_PROPERTY_PREFIX + originalDependency.getGroupId();
if (versionProperties.getProperty(versionPropertyName) != null
&& !versionProperties.getProperty(versionPropertyName).equals(originalDependency.getVersion())) {
versionPropertyName = VERSION_PROPERTY_PREFIX + originalDependency.getGroupId() + "." + originalDependency.getArtifactId();
}
versionProperties.setProperty(versionPropertyName, originalDependency.getVersion());
Dependency dep = new Dependency();
dep.setGroupId(originalDependency.getGroupId());
dep.setArtifactId(originalDependency.getArtifactId());
dep.setVersion(originalDependency.getVersion());
if (!StringUtils.isEmpty(originalDependency.getClassifier())) {
dep.setClassifier(originalDependency.getClassifier());
}
if (!StringUtils.isEmpty(originalDependency.getType())) {
dep.setType(originalDependency.getType());
}
if (!StringUtils.isEmpty(originalDependency.getScope())) {
dep.setScope(originalDependency.getScope());
}
if (exclusions != null) {
applyExclusions(originalDependency, dep);
}
if (inheritExclusions) {
inheritExclusions(originalDependency, dep);
}
depMgmt.addDependency(dep);
}
pomModel.setDependencyManagement(depMgmt);
getLog().debug("Added " + depMgmt.getDependencies().size() + " dependencies to dependency management.");
}
private void inheritExclusions(Dependency originalDependency, Dependency dep) {
for (Exclusion originalExclusion : originalDependency.getExclusions()) {
dep.addExclusion(originalExclusion.clone());
}
}
boolean isExcludedDependency(Dependency dependency) {
if (dependencyExclusions == null || dependencyExclusions.size() == 0) {
return false;
}
for (DependencyExclusion exclusion : dependencyExclusions) {
if (matchesExcludedDependency(dependency, exclusion)) {
getLog().debug("Artifact " + dependency.getGroupId() + ":" + dependency.getArtifactId() + " matches excluded dependency " + exclusion.getGroupId() + ":" + exclusion.getArtifactId());
return true;
}
}
return false;
}
boolean matchesExcludedDependency(Dependency artifact, DependencyExclusion exclusion) {
String groupId = defaultAndTrim(artifact.getGroupId());
String artifactId = defaultAndTrim(artifact.getArtifactId());
String exclusionGroupId = defaultAndTrim(exclusion.getGroupId());
String exclusionArtifactId = defaultAndTrim(exclusion.getArtifactId());
boolean groupIdMatched = ("*".equals(exclusionGroupId) || groupId.equals(exclusionGroupId));
boolean artifactIdMatched = ("*".equals(exclusionArtifactId) || artifactId.equals(exclusionArtifactId));
return groupIdMatched && artifactIdMatched;
}
private String defaultAndTrim(String string) {
return defaultString(trim(string), "");
}
private void applyExclusions(Dependency artifact, Dependency dep) {
for (BomExclusion exclusion : exclusions) {
if (exclusion.getDependencyGroupId().equals(artifact.getGroupId()) &&
exclusion.getDependencyArtifactId().equals(artifact.getArtifactId())) {
Exclusion ex = new Exclusion();
ex.setGroupId(exclusion.getExclusionGroupId());
ex.setArtifactId(exclusion.getExclusionArtifactId());
dep.addExclusion(ex);
}
}
}
private Map createDependencyMap(DependencyManagement dependencyManagement) {
if (dependencyManagement == null) {
return Collections.emptyMap();
}
Map dependencyMap = new HashMap<>();
for (Dependency dep : dependencyManagement.getDependencies()) {
dependencyMap.put(new DependencyId(dep), dep);
}
return dependencyMap;
}
static class ModelWriter {
void writeModel(Model pomModel, File outputFile)
throws MojoExecutionException {
if (!outputFile.getParentFile().exists()) {
outputFile.getParentFile().mkdirs();
}
try (FileWriter writer = new FileWriter(outputFile)) {
MavenXpp3Writer mavenWriter = new MavenXpp3Writer();
mavenWriter.write(writer, pomModel);
} catch (IOException e) {
e.printStackTrace();
throw new MojoExecutionException("Unable to write pom file.", e);
}
}
}
}