org.codehaus.mojo.versions.api.DefaultVersionsHelper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of versions-common Show documentation
Show all versions of versions-common Show documentation
Common components for the Versions Maven Plugin
package org.codehaus.mojo.versions.api;
/*
* 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.
*/
import java.io.BufferedInputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
import org.apache.maven.artifact.versioning.Restriction;
import org.apache.maven.artifact.versioning.VersionRange;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Plugin;
import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.apache.maven.repository.RepositorySystem;
import org.apache.maven.wagon.Wagon;
import org.apache.maven.wagon.authentication.AuthenticationInfo;
import org.apache.maven.wagon.observers.Debug;
import org.apache.maven.wagon.proxy.ProxyInfo;
import org.codehaus.mojo.versions.model.IgnoreVersion;
import org.codehaus.mojo.versions.model.Rule;
import org.codehaus.mojo.versions.model.RuleSet;
import org.codehaus.mojo.versions.model.io.xpp3.RuleXpp3Reader;
import org.codehaus.mojo.versions.ordering.VersionComparator;
import org.codehaus.mojo.versions.ordering.VersionComparators;
import org.codehaus.mojo.versions.utils.DefaultArtifactVersionCache;
import org.codehaus.mojo.versions.utils.DependencyBuilder;
import org.codehaus.mojo.versions.utils.DependencyComparator;
import org.codehaus.mojo.versions.utils.PluginComparator;
import org.codehaus.mojo.versions.utils.RegexUtils;
import org.codehaus.mojo.versions.utils.VersionsExpressionEvaluator;
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import org.eclipse.aether.repository.AuthenticationContext;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.repository.RepositoryPolicy;
import org.eclipse.aether.resolution.ArtifactRequest;
import org.eclipse.aether.resolution.ArtifactResult;
import org.eclipse.aether.resolution.VersionRangeRequest;
import org.eclipse.aether.resolution.VersionRangeResolutionException;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.Optional.empty;
import static java.util.Optional.of;
import static java.util.Optional.ofNullable;
import static org.apache.maven.RepositoryUtils.toArtifact;
/**
* Helper class that provides common functionality required by both the mojos and the reports.
*
* @author Stephen Connolly
* @since 1.0-alpha-3
*/
public class DefaultVersionsHelper implements VersionsHelper {
private static final String CLASSPATH_PROTOCOL = "classpath";
private static final String TYPE_EXACT = "exact";
private static final String TYPE_REGEX = "regex";
private static final int LOOKUP_PARALLEL_THREADS = 5;
/**
* The artifact comparison rules to use.
*
* @since 1.0-alpha-3
*/
private RuleSet ruleSet;
private final RepositorySystem repositorySystem;
private final org.eclipse.aether.RepositorySystem aetherRepositorySystem;
/**
* The {@link Log} to send log messages to.
*
* @since 1.0-alpha-3
*/
private final Log log;
/**
* The maven session.
*
* @since 1.0-beta-1
*/
private final MavenSession mavenSession;
private final MojoExecution mojoExecution;
/**
* A cache mapping artifacts to their best fitting rule, since looking up
* this information can be quite costly.
*
* @since 2.12
*/
private final Map artifactBestFitRule = new HashMap<>();
private final List remoteProjectRepositories;
private final List remotePluginRepositories;
private final List remoteRepositories;
/**
* Private constructor used by the builder
*/
private DefaultVersionsHelper(
RepositorySystem repositorySystem,
org.eclipse.aether.RepositorySystem aetherRepositorySystem,
MavenSession mavenSession,
MojoExecution mojoExecution,
Log log) {
this.repositorySystem = repositorySystem;
this.aetherRepositorySystem = aetherRepositorySystem;
this.mavenSession = mavenSession;
this.mojoExecution = mojoExecution;
this.log = log;
this.remoteProjectRepositories = Optional.ofNullable(mavenSession)
.map(MavenSession::getCurrentProject)
.map(MavenProject::getRemoteProjectRepositories)
.map(DefaultVersionsHelper::adjustRemoteRepositoriesRefreshPolicy)
.orElseGet(Collections::emptyList);
this.remotePluginRepositories = Optional.ofNullable(mavenSession)
.map(MavenSession::getCurrentProject)
.map(MavenProject::getRemotePluginRepositories)
.map(DefaultVersionsHelper::adjustRemoteRepositoriesRefreshPolicy)
.orElseGet(Collections::emptyList);
this.remoteRepositories = Stream.concat(remoteProjectRepositories.stream(), remotePluginRepositories.stream())
.distinct()
.collect(Collectors.toList());
}
static List adjustRemoteRepositoriesRefreshPolicy(List remoteRepositories) {
return remoteRepositories.stream()
.map(DefaultVersionsHelper::adjustRemoteRepositoryRefreshPolicy)
.collect(Collectors.toList());
}
static RemoteRepository adjustRemoteRepositoryRefreshPolicy(RemoteRepository remoteRepository) {
RepositoryPolicy snapshotPolicy = remoteRepository.getPolicy(true);
RepositoryPolicy releasePolicy = remoteRepository.getPolicy(false);
RepositoryPolicy newSnapshotPolicy = null;
RepositoryPolicy newReleasePolicy = null;
if (snapshotPolicy.isEnabled()
&& RepositoryPolicy.UPDATE_POLICY_NEVER.equals(snapshotPolicy.getUpdatePolicy())) {
newSnapshotPolicy = new RepositoryPolicy(
true, RepositoryPolicy.UPDATE_POLICY_DAILY, snapshotPolicy.getChecksumPolicy());
}
if (releasePolicy.isEnabled() && RepositoryPolicy.UPDATE_POLICY_NEVER.equals(releasePolicy.getUpdatePolicy())) {
newReleasePolicy =
new RepositoryPolicy(true, RepositoryPolicy.UPDATE_POLICY_DAILY, releasePolicy.getChecksumPolicy());
}
if (newSnapshotPolicy != null || newReleasePolicy != null) {
RemoteRepository.Builder builder = new RemoteRepository.Builder(remoteRepository);
if (newSnapshotPolicy != null) {
builder.setSnapshotPolicy(newSnapshotPolicy);
}
if (newReleasePolicy != null) {
builder.setReleasePolicy(newReleasePolicy);
}
return builder.build();
} else {
return remoteRepository;
}
}
static boolean exactMatch(String wildcardRule, String value) {
Pattern p = Pattern.compile(RegexUtils.convertWildcardsToRegex(wildcardRule, true));
return p.matcher(value).matches();
}
static boolean match(String wildcardRule, String value) {
Pattern p = Pattern.compile(RegexUtils.convertWildcardsToRegex(wildcardRule, false));
return p.matcher(value).matches();
}
static boolean isClasspathUri(String uri) {
return (uri != null && uri.startsWith(CLASSPATH_PROTOCOL + ":"));
}
@Override
public Log getLog() {
return log;
}
@Override
public ArtifactVersions lookupArtifactVersions(
Artifact artifact, VersionRange versionRange, boolean usePluginRepositories)
throws VersionRetrievalException {
return lookupArtifactVersions(artifact, versionRange, usePluginRepositories, !usePluginRepositories);
}
@Override
public ArtifactVersions lookupArtifactVersions(
Artifact artifact, VersionRange versionRange, boolean usePluginRepositories, boolean useProjectRepositories)
throws VersionRetrievalException {
try {
Collection ignoredVersions = getIgnoredVersions(artifact);
if (!ignoredVersions.isEmpty() && getLog().isDebugEnabled()) {
getLog().debug("Found ignored versions: "
+ ignoredVersions.stream().map(IgnoreVersion::toString).collect(Collectors.joining(", ")));
}
final List repositories;
if (usePluginRepositories && !useProjectRepositories) {
repositories = remotePluginRepositories;
} else if (!usePluginRepositories && useProjectRepositories) {
repositories = remoteProjectRepositories;
} else if (usePluginRepositories) {
repositories = remoteRepositories;
} else {
// testing?
repositories = emptyList();
}
return new ArtifactVersions(
artifact,
aetherRepositorySystem
.resolveVersionRange(
mavenSession.getRepositorySession(),
new VersionRangeRequest(
toArtifact(artifact)
.setVersion(ofNullable(versionRange)
.map(VersionRange::getRestrictions)
.flatMap(list -> list.stream()
.findFirst()
.map(Restriction::toString))
.orElse("(,)")),
repositories,
"lookupArtifactVersions"))
.getVersions()
.stream()
.filter(v -> ignoredVersions.stream().noneMatch(i -> {
if (TYPE_REGEX.equals(i.getType())
&& Pattern.compile(i.getVersion())
.matcher(v.toString())
.matches()) {
if (getLog().isDebugEnabled()) {
getLog().debug("Version " + v + " for artifact "
+ ArtifactUtils.versionlessKey(artifact)
+ " found on ignore list: "
+ i);
}
return true;
}
if (TYPE_EXACT.equals(i.getType())
&& i.getVersion().equals(v.toString())) {
if (getLog().isDebugEnabled()) {
getLog().debug("Version " + v + " for artifact "
+ ArtifactUtils.versionlessKey(artifact)
+ " found on ignore list: "
+ i);
}
return true;
}
return false;
}))
.map(v -> DefaultArtifactVersionCache.of(v.toString()))
.collect(Collectors.toList()),
getVersionComparator(artifact));
} catch (VersionRangeResolutionException e) {
throw new VersionRetrievalException(e.getMessage(), e);
}
}
@Override
public ArtifactVersions lookupArtifactVersions(Artifact artifact, boolean usePluginRepositories)
throws VersionRetrievalException {
return lookupArtifactVersions(artifact, null, usePluginRepositories);
}
/**
* Returns a list of versions which should not be considered when looking for updates.
*
* @param artifact The artifact
* @return List of ignored version
*/
private List getIgnoredVersions(Artifact artifact) {
final List ret = new ArrayList<>();
for (final IgnoreVersion ignoreVersion : ruleSet.getIgnoreVersions()) {
if (!TYPE_EXACT.equals(ignoreVersion.getType()) && !TYPE_REGEX.equals(ignoreVersion.getType())) {
getLog().warn("The type attribute '" + ignoreVersion.getType() + "' for global ignoreVersion["
+ ignoreVersion + "] is not valid." + " Please use either '" + TYPE_EXACT + "' or '"
+ TYPE_REGEX
+ "'.");
} else {
ret.add(ignoreVersion);
}
}
final Rule rule = getBestFitRule(artifact.getGroupId(), artifact.getArtifactId());
if (rule != null) {
for (IgnoreVersion ignoreVersion : rule.getIgnoreVersions()) {
if (!TYPE_EXACT.equals(ignoreVersion.getType()) && !TYPE_REGEX.equals(ignoreVersion.getType())) {
getLog().warn("The type attribute '" + ignoreVersion.getType() + "' for " + rule + " is not valid."
+ " Please use either '" + TYPE_EXACT + "' or '" + TYPE_REGEX + "'.");
} else {
ret.add(ignoreVersion);
}
}
}
return ret;
}
@Override
public void resolveArtifact(Artifact artifact, boolean usePluginRepositories) throws ArtifactResolutionException {
try {
ArtifactResult artifactResult = aetherRepositorySystem.resolveArtifact(
mavenSession.getRepositorySession(),
new ArtifactRequest(
toArtifact(artifact),
usePluginRepositories
? mavenSession.getCurrentProject().getRemotePluginRepositories()
: mavenSession.getCurrentProject().getRemoteProjectRepositories(),
getClass().getName()));
artifact.setFile(artifactResult.getArtifact().getFile());
artifact.setVersion(artifactResult.getArtifact().getVersion());
artifact.setResolved(artifactResult.isResolved());
} catch (org.eclipse.aether.resolution.ArtifactResolutionException e) {
throw new ArtifactResolutionException(e.getMessage(), artifact);
}
}
@Override
public VersionComparator getVersionComparator(Artifact artifact) {
return getVersionComparator(artifact.getGroupId(), artifact.getArtifactId());
}
@Override
public VersionComparator getVersionComparator(String groupId, String artifactId) {
Rule rule = getBestFitRule(groupId, artifactId);
final String comparisonMethod = rule == null ? ruleSet.getComparisonMethod() : rule.getComparisonMethod();
return VersionComparators.getVersionComparator(comparisonMethod);
}
/**
* Find the rule, if any, which best fits the artifact details given.
*
* @param groupId Group id of the artifact
* @param artifactId Artifact id of the artifact
* @return Rule which best describes the given artifact
*/
protected Rule getBestFitRule(String groupId, String artifactId) {
String groupArtifactId = groupId + ':' + artifactId;
if (artifactBestFitRule.containsKey(groupArtifactId)) {
return artifactBestFitRule.get(groupArtifactId);
}
Rule bestFit = null;
final List rules = ruleSet.getRules();
int bestGroupIdScore = Integer.MAX_VALUE;
int bestArtifactIdScore = Integer.MAX_VALUE;
boolean exactGroupId = false;
boolean exactArtifactId = false;
for (Rule rule : rules) {
int groupIdScore = RegexUtils.getWildcardScore(rule.getGroupId());
if (groupIdScore > bestGroupIdScore) {
continue;
}
boolean exactMatch = exactMatch(rule.getGroupId(), groupId);
boolean match = exactMatch || match(rule.getGroupId(), groupId);
if (!match || (exactGroupId && !exactMatch)) {
continue;
}
if (bestGroupIdScore > groupIdScore) {
bestArtifactIdScore = Integer.MAX_VALUE;
exactArtifactId = false;
}
bestGroupIdScore = groupIdScore;
if (exactMatch && !exactGroupId) {
exactGroupId = true;
bestArtifactIdScore = Integer.MAX_VALUE;
exactArtifactId = false;
}
int artifactIdScore = RegexUtils.getWildcardScore(rule.getArtifactId());
if (artifactIdScore > bestArtifactIdScore) {
continue;
}
exactMatch = exactMatch(rule.getArtifactId(), artifactId);
match = exactMatch || match(rule.getArtifactId(), artifactId);
if (!match || (exactArtifactId && !exactMatch)) {
continue;
}
bestArtifactIdScore = artifactIdScore;
if (exactMatch && !exactArtifactId) {
exactArtifactId = true;
}
bestFit = rule;
}
artifactBestFitRule.put(groupArtifactId, bestFit);
return bestFit;
}
@Override
public Artifact createPluginArtifact(String groupId, String artifactId, String version) {
Plugin plugin = new Plugin();
plugin.setGroupId(groupId);
plugin.setArtifactId(artifactId);
plugin.setVersion(StringUtils.isNotBlank(version) ? version : "[0,]");
return repositorySystem.createPluginArtifact(plugin);
}
@Override
public Artifact createDependencyArtifact(
String groupId,
String artifactId,
String version,
String type,
String classifier,
String scope,
boolean optional) {
return repositorySystem.createDependencyArtifact(DependencyBuilder.newBuilder()
.withGroupId(groupId)
.withArtifactId(artifactId)
.withType(type)
.withClassifier(classifier)
.withScope(scope)
.withOptional(optional)
.withVersion(StringUtils.isNotBlank(version) ? version : "[0,]")
.build());
}
@Override
public Artifact createDependencyArtifact(
String groupId, String artifactId, String version, String type, String classifier, String scope) {
return createDependencyArtifact(groupId, artifactId, version, type, classifier, scope, false);
}
@Override
public Artifact createDependencyArtifact(Dependency dependency) {
if (StringUtils.isBlank(dependency.getVersion())) {
dependency = dependency.clone();
dependency.setVersion("[,0]");
}
return repositorySystem.createDependencyArtifact(dependency);
}
@Override
public Set extractArtifacts(Collection mavenProjects) {
Set result = new HashSet<>();
for (MavenProject project : mavenProjects) {
result.add(project.getArtifact());
}
return result;
}
@Override
public ArtifactVersion createArtifactVersion(String version) {
return DefaultArtifactVersionCache.of(version);
}
public Map lookupDependenciesUpdates(
Stream dependencies,
boolean usePluginRepositories,
boolean useProjectRepositories,
boolean allowSnapshots)
throws VersionRetrievalException {
ExecutorService executor = Executors.newFixedThreadPool(LOOKUP_PARALLEL_THREADS);
try {
Map dependencyUpdates = new TreeMap<>(DependencyComparator.INSTANCE);
List>> futures = dependencies
.map(dependency -> executor.submit(() -> new ImmutablePair<>(
dependency,
lookupDependencyUpdates(
dependency, usePluginRepositories, useProjectRepositories, allowSnapshots))))
.collect(Collectors.toList());
for (Future extends Pair> details : futures) {
Pair pair = details.get();
dependencyUpdates.put(pair.getKey(), pair.getValue());
}
return dependencyUpdates;
} catch (ExecutionException | InterruptedException ie) {
throw new VersionRetrievalException(
"Unable to acquire metadata for dependencies " + dependencies + ": " + ie.getMessage(), ie);
} finally {
executor.shutdown();
}
}
@Override
public Map lookupDependenciesUpdates(
Stream dependencies, boolean usePluginRepositories, boolean allowSnapshots)
throws VersionRetrievalException {
return lookupDependenciesUpdates(dependencies, usePluginRepositories, !usePluginRepositories, allowSnapshots);
}
@Override
public ArtifactVersions lookupDependencyUpdates(
Dependency dependency,
boolean usePluginRepositories,
boolean useProjectRepositories,
boolean allowSnapshots)
throws VersionRetrievalException {
ArtifactVersions allVersions = lookupArtifactVersions(
createDependencyArtifact(dependency), null, usePluginRepositories, useProjectRepositories);
return new ArtifactVersions(
allVersions.getArtifact(),
Arrays.stream(allVersions.getAllUpdates(allowSnapshots)).collect(Collectors.toList()),
allVersions.getVersionComparator());
}
@Override
public Map lookupPluginsUpdates(Stream plugins, boolean allowSnapshots)
throws VersionRetrievalException {
ExecutorService executor = Executors.newFixedThreadPool(LOOKUP_PARALLEL_THREADS);
try {
Map pluginUpdates = new TreeMap<>(PluginComparator.INSTANCE);
List>> futures = plugins.map(
p -> executor.submit(() -> new ImmutablePair<>(p, lookupPluginUpdates(p, allowSnapshots))))
.collect(Collectors.toList());
for (Future extends Pair> details : futures) {
Pair pair = details.get();
pluginUpdates.put(pair.getKey(), pair.getValue());
}
return pluginUpdates;
} catch (ExecutionException | InterruptedException ie) {
throw new VersionRetrievalException(
"Unable to acquire metadata for plugins " + plugins + ": " + ie.getMessage(), ie);
} finally {
executor.shutdown();
}
}
@Override
public PluginUpdatesDetails lookupPluginUpdates(Plugin plugin, boolean allowSnapshots)
throws VersionRetrievalException {
String version = plugin.getVersion() != null ? plugin.getVersion() : "LATEST";
Set pluginDependencies = new TreeSet<>(DependencyComparator.INSTANCE);
if (plugin.getDependencies() != null) {
pluginDependencies.addAll(plugin.getDependencies());
}
Map pluginDependencyDetails =
lookupDependenciesUpdates(pluginDependencies.stream(), false, allowSnapshots);
ArtifactVersions allVersions = lookupArtifactVersions(
createPluginArtifact(plugin.getGroupId(), plugin.getArtifactId(), version), true);
ArtifactVersions updatedVersions = new ArtifactVersions(
allVersions.getArtifact(),
Arrays.stream(allVersions.getAllUpdates(allowSnapshots)).collect(Collectors.toList()),
allVersions.getVersionComparator());
return new PluginUpdatesDetails(updatedVersions, pluginDependencyDetails, allowSnapshots);
}
@Override
public ExpressionEvaluator getExpressionEvaluator(MavenProject project) {
return new VersionsExpressionEvaluator(mavenSession, mojoExecution);
}
@Override
public Map getVersionPropertiesMap(VersionPropertiesMapRequest request)
throws MojoExecutionException {
Map properties = new HashMap<>();
if (request.getPropertyDefinitions() != null) {
Arrays.stream(request.getPropertyDefinitions()).forEach(p -> properties.put(p.getName(), p));
}
Map builders = new HashMap<>();
if (request.isAutoLinkItems()) {
final PropertyVersionsBuilder[] propertyVersionsBuilders;
try {
propertyVersionsBuilders = PomHelper.getPropertyVersionsBuilders(
this, request.getMavenProject(), request.isIncludeParent());
} catch (ExpressionEvaluationException | IOException e) {
throw new MojoExecutionException(e.getMessage(), e);
}
for (PropertyVersionsBuilder propertyVersionsBuilder : propertyVersionsBuilders) {
final String name = propertyVersionsBuilder.getName();
builders.put(name, propertyVersionsBuilder);
if (!properties.containsKey(name)) {
final Property value = new Property(name);
getLog().debug("Property ${" + name + "}: Adding inferred version range of "
+ propertyVersionsBuilder.getVersionRange());
value.setVersion(propertyVersionsBuilder.getVersionRange());
properties.put(name, value);
}
}
}
List includePropertiesList = request.getIncludeProperties() != null
? Arrays.asList(request.getIncludeProperties().split("\\s*,\\s*"))
: Collections.emptyList();
List excludePropertiesList = request.getExcludeProperties() != null
? Arrays.asList(request.getExcludeProperties().split("\\s*,\\s*"))
: Collections.emptyList();
getLog().debug("Searching for properties associated with builders");
Iterator i = properties.values().iterator();
while (i.hasNext()) {
Property property = i.next();
getLog().debug("includePropertiesList:" + includePropertiesList + " property: " + property.getName());
getLog().debug("excludePropertiesList:" + excludePropertiesList + " property: " + property.getName());
if (!includePropertiesList.isEmpty() && !includePropertiesList.contains(property.getName())) {
getLog().debug("Skipping property ${" + property.getName() + "}");
i.remove();
} else if (!excludePropertiesList.isEmpty() && excludePropertiesList.contains(property.getName())) {
getLog().debug("Ignoring property ${" + property.getName() + "}");
i.remove();
}
}
i = properties.values().iterator();
Map propertyVersions = new LinkedHashMap<>(properties.size());
while (i.hasNext()) {
Property property = i.next();
getLog().debug("Property ${" + property.getName() + "}");
PropertyVersionsBuilder builder = builders.get(property.getName());
if (builder == null || !builder.isAssociated()) {
getLog().debug("Property ${" + property.getName() + "}: Looks like this property is not "
+ "associated with any dependency...");
builder = new PropertyVersionsBuilder(null, property.getName(), this);
}
if (!property.isAutoLinkDependencies()) {
getLog().debug("Property ${" + property.getName() + "}: Removing any autoLinkDependencies");
builder.clearAssociations();
}
Dependency[] dependencies = property.getDependencies();
if (dependencies != null) {
for (Dependency dependency : dependencies) {
getLog().debug("Property ${" + property.getName() + "}: Adding association to " + dependency);
builder.withAssociation(this.createDependencyArtifact(dependency), false);
}
}
try {
if (property.isAutoLinkDependencies()
&& StringUtils.isEmpty(property.getVersion())
&& !StringUtils.isEmpty(builder.getVersionRange())) {
getLog().debug("Property ${" + property.getName() + "}: Adding inferred version range of "
+ builder.getVersionRange());
property.setVersion(builder.getVersionRange());
}
final String currentVersion =
request.getMavenProject().getProperties().getProperty(property.getName());
property.setValue(currentVersion);
final PropertyVersions versions;
try {
if (currentVersion != null) {
builder.withCurrentVersion(DefaultArtifactVersionCache.of(currentVersion))
.withCurrentVersionRange(VersionRange.createFromVersionSpec(currentVersion));
}
} catch (InvalidVersionSpecificationException e) {
throw new RuntimeException(e);
}
versions = builder.build();
propertyVersions.put(property, versions);
} catch (VersionRetrievalException e) {
throw new MojoExecutionException(e.getMessage(), e);
}
}
return propertyVersions;
}
/**
* Builder class for {@linkplain DefaultVersionsHelper}
*/
public static class Builder {
private RepositorySystem repositorySystem;
private Collection ignoredVersions;
private RuleSet ruleSet;
private String serverId;
private String rulesUri;
private Log log;
private MavenSession mavenSession;
private MojoExecution mojoExecution;
private org.eclipse.aether.RepositorySystem aetherRepositorySystem;
private Map wagonMap;
public Builder() {}
private static RuleSet getRulesFromClasspath(String uri, Log logger) throws MojoExecutionException {
logger.debug("Going to load rules from \"" + uri + "\"");
String choppedUrl = uri.substring(CLASSPATH_PROTOCOL.length() + 3);
URL url = DefaultVersionsHelper.class.getResource(choppedUrl);
if (url == null) {
throw new MojoExecutionException("Resource \"" + uri + "\" not found in classpath.");
}
try (BufferedInputStream bis = new BufferedInputStream(url.openStream())) {
RuleSet result = new RuleXpp3Reader().read(bis);
logger.debug("Loaded rules from \"" + uri + "\" successfully");
return result;
} catch (IOException | XmlPullParserException e) {
throw new MojoExecutionException("Could not load specified rules from " + uri, e);
}
}
/**
* Creates the enriched version of the ruleSet given as parameter; the ruleSet will contain the
* set of ignored versions passed on top of its own (if defined).
*
* If the {@code originalRuleSet} is {@code null}, a new {@linkplain RuleSet} will be created as
* a result.
*
* The method does not change the {@code originalRuleSet} object.
*
* @param ignoredVersions collection of ignored version to enrich the clone of the original rule set
* @param originalRuleSet original rule set
* @return new RuleSet object containing the (if passed) cloned version of the rule set, enriched with
* the given set of ignored versions
*/
@SuppressWarnings("checkstyle:AvoidNestedBlocks")
private static RuleSet enrichRuleSet(Collection ignoredVersions, RuleSet originalRuleSet) {
RuleSet ruleSet = new RuleSet();
if (originalRuleSet != null) {
ruleSet.setComparisonMethod(originalRuleSet.getComparisonMethod());
if (originalRuleSet.getRules() != null) {
ruleSet.setRules(new ArrayList<>(originalRuleSet.getRules()));
}
if (originalRuleSet.getIgnoreVersions() != null) {
ruleSet.setIgnoreVersions(new ArrayList<>(originalRuleSet.getIgnoreVersions()));
}
}
if (ruleSet.getIgnoreVersions() == null) {
ruleSet.setIgnoreVersions(new ArrayList<>());
}
ruleSet.getIgnoreVersions()
.addAll(ignoredVersions.stream()
.map(v -> {
IgnoreVersion ignoreVersion = new IgnoreVersion();
ignoreVersion.setType(TYPE_REGEX);
ignoreVersion.setVersion(v);
return ignoreVersion;
})
.collect(Collectors.toList()));
return ruleSet;
}
private static class RulesUri {
String basePath;
String resource;
private RulesUri(String basePath, String resource) {
this.basePath = basePath;
this.resource = resource;
}
static RulesUri build(String rulesUri) throws URISyntaxException {
int split = rulesUri.lastIndexOf('/');
return split == -1
? new RulesUri(rulesUri, "")
: new RulesUri(
rulesUri.substring(0, split) + '/',
split + 1 < rulesUri.length() ? rulesUri.substring(split + 1) : "");
}
}
private RemoteRepository remoteRepository(RulesUri uri) {
RemoteRepository prototype = new RemoteRepository.Builder(serverId, null, uri.basePath).build();
RemoteRepository.Builder builder = new RemoteRepository.Builder(prototype);
ofNullable(mavenSession.getRepositorySession().getProxySelector().getProxy(prototype))
.ifPresent(builder::setProxy);
ofNullable(mavenSession
.getRepositorySession()
.getAuthenticationSelector()
.getAuthentication(prototype))
.ifPresent(builder::setAuthentication);
ofNullable(mavenSession.getRepositorySession().getMirrorSelector().getMirror(prototype))
.ifPresent(mirror -> builder.setMirroredRepositories(singletonList(mirror)));
return builder.build();
}
private Optional getProxyInfo(RemoteRepository repository) {
return ofNullable(repository.getProxy()).map(proxy -> new ProxyInfo() {
{
setHost(proxy.getHost());
setPort(proxy.getPort());
setType(proxy.getType());
ofNullable(proxy.getAuthentication()).ifPresent(auth -> {
try (AuthenticationContext authCtx =
AuthenticationContext.forProxy(mavenSession.getRepositorySession(), repository)) {
ofNullable(authCtx.get(AuthenticationContext.USERNAME))
.ifPresent(this::setUserName);
ofNullable(authCtx.get(AuthenticationContext.PASSWORD))
.ifPresent(this::setPassword);
ofNullable(authCtx.get(AuthenticationContext.NTLM_DOMAIN))
.ifPresent(this::setNtlmDomain);
ofNullable(authCtx.get(AuthenticationContext.NTLM_WORKSTATION))
.ifPresent(this::setNtlmHost);
}
});
}
});
}
private Optional getAuthenticationInfo(RemoteRepository repository) {
return ofNullable(repository.getAuthentication()).map(authentication -> new AuthenticationInfo() {
{
try (AuthenticationContext authCtx =
AuthenticationContext.forRepository(mavenSession.getRepositorySession(), repository)) {
ofNullable(authCtx.get(AuthenticationContext.USERNAME)).ifPresent(this::setUserName);
ofNullable(authCtx.get(AuthenticationContext.PASSWORD)).ifPresent(this::setPassword);
ofNullable(authCtx.get(AuthenticationContext.PRIVATE_KEY_PASSPHRASE))
.ifPresent(this::setPassphrase);
ofNullable(authCtx.get(AuthenticationContext.PRIVATE_KEY_PATH))
.ifPresent(this::setPrivateKey);
}
}
});
}
private org.apache.maven.wagon.repository.Repository wagonRepository(RemoteRepository repository) {
return new org.apache.maven.wagon.repository.Repository(repository.getId(), repository.getUrl());
}
private RuleSet getRulesUsingWagon() throws MojoExecutionException {
RulesUri uri;
try {
uri = RulesUri.build(rulesUri);
} catch (URISyntaxException e) {
log.warn("Invalid rulesUri protocol: " + e.getMessage());
return null;
}
RemoteRepository repository = remoteRepository(uri);
return ofNullable(wagonMap.get(repository.getProtocol()))
.map(wagon -> {
if (log.isDebugEnabled()) {
Debug debug = new Debug();
wagon.addSessionListener(debug);
wagon.addTransferListener(debug);
}
try {
Optional proxyInfo = getProxyInfo(repository);
Optional authenticationInfo = getAuthenticationInfo(repository);
if (log.isDebugEnabled()) {
log.debug("Connecting to remote repository \"" + repository.getId() + "\""
+ proxyInfo
.map(pi -> " using proxy " + pi.getHost() + ":" + pi.getPort())
.orElse("")
+ authenticationInfo
.map(ai -> " as " + ai.getUserName())
.orElse(""));
}
wagon.connect(
wagonRepository(repository),
getAuthenticationInfo(repository).orElse(null),
getProxyInfo(repository).orElse(null));
try {
Path tempFile = Files.createTempFile("rules-", ".xml");
wagon.get(uri.resource, tempFile.toFile());
try (BufferedInputStream is = new BufferedInputStream(Files.newInputStream(tempFile))) {
return new RuleXpp3Reader().read(is);
} finally {
Files.deleteIfExists(tempFile);
}
} finally {
wagon.disconnect();
}
} catch (Exception e) {
log.warn(e.getMessage());
return null;
}
})
.orElseThrow(() -> new MojoExecutionException("Could not load specified rules from " + rulesUri));
}
public static Optional protocol(final String url) {
int pos = url.indexOf(":");
return pos == -1 ? empty() : of(url.substring(0, pos).trim());
}
public Builder withRepositorySystem(RepositorySystem repositorySystem) {
this.repositorySystem = repositorySystem;
return this;
}
public Builder withIgnoredVersions(Collection ignoredVersions) {
this.ignoredVersions = ignoredVersions;
return this;
}
public Builder withRuleSet(RuleSet ruleSet) {
this.ruleSet = ruleSet;
return this;
}
public Builder withServerId(String serverId) {
this.serverId = serverId;
return this;
}
public Builder withRulesUri(String rulesUri) {
this.rulesUri = rulesUri;
return this;
}
public Builder withLog(Log log) {
this.log = log;
return this;
}
public Builder withMavenSession(MavenSession mavenSession) {
this.mavenSession = mavenSession;
return this;
}
public Builder withMojoExecution(MojoExecution mojoExecution) {
this.mojoExecution = mojoExecution;
return this;
}
public Builder withAetherRepositorySystem(org.eclipse.aether.RepositorySystem aetherRepositorySystem) {
this.aetherRepositorySystem = aetherRepositorySystem;
return this;
}
public Builder withWagonMap(Map wagonMap) {
this.wagonMap = wagonMap;
return this;
}
/**
* Builds the constructed {@linkplain DefaultVersionsHelper} object
* @return constructed {@linkplain DefaultVersionsHelper}
* @throws MojoExecutionException should the constructor with the RuleSet retrieval doesn't succeed
*/
public DefaultVersionsHelper build() throws MojoExecutionException {
DefaultVersionsHelper instance = new DefaultVersionsHelper(
repositorySystem, aetherRepositorySystem, mavenSession, mojoExecution, log);
if (ruleSet != null) {
if (!isBlank(rulesUri)) {
log.warn("rulesUri is ignored if rules are specified in pom or as parameters");
}
instance.ruleSet = ruleSet;
} else {
instance.ruleSet = isBlank(rulesUri)
? new RuleSet()
: isClasspathUri(rulesUri) ? getRulesFromClasspath(rulesUri, log) : getRulesUsingWagon();
}
if (ignoredVersions != null && !ignoredVersions.isEmpty()) {
instance.ruleSet = enrichRuleSet(ignoredVersions, instance.ruleSet);
}
return instance;
}
private static boolean isBlank(String s) {
return s == null || s.trim().isEmpty();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy