blob: 1da5c2eed9649a085c31b27eb8aadfb293683d60 [file] [log] [blame]
/*
* 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.
*/
package org.apache.maven.plugin.resources.remote;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.TreeMap;
import org.apache.maven.model.Build;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.DependencyManagement;
import org.apache.maven.model.DeploymentRepository;
import org.apache.maven.model.DistributionManagement;
import org.apache.maven.model.Extension;
import org.apache.maven.model.Model;
import org.apache.maven.model.PluginManagement;
import org.apache.maven.model.ReportPlugin;
import org.apache.maven.model.ReportSet;
import org.apache.maven.model.Reporting;
import org.apache.maven.model.Resource;
import org.apache.maven.model.Scm;
import org.apache.maven.model.Site;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.xml.Xpp3Dom;
/**
* DefaultModelInheritanceAssembler
*/
public class ModelInheritanceAssembler {
// TODO Remove this!
public void assembleBuildInheritance(Build childBuild, Build parentBuild, boolean handleAsInheritance) {
// The build has been set but we want to step in here and fill in
// values that have not been set by the child.
if (childBuild.getSourceDirectory() == null) {
childBuild.setSourceDirectory(parentBuild.getSourceDirectory());
}
if (childBuild.getScriptSourceDirectory() == null) {
childBuild.setScriptSourceDirectory(parentBuild.getScriptSourceDirectory());
}
if (childBuild.getTestSourceDirectory() == null) {
childBuild.setTestSourceDirectory(parentBuild.getTestSourceDirectory());
}
if (childBuild.getOutputDirectory() == null) {
childBuild.setOutputDirectory(parentBuild.getOutputDirectory());
}
if (childBuild.getTestOutputDirectory() == null) {
childBuild.setTestOutputDirectory(parentBuild.getTestOutputDirectory());
}
// Extensions are accumulated
mergeExtensionLists(childBuild, parentBuild);
if (childBuild.getDirectory() == null) {
childBuild.setDirectory(parentBuild.getDirectory());
}
if (childBuild.getDefaultGoal() == null) {
childBuild.setDefaultGoal(parentBuild.getDefaultGoal());
}
if (childBuild.getFinalName() == null) {
childBuild.setFinalName(parentBuild.getFinalName());
}
ModelUtils.mergeFilterLists(childBuild.getFilters(), parentBuild.getFilters());
List<Resource> resources = childBuild.getResources();
if ((resources == null) || resources.isEmpty()) {
childBuild.setResources(parentBuild.getResources());
}
resources = childBuild.getTestResources();
if ((resources == null) || resources.isEmpty()) {
childBuild.setTestResources(parentBuild.getTestResources());
}
// Plugins are aggregated if Plugin.inherit != false
ModelUtils.mergePluginLists(childBuild, parentBuild, handleAsInheritance);
// Plugin management :: aggregate
PluginManagement dominantPM = childBuild.getPluginManagement();
PluginManagement recessivePM = parentBuild.getPluginManagement();
if ((dominantPM == null) && (recessivePM != null)) {
// FIXME: Filter out the inherited == false stuff!
childBuild.setPluginManagement(recessivePM);
} else {
ModelUtils.mergePluginLists(childBuild.getPluginManagement(), parentBuild.getPluginManagement(), false);
}
}
private void assembleScmInheritance(Model child, Model parent, String childPathAdjustment, boolean appendPaths) {
if (parent.getScm() != null) {
Scm parentScm = parent.getScm();
Scm childScm = child.getScm();
if (childScm == null) {
childScm = new Scm();
child.setScm(childScm);
}
if (StringUtils.isEmpty(childScm.getConnection()) && !StringUtils.isEmpty(parentScm.getConnection())) {
childScm.setConnection(
appendPath(parentScm.getConnection(), child.getArtifactId(), childPathAdjustment, appendPaths));
}
if (StringUtils.isEmpty(childScm.getDeveloperConnection())
&& !StringUtils.isEmpty(parentScm.getDeveloperConnection())) {
childScm.setDeveloperConnection(appendPath(
parentScm.getDeveloperConnection(), child.getArtifactId(), childPathAdjustment, appendPaths));
}
if (StringUtils.isEmpty(childScm.getUrl()) && !StringUtils.isEmpty(parentScm.getUrl())) {
childScm.setUrl(
appendPath(parentScm.getUrl(), child.getArtifactId(), childPathAdjustment, appendPaths));
}
}
}
public void copyModel(Model dest, Model source) {
assembleModelInheritance(dest, source, null, false);
}
public void assembleModelInheritance(Model child, Model parent, String childPathAdjustment) {
assembleModelInheritance(child, parent, childPathAdjustment, true);
}
public void assembleModelInheritance(Model child, Model parent) {
assembleModelInheritance(child, parent, null, true);
}
private void assembleModelInheritance(Model child, Model parent, String childPathAdjustment, boolean appendPaths) {
// cannot inherit from null parent.
if (parent == null) {
return;
}
// Group id
if (child.getGroupId() == null) {
child.setGroupId(parent.getGroupId());
}
// version
if (child.getVersion() == null) {
// The parent version may have resolved to something different, so we take what we asked for...
// instead of - child.setVersion( parent.getVersion() );
if (child.getParent() != null) {
child.setVersion(child.getParent().getVersion());
}
}
// inceptionYear
if (child.getInceptionYear() == null) {
child.setInceptionYear(parent.getInceptionYear());
}
// url
if (child.getUrl() == null) {
if (parent.getUrl() != null) {
child.setUrl(appendPath(parent.getUrl(), child.getArtifactId(), childPathAdjustment, appendPaths));
} else {
child.setUrl(parent.getUrl());
}
}
assembleDistributionInheritance(child, parent, childPathAdjustment, appendPaths);
// issueManagement
if (child.getIssueManagement() == null) {
child.setIssueManagement(parent.getIssueManagement());
}
// description
if (child.getDescription() == null) {
child.setDescription(parent.getDescription());
}
// Organization
if (child.getOrganization() == null) {
child.setOrganization(parent.getOrganization());
}
// Scm
assembleScmInheritance(child, parent, childPathAdjustment, appendPaths);
// ciManagement
if (child.getCiManagement() == null) {
child.setCiManagement(parent.getCiManagement());
}
// developers
if (child.getDevelopers().size() == 0) {
child.setDevelopers(parent.getDevelopers());
}
// licenses
if (child.getLicenses().size() == 0) {
child.setLicenses(parent.getLicenses());
}
// developers
if (child.getContributors().size() == 0) {
child.setContributors(parent.getContributors());
}
// mailingLists
if (child.getMailingLists().size() == 0) {
child.setMailingLists(parent.getMailingLists());
}
// Build
assembleBuildInheritance(child, parent);
assembleDependencyInheritance(child, parent);
child.setRepositories(ModelUtils.mergeRepositoryLists(child.getRepositories(), parent.getRepositories()));
// child.setPluginRepositories(
// ModelUtils.mergeRepositoryLists( child.getPluginRepositories(), parent.getPluginRepositories() )
// );
assembleReportingInheritance(child, parent);
assembleDependencyManagementInheritance(child, parent);
Properties props = new Properties();
props.putAll(parent.getProperties());
props.putAll(child.getProperties());
child.setProperties(props);
}
// TODO Remove this!
private void assembleDependencyManagementInheritance(Model child, Model parent) {
DependencyManagement parentDepMgmt = parent.getDependencyManagement();
DependencyManagement childDepMgmt = child.getDependencyManagement();
if (parentDepMgmt != null) {
if (childDepMgmt == null) {
child.setDependencyManagement(parentDepMgmt);
} else {
List<Dependency> childDeps = childDepMgmt.getDependencies();
Map<String, Dependency> mappedChildDeps = new TreeMap<>();
for (Dependency dep : childDeps) {
mappedChildDeps.put(dep.getManagementKey(), dep);
}
for (Dependency dep : parentDepMgmt.getDependencies()) {
if (!mappedChildDeps.containsKey(dep.getManagementKey())) {
childDepMgmt.addDependency(dep);
}
}
}
}
}
private void assembleReportingInheritance(Model child, Model parent) {
// Reports :: aggregate
Reporting childReporting = child.getReporting();
Reporting parentReporting = parent.getReporting();
if (parentReporting != null) {
if (childReporting == null) {
childReporting = new Reporting();
child.setReporting(childReporting);
}
childReporting.setExcludeDefaults(parentReporting.isExcludeDefaults());
if (StringUtils.isEmpty(childReporting.getOutputDirectory())) {
childReporting.setOutputDirectory(parentReporting.getOutputDirectory());
}
mergeReportPluginLists(childReporting, parentReporting, true);
}
}
private static void mergeReportPluginLists(Reporting child, Reporting parent, boolean handleAsInheritance) {
if ((child == null) || (parent == null)) {
// nothing to do.
return;
}
List<ReportPlugin> parentPlugins = parent.getPlugins();
if ((parentPlugins != null) && !parentPlugins.isEmpty()) {
Map<String, ReportPlugin> assembledPlugins = new TreeMap<>();
Map<String, ReportPlugin> childPlugins = child.getReportPluginsAsMap();
for (ReportPlugin parentPlugin : parentPlugins) {
String parentInherited = parentPlugin.getInherited();
if (!handleAsInheritance || (parentInherited == null) || Boolean.parseBoolean(parentInherited)) {
ReportPlugin assembledPlugin = parentPlugin;
ReportPlugin childPlugin = childPlugins.get(parentPlugin.getKey());
if (childPlugin != null) {
assembledPlugin = childPlugin;
mergeReportPluginDefinitions(childPlugin, parentPlugin, handleAsInheritance);
}
if (handleAsInheritance && (parentInherited == null)) {
assembledPlugin.unsetInheritanceApplied();
}
assembledPlugins.put(assembledPlugin.getKey(), assembledPlugin);
}
}
for (ReportPlugin childPlugin : childPlugins.values()) {
if (!assembledPlugins.containsKey(childPlugin.getKey())) {
assembledPlugins.put(childPlugin.getKey(), childPlugin);
}
}
child.setPlugins(new ArrayList<>(assembledPlugins.values()));
child.flushReportPluginMap();
}
}
private static void mergeReportSetDefinitions(ReportSet child, ReportSet parent) {
List<String> parentReports = parent.getReports();
List<String> childReports = child.getReports();
List<String> reports = new ArrayList<>();
if ((childReports != null) && !childReports.isEmpty()) {
reports.addAll(childReports);
}
if (parentReports != null) {
for (String report : parentReports) {
if (!reports.contains(report)) {
reports.add(report);
}
}
}
child.setReports(reports);
Xpp3Dom childConfiguration = (Xpp3Dom) child.getConfiguration();
Xpp3Dom parentConfiguration = (Xpp3Dom) parent.getConfiguration();
childConfiguration = Xpp3Dom.mergeXpp3Dom(childConfiguration, parentConfiguration);
child.setConfiguration(childConfiguration);
}
public static void mergeReportPluginDefinitions(
ReportPlugin child, ReportPlugin parent, boolean handleAsInheritance) {
if ((child == null) || (parent == null)) {
// nothing to do.
return;
}
if ((child.getVersion() == null) && (parent.getVersion() != null)) {
child.setVersion(parent.getVersion());
}
// from here to the end of the method is dealing with merging of the <executions/> section.
String parentInherited = parent.getInherited();
boolean parentIsInherited = (parentInherited == null) || Boolean.parseBoolean(parentInherited);
List<ReportSet> parentReportSets = parent.getReportSets();
if ((parentReportSets != null) && !parentReportSets.isEmpty()) {
Map<String, ReportSet> assembledReportSets = new TreeMap<>();
Map<String, ReportSet> childReportSets = child.getReportSetsAsMap();
for (ReportSet parentReportSet : parentReportSets) {
if (!handleAsInheritance || parentIsInherited) {
ReportSet assembledReportSet = parentReportSet;
ReportSet childReportSet = childReportSets.get(parentReportSet.getId());
if (childReportSet != null) {
mergeReportSetDefinitions(childReportSet, parentReportSet);
assembledReportSet = childReportSet;
} else if (handleAsInheritance && (parentInherited == null)) {
parentReportSet.unsetInheritanceApplied();
}
assembledReportSets.put(assembledReportSet.getId(), assembledReportSet);
}
}
for (Map.Entry<String, ReportSet> entry : childReportSets.entrySet()) {
String id = entry.getKey();
if (!assembledReportSets.containsKey(id)) {
assembledReportSets.put(id, entry.getValue());
}
}
child.setReportSets(new ArrayList<>(assembledReportSets.values()));
child.flushReportSetMap();
}
}
// TODO Remove this!
private void assembleDependencyInheritance(Model child, Model parent) {
Map<String, Dependency> depsMap = new LinkedHashMap<>();
List<Dependency> deps = parent.getDependencies();
if (deps != null) {
for (Dependency dependency : deps) {
depsMap.put(dependency.getManagementKey(), dependency);
}
}
deps = child.getDependencies();
if (deps != null) {
for (Dependency dependency : deps) {
depsMap.put(dependency.getManagementKey(), dependency);
}
}
child.setDependencies(new ArrayList<>(depsMap.values()));
}
private void assembleBuildInheritance(Model child, Model parent) {
Build childBuild = child.getBuild();
Build parentBuild = parent.getBuild();
if (parentBuild != null) {
if (childBuild == null) {
childBuild = new Build();
child.setBuild(childBuild);
}
assembleBuildInheritance(childBuild, parentBuild, true);
}
}
private void assembleDistributionInheritance(
Model child, Model parent, String childPathAdjustment, boolean appendPaths) {
if (parent.getDistributionManagement() != null) {
DistributionManagement parentDistMgmt = parent.getDistributionManagement();
DistributionManagement childDistMgmt = child.getDistributionManagement();
if (childDistMgmt == null) {
childDistMgmt = new DistributionManagement();
child.setDistributionManagement(childDistMgmt);
}
if (childDistMgmt.getSite() == null) {
if (parentDistMgmt.getSite() != null) {
Site site = new Site();
childDistMgmt.setSite(site);
site.setId(parentDistMgmt.getSite().getId());
site.setName(parentDistMgmt.getSite().getName());
site.setUrl(parentDistMgmt.getSite().getUrl());
if (site.getUrl() != null) {
site.setUrl(appendPath(site.getUrl(), child.getArtifactId(), childPathAdjustment, appendPaths));
}
}
}
if (childDistMgmt.getRepository() == null) {
if (parentDistMgmt.getRepository() != null) {
DeploymentRepository repository = copyDistributionRepository(parentDistMgmt.getRepository());
childDistMgmt.setRepository(repository);
}
}
if (childDistMgmt.getSnapshotRepository() == null) {
if (parentDistMgmt.getSnapshotRepository() != null) {
DeploymentRepository repository =
copyDistributionRepository(parentDistMgmt.getSnapshotRepository());
childDistMgmt.setSnapshotRepository(repository);
}
}
if (StringUtils.isEmpty(childDistMgmt.getDownloadUrl())) {
childDistMgmt.setDownloadUrl(parentDistMgmt.getDownloadUrl());
}
// NOTE: We SHOULD NOT be inheriting status, since this is an assessment of the POM quality.
// NOTE: We SHOULD NOT be inheriting relocation, since this relates to a single POM
}
}
private static DeploymentRepository copyDistributionRepository(DeploymentRepository parentRepository) {
DeploymentRepository repository = new DeploymentRepository();
repository.setId(parentRepository.getId());
repository.setName(parentRepository.getName());
repository.setUrl(parentRepository.getUrl());
repository.setLayout(parentRepository.getLayout());
repository.setUniqueVersion(parentRepository.isUniqueVersion());
return repository;
}
// TODO This should eventually be migrated to DefaultPathTranslator.
protected String appendPath(String parentPath, String childPath, String pathAdjustment, boolean appendPaths) {
String uncleanPath = parentPath;
if (appendPaths) {
if (pathAdjustment != null) {
uncleanPath += "/" + pathAdjustment;
}
if (childPath != null) {
uncleanPath += "/" + childPath;
}
}
String cleanedPath = "";
int protocolIdx = uncleanPath.indexOf("://");
if (protocolIdx > -1) {
cleanedPath = uncleanPath.substring(0, protocolIdx + 3);
uncleanPath = uncleanPath.substring(protocolIdx + 3);
}
if (uncleanPath.startsWith("/")) {
cleanedPath += "/";
}
return cleanedPath + resolvePath(uncleanPath);
}
// TODO Move this to plexus-utils' PathTool.
private static String resolvePath(String uncleanPath) {
LinkedList<String> pathElements = new LinkedList<>();
StringTokenizer tokenizer = new StringTokenizer(uncleanPath, "/");
while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken();
switch (token) {
case "":
// Empty path entry ("...//.."), remove.
break;
case "..":
if (pathElements.isEmpty()) {
// FIXME: somehow report to the user
// that there are too many '..' elements.
// For now, ignore the extra '..'.
} else {
pathElements.removeLast();
}
break;
default:
pathElements.addLast(token);
break;
}
}
StringBuilder cleanedPath = new StringBuilder();
while (!pathElements.isEmpty()) {
cleanedPath.append(pathElements.removeFirst());
if (!pathElements.isEmpty()) {
cleanedPath.append('/');
}
}
return cleanedPath.toString();
}
private static void mergeExtensionLists(Build childBuild, Build parentBuild) {
for (Extension e : parentBuild.getExtensions()) {
if (!childBuild.getExtensions().contains(e)) {
childBuild.addExtension(e);
}
}
}
}