Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2020 CQ Maven Plugin
* project contributors as indicated by the @author tags.
*
* 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.l2x6.cq.common;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.xml.XMLConstants;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.DependencyManagement;
import org.apache.maven.model.Exclusion;
import org.apache.maven.model.InputLocation;
import org.apache.maven.model.InputLocation.StringFormatter;
import org.apache.maven.model.InputSource;
import org.apache.maven.model.Model;
import org.apache.maven.model.Parent;
import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
import org.apache.maven.model.io.xpp3.MavenXpp3WriterEx;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.assertj.core.util.diff.Delta;
import org.assertj.core.util.diff.DiffUtils;
import org.codehaus.plexus.util.StringUtils;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.collection.CollectRequest;
import org.eclipse.aether.collection.DependencyCollectionException;
import org.eclipse.aether.graph.DependencyNode;
import org.eclipse.aether.graph.DependencyVisitor;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.util.graph.transformer.ConflictResolver;
import org.jdom2.Document;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import org.l2x6.pom.tuner.ExpressionEvaluator;
import org.l2x6.pom.tuner.MavenSourceTree;
import org.l2x6.pom.tuner.PomTransformer;
import org.l2x6.pom.tuner.PomTransformer.ContainerElement;
import org.l2x6.pom.tuner.PomTransformer.NodeGavtcs;
import org.l2x6.pom.tuner.PomTransformer.SimpleElementWhitespace;
import org.l2x6.pom.tuner.PomTransformer.TransformationContext;
import org.l2x6.pom.tuner.model.Ga;
import org.l2x6.pom.tuner.model.Gav;
import org.l2x6.pom.tuner.model.GavPattern;
import org.l2x6.pom.tuner.model.GavSet;
import org.l2x6.pom.tuner.model.Gavtcs;
import org.l2x6.pom.tuner.model.Module;
import org.l2x6.pom.tuner.model.Profile;
import org.w3c.dom.Node;
import static java.util.stream.Collectors.joining;
public class FlattenBomTask {
public static class BomEntryTransformation {
private GavPattern gavPattern;
private Set internalExclusions = new TreeSet<>();
private Pattern versionPattern;
private String versionReplace;
public BomEntryTransformation() {
}
public BomEntryTransformation(String gavPattern, String versionReplacement, String exclusions, String addExclusions) {
if (gavPattern != null) {
setGavPattern(gavPattern);
}
if (versionReplacement != null) {
setVersionReplacement(versionReplacement);
}
if (exclusions != null) {
setExclusions(exclusions);
}
if (addExclusions != null) {
setAddExclusions(addExclusions);
}
}
public List getAddExclusions() {
return internalExclusions.stream()
.map(ga -> {
final Exclusion excl = new Exclusion();
excl.setGroupId(ga.getGroupId());
excl.setArtifactId(ga.getArtifactId());
return excl;
})
.collect(Collectors.toList());
}
public void setAddExclusions(String exclusions) {
for (String rawExcl : exclusions.split("[,\\s]+")) {
this.internalExclusions.add(GavPattern.of(rawExcl).asWildcardGa());
}
}
/**
* An alias for {@link #setAddExclusions(String)}
*
* @param exclusions items to exclude
* @deprecated use {@link #setAddExclusions(String)}
*/
@Deprecated
public void setExclusions(String exclusions) {
setAddExclusions(exclusions);
}
public GavPattern getGavPattern() {
return gavPattern;
}
public void setGavPattern(String gavPattern) {
this.gavPattern = GavPattern.of(gavPattern);
}
public String replaceVersion(String version) {
return versionPattern == null ? version : versionPattern.matcher(version).replaceAll(versionReplace);
}
public void setVersionReplacement(String versionReplacement) {
final int slashPos = versionReplacement.indexOf('/');
if (slashPos < 1) {
throw new IllegalStateException(
"versionReplacement is expected to contain exactly one slash (/); found " + versionReplacement);
}
this.versionPattern = Pattern.compile(versionReplacement.substring(0, slashPos));
this.versionReplace = versionReplacement.substring(slashPos + 1);
}
@Override
public String toString() {
return "BomEntryTransformation [gavPattern=" + gavPattern + ", internalExclusions=" + internalExclusions
+ ", versionReplace=" + versionReplace + "]";
}
}
static class DependencyCollector implements DependencyVisitor {
private final Set allTransitives = new TreeSet<>();
private final GavSet excludes;
private final BiConsumer exclusionConsumer;
private final Deque stack = new ArrayDeque<>();
private final GavSet bannedDependencies;
private final Predicate isCurrentBomEntry;
private final Predicate isCurrentBomOrIncludedEntry;
private final GavSet suspects;
private final Consumer> suspectConsumer;
private final Map> additionalBomConstraits;
private final Log log;
private final boolean format;
public DependencyCollector(
GavSet excludes,
BiConsumer exclusionConsumer,
GavSet bannedDependencies,
Predicate isCurrentBomEntry,
Predicate isCurrentBomIncludedEntry,
Map> additionalBomConstraits,
GavSet suspects,
Consumer> suspectConsumer,
Log log,
boolean format) {
this.excludes = excludes;
this.exclusionConsumer = exclusionConsumer;
this.bannedDependencies = bannedDependencies;
this.isCurrentBomEntry = isCurrentBomEntry;
this.isCurrentBomOrIncludedEntry = isCurrentBomIncludedEntry;
this.additionalBomConstraits = additionalBomConstraits;
this.suspects = suspects;
this.suspectConsumer = suspectConsumer;
this.log = log;
this.format = format;
}
@Override
public boolean visitLeave(DependencyNode node) {
if (!format || node.getData().get(ConflictResolver.NODE_DATA_WINNER) == null) {
/*
* We always push in non-format mode, so we have to always pop, thus saving some node.getData() map
* lookups
*/
stack.pop();
}
return true;
}
@Override
public boolean visitEnter(DependencyNode node) {
final Artifact a = node.getArtifact();
final Ga ga = new Ga(a.getGroupId(), a.getArtifactId());
DependencyNode winner;
if (format && (winner = (DependencyNode) node.getData().get(ConflictResolver.NODE_DATA_WINNER)) != null) {
/* We use ConflictResolver.CONFIG_PROP_VERBOSE = true only when format is true */
/* Recurse the winner instead of the current looser */
if (!stack.contains(ga)) {
winner.accept(this);
}
return false; // should have empty children anyway as stated in class level JavaDoc of ConflictResolver
}
boolean result = true;
if (!excludes.contains(a.getGroupId(), a.getArtifactId())) {
if (bannedDependencies.contains(ga)) {
result = false;
/*
* Find the closest own managed dependent and register an exclusion there
* This is to make the enforcer happy when the BOM is taken from the reactor.
* The reactor BOM is not flattened and the bomEntryTransformations are thus not applied there.
* Hence adding an exclusion on our own entry may help
*/
final Optional dependent = stack.stream()
.filter(isCurrentBomEntry)
.findFirst();
if (dependent.isPresent()) {
exclusionConsumer.accept(dependent.get(), ga);
}
/* Find the closest included managed dependent and register an exclusion there */
final Optional includedDependent = stack.stream()
.filter(isCurrentBomOrIncludedEntry)
.findFirst();
if (includedDependent.isPresent() && !Objects.equals(includedDependent.get(), dependent.orElse(null))) {
exclusionConsumer.accept(includedDependent.get(), ga);
} else if (!dependent.isPresent()
&& !includedDependent.isPresent()) {
/* Look if this banned dependency comes via some additional BOM, such as Quarkus BOM */
final Map> missingAddionalBomExclusions = new TreeMap>();
stack.stream()
.forEach(stackEntry -> Optional.ofNullable(additionalBomConstraits.get(stackEntry))
.ifPresent(additionalBomGavs -> additionalBomGavs.stream()
.forEach(bomGav -> missingAddionalBomExclusions.put(bomGav,
new SimpleImmutableEntry<>(stackEntry, ga)))));
if (!missingAddionalBomExclusions.isEmpty()) {
missingAddionalBomExclusions.forEach((Gav additionalBomGav, Map.Entry entry) -> log.warn(
additionalBomGav + " is possibly missing an exclusion on " + entry.getKey() + ":\n\n"
+ " \n"
+ " " + entry.getValue().getGroupId() + "\n"
+ " " + entry.getValue().getArtifactId() + "\n"
+ " \n"));
} else {
throw new IllegalStateException(
"Cannot link banned dependency to any own or included BOM entry:\n " + ga + "\n -> "
+ stack.stream().map(Ga::toString).collect(Collectors.joining("\n -> ")));
}
}
}
allTransitives.add(ga);
}
stack.push(ga);
if (suspects.contains(ga)) {
suspectConsumer.accept(stack);
}
return result;
}
}
private static class InputLocationStringFormatter
extends InputLocation.StringFormatter {
private final String versionSuffix;
public InputLocationStringFormatter(String version) {
this.versionSuffix = ":" + version;
}
private static final String GAV_PREFIX = FlattenBomTask.ORG_APACHE_CAMEL_QUARKUS_GROUP_ID + ":";
public String toString(InputLocation location) {
InputSource source = location.getSource();
String s = source.getModelId(); // by default, display modelId
if (StringUtils.isBlank(s) || s.contains("[unknown-version]")) {
// unless it is blank or does not provide version information
s = source.toString();
}
if (s.startsWith(GAV_PREFIX)) {
s = s.replace(versionSuffix, ":${project.version}");
}
return "#} " + s + " ";
}
}
private static class BomEntryTransformationData {
final BomEntryTransformation bomEntryTransformation;
final ContainerElement containerElement;
public BomEntryTransformationData(BomEntryTransformation bomEntryTransformation, ContainerElement containerElement) {
this.bomEntryTransformation = bomEntryTransformation;
this.containerElement = containerElement;
}
public void addExclusions(Set missingExclusions) {
Set existingExclusions = bomEntryTransformation.internalExclusions;
if (!existingExclusions.containsAll(missingExclusions)) {
existingExclusions.addAll(missingExclusions);
containerElement.addOrSetChildTextElement("addExclusions",
existingExclusions.stream().map(Ga::toString).collect(Collectors.joining(",")));
final Optional exclusions = containerElement.getChildContainerElement("exclusions");
if (exclusions.isPresent()) {
exclusions.get().remove(true, true);
}
}
}
public static BomEntryTransformationData create(GavPattern pattern, Set missingExclusions,
ContainerElement parent) {
final BomEntryTransformation transformation = new BomEntryTransformation();
transformation.setGavPattern(pattern.toString());
final String exclusions = missingExclusions.stream().map(Ga::toString).collect(Collectors.joining(","));
transformation.setAddExclusions(exclusions);
ContainerElement node = parent.addChildContainerElement("autogeneratedBomEntryTransformation");
node.addChildTextElement("gavPattern", pattern.toString());
node.addChildTextElement("addExclusions", exclusions);
return new BomEntryTransformationData(transformation, node);
}
}
private static class RequiredGas {
private final Set gas;
private final Map> expectedExclusions;
public RequiredGas(Set gas, Map> expectedExclusions) {
this.gas = gas;
this.expectedExclusions = expectedExclusions;
}
}
private static class ExpectedExclusions {
final Map> expectedExclusions = new TreeMap<>();
public void add(Ga bomEntry, Ga exclusion) {
expectedExclusions.compute(bomEntry, (Ga k, Set v) -> {
(v == null ? v = new TreeSet() : v).add(exclusion);
return v;
});
}
}
public static enum InstallFlavor {
FULL, REDUCED, REDUCED_VERBOSE, ORIGINAL
}
private final List resolutionEntryPointIncludes;
private final List resolutionEntryPointExcludes;
private final List resolutionSuspects;
private final List originExcludes;
private final List bomEntryTransformations;
private final GavSet requiredBomEntries;
private final OnFailure onCheckFailure;
private final Model effectivePomModel;
private final String version;
private final Path basePath;
private final Path rootModuleDirectory;
private final Path fullPomPath;
private final Path reducedVerbosePamPath;
private final Path reducedPomPath;
private final Charset charset;
private final Log log;
private final List repositories;
private final RepositorySystem repoSystem;
private final RepositorySystemSession repoSession;
private final Predicate profiles;
private final boolean format;
private final SimpleElementWhitespace simpleElementWhitespace;
private final MavenProject project;
private final FlattenBomTask.InstallFlavor installFlavor;
private final boolean quickly;
private final GavSet bannedDependencies;
private final List ownManagedDependencies;
private final Path localRepositoryPath;
private final List additionalBoms;
private static final Pattern LOCATION_COMMENT_PATTERN = Pattern.compile("\\s*\\Q