[MNG-8006] [MNG-8021] SPI to contribute properties and more (#1384)

Create _aether internal_ "extenders" components to serve several purposes:
* extender to meddle with exec request, for example to mediate between effective properties SPI (exec request extender)
* extender to meddle with prepped session and related bits, for example to move out deprecated code from session factory (session extender)

This PR implements M4 API SPI for contributing effective properties and exposes method for effective properties on `Session`.
* `Session` should expose properties service "ready" for interpolation, otherwise each interpolating code (plugin, etc) would need to construct the "effective" ones themselves, repeating same steps over and over again.
* SPI can contribute to user properties
* `Session` exposed properties are all immutable (sans effective, that is computed on each call).
* and lastly, a cleanup: all packages within `o.a.m.internal.aether` are now package protected, to tighten internal encapsulation. New core package `o.a.m.resolver` introduced that contains 2 publicly accessible classes.

---

https://issues.apache.org/jira/browse/MNG-8006
https://issues.apache.org/jira/browse/MNG-8021
This commit is contained in:
Tamas Cservenak 2024-01-19 12:00:28 +01:00 committed by GitHub
parent 3f47580dcc
commit 6afa4770cb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 555 additions and 217 deletions

View File

@ -20,6 +20,7 @@
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.apache.maven.api.annotations.Experimental;
@ -133,4 +134,12 @@ default String getId() {
@Nonnull
List<RemoteRepository> getRemotePluginRepositories();
/**
* Returns the project properties as immutable map.
*
* @see org.apache.maven.api.services.ProjectManager#setProperty(Project, String, String)
*/
@Nonnull
Map<String, String> getProperties();
}

View File

@ -28,6 +28,7 @@
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.annotations.Nonnull;
import org.apache.maven.api.annotations.Nullable;
import org.apache.maven.api.annotations.ThreadSafe;
import org.apache.maven.api.model.Repository;
import org.apache.maven.api.services.DependencyCoordinateFactory;
@ -55,8 +56,8 @@ public interface Session {
SessionData getData();
/**
* Gets the user properties to use for interpolation. The user properties have been configured directly by the user,
* e.g. via the {@code -Dkey=value} parameter on the command line.
* Returns immutable user properties to use for interpolation. The user properties have been configured directly
* by the user, e.g. via the {@code -Dkey=value} parameter on the command line.
*
* @return the user properties, never {@code null}
*/
@ -64,14 +65,37 @@ public interface Session {
Map<String, String> getUserProperties();
/**
* Gets the system properties to use for interpolation. The system properties are collected from the runtime
* environment such as {@link System#getProperties()} and environment variables.
* Returns immutable system properties to use for interpolation. The system properties are collected from the
* runtime environment such as {@link System#getProperties()} and environment variables
* (prefixed with {@code env.}).
*
* @return the system properties, never {@code null}
*/
@Nonnull
Map<String, String> getSystemProperties();
/**
* Each invocation computes a new map of effective properties. To be used in interpolation.
* <p>
* Effective properties are computed from system, user and optionally project properties, layered with
* defined precedence onto each other to achieve proper precedence. Precedence is defined as:
* <ul>
* <li>System properties (lowest precedence)</li>
* <li>Project properties (optional)</li>
* <li>User properties (highest precedence)</li>
* </ul>
* Note: Project properties contains properties injected from profiles, if applicable. Their precedence is
* {@code profile > project}, hence active profile property may override project property.
* <p>
* The caller of this method should decide whether there is a project in scope (hence, a project instance
* needs to be passed) or not.
*
* @param project {@link Project} or {@code null}.
* @return the effective properties, never {@code null}
*/
@Nonnull
Map<String, String> getEffectiveProperties(@Nullable Project project);
/**
* Returns the current maven version
* @return the maven version, never {@code null}

View File

@ -0,0 +1,37 @@
/*
* 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.api.spi;
import java.util.Map;
import org.apache.maven.api.annotations.Experimental;
/**
* Component able to contribute to Maven session user properties. This SPI component is invoked
* very early, while there is no session created yet.
*/
@Experimental
public interface PropertyContributor {
/**
* Invoked just before session is created with a mutable map that carries collected user properties so far.
*
* @param userProperties The mutable user properties, never {@code null}.
*/
void contribute(Map<String, String> userProperties);
}

View File

@ -59,8 +59,6 @@
import org.apache.maven.execution.ProjectDependencyGraph;
import org.apache.maven.graph.GraphBuilder;
import org.apache.maven.graph.ProjectSelector;
import org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory;
import org.apache.maven.internal.aether.MavenChainedWorkspaceReader;
import org.apache.maven.internal.impl.DefaultSessionFactory;
import org.apache.maven.internal.impl.InternalSession;
import org.apache.maven.lifecycle.LifecycleExecutionException;
@ -71,6 +69,8 @@
import org.apache.maven.model.superpom.SuperPomProvider;
import org.apache.maven.plugin.LegacySupport;
import org.apache.maven.project.MavenProject;
import org.apache.maven.resolver.MavenChainedWorkspaceReader;
import org.apache.maven.resolver.RepositorySystemSessionFactory;
import org.apache.maven.session.scope.internal.SessionScope;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.RepositorySystemSession.CloseableSession;
@ -99,7 +99,7 @@ public class DefaultMaven implements Maven {
private final SessionScope sessionScope;
private final DefaultRepositorySystemSessionFactory repositorySessionFactory;
private final RepositorySystemSessionFactory repositorySessionFactory;
private final GraphBuilder graphBuilder;
@ -123,7 +123,7 @@ public DefaultMaven(
ExecutionEventCatapult eventCatapult,
LegacySupport legacySupport,
SessionScope sessionScope,
DefaultRepositorySystemSessionFactory repositorySessionFactory,
RepositorySystemSessionFactory repositorySessionFactory,
@Named(GraphBuilder.HINT) GraphBuilder graphBuilder,
BuildResumptionAnalyzer buildResumptionAnalyzer,
BuildResumptionDataRepository buildResumptionDataRepository,

View File

@ -20,16 +20,10 @@
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@ -37,15 +31,13 @@
import org.apache.maven.api.services.TypeRegistry;
import org.apache.maven.api.xml.XmlNode;
import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.Authentication;
import org.apache.maven.bridge.MavenRepositorySystem;
import org.apache.maven.eventspy.internal.EventSpyDispatcher;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.internal.xml.XmlNodeImpl;
import org.apache.maven.internal.xml.XmlPlexusConfiguration;
import org.apache.maven.model.ModelBase;
import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
import org.apache.maven.resolver.RepositorySystemSessionFactory;
import org.apache.maven.rtinfo.RuntimeInformation;
import org.apache.maven.settings.Mirror;
import org.apache.maven.settings.Proxy;
@ -63,10 +55,6 @@
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.collection.VersionFilter;
import org.eclipse.aether.repository.AuthenticationContext;
import org.eclipse.aether.repository.AuthenticationSelector;
import org.eclipse.aether.repository.ProxySelector;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.repository.RepositoryPolicy;
import org.eclipse.aether.resolution.ResolutionErrorPolicy;
import org.eclipse.aether.util.graph.manager.ClassicDependencyManager;
@ -86,11 +74,14 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static java.util.Objects.requireNonNull;
/**
* @since 3.3.0
*/
@Named
public class DefaultRepositorySystemSessionFactory {
@Singleton
class DefaultRepositorySystemSessionFactory implements RepositorySystemSessionFactory {
/**
* User property for version filters expression, a semicolon separated list of filters to apply. By default, no version
* filter is applied (like in Maven 3).
@ -188,16 +179,22 @@ public class DefaultRepositorySystemSessionFactory {
private final VersionScheme versionScheme;
private final Map<String, MavenExecutionRequestExtender> requestExtenders;
private final Map<String, RepositorySystemSessionExtender> sessionExtenders;
@SuppressWarnings("checkstyle:ParameterNumber")
@Inject
public DefaultRepositorySystemSessionFactory(
DefaultRepositorySystemSessionFactory(
ArtifactHandlerManager artifactHandlerManager,
RepositorySystem repoSystem,
SettingsDecrypter settingsDecrypter,
EventSpyDispatcher eventSpyDispatcher,
RuntimeInformation runtimeInformation,
TypeRegistry typeRegistry,
VersionScheme versionScheme) {
VersionScheme versionScheme,
Map<String, MavenExecutionRequestExtender> requestExtenders,
Map<String, RepositorySystemSessionExtender> sessionExtenders) {
this.artifactHandlerManager = artifactHandlerManager;
this.repoSystem = repoSystem;
this.settingsDecrypter = settingsDecrypter;
@ -205,6 +202,8 @@ public DefaultRepositorySystemSessionFactory(
this.runtimeInformation = runtimeInformation;
this.typeRegistry = typeRegistry;
this.versionScheme = versionScheme;
this.requestExtenders = requestExtenders;
this.sessionExtenders = sessionExtenders;
}
@Deprecated
@ -212,25 +211,31 @@ public RepositorySystemSession newRepositorySession(MavenExecutionRequest reques
return newRepositorySessionBuilder(request).build();
}
@SuppressWarnings("checkstyle:methodLength")
@SuppressWarnings({"checkstyle:methodLength"})
public SessionBuilder newRepositorySessionBuilder(MavenExecutionRequest request) {
SessionBuilder session = MavenRepositorySystemUtils.newSession(
repoSystem.createSessionBuilder(), new TypeRegistryAdapter(typeRegistry));
session.setCache(request.getRepositoryCache());
requireNonNull(request, "request");
Map<Object, Object> configProps = new LinkedHashMap<>();
// apply MavenExecutionRequestExtenders
for (MavenExecutionRequestExtender requestExtender : requestExtenders.values()) {
requestExtender.extend(request);
}
SessionBuilder sessionBuilder = MavenRepositorySystemUtils.newSession(
repoSystem.createSessionBuilder(), new TypeRegistryAdapter(typeRegistry));
sessionBuilder.setCache(request.getRepositoryCache());
// this map is read ONLY to get config from (profiles + env + system + user)
Map<String, String> mergedProps = createMergedProperties(request);
// configProps map is kept "pristine", is written ONLY, the mandatory resolver config
Map<String, Object> configProps = new LinkedHashMap<>();
configProps.put(ConfigurationProperties.USER_AGENT, getUserAgent());
configProps.put(ConfigurationProperties.INTERACTIVE, request.isInteractiveMode());
configProps.put("maven.startTime", request.getStartTime());
// First add properties populated from settings.xml
configProps.putAll(getPropertiesFromRequestedProfiles(request));
// Resolver's ConfigUtils solely rely on config properties, that is why we need to add both here as well.
configProps.putAll(request.getSystemProperties());
configProps.putAll(request.getUserProperties());
session.setOffline(request.isOffline());
session.setChecksumPolicy(request.getGlobalChecksumPolicy());
session.setUpdatePolicy(
sessionBuilder.setOffline(request.isOffline());
sessionBuilder.setChecksumPolicy(request.getGlobalChecksumPolicy());
sessionBuilder.setUpdatePolicy(
request.isNoSnapshotUpdates()
? RepositoryPolicy.UPDATE_POLICY_NEVER
: request.isUpdateSnapshots() ? RepositoryPolicy.UPDATE_POLICY_ALWAYS : null);
@ -242,18 +247,18 @@ public SessionBuilder newRepositorySessionBuilder(MavenExecutionRequest request)
errorPolicy |= request.isCacheTransferError()
? ResolutionErrorPolicy.CACHE_TRANSFER_ERROR
: ResolutionErrorPolicy.CACHE_DISABLED;
session.setResolutionErrorPolicy(
sessionBuilder.setResolutionErrorPolicy(
new SimpleResolutionErrorPolicy(errorPolicy, errorPolicy | ResolutionErrorPolicy.CACHE_NOT_FOUND));
session.setArtifactDescriptorPolicy(new SimpleArtifactDescriptorPolicy(
sessionBuilder.setArtifactDescriptorPolicy(new SimpleArtifactDescriptorPolicy(
request.isIgnoreMissingArtifactDescriptor(), request.isIgnoreInvalidArtifactDescriptor()));
VersionFilter versionFilter = buildVersionFilter((String) configProps.get(MAVEN_VERSION_FILTERS));
VersionFilter versionFilter = buildVersionFilter(mergedProps.get(MAVEN_VERSION_FILTERS));
if (versionFilter != null) {
session.setVersionFilter(versionFilter);
sessionBuilder.setVersionFilter(versionFilter);
}
session.setArtifactTypeRegistry(RepositoryUtils.newArtifactTypeRegistry(artifactHandlerManager));
sessionBuilder.setArtifactTypeRegistry(RepositoryUtils.newArtifactTypeRegistry(artifactHandlerManager));
DefaultSettingsDecryptionRequest decrypt = new DefaultSettingsDecryptionRequest();
decrypt.setProxies(request.getProxies());
@ -277,7 +282,7 @@ public SessionBuilder newRepositorySessionBuilder(MavenExecutionRequest request)
mirror.getMirrorOf(),
mirror.getMirrorOfLayouts());
}
session.setMirrorSelector(mirrorSelector);
sessionBuilder.setMirrorSelector(mirrorSelector);
DefaultProxySelector proxySelector = new DefaultProxySelector();
for (Proxy proxy : decrypted.getProxies()) {
@ -288,7 +293,7 @@ public SessionBuilder newRepositorySessionBuilder(MavenExecutionRequest request)
proxy.getProtocol(), proxy.getHost(), proxy.getPort(), authBuilder.build()),
proxy.getNonProxyHosts());
}
session.setProxySelector(proxySelector);
sessionBuilder.setProxySelector(proxySelector);
// Note: we do NOT use WagonTransportConfigurationKeys here as Maven Core does NOT depend on Wagon Transport
// and this is okay and "good thing".
@ -381,9 +386,9 @@ public SessionBuilder newRepositorySessionBuilder(MavenExecutionRequest request)
configProps.put("aether.transport.wagon.perms.fileMode." + server.getId(), server.getFilePermissions());
configProps.put("aether.transport.wagon.perms.dirMode." + server.getId(), server.getDirectoryPermissions());
}
session.setAuthenticationSelector(authSelector);
sessionBuilder.setAuthenticationSelector(authSelector);
Object transport = configProps.getOrDefault(MAVEN_RESOLVER_TRANSPORT_KEY, MAVEN_RESOLVER_TRANSPORT_DEFAULT);
Object transport = mergedProps.getOrDefault(MAVEN_RESOLVER_TRANSPORT_KEY, MAVEN_RESOLVER_TRANSPORT_DEFAULT);
if (MAVEN_RESOLVER_TRANSPORT_DEFAULT.equals(transport)) {
// The "default" mode (user did not set anything) from now on defaults to AUTO
} else if (MAVEN_RESOLVER_TRANSPORT_JDK.equals(transport)) {
@ -411,47 +416,50 @@ public SessionBuilder newRepositorySessionBuilder(MavenExecutionRequest request)
+ MAVEN_RESOLVER_TRANSPORT_AUTO);
}
session.setUserProperties(request.getUserProperties());
session.setSystemProperties(request.getSystemProperties());
session.setConfigProperties(configProps);
session.setIgnoreArtifactDescriptorRepositories(request.isIgnoreTransitiveRepositories());
sessionBuilder.setIgnoreArtifactDescriptorRepositories(request.isIgnoreTransitiveRepositories());
session.setTransferListener(request.getTransferListener());
sessionBuilder.setTransferListener(request.getTransferListener());
RepositoryListener repositoryListener = eventSpyDispatcher.chainListener(new LoggingRepositoryListener(logger));
boolean recordReverseTree = configProps.containsKey(MAVEN_REPO_LOCAL_RECORD_REVERSE_TREE)
&& Boolean.parseBoolean((String) configProps.get(MAVEN_REPO_LOCAL_RECORD_REVERSE_TREE));
boolean recordReverseTree = Boolean.parseBoolean(
mergedProps.getOrDefault(MAVEN_REPO_LOCAL_RECORD_REVERSE_TREE, Boolean.FALSE.toString()));
if (recordReverseTree) {
repositoryListener = new ChainedRepositoryListener(repositoryListener, new ReverseTreeRepositoryListener());
}
session.setRepositoryListener(repositoryListener);
sessionBuilder.setRepositoryListener(repositoryListener);
injectMirror(request.getRemoteRepositories(), request.getMirrors());
injectProxy(proxySelector, request.getRemoteRepositories());
injectAuthentication(authSelector, request.getRemoteRepositories());
injectMirror(request.getPluginArtifactRepositories(), request.getMirrors());
injectProxy(proxySelector, request.getPluginArtifactRepositories());
injectAuthentication(authSelector, request.getPluginArtifactRepositories());
String resolverDependencyManagerTransitivity = (String)
configProps.getOrDefault(MAVEN_RESOLVER_DEPENDENCY_MANAGER_TRANSITIVITY_KEY, Boolean.TRUE.toString());
session.setDependencyManager(
String resolverDependencyManagerTransitivity =
mergedProps.getOrDefault(MAVEN_RESOLVER_DEPENDENCY_MANAGER_TRANSITIVITY_KEY, Boolean.TRUE.toString());
sessionBuilder.setDependencyManager(
new ClassicDependencyManager(Boolean.parseBoolean(resolverDependencyManagerTransitivity)));
ArrayList<File> paths = new ArrayList<>();
paths.add(new File(request.getLocalRepository().getBasedir()));
String localRepoTail = (String) configProps.get(MAVEN_REPO_LOCAL_TAIL);
String localRepoTail = mergedProps.get(MAVEN_REPO_LOCAL_TAIL);
if (localRepoTail != null) {
Arrays.stream(localRepoTail.split(","))
.filter(p -> p != null && !p.trim().isEmpty())
.map(File::new)
.forEach(paths::add);
}
session.withLocalRepositoryBaseDirectories(paths);
sessionBuilder.withLocalRepositoryBaseDirectories(paths);
return session;
for (RepositorySystemSessionExtender extender : sessionExtenders.values()) {
extender.extend(request, configProps, mirrorSelector, proxySelector, authSelector);
}
// at this point we have "config" with pure MANDATORY resolver config, so resolver final config properties are
// mergedProperties + configProperties
HashMap<String, Object> finalConfigProperties = new HashMap<>();
finalConfigProperties.putAll(mergedProps);
finalConfigProperties.putAll(configProps);
sessionBuilder.setUserProperties(request.getUserProperties());
sessionBuilder.setSystemProperties(request.getSystemProperties());
sessionBuilder.setConfigProperties(finalConfigProperties);
return sessionBuilder;
}
private VersionFilter buildVersionFilter(String filterExpression) {
@ -520,7 +528,17 @@ private VersionRange parseVersionRange(String spec) {
}
}
private Map<?, ?> getPropertiesFromRequestedProfiles(MavenExecutionRequest request) {
@SuppressWarnings({"unchecked", "rawtypes"})
private Map<String, String> createMergedProperties(MavenExecutionRequest request) {
// this throwaway map is really ONLY to get config from (profiles + env + system + user)
Map<String, String> mergedProps = new HashMap<>();
mergedProps.putAll(getPropertiesFromRequestedProfiles(request));
mergedProps.putAll(new HashMap<String, String>((Map) request.getSystemProperties()));
mergedProps.putAll(new HashMap<String, String>((Map) request.getUserProperties()));
return mergedProps;
}
private Map<String, String> getPropertiesFromRequestedProfiles(MavenExecutionRequest request) {
HashSet<String> activeProfileId =
new HashSet<>(request.getProfileActivation().getRequiredActiveProfileIds());
activeProfileId.addAll(request.getProfileActivation().getOptionalActiveProfileIds());
@ -529,7 +547,9 @@ private VersionRange parseVersionRange(String spec) {
.filter(profile -> activeProfileId.contains(profile.getId()))
.map(ModelBase::getProperties)
.flatMap(properties -> properties.entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (k1, k2) -> k2));
.filter(e -> e.getValue() != null)
.collect(Collectors.toMap(
e -> String.valueOf(e.getKey()), e -> String.valueOf(e.getValue()), (k1, k2) -> k2));
}
private String getUserAgent() {
@ -538,95 +558,4 @@ private String getUserAgent() {
return "Apache-Maven" + version + " (Java " + System.getProperty("java.version") + "; "
+ System.getProperty("os.name") + " " + System.getProperty("os.version") + ")";
}
private void injectMirror(List<ArtifactRepository> repositories, List<Mirror> mirrors) {
if (repositories != null && mirrors != null) {
for (ArtifactRepository repository : repositories) {
Mirror mirror = MavenRepositorySystem.getMirror(repository, mirrors);
injectMirror(repository, mirror);
}
}
}
private void injectMirror(ArtifactRepository repository, Mirror mirror) {
if (mirror != null) {
ArtifactRepository original = MavenRepositorySystem.createArtifactRepository(
repository.getId(),
repository.getUrl(),
repository.getLayout(),
repository.getSnapshots(),
repository.getReleases());
repository.setMirroredRepositories(Collections.singletonList(original));
repository.setId(mirror.getId());
repository.setUrl(mirror.getUrl());
if (mirror.getLayout() != null && !mirror.getLayout().isEmpty()) {
repository.setLayout(original.getLayout());
}
repository.setBlocked(mirror.isBlocked());
}
}
private void injectProxy(ProxySelector selector, List<ArtifactRepository> repositories) {
if (repositories != null && selector != null) {
for (ArtifactRepository repository : repositories) {
repository.setProxy(getProxy(selector, repository));
}
}
}
private org.apache.maven.repository.Proxy getProxy(ProxySelector selector, ArtifactRepository repository) {
if (selector != null) {
RemoteRepository repo = RepositoryUtils.toRepo(repository);
org.eclipse.aether.repository.Proxy proxy = selector.getProxy(repo);
if (proxy != null) {
org.apache.maven.repository.Proxy p = new org.apache.maven.repository.Proxy();
p.setHost(proxy.getHost());
p.setProtocol(proxy.getType());
p.setPort(proxy.getPort());
if (proxy.getAuthentication() != null) {
repo = new RemoteRepository.Builder(repo).setProxy(proxy).build();
AuthenticationContext authCtx = AuthenticationContext.forProxy(null, repo);
p.setUserName(authCtx.get(AuthenticationContext.USERNAME));
p.setPassword(authCtx.get(AuthenticationContext.PASSWORD));
p.setNtlmDomain(authCtx.get(AuthenticationContext.NTLM_DOMAIN));
p.setNtlmHost(authCtx.get(AuthenticationContext.NTLM_WORKSTATION));
authCtx.close();
}
return p;
}
}
return null;
}
private void injectAuthentication(AuthenticationSelector selector, List<ArtifactRepository> repositories) {
if (repositories != null && selector != null) {
for (ArtifactRepository repository : repositories) {
repository.setAuthentication(getAuthentication(selector, repository));
}
}
}
private Authentication getAuthentication(AuthenticationSelector selector, ArtifactRepository repository) {
if (selector != null) {
RemoteRepository repo = RepositoryUtils.toRepo(repository);
org.eclipse.aether.repository.Authentication auth = selector.getAuthentication(repo);
if (auth != null) {
repo = new RemoteRepository.Builder(repo)
.setAuthentication(auth)
.build();
AuthenticationContext authCtx = AuthenticationContext.forRepository(null, repo);
Authentication result = new Authentication(
authCtx.get(AuthenticationContext.USERNAME), authCtx.get(AuthenticationContext.PASSWORD));
result.setPrivateKey(authCtx.get(AuthenticationContext.PRIVATE_KEY_PATH));
result.setPassphrase(authCtx.get(AuthenticationContext.PRIVATE_KEY_PASSPHRASE));
authCtx.close();
return result;
}
}
return null;
}
}

View File

@ -0,0 +1,154 @@
/*
* 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.internal.aether;
import javax.inject.Named;
import javax.inject.Singleton;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.apache.maven.RepositoryUtils;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.Authentication;
import org.apache.maven.bridge.MavenRepositorySystem;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.settings.Mirror;
import org.eclipse.aether.repository.AuthenticationContext;
import org.eclipse.aether.repository.AuthenticationSelector;
import org.eclipse.aether.repository.MirrorSelector;
import org.eclipse.aether.repository.ProxySelector;
import org.eclipse.aether.repository.RemoteRepository;
/**
* Extender that fills in legacy bits (using legacy code).
*
* @since 4.0.0
*/
@Named
@Singleton
class LegacyRepositorySystemSessionExtender implements RepositorySystemSessionExtender {
@Override
public void extend(
MavenExecutionRequest mavenExecutionRequest,
Map<String, Object> configProperties,
MirrorSelector mirrorSelector,
ProxySelector proxySelector,
AuthenticationSelector authenticationSelector) {
injectMirror(mavenExecutionRequest.getRemoteRepositories(), mavenExecutionRequest.getMirrors());
injectProxy(proxySelector, mavenExecutionRequest.getRemoteRepositories());
injectAuthentication(authenticationSelector, mavenExecutionRequest.getRemoteRepositories());
injectMirror(mavenExecutionRequest.getPluginArtifactRepositories(), mavenExecutionRequest.getMirrors());
injectProxy(proxySelector, mavenExecutionRequest.getPluginArtifactRepositories());
injectAuthentication(authenticationSelector, mavenExecutionRequest.getPluginArtifactRepositories());
}
private void injectMirror(List<ArtifactRepository> repositories, List<Mirror> mirrors) {
if (repositories != null && mirrors != null) {
for (ArtifactRepository repository : repositories) {
Mirror mirror = MavenRepositorySystem.getMirror(repository, mirrors);
injectMirror(repository, mirror);
}
}
}
private void injectMirror(ArtifactRepository repository, Mirror mirror) {
if (mirror != null) {
ArtifactRepository original = MavenRepositorySystem.createArtifactRepository(
repository.getId(),
repository.getUrl(),
repository.getLayout(),
repository.getSnapshots(),
repository.getReleases());
repository.setMirroredRepositories(Collections.singletonList(original));
repository.setId(mirror.getId());
repository.setUrl(mirror.getUrl());
if (mirror.getLayout() != null && !mirror.getLayout().isEmpty()) {
repository.setLayout(original.getLayout());
}
repository.setBlocked(mirror.isBlocked());
}
}
private void injectProxy(ProxySelector selector, List<ArtifactRepository> repositories) {
if (repositories != null && selector != null) {
for (ArtifactRepository repository : repositories) {
repository.setProxy(getProxy(selector, repository));
}
}
}
private org.apache.maven.repository.Proxy getProxy(ProxySelector selector, ArtifactRepository repository) {
if (selector != null) {
RemoteRepository repo = RepositoryUtils.toRepo(repository);
org.eclipse.aether.repository.Proxy proxy = selector.getProxy(repo);
if (proxy != null) {
org.apache.maven.repository.Proxy p = new org.apache.maven.repository.Proxy();
p.setHost(proxy.getHost());
p.setProtocol(proxy.getType());
p.setPort(proxy.getPort());
if (proxy.getAuthentication() != null) {
repo = new RemoteRepository.Builder(repo).setProxy(proxy).build();
AuthenticationContext authCtx = AuthenticationContext.forProxy(null, repo);
p.setUserName(authCtx.get(AuthenticationContext.USERNAME));
p.setPassword(authCtx.get(AuthenticationContext.PASSWORD));
p.setNtlmDomain(authCtx.get(AuthenticationContext.NTLM_DOMAIN));
p.setNtlmHost(authCtx.get(AuthenticationContext.NTLM_WORKSTATION));
authCtx.close();
}
return p;
}
}
return null;
}
private void injectAuthentication(AuthenticationSelector selector, List<ArtifactRepository> repositories) {
if (repositories != null && selector != null) {
for (ArtifactRepository repository : repositories) {
repository.setAuthentication(getAuthentication(selector, repository));
}
}
}
private Authentication getAuthentication(AuthenticationSelector selector, ArtifactRepository repository) {
if (selector != null) {
RemoteRepository repo = RepositoryUtils.toRepo(repository);
org.eclipse.aether.repository.Authentication auth = selector.getAuthentication(repo);
if (auth != null) {
repo = new RemoteRepository.Builder(repo)
.setAuthentication(auth)
.build();
AuthenticationContext authCtx = AuthenticationContext.forRepository(null, repo);
Authentication result = new Authentication(
authCtx.get(AuthenticationContext.USERNAME), authCtx.get(AuthenticationContext.PASSWORD));
result.setPrivateKey(authCtx.get(AuthenticationContext.PRIVATE_KEY_PATH));
result.setPassphrase(authCtx.get(AuthenticationContext.PRIVATE_KEY_PASSPHRASE));
authCtx.close();
return result;
}
}
return null;
}
}

View File

@ -0,0 +1,31 @@
/*
* 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.internal.aether;
import org.apache.maven.execution.MavenExecutionRequest;
/**
* Strictly internal component able to "extend" {@link MavenExecutionRequest} in some way before it is used to
* construct resolver session.
*
* @since 4.0.0
*/
interface MavenExecutionRequestExtender {
void extend(MavenExecutionRequest mavenExecutionRequest);
}

View File

@ -0,0 +1,58 @@
/*
* 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.internal.aether;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.apache.maven.api.spi.PropertyContributor;
import org.apache.maven.execution.MavenExecutionRequest;
/**
* Extender that manages {@link PropertyContributor}.
*
* @since 4.0.0
*/
@Named
@Singleton
class PropertyContributorExtender implements MavenExecutionRequestExtender {
private final Map<String, PropertyContributor> effectivePropertyContributors;
@Inject
PropertyContributorExtender(Map<String, PropertyContributor> effectivePropertyContributors) {
this.effectivePropertyContributors = effectivePropertyContributors;
}
@SuppressWarnings({"rawtypes", "unchecked"})
@Override
public void extend(MavenExecutionRequest mavenExecutionRequest) {
HashMap<String, String> userPropertiesMap = new HashMap<>((Map) mavenExecutionRequest.getUserProperties());
for (PropertyContributor contributor : effectivePropertyContributors.values()) {
contributor.contribute(userPropertiesMap);
}
Properties newProperties = new Properties();
newProperties.putAll(userPropertiesMap);
mavenExecutionRequest.setUserProperties(newProperties);
}
}

View File

@ -0,0 +1,40 @@
/*
* 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.internal.aether;
import java.util.Map;
import org.apache.maven.execution.MavenExecutionRequest;
import org.eclipse.aether.repository.AuthenticationSelector;
import org.eclipse.aether.repository.MirrorSelector;
import org.eclipse.aether.repository.ProxySelector;
/**
* Strictly internal component able to "extend" session in some way.
*
* @since 4.0.0
*/
interface RepositorySystemSessionExtender {
void extend(
MavenExecutionRequest mavenExecutionRequest,
Map<String, Object> configProperties,
MirrorSelector mirrorSelector,
ProxySelector proxySelector,
AuthenticationSelector authenticationSelector);
}

View File

@ -26,10 +26,10 @@
import static java.util.Objects.requireNonNull;
public class TypeRegistryAdapter implements ArtifactTypeRegistry {
class TypeRegistryAdapter implements ArtifactTypeRegistry {
private final TypeRegistry typeRegistry;
public TypeRegistryAdapter(TypeRegistry typeRegistry) {
TypeRegistryAdapter(TypeRegistry typeRegistry) {
this.typeRegistry = requireNonNull(typeRegistry, "typeRegistry");
}

View File

@ -20,10 +20,7 @@
import java.io.File;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.*;
import org.apache.maven.RepositoryUtils;
import org.apache.maven.api.*;
@ -154,6 +151,11 @@ public List<RemoteRepository> getRemotePluginRepositories() {
return new MappedList<>(project.getRemotePluginRepositories(), session::getRemoteRepository);
}
@Override
public Map<String, String> getProperties() {
return Collections.unmodifiableMap(new PropertiesAsMap(project.getProperties()));
}
@Nonnull
private DependencyCoordinate toDependency(org.apache.maven.api.model.Dependency dependency) {
return new DependencyCoordinate() {

View File

@ -20,11 +20,7 @@
import java.nio.file.Path;
import java.time.Instant;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
@ -107,13 +103,24 @@ public Settings getSettings() {
@Nonnull
@Override
public Map<String, String> getUserProperties() {
return new PropertiesAsMap(mavenSession.getUserProperties());
return Collections.unmodifiableMap(new PropertiesAsMap(mavenSession.getUserProperties()));
}
@Nonnull
@Override
public Map<String, String> getSystemProperties() {
return new PropertiesAsMap(mavenSession.getSystemProperties());
return Collections.unmodifiableMap(new PropertiesAsMap(mavenSession.getSystemProperties()));
}
@Nonnull
@Override
public Map<String, String> getEffectiveProperties(@Nullable Project project) {
HashMap<String, String> result = new HashMap<>(new PropertiesAsMap(mavenSession.getSystemProperties()));
if (project != null) {
result.putAll(project.getProperties());
}
result.putAll(new PropertiesAsMap(mavenSession.getUserProperties()));
return result;
}
@Nonnull

View File

@ -24,7 +24,6 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import org.apache.maven.api.MojoExecution;
import org.apache.maven.api.Project;
@ -54,15 +53,15 @@
* @see MojoExecution
*/
public class PluginParameterExpressionEvaluatorV4 implements TypeAwareExpressionEvaluator {
private Session session;
private final Session session;
private MojoExecution mojoExecution;
private final MojoExecution mojoExecution;
private Project project;
private final Project project;
private Path basedir;
private final Path basedir;
private Properties properties;
private final Map<String, String> properties;
public PluginParameterExpressionEvaluatorV4(Session session, Project project) {
this(session, project, null);
@ -71,16 +70,9 @@ public PluginParameterExpressionEvaluatorV4(Session session, Project project) {
public PluginParameterExpressionEvaluatorV4(Session session, Project project, MojoExecution mojoExecution) {
this.session = session;
this.mojoExecution = mojoExecution;
this.properties = new Properties();
this.properties = session.getEffectiveProperties(project);
this.project = project;
//
// Maven4: We may want to evaluate how this is used but we add these separate as the
// getExecutionProperties is deprecated in MavenSession.
//
this.properties.putAll(session.getUserProperties());
this.properties.putAll(session.getSystemProperties());
Path basedir = null;
if (project != null) {
@ -198,11 +190,7 @@ public Object evaluate(String expr, Class<?> type) throws ExpressionEvaluationEx
// to run a single test so I want to specify that class on the cli as
// a parameter.
value = properties.getProperty(expression);
}
if ((value == null) && ((project != null) && (project.getModel().getProperties() != null))) {
value = project.getModel().getProperties().get(expression);
value = properties.get(expression);
}
}

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.internal.aether;
package org.apache.maven.resolver;
import java.io.File;
import java.util.*;

View File

@ -0,0 +1,40 @@
/*
* 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.resolver;
import org.apache.maven.execution.MavenExecutionRequest;
import org.eclipse.aether.RepositorySystemSession.SessionBuilder;
/**
* Factory for Resolver session.
*
* @since 4.0.0
*/
public interface RepositorySystemSessionFactory {
/**
* Creates "ready to use" session builder instance. The factory does not set up one thing: the
* {@link org.eclipse.aether.repository.WorkspaceReader}s, that is caller duty to figure out. Workspace readers
* should be set up as very last thing before using resolver session, that is built by invoking
* {@link SessionBuilder#build()} method.
*
* @param request The maven execution request, must not be {@code null}.
* @return The session builder "ready to use" without workspace readers.
*/
SessionBuilder newRepositorySessionBuilder(MavenExecutionRequest request);
}

View File

@ -22,6 +22,7 @@
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@ -88,7 +89,9 @@ void isNoSnapshotUpdatesTest() throws InvalidRepositoryException {
eventSpyDispatcher,
information,
defaultTypeRegistry,
versionScheme);
versionScheme,
Collections.emptyMap(),
Collections.emptyMap());
MavenExecutionRequest request = new DefaultMavenExecutionRequest();
request.setLocalRepository(getLocalRepository());
@ -111,7 +114,9 @@ void isSnapshotUpdatesTest() throws InvalidRepositoryException {
eventSpyDispatcher,
information,
defaultTypeRegistry,
versionScheme);
versionScheme,
Collections.emptyMap(),
Collections.emptyMap());
MavenExecutionRequest request = new DefaultMavenExecutionRequest();
request.setLocalRepository(getLocalRepository());
@ -146,7 +151,9 @@ void wagonProviderConfigurationTest() throws InvalidRepositoryException {
eventSpyDispatcher,
information,
defaultTypeRegistry,
versionScheme);
versionScheme,
Collections.emptyMap(),
Collections.emptyMap());
PlexusConfiguration plexusConfiguration = (PlexusConfiguration) systemSessionFactory
.newRepositorySession(request)
@ -189,7 +196,9 @@ void httpConfigurationWithHttpHeadersTest() throws InvalidRepositoryException {
eventSpyDispatcher,
information,
defaultTypeRegistry,
versionScheme);
versionScheme,
Collections.emptyMap(),
Collections.emptyMap());
Map<String, String> headers = (Map<String, String>) systemSessionFactory
.newRepositorySession(request)
@ -226,7 +235,9 @@ void connectTimeoutConfigurationTest() throws InvalidRepositoryException {
eventSpyDispatcher,
information,
defaultTypeRegistry,
versionScheme);
versionScheme,
Collections.emptyMap(),
Collections.emptyMap());
int connectionTimeout = (Integer) systemSessionFactory
.newRepositorySession(request)
@ -267,7 +278,9 @@ void connectionTimeoutFromHttpConfigurationTest() throws InvalidRepositoryExcept
eventSpyDispatcher,
information,
defaultTypeRegistry,
versionScheme);
versionScheme,
Collections.emptyMap(),
Collections.emptyMap());
int connectionTimeout = (Integer) systemSessionFactory
.newRepositorySession(request)
@ -302,7 +315,9 @@ void requestTimeoutConfigurationTest() throws InvalidRepositoryException {
eventSpyDispatcher,
information,
defaultTypeRegistry,
versionScheme);
versionScheme,
Collections.emptyMap(),
Collections.emptyMap());
int requestTimeout = (Integer) systemSessionFactory
.newRepositorySession(request)
@ -343,7 +358,9 @@ void readTimeoutFromHttpConfigurationTest() throws InvalidRepositoryException {
eventSpyDispatcher,
information,
defaultTypeRegistry,
versionScheme);
versionScheme,
Collections.emptyMap(),
Collections.emptyMap());
int requestTimeout = (Integer) systemSessionFactory
.newRepositorySession(request)
@ -361,7 +378,9 @@ void transportConfigurationTest() throws InvalidRepositoryException {
eventSpyDispatcher,
information,
defaultTypeRegistry,
versionScheme);
versionScheme,
Collections.emptyMap(),
Collections.emptyMap());
MavenExecutionRequest request = new DefaultMavenExecutionRequest();
request.setLocalRepository(getLocalRepository());
@ -407,7 +426,9 @@ void versionFilteringTest() throws InvalidRepositoryException {
eventSpyDispatcher,
information,
defaultTypeRegistry,
versionScheme);
versionScheme,
Collections.emptyMap(),
Collections.emptyMap());
MavenExecutionRequest request = new DefaultMavenExecutionRequest();
request.setLocalRepository(getLocalRepository());

View File

@ -27,10 +27,10 @@
import org.apache.maven.bridge.MavenRepositorySystem;
import org.apache.maven.execution.DefaultMavenExecutionRequest;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory;
import org.apache.maven.project.DefaultProjectBuildingRequest;
import org.apache.maven.project.ProjectBuilder;
import org.apache.maven.project.ProjectBuildingResult;
import org.apache.maven.resolver.RepositorySystemSessionFactory;
import org.codehaus.plexus.testing.PlexusTest;
import org.junit.jupiter.api.Test;
@ -46,7 +46,7 @@ public class ModelBuilderTest {
MavenRepositorySystem repositorySystem;
@Inject
DefaultRepositorySystemSessionFactory repositorySessionFactory;
RepositorySystemSessionFactory repositorySessionFactory;
@Test
void testModelBuilder() throws Exception {
@ -54,7 +54,9 @@ void testModelBuilder() throws Exception {
mavenRequest.setLocalRepository(repositorySystem.createLocalRepository(new File("target/test-repo/")));
DefaultProjectBuildingRequest request = new DefaultProjectBuildingRequest();
request.setRepositorySession(repositorySessionFactory.newRepositorySession(mavenRequest));
request.setRepositorySession(repositorySessionFactory
.newRepositorySessionBuilder(mavenRequest)
.build());
List<ProjectBuildingResult> results = projectBuilder.build(
Collections.singletonList(new File("src/test/resources/projects/tree/pom.xml")), true, request);

View File

@ -38,7 +38,6 @@
import org.apache.maven.artifact.DefaultArtifact;
import org.apache.maven.artifact.handler.DefaultArtifactHandler;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.bridge.MavenRepositorySystem;
import org.apache.maven.configuration.internal.EnhancedComponentConfigurator;
import org.apache.maven.execution.DefaultMavenExecutionRequest;
import org.apache.maven.execution.DefaultMavenExecutionResult;
@ -86,9 +85,6 @@ public class PluginParameterExpressionEvaluatorV4Test extends AbstractCoreMavenC
@Inject
PlexusContainer container;
@Inject
private MavenRepositorySystem factory;
private Path rootDirectory;
@Test

View File

@ -34,10 +34,10 @@
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.extension.internal.CoreExports;
import org.apache.maven.extension.internal.CoreExtensionEntry;
import org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory;
import org.apache.maven.internal.aether.MavenChainedWorkspaceReader;
import org.apache.maven.plugin.PluginResolutionException;
import org.apache.maven.plugin.internal.DefaultPluginDependenciesResolver;
import org.apache.maven.resolver.MavenChainedWorkspaceReader;
import org.apache.maven.resolver.RepositorySystemSessionFactory;
import org.codehaus.plexus.DefaultPlexusContainer;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.classworlds.ClassWorld;
@ -72,7 +72,7 @@ public class BootstrapCoreExtensionManager {
private final DefaultPluginDependenciesResolver pluginDependenciesResolver;
private final DefaultRepositorySystemSessionFactory repositorySystemSessionFactory;
private final RepositorySystemSessionFactory repositorySystemSessionFactory;
private final CoreExports coreExports;
@ -85,7 +85,7 @@ public class BootstrapCoreExtensionManager {
@Inject
public BootstrapCoreExtensionManager(
DefaultPluginDependenciesResolver pluginDependenciesResolver,
DefaultRepositorySystemSessionFactory repositorySystemSessionFactory,
RepositorySystemSessionFactory repositorySystemSessionFactory,
CoreExports coreExports,
PlexusContainer container,
@Nullable @Named("ide") WorkspaceReader ideWorkspaceReader) {