[MNG-8385] Introduce proto session, make CLIng use PropertyContributor (#1929)

And make use of it in CLIng. Also, move from "late" Resolver session factory to "early" CLIng invocation of `PropertyContributor` SPI and make contribution visible across whole Maven, not only Resolver.

---

https://issues.apache.org/jira/browse/MNG-8385
This commit is contained in:
Tamas Cservenak 2024-11-20 20:58:27 +01:00 committed by GitHub
parent 5c02857a96
commit fcd9c0f018
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
36 changed files with 584 additions and 1794 deletions

View File

@ -0,0 +1,212 @@
/*
* 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;
import java.nio.file.Path;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
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 static java.util.Objects.requireNonNull;
/**
* The proto session, material used to create {@link Session}.
*
* @since 4.0.0
*/
@Experimental
@ThreadSafe
public interface ProtoSession {
/**
* 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}
*/
@Nonnull
Map<String, String> getUserProperties();
/**
* 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();
/**
* Returns the start time of the session.
*
* @return the start time as an Instant object, never {@code null}
*/
@Nonnull
Instant getStartTime();
/**
* Gets the directory of the topmost project being built, usually the current directory or the
* directory pointed at by the {@code -f/--file} command line argument.
*
* @return the directory of the topmost project, never {@code null}
* @see Project#isTopProject()
* @see #getRootDirectory()
*/
@Nonnull
Path getTopDirectory();
/**
* Gets the root directory of the session, which is the root directory for the top directory project.
*
* @return the root directory, never {@code null}
* @throws IllegalStateException if the root directory could not be found
* @see #getTopDirectory()
* @see Project#getRootDirectory()
* @see Project#isRootProject()
*/
@Nonnull
Path getRootDirectory();
/**
* Returns a proto session builder of this instance.
*/
@Nonnull
default Builder toBuilder() {
try {
return new Builder(
getUserProperties(), getSystemProperties(), getStartTime(), getTopDirectory(), getRootDirectory());
} catch (IllegalStateException e) {
return new Builder(getUserProperties(), getSystemProperties(), getStartTime(), getTopDirectory(), null);
}
}
/**
* Returns new builder from scratch.
*/
static Builder newBuilder() {
return new Builder().withStartTime(Instant.now());
}
class Builder {
private Map<String, String> userProperties;
private Map<String, String> systemProperties;
private Instant startTime;
private Path topDirectory;
private Path rootDirectory;
private Builder() {}
private Builder(
Map<String, String> userProperties,
Map<String, String> systemProperties,
Instant startTime,
Path topDirectory,
Path rootDirectory) {
this.userProperties = userProperties;
this.systemProperties = systemProperties;
this.startTime = startTime;
this.topDirectory = topDirectory;
this.rootDirectory = rootDirectory;
}
public Builder withUserProperties(@Nonnull Map<String, String> userProperties) {
this.userProperties = new HashMap<>(userProperties);
return this;
}
public Builder withSystemProperties(@Nonnull Map<String, String> systemProperties) {
this.systemProperties = new HashMap<>(systemProperties);
return this;
}
public Builder withStartTime(@Nonnull Instant startTime) {
this.startTime = requireNonNull(startTime, "startTime");
return this;
}
public Builder withTopDirectory(@Nonnull Path topDirectory) {
this.topDirectory = requireNonNull(topDirectory, "topDirectory");
return this;
}
public Builder withRootDirectory(@Nullable Path rootDirectory) {
this.rootDirectory = rootDirectory;
return this;
}
public ProtoSession build() {
return new Impl(userProperties, systemProperties, startTime, topDirectory, rootDirectory);
}
private static class Impl implements ProtoSession {
private final Map<String, String> userProperties;
private final Map<String, String> systemProperties;
private final Instant startTime;
private final Path topDirectory;
private final Path rootDirectory;
private Impl(
Map<String, String> userProperties,
Map<String, String> systemProperties,
Instant startTime,
Path topDirectory,
Path rootDirectory) {
this.userProperties = requireNonNull(userProperties);
this.systemProperties = requireNonNull(systemProperties);
this.startTime = requireNonNull(startTime);
this.topDirectory = requireNonNull(topDirectory);
this.rootDirectory = rootDirectory;
}
@Override
public Map<String, String> getUserProperties() {
return userProperties;
}
@Override
public Map<String, String> getSystemProperties() {
return systemProperties;
}
@Override
public Instant getStartTime() {
return startTime;
}
@Override
public Path getTopDirectory() {
return topDirectory;
}
@Override
public Path getRootDirectory() {
if (rootDirectory == null) {
throw new IllegalStateException("root directory not set");
}
return rootDirectory;
}
}
}
}

View File

@ -19,7 +19,6 @@
package org.apache.maven.api;
import java.nio.file.Path;
import java.time.Instant;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@ -46,7 +45,15 @@ import org.apache.maven.api.settings.Settings;
*/
@Experimental
@ThreadSafe
public interface Session {
public interface Session extends ProtoSession {
/**
* Returns the current maven version.
*
* @return the maven version, never {@code null}
*/
@Nonnull
Version getMavenVersion();
/**
* Retrieves the settings for the current session.
@ -80,25 +87,6 @@ public interface Session {
@Nonnull
SessionData getData();
/**
* 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}
*/
@Nonnull
Map<String, String> getUserProperties();
/**
* 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>
@ -121,14 +109,6 @@ public interface Session {
@Nonnull
Map<String, String> getEffectiveProperties(@Nullable Project project);
/**
* Returns the current maven version.
*
* @return the maven version, never {@code null}
*/
@Nonnull
Version getMavenVersion();
/**
* Returns the degree of concurrency for the build.
*
@ -136,37 +116,6 @@ public interface Session {
*/
int getDegreeOfConcurrency();
/**
* Returns the start time of the session.
*
* @return the start time as an Instant object, never {@code null}
*/
@Nonnull
Instant getStartTime();
/**
* Gets the directory of the topmost project being built, usually the current directory or the
* directory pointed at by the {@code -f/--file} command line argument.
*
* @return the directory of the topmost project, never {@code null}
* @see Project#isTopProject()
* @see #getRootDirectory()
*/
@Nonnull
Path getTopDirectory();
/**
* Gets the root directory of the session, which is the root directory for the top directory project.
*
* @return the root directory, never {@code null}
* @throws IllegalStateException if the root directory could not be found
* @see #getTopDirectory()
* @see Project#getRootDirectory()
* @see Project#isRootProject()
*/
@Nonnull
Path getRootDirectory();
/**
* Retrieves a list of projects associated with the session.
*

View File

@ -167,7 +167,7 @@ public interface ArtifactCoordinatesFactoryRequest {
session, groupId, artifactId, version, classifier, extension, type, coordinateString);
}
private static class DefaultArtifactFactoryRequestArtifact extends BaseRequest
private static class DefaultArtifactFactoryRequestArtifact extends BaseRequest<Session>
implements ArtifactCoordinatesFactoryRequest {
private final String groupId;
private final String artifactId;

View File

@ -101,7 +101,8 @@ public interface ArtifactDeployerRequest {
return new DefaultArtifactDeployerRequest(session, repository, artifacts, retryFailedDeploymentCount);
}
private static class DefaultArtifactDeployerRequest extends BaseRequest implements ArtifactDeployerRequest {
private static class DefaultArtifactDeployerRequest extends BaseRequest<Session>
implements ArtifactDeployerRequest {
private final RemoteRepository repository;
private final Collection<ProducedArtifact> artifacts;

View File

@ -136,7 +136,8 @@ public interface ArtifactFactoryRequest {
session, groupId, artifactId, version, classifier, extension, type);
}
private static class DefaultArtifactFactoryRequest extends BaseRequest implements ArtifactFactoryRequest {
private static class DefaultArtifactFactoryRequest extends BaseRequest<Session>
implements ArtifactFactoryRequest {
private final String groupId;
private final String artifactId;
private final String version;

View File

@ -83,7 +83,7 @@ public interface ArtifactInstallerRequest {
return new DefaultArtifactInstallerRequest(session, artifacts);
}
static class DefaultArtifactInstallerRequest extends BaseRequest implements ArtifactInstallerRequest {
static class DefaultArtifactInstallerRequest extends BaseRequest<Session> implements ArtifactInstallerRequest {
private final Collection<ProducedArtifact> artifacts;

View File

@ -106,7 +106,8 @@ public interface ArtifactResolverRequest {
return new DefaultArtifactResolverRequest(session, coordinates, repositories);
}
private static class DefaultArtifactResolverRequest extends BaseRequest implements ArtifactResolverRequest {
private static class DefaultArtifactResolverRequest extends BaseRequest<Session>
implements ArtifactResolverRequest {
@Nonnull
private final Collection<? extends ArtifactCoordinates> coordinates;

View File

@ -22,7 +22,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import org.apache.maven.api.Session;
import org.apache.maven.api.ProtoSession;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.annotations.Nonnull;
@ -32,16 +32,16 @@ import org.apache.maven.api.annotations.Nonnull;
* @since 4.0.0
*/
@Experimental
abstract class BaseRequest {
abstract class BaseRequest<S extends ProtoSession> {
private final Session session;
private final S session;
protected BaseRequest(@Nonnull Session session) {
protected BaseRequest(@Nonnull S session) {
this.session = nonNull(session, "session cannot be null");
}
@Nonnull
public Session getSession() {
public S getSession() {
return session;
}

View File

@ -202,7 +202,7 @@ public interface DependencyCoordinatesFactoryRequest extends ArtifactCoordinates
exclusions);
}
private static class DefaultDependencyCoordinatesFactoryRequest extends BaseRequest
private static class DefaultDependencyCoordinatesFactoryRequest extends BaseRequest<Session>
implements DependencyCoordinatesFactoryRequest {
private final String groupId;
private final String artifactId;

View File

@ -360,7 +360,8 @@ public interface DependencyResolverRequest {
repositories);
}
static class DefaultDependencyResolverRequest extends BaseRequest implements DependencyResolverRequest {
static class DefaultDependencyResolverRequest extends BaseRequest<Session>
implements DependencyResolverRequest {
private final RequestType requestType;
private final Project project;
private final Artifact rootArtifact;

View File

@ -290,7 +290,7 @@ public interface ModelBuilderRequest {
lifecycleBindingsInjector);
}
private static class DefaultModelBuilderRequest extends BaseRequest implements ModelBuilderRequest {
private static class DefaultModelBuilderRequest extends BaseRequest<Session> implements ModelBuilderRequest {
private final RequestType requestType;
private final boolean locationTracking;
private final boolean recursive;

View File

@ -125,7 +125,8 @@ public interface ProjectBuilderRequest {
session, path, source, allowStubModel, recursive, processPlugins, repositories);
}
private static class DefaultProjectBuilderRequest extends BaseRequest implements ProjectBuilderRequest {
private static class DefaultProjectBuilderRequest extends BaseRequest<Session>
implements ProjectBuilderRequest {
private final Path path;
private final Source source;
private final boolean allowStubModel;

View File

@ -23,7 +23,7 @@ import java.nio.file.Path;
import java.util.Optional;
import java.util.function.Function;
import org.apache.maven.api.Session;
import org.apache.maven.api.ProtoSession;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.annotations.Immutable;
import org.apache.maven.api.annotations.Nonnull;
@ -40,7 +40,7 @@ import static org.apache.maven.api.services.BaseRequest.nonNull;
public interface SettingsBuilderRequest {
@Nonnull
Session getSession();
ProtoSession getSession();
/**
* Gets the installation settings source.
@ -76,19 +76,21 @@ public interface SettingsBuilderRequest {
@Nonnull
static SettingsBuilderRequest build(
@Nonnull Session session, @Nonnull Source installationSettingsSource, @Nonnull Source userSettingsSource) {
@Nonnull ProtoSession session,
@Nonnull Source installationSettingsSource,
@Nonnull Source userSettingsSource) {
return build(session, installationSettingsSource, null, userSettingsSource);
}
@Nonnull
static SettingsBuilderRequest build(
@Nonnull Session session, @Nonnull Path installationSettingsPath, @Nonnull Path userSettingsPath) {
@Nonnull ProtoSession session, @Nonnull Path installationSettingsPath, @Nonnull Path userSettingsPath) {
return build(session, Source.fromPath(installationSettingsPath), null, Source.fromPath(userSettingsPath));
}
@Nonnull
static SettingsBuilderRequest build(
@Nonnull Session session,
@Nonnull ProtoSession session,
@Nullable Source installationSettingsSource,
@Nullable Source projectSettingsSource,
@Nullable Source userSettingsSource) {
@ -102,7 +104,7 @@ public interface SettingsBuilderRequest {
@Nonnull
static SettingsBuilderRequest build(
@Nonnull Session session,
@Nonnull ProtoSession session,
@Nullable Path installationSettingsPath,
@Nullable Path projectSettingsPath,
@Nullable Path userSettingsPath) {
@ -130,13 +132,13 @@ public interface SettingsBuilderRequest {
@NotThreadSafe
class SettingsBuilderRequestBuilder {
Session session;
ProtoSession session;
Source installationSettingsSource;
Source projectSettingsSource;
Source userSettingsSource;
Function<String, String> interpolationSource;
public SettingsBuilderRequestBuilder session(Session session) {
public SettingsBuilderRequestBuilder session(ProtoSession session) {
this.session = session;
return this;
}
@ -170,7 +172,8 @@ public interface SettingsBuilderRequest {
interpolationSource);
}
private static class DefaultSettingsBuilderRequest extends BaseRequest implements SettingsBuilderRequest {
private static class DefaultSettingsBuilderRequest extends BaseRequest<ProtoSession>
implements SettingsBuilderRequest {
private final Source installationSettingsSource;
private final Source projectSettingsSource;
private final Source userSettingsSource;
@ -178,7 +181,7 @@ public interface SettingsBuilderRequest {
@SuppressWarnings("checkstyle:ParameterNumber")
DefaultSettingsBuilderRequest(
@Nonnull Session session,
@Nonnull ProtoSession session,
@Nullable Source installationSettingsSource,
@Nullable Source projectSettingsSource,
@Nullable Source userSettingsSource,

View File

@ -22,7 +22,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;
import org.apache.maven.api.Session;
import org.apache.maven.api.ProtoSession;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.annotations.Nonnull;
import org.apache.maven.api.annotations.NotThreadSafe;
@ -37,7 +37,7 @@ import static org.apache.maven.api.services.BaseRequest.nonNull;
@Experimental
public interface ToolchainsBuilderRequest {
@Nonnull
Session getSession();
ProtoSession getSession();
/**
* Gets the installation Toolchains source.
@ -57,7 +57,7 @@ public interface ToolchainsBuilderRequest {
@Nonnull
static ToolchainsBuilderRequest build(
@Nonnull Session session,
@Nonnull ProtoSession session,
@Nullable Source installationToolchainsFile,
@Nullable Source userToolchainsSource) {
return builder()
@ -69,7 +69,9 @@ public interface ToolchainsBuilderRequest {
@Nonnull
static ToolchainsBuilderRequest build(
@Nonnull Session session, @Nullable Path installationToolchainsFile, @Nullable Path userToolchainsPath) {
@Nonnull ProtoSession session,
@Nullable Path installationToolchainsFile,
@Nullable Path userToolchainsPath) {
return builder()
.session(nonNull(session, "session cannot be null"))
.installationToolchainsSource(
@ -90,11 +92,11 @@ public interface ToolchainsBuilderRequest {
@NotThreadSafe
class ToolchainsBuilderRequestBuilder {
Session session;
ProtoSession session;
Source installationToolchainsSource;
Source userToolchainsSource;
public ToolchainsBuilderRequestBuilder session(Session session) {
public ToolchainsBuilderRequestBuilder session(ProtoSession session) {
this.session = session;
return this;
}
@ -114,13 +116,14 @@ public interface ToolchainsBuilderRequest {
session, installationToolchainsSource, userToolchainsSource);
}
private static class DefaultToolchainsBuilderRequest extends BaseRequest implements ToolchainsBuilderRequest {
private static class DefaultToolchainsBuilderRequest extends BaseRequest<ProtoSession>
implements ToolchainsBuilderRequest {
private final Source installationToolchainsSource;
private final Source userToolchainsSource;
@SuppressWarnings("checkstyle:ParameterNumber")
DefaultToolchainsBuilderRequest(
@Nonnull Session session,
@Nonnull ProtoSession session,
@Nullable Source installationToolchainsSource,
@Nullable Source userToolchainsSource) {
super(session);

View File

@ -94,7 +94,8 @@ public interface VersionRangeResolverRequest {
return new DefaultVersionResolverRequest(session, artifactCoordinates, repositories);
}
private static class DefaultVersionResolverRequest extends BaseRequest implements VersionRangeResolverRequest {
private static class DefaultVersionResolverRequest extends BaseRequest<Session>
implements VersionRangeResolverRequest {
private final ArtifactCoordinates artifactCoordinates;
private final List<RemoteRepository> repositories;

View File

@ -96,7 +96,8 @@ public interface VersionResolverRequest {
return new DefaultVersionResolverRequest(session, artifactCoordinates, repositories);
}
private static class DefaultVersionResolverRequest extends BaseRequest implements VersionResolverRequest {
private static class DefaultVersionResolverRequest extends BaseRequest<Session>
implements VersionResolverRequest {
private final ArtifactCoordinates artifactCoordinates;
private final List<RemoteRepository> repositories;

View File

@ -18,8 +18,10 @@
*/
package org.apache.maven.api.spi;
import java.util.HashMap;
import java.util.Map;
import org.apache.maven.api.ProtoSession;
import org.apache.maven.api.annotations.Consumer;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.di.Named;
@ -38,6 +40,21 @@ public interface PropertyContributor extends SpiService {
* 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}.
* @see #contribute(ProtoSession)
*/
void contribute(Map<String, String> userProperties);
default void contribute(Map<String, String> userProperties) {}
/**
* Invoked just before session is created with proto session instance. The proto session contains user and
* system properties collected so far, along with other information. This method should return altered
* (contributions applied) user properties, not only the "new" or "added" properties!
*
* @param protoSession The proto session, never {@code null}.
* @return The user properties with contributions.
*/
default Map<String, String> contribute(ProtoSession protoSession) {
HashMap<String, String> userProperties = new HashMap<>(protoSession.getUserProperties());
contribute(userProperties);
return userProperties;
}
}

View File

@ -27,13 +27,12 @@ import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import org.apache.maven.api.Session;
import org.apache.maven.api.ProtoSession;
import org.apache.maven.api.cli.InvokerException;
import org.apache.maven.api.cli.InvokerRequest;
import org.apache.maven.api.cli.Logger;
import org.apache.maven.api.services.Lookup;
import org.apache.maven.api.settings.Settings;
import org.apache.maven.cling.invoker.mvn.ProtoSession;
import org.apache.maven.cling.logging.Slf4jConfiguration;
import org.jline.terminal.Terminal;
import org.slf4j.ILoggerFactory;
@ -46,7 +45,6 @@ public class LookupContext implements AutoCloseable {
public final Function<String, Path> cwdResolver;
public final Function<String, Path> installationResolver;
public final Function<String, Path> userResolver;
public final Session session;
protected LookupContext(InvokerRequest invokerRequest) {
this.invokerRequest = requireNonNull(invokerRequest);
@ -58,12 +56,23 @@ public class LookupContext implements AutoCloseable {
this.logger = invokerRequest.parserRequest().logger();
Map<String, String> user = new HashMap<>(invokerRequest.userProperties());
user.put("session.rootDirectory", invokerRequest.rootDirectory().toString());
user.put("session.topDirectory", invokerRequest.topDirectory().toString());
Map<String, String> system = new HashMap<>(invokerRequest.systemProperties());
this.session = ProtoSession.create(user, system);
if (invokerRequest.rootDirectory().isEmpty()) {
user.put(
"session.rootDirectory",
invokerRequest.rootDirectory().get().toString());
}
this.protoSession = ProtoSession.newBuilder()
.withSystemProperties(invokerRequest.systemProperties())
.withUserProperties(user)
.withTopDirectory(invokerRequest.topDirectory())
.withRootDirectory(invokerRequest.rootDirectory().orElse(null))
.build();
}
// this one "evolves" as process progresses (instance is immutable but instances are replaced)
public ProtoSession protoSession;
public Logger logger;
public ILoggerFactory loggerFactory;
public Slf4jConfiguration slf4jConfiguration;
@ -76,9 +85,6 @@ public class LookupContext implements AutoCloseable {
public boolean interactive;
public Path localRepositoryPath;
public Path installationSettingsPath;
public Path projectSettingsPath;
public Path userSettingsPath;
public Settings effectiveSettings;
public final List<AutoCloseable> closeables = new ArrayList<>();

View File

@ -33,6 +33,7 @@ import java.util.function.Consumer;
import java.util.function.Function;
import org.apache.maven.api.Constants;
import org.apache.maven.api.ProtoSession;
import org.apache.maven.api.cli.Invoker;
import org.apache.maven.api.cli.InvokerException;
import org.apache.maven.api.cli.InvokerRequest;
@ -40,6 +41,7 @@ import org.apache.maven.api.cli.Logger;
import org.apache.maven.api.cli.Options;
import org.apache.maven.api.services.BuilderProblem;
import org.apache.maven.api.services.Interpolator;
import org.apache.maven.api.services.Lookup;
import org.apache.maven.api.services.MavenException;
import org.apache.maven.api.services.MessageBuilder;
import org.apache.maven.api.services.SettingsBuilder;
@ -52,12 +54,14 @@ import org.apache.maven.api.settings.Proxy;
import org.apache.maven.api.settings.Repository;
import org.apache.maven.api.settings.Server;
import org.apache.maven.api.settings.Settings;
import org.apache.maven.api.spi.PropertyContributor;
import org.apache.maven.artifact.InvalidRepositoryException;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
import org.apache.maven.artifact.repository.MavenArtifactRepository;
import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
import org.apache.maven.bridge.MavenRepositorySystem;
import org.apache.maven.cling.invoker.spi.PropertyContributorsHolder;
import org.apache.maven.cling.logging.Slf4jConfiguration;
import org.apache.maven.cling.logging.Slf4jConfigurationFactory;
import org.apache.maven.cling.transfer.ConsoleMavenTransferListener;
@ -124,7 +128,7 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
}
protected int doInvoke(C context) throws Exception {
pushProperties(context);
pushCoreProperties(context);
validate(context);
prepare(context);
configureLogging(context);
@ -132,6 +136,8 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
helpOrVersionAndMayExit(context);
preCommands(context);
container(context);
postContainer(context);
pushUserProperties(context);
lookup(context);
init(context);
postCommands(context);
@ -157,14 +163,18 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
protected abstract C createContext(InvokerRequest invokerRequest) throws InvokerException;
protected void pushProperties(C context) throws Exception {
InvokerRequest invokerRequest = context.invokerRequest;
HashSet<String> sys = new HashSet<>(invokerRequest.systemProperties().keySet());
invokerRequest.userProperties().entrySet().stream()
protected void pushCoreProperties(C context) throws Exception {
System.setProperty(
Constants.MAVEN_HOME,
context.invokerRequest.installationDirectory().toString());
}
protected void pushUserProperties(C context) throws Exception {
ProtoSession protoSession = context.protoSession;
HashSet<String> sys = new HashSet<>(protoSession.getSystemProperties().keySet());
protoSession.getUserProperties().entrySet().stream()
.filter(k -> !sys.contains(k.getKey()))
.forEach(k -> System.setProperty(k.getKey(), k.getValue()));
System.setProperty(
Constants.MAVEN_HOME, invokerRequest.installationDirectory().toString());
}
protected void validate(C context) throws Exception {}
@ -172,10 +182,9 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
protected void prepare(C context) throws Exception {}
protected void configureLogging(C context) throws Exception {
InvokerRequest invokerRequest = context.invokerRequest;
// LOG COLOR
Options mavenOptions = invokerRequest.options();
Map<String, String> userProperties = invokerRequest.userProperties();
Options mavenOptions = context.invokerRequest.options();
Map<String, String> userProperties = context.protoSession.getUserProperties();
String styleColor = mavenOptions
.color()
.orElse(userProperties.getOrDefault(
@ -381,6 +390,19 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
return new PlexusContainerCapsuleFactory<>();
}
protected void postContainer(C context) throws Exception {
ProtoSession protoSession = context.protoSession;
for (PropertyContributor propertyContributor : context.lookup
.lookup(PropertyContributorsHolder.class)
.getPropertyContributors()
.values()) {
protoSession = protoSession.toBuilder()
.withUserProperties(propertyContributor.contribute(protoSession))
.build();
}
context.protoSession = protoSession;
}
protected void lookup(C context) throws Exception {}
protected void init(C context) throws Exception {}
@ -427,7 +449,8 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
throw new FileNotFoundException("The specified user settings file does not exist: " + userSettingsFile);
}
} else {
String userSettingsFileStr = context.invokerRequest.userProperties().get(Constants.MAVEN_USER_SETTINGS);
String userSettingsFileStr =
context.protoSession.getUserProperties().get(Constants.MAVEN_USER_SETTINGS);
if (userSettingsFileStr != null) {
userSettingsFile = context.userResolver.apply(userSettingsFileStr);
}
@ -445,7 +468,7 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
}
} else {
String projectSettingsFileStr =
context.invokerRequest.userProperties().get(Constants.MAVEN_PROJECT_SETTINGS);
context.protoSession.getUserProperties().get(Constants.MAVEN_PROJECT_SETTINGS);
if (projectSettingsFileStr != null) {
projectSettingsFile = context.cwdResolver.apply(projectSettingsFileStr);
}
@ -463,20 +486,16 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
}
} else {
String installationSettingsFileStr =
context.invokerRequest.userProperties().get(Constants.MAVEN_INSTALLATION_SETTINGS);
context.protoSession.getUserProperties().get(Constants.MAVEN_INSTALLATION_SETTINGS);
if (installationSettingsFileStr != null) {
installationSettingsFile = context.installationResolver.apply(installationSettingsFileStr);
}
}
context.installationSettingsPath = installationSettingsFile;
context.projectSettingsPath = projectSettingsFile;
context.userSettingsPath = userSettingsFile;
Function<String, String> interpolationSource = Interpolator.chain(
context.invokerRequest.userProperties()::get, context.invokerRequest.systemProperties()::get);
context.protoSession.getUserProperties()::get, context.protoSession.getSystemProperties()::get);
SettingsBuilderRequest settingsRequest = SettingsBuilderRequest.builder()
.session(context.session)
.session(context.protoSession)
.installationSettingsSource(
installationSettingsFile != null && Files.exists(installationSettingsFile)
? Source.fromPath(installationSettingsFile)
@ -540,9 +559,9 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
protected Path localRepositoryPath(C context) {
// user override
String userDefinedLocalRepo = context.invokerRequest.userProperties().get(Constants.MAVEN_REPO_LOCAL);
String userDefinedLocalRepo = context.protoSession.getUserProperties().get(Constants.MAVEN_REPO_LOCAL);
if (userDefinedLocalRepo == null) {
userDefinedLocalRepo = context.invokerRequest.systemProperties().get(Constants.MAVEN_REPO_LOCAL);
userDefinedLocalRepo = context.protoSession.getUserProperties().get(Constants.MAVEN_REPO_LOCAL);
if (userDefinedLocalRepo != null) {
context.logger.warn("The property '" + Constants.MAVEN_REPO_LOCAL
+ "' has been set using a JVM system property which is deprecated. "
@ -560,11 +579,11 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
}
// defaults
return context.userResolver
.apply(context.invokerRequest.userProperties().get(Constants.MAVEN_USER_CONF))
.apply(context.protoSession.getUserProperties().get(Constants.MAVEN_USER_CONF))
.resolve("repository");
}
protected void populateRequest(C context, MavenExecutionRequest request) throws Exception {
protected void populateRequest(C context, Lookup lookup, MavenExecutionRequest request) throws Exception {
populateRequestFromSettings(request, context.effectiveSettings);
Options options = context.invokerRequest.options();
@ -575,8 +594,8 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
request.setInteractiveMode(context.interactive);
request.setShowErrors(options.showErrors().orElse(false));
request.setBaseDirectory(context.invokerRequest.topDirectory().toFile());
request.setSystemProperties(toProperties(context.invokerRequest.systemProperties()));
request.setUserProperties(toProperties(context.invokerRequest.userProperties()));
request.setSystemProperties(toProperties(context.protoSession.getSystemProperties()));
request.setUserProperties(toProperties(context.protoSession.getUserProperties()));
request.setTopDirectory(context.invokerRequest.topDirectory());
if (context.invokerRequest.rootDirectory().isPresent()) {
@ -720,7 +739,7 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
}
protected boolean isRunningOnCI(C context) {
String ciEnv = context.invokerRequest.systemProperties().get("env.CI");
String ciEnv = context.protoSession.getSystemProperties().get("env.CI");
return ciEnv != null && !"false".equals(ciEnv);
}

View File

@ -30,6 +30,7 @@ import java.util.function.Function;
import com.google.inject.AbstractModule;
import com.google.inject.Module;
import org.apache.maven.api.Constants;
import org.apache.maven.api.ProtoSession;
import org.apache.maven.api.cli.InvokerException;
import org.apache.maven.api.cli.InvokerRequest;
import org.apache.maven.api.cli.Logger;
@ -47,6 +48,7 @@ import org.apache.maven.execution.scope.internal.MojoExecutionScope;
import org.apache.maven.execution.scope.internal.MojoExecutionScopeModule;
import org.apache.maven.extension.internal.CoreExports;
import org.apache.maven.extension.internal.CoreExtensionEntry;
import org.apache.maven.internal.impl.DefaultLookup;
import org.apache.maven.session.scope.internal.SessionScope;
import org.apache.maven.session.scope.internal.SessionScopeModule;
import org.codehaus.plexus.ContainerConfiguration;
@ -108,11 +110,11 @@ public class PlexusContainerCapsuleFactory<C extends LookupContext> implements C
Thread.currentThread().setContextClassLoader(container.getContainerRealm());
container.setLoggerManager(createLoggerManager());
InvokerRequest invokerRequest = context.invokerRequest;
ProtoSession protoSession = context.protoSession;
Function<String, String> extensionSource = expression -> {
String value = invokerRequest.userProperties().get(expression);
String value = protoSession.getUserProperties().get(expression);
if (value == null) {
value = invokerRequest.systemProperties().get(expression);
value = protoSession.getSystemProperties().get(expression);
}
return value;
};
@ -189,10 +191,10 @@ public class PlexusContainerCapsuleFactory<C extends LookupContext> implements C
protected void customizeContainer(C context, PlexusContainer container) throws Exception {}
protected List<Path> parseExtClasspath(C context) throws Exception {
InvokerRequest invokerRequest = context.invokerRequest;
String extClassPath = invokerRequest.userProperties().get(Constants.MAVEN_EXT_CLASS_PATH);
ProtoSession protoSession = context.protoSession;
String extClassPath = protoSession.getUserProperties().get(Constants.MAVEN_EXT_CLASS_PATH);
if (extClassPath == null) {
extClassPath = invokerRequest.systemProperties().get(Constants.MAVEN_EXT_CLASS_PATH);
extClassPath = protoSession.getSystemProperties().get(Constants.MAVEN_EXT_CLASS_PATH);
if (extClassPath != null) {
context.logger.warn("The property '" + Constants.MAVEN_EXT_CLASS_PATH
+ "' has been set using a JVM system property which is deprecated. "
@ -272,7 +274,7 @@ public class PlexusContainerCapsuleFactory<C extends LookupContext> implements C
DefaultPlexusContainer container = new DefaultPlexusContainer(cc, new AbstractModule() {
@Override
protected void configure() {
bind(ILoggerFactory.class).toInstance(context.loggerFactory);
bind(ILoggerFactory.class).toProvider(() -> context.loggerFactory);
}
});
@ -286,7 +288,7 @@ public class PlexusContainerCapsuleFactory<C extends LookupContext> implements C
invoker.settings(context, container.lookup(SettingsBuilder.class));
MavenExecutionRequest mer = new DefaultMavenExecutionRequest();
invoker.populateRequest(context, mer);
invoker.populateRequest(context, new DefaultLookup(container), mer);
mer = container.lookup(MavenExecutionRequestPopulator.class).populateDefaults(mer);
return Collections.unmodifiableList(container
.lookup(BootstrapCoreExtensionManager.class)

View File

@ -20,11 +20,8 @@ package org.apache.maven.cling.invoker.mvn;
import org.apache.maven.Maven;
import org.apache.maven.api.cli.InvokerRequest;
import org.apache.maven.api.services.model.ModelProcessor;
import org.apache.maven.cling.invoker.LookupContext;
import org.apache.maven.eventspy.internal.EventSpyDispatcher;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.MavenExecutionRequestPopulator;
import org.apache.maven.logging.BuildEventListener;
@SuppressWarnings("VisibilityModifier")
@ -34,9 +31,7 @@ public class MavenContext extends LookupContext {
}
public BuildEventListener buildEventListener;
public MavenExecutionRequest mavenExecutionRequest;
public EventSpyDispatcher eventSpyDispatcher;
public MavenExecutionRequestPopulator mavenExecutionRequestPopulator;
public ModelProcessor modelProcessor;
public Maven maven;
}

View File

@ -38,6 +38,7 @@ import org.apache.maven.api.cli.InvokerRequest;
import org.apache.maven.api.cli.Logger;
import org.apache.maven.api.cli.mvn.MavenOptions;
import org.apache.maven.api.services.BuilderProblem;
import org.apache.maven.api.services.Lookup;
import org.apache.maven.api.services.SettingsBuilderRequest;
import org.apache.maven.api.services.SettingsBuilderResult;
import org.apache.maven.api.services.Source;
@ -88,13 +89,13 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
@Override
protected int execute(C context) throws Exception {
toolchains(context);
populateRequest(context, context.mavenExecutionRequest);
return doExecute(context);
MavenExecutionRequest request = prepareMavenExecutionRequest();
toolchains(context, request);
populateRequest(context, context.lookup, request);
return doExecute(context, request);
}
@Override
protected void prepare(C context) throws Exception {
protected MavenExecutionRequest prepareMavenExecutionRequest() throws Exception {
// explicitly fill in "defaults"?
DefaultMavenExecutionRequest mavenExecutionRequest = new DefaultMavenExecutionRequest();
mavenExecutionRequest.setRepositoryCache(new DefaultRepositoryCache());
@ -108,26 +109,24 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
mavenExecutionRequest.setLoggingLevel(MavenExecutionRequest.LOGGING_LEVEL_INFO);
mavenExecutionRequest.setDegreeOfConcurrency(1);
mavenExecutionRequest.setBuilderId("singlethreaded");
context.mavenExecutionRequest = mavenExecutionRequest;
return mavenExecutionRequest;
}
@Override
protected void lookup(C context) throws Exception {
context.eventSpyDispatcher = context.lookup.lookup(EventSpyDispatcher.class);
context.mavenExecutionRequestPopulator = context.lookup.lookup(MavenExecutionRequestPopulator.class);
context.modelProcessor = context.lookup.lookup(ModelProcessor.class);
context.maven = context.lookup.lookup(Maven.class);
}
@Override
protected void init(C context) throws Exception {
super.init(context);
InvokerRequest invokerRequest = context.invokerRequest;
Map<String, Object> data = new HashMap<>();
data.put("plexus", context.lookup.lookup(PlexusContainer.class));
data.put("workingDirectory", invokerRequest.cwd().toString());
data.put("systemProperties", toProperties(invokerRequest.systemProperties()));
data.put("userProperties", toProperties(invokerRequest.userProperties()));
data.put("systemProperties", toProperties(context.protoSession.getSystemProperties()));
data.put("userProperties", toProperties(context.protoSession.getUserProperties()));
data.put("versionProperties", CLIReportingUtils.getBuildProperties());
context.eventSpyDispatcher.init(() -> data);
}
@ -181,7 +180,7 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
}
}
protected void toolchains(C context) throws Exception {
protected void toolchains(C context, MavenExecutionRequest request) throws Exception {
Path userToolchainsFile = null;
if (context.invokerRequest.options().altUserToolchains().isPresent()) {
@ -194,7 +193,7 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
}
} else {
String userToolchainsFileStr =
context.invokerRequest.userProperties().get(Constants.MAVEN_USER_TOOLCHAINS);
context.protoSession.getUserProperties().get(Constants.MAVEN_USER_TOOLCHAINS);
if (userToolchainsFileStr != null) {
userToolchainsFile = context.cwdResolver.apply(userToolchainsFileStr);
}
@ -212,19 +211,18 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
}
} else {
String installationToolchainsFileStr =
context.invokerRequest.userProperties().get(Constants.MAVEN_INSTALLATION_TOOLCHAINS);
context.protoSession.getUserProperties().get(Constants.MAVEN_INSTALLATION_TOOLCHAINS);
if (installationToolchainsFileStr != null) {
installationToolchainsFile = context.cwdResolver.apply(installationToolchainsFileStr);
}
}
context.mavenExecutionRequest.setInstallationToolchainsFile(
request.setInstallationToolchainsFile(
installationToolchainsFile != null ? installationToolchainsFile.toFile() : null);
context.mavenExecutionRequest.setUserToolchainsFile(
userToolchainsFile != null ? userToolchainsFile.toFile() : null);
request.setUserToolchainsFile(userToolchainsFile != null ? userToolchainsFile.toFile() : null);
ToolchainsBuilderRequest toolchainsRequest = ToolchainsBuilderRequest.builder()
.session(context.session)
.session(context.protoSession)
.installationToolchainsSource(
installationToolchainsFile != null && Files.isRegularFile(installationToolchainsFile)
? Source.fromPath(installationToolchainsFile)
@ -245,9 +243,12 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
context.eventSpyDispatcher.onEvent(toolchainsResult);
context.mavenExecutionRequestPopulator.populateFromToolchains(
context.mavenExecutionRequest,
new org.apache.maven.toolchain.model.PersistedToolchains(toolchainsResult.getEffectiveToolchains()));
context.lookup
.lookup(MavenExecutionRequestPopulator.class)
.populateFromToolchains(
request,
new org.apache.maven.toolchain.model.PersistedToolchains(
toolchainsResult.getEffectiveToolchains()));
if (!toolchainsResult.getProblems().isEmpty()) {
context.logger.warn("");
@ -262,8 +263,8 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
}
@Override
protected void populateRequest(C context, MavenExecutionRequest request) throws Exception {
super.populateRequest(context, request);
protected void populateRequest(C context, Lookup lookup, MavenExecutionRequest request) throws Exception {
super.populateRequest(context, lookup, request);
if (context.invokerRequest.rootDirectory().isEmpty()) {
// maven requires this to be set; so default it (and see below at POM)
request.setMultiModuleProjectDirectory(
@ -280,7 +281,7 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
request.setUpdateSnapshots(options.updateSnapshots().orElse(false));
request.setGlobalChecksumPolicy(determineGlobalChecksumPolicy(context));
Path pom = determinePom(context);
Path pom = determinePom(context, lookup);
if (pom != null) {
request.setPom(pom.toFile());
if (pom.getParent() != null) {
@ -344,14 +345,16 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
}
}
protected Path determinePom(C context) {
protected Path determinePom(C context, Lookup lookup) {
Path current = context.invokerRequest.cwd();
MavenOptions options = (MavenOptions) context.invokerRequest.options();
if (options.alternatePomFile().isPresent()) {
current = context.cwdResolver.apply(options.alternatePomFile().get());
}
if (context.modelProcessor != null) {
return context.modelProcessor.locateExistingPom(current);
ModelProcessor modelProcessor =
lookup.lookupOptional(ModelProcessor.class).orElse(null);
if (modelProcessor != null) {
return modelProcessor.locateExistingPom(current);
} else {
return Files.isRegularFile(current) ? current : null;
}
@ -467,9 +470,7 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
}
}
protected int doExecute(C context) throws Exception {
MavenExecutionRequest request = context.mavenExecutionRequest;
protected int doExecute(C context, MavenExecutionRequest request) throws Exception {
context.eventSpyDispatcher.onEvent(request);
MavenExecutionResult result;

View File

@ -1,409 +0,0 @@
/*
* 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.cling.invoker.mvn;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.maven.api.Artifact;
import org.apache.maven.api.Lifecycle;
import org.apache.maven.api.Packaging;
import org.apache.maven.api.ProducedArtifact;
import org.apache.maven.api.Project;
import org.apache.maven.api.RemoteRepository;
import org.apache.maven.api.Session;
import org.apache.maven.api.Type;
import org.apache.maven.api.Version;
import org.apache.maven.api.di.Provides;
import org.apache.maven.api.di.SessionScoped;
import org.apache.maven.api.model.PluginContainer;
import org.apache.maven.api.model.Profile;
import org.apache.maven.api.services.ArtifactManager;
import org.apache.maven.api.services.LifecycleRegistry;
import org.apache.maven.api.services.Lookup;
import org.apache.maven.api.services.MavenException;
import org.apache.maven.api.services.PackagingRegistry;
import org.apache.maven.api.services.RepositoryFactory;
import org.apache.maven.api.services.SettingsBuilder;
import org.apache.maven.api.services.TypeRegistry;
import org.apache.maven.api.settings.Settings;
import org.apache.maven.api.spi.TypeProvider;
import org.apache.maven.di.Injector;
import org.apache.maven.di.Key;
import org.apache.maven.di.impl.DIException;
import org.apache.maven.internal.impl.AbstractSession;
import org.apache.maven.internal.impl.InternalSession;
import org.apache.maven.internal.impl.di.SessionScope;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.impl.RemoteRepositoryManager;
import org.eclipse.aether.repository.LocalRepository;
import org.eclipse.aether.repository.LocalRepositoryManager;
public class ProtoSession extends AbstractSession {
private final Map<String, String> userProperties;
private final Map<String, String> systemProperties;
private final Instant startTime = Instant.now();
ProtoSession(RepositorySystemSession session, RepositorySystem repositorySystem, Lookup lookup) {
this(session, repositorySystem, Collections.emptyList(), null, lookup, new Context(Map.of(), Map.of()));
}
protected ProtoSession(
RepositorySystemSession session,
RepositorySystem repositorySystem,
List<RemoteRepository> repositories,
List<org.eclipse.aether.repository.RemoteRepository> resolverRepositories,
Lookup lookup,
Context context) {
super(session, repositorySystem, repositories, resolverRepositories, lookup);
userProperties = context.userProperties;
systemProperties = context.systemProperties;
}
/**
*
*/
public static Session create() {
Map<String, String> properties = new HashMap<>();
// Env variables prefixed with "env."
System.getenv().forEach((k, v) -> properties.put("env." + k, v));
// Java System properties
System.getProperties().forEach((k, v) -> properties.put(k.toString(), v.toString()));
// create session
return create(Map.of(), properties);
}
/**
* Create a new session.
*/
public static Session create(Map<String, String> userProperties, Map<String, String> systemProperties) {
Injector injector = Injector.create();
injector.bindInstance(Injector.class, injector);
injector.bindInstance(Context.class, new Context(userProperties, systemProperties));
injector.bindImplicit(Providers.class);
injector.discover(ProtoSession.class.getClassLoader());
Session session = injector.getInstance(Session.class);
SessionScope scope = new SessionScope();
scope.enter();
scope.seed(Session.class, session);
injector.bindScope(SessionScoped.class, scope);
return session;
}
record Context(Map<String, String> userProperties, Map<String, String> systemProperties) {}
@Override
protected Session newSession(RepositorySystemSession session, List<RemoteRepository> repositories) {
return new ProtoSession(
session, repositorySystem, repositories, null, lookup, new Context(userProperties, systemProperties));
}
@Override
public Settings getSettings() {
return Settings.newInstance();
}
@Override
public Map<String, String> getUserProperties() {
return Map.of();
}
@Override
public Map<String, String> getSystemProperties() {
return systemProperties;
}
@Override
public Map<String, String> getEffectiveProperties(Project project) {
HashMap<String, String> result = new HashMap<>(getSystemProperties());
if (project != null) {
result.putAll(project.getModel().getProperties());
}
result.putAll(getUserProperties());
return result;
}
@Override
public Version getMavenVersion() {
return null;
}
@Override
public int getDegreeOfConcurrency() {
return 0;
}
@Override
public Instant getStartTime() {
return startTime;
}
@Override
public Path getTopDirectory() {
return null;
}
@Override
public Path getRootDirectory() {
throw new IllegalStateException();
}
@Override
public List<Project> getProjects() {
return List.of();
}
@Override
public Map<String, Object> getPluginContext(Project project) {
throw new UnsupportedInStandaloneModeException();
}
static class Providers {
@Provides
@SuppressWarnings("unused")
static Lookup newLookup(Injector injector) {
return new Lookup() {
@Override
public <T> T lookup(Class<T> type) {
try {
return injector.getInstance(type);
} catch (DIException e) {
throw new MavenException("Unable to locate instance of type " + type, e);
}
}
@Override
public <T> T lookup(Class<T> type, String name) {
try {
return injector.getInstance(Key.of(type, name));
} catch (DIException e) {
throw new MavenException("Unable to locate instance of type " + type, e);
}
}
@Override
public <T> Optional<T> lookupOptional(Class<T> type) {
try {
return Optional.of(injector.getInstance(type));
} catch (DIException e) {
return Optional.empty();
}
}
@Override
public <T> Optional<T> lookupOptional(Class<T> type, String name) {
try {
return Optional.of(injector.getInstance(Key.of(type, name)));
} catch (DIException e) {
return Optional.empty();
}
}
@Override
public <T> List<T> lookupList(Class<T> type) {
return injector.getInstance(new Key<List<T>>() {});
}
@Override
public <T> Map<String, T> lookupMap(Class<T> type) {
return injector.getInstance(new Key<Map<String, T>>() {});
}
};
}
@Provides
@SuppressWarnings("unused")
static ArtifactManager newArtifactManager() {
return new ArtifactManager() {
private final Map<Artifact, Path> paths = new ConcurrentHashMap<>();
@Override
public Optional<Path> getPath(Artifact artifact) {
return Optional.ofNullable(paths.get(artifact));
}
@Override
public void setPath(ProducedArtifact artifact, Path path) {
paths.put(artifact, path);
}
};
}
@Provides
@SuppressWarnings("unused")
static PackagingRegistry newPackagingRegistry(TypeRegistry typeRegistry) {
return id -> Optional.of(new DumbPackaging(id, typeRegistry.require(id), Map.of()));
}
@Provides
@SuppressWarnings("unused")
static TypeRegistry newTypeRegistry(List<TypeProvider> providers) {
return new TypeRegistry() {
@Override
public Optional<Type> lookup(String id) {
return providers.stream()
.flatMap(p -> p.provides().stream())
.filter(t -> Objects.equals(id, t.id()))
.findAny();
}
};
}
@Provides
@SuppressWarnings("unused")
static LifecycleRegistry newLifecycleRegistry() {
return new LifecycleRegistry() {
@Override
public Iterator<Lifecycle> iterator() {
return Collections.emptyIterator();
}
@Override
public Optional<Lifecycle> lookup(String id) {
return Optional.empty();
}
@Override
public List<String> computePhases(Lifecycle lifecycle) {
return List.of();
}
};
}
@Provides
@SuppressWarnings("unused")
static RepositorySystemSupplier newRepositorySystemSupplier() {
return new RepositorySystemSupplier();
}
@Provides
@SuppressWarnings("unused")
static RepositorySystem newRepositorySystem(RepositorySystemSupplier repositorySystemSupplier) {
return repositorySystemSupplier.getRepositorySystem();
}
@Provides
@SuppressWarnings("unused")
static RemoteRepositoryManager newRemoteRepositoryManager(RepositorySystemSupplier repositorySystemSupplier) {
return repositorySystemSupplier.getRemoteRepositoryManager();
}
@Provides
@SuppressWarnings("unused")
static Session newSession(RepositorySystem system, Lookup lookup, Context context) {
// SettingsDecrypter settingsDecrypter =
// (SettingsDecrypter)Objects.requireNonNull(this.createSettingsDecrypter(preBoot));
// new DefaultProfileSelector(List.of(
// new JdkVersionProfileActivator(),
// new PropertyProfileActivator(),
// new OperatingSystemProfileActivator(),
// new FileProfileActivator(new ProfileActivationFilePathInterpolator(
// new DefaultPathTranslator(), new DefaultRootLocator()))));
Map<String, String> properties = context.systemProperties;
Path userHome = Paths.get(properties.get("user.home"));
Path mavenUserHome = userHome.resolve(".m2");
Path mavenSystemHome = properties.containsKey("maven.home")
? Paths.get(properties.get("maven.home"))
: properties.containsKey("env.MAVEN_HOME") ? Paths.get(properties.get("env.MAVEN_HOME")) : null;
DefaultRepositorySystemSession rsession = new DefaultRepositorySystemSession(h -> false);
rsession.setSystemProperties(properties);
rsession.setConfigProperties(properties);
ProtoSession session = new ProtoSession(
rsession,
system,
List.of(lookup.lookup(RepositoryFactory.class)
.createRemote("central", "https://repo.maven.apache.org/maven2")),
null,
lookup,
context);
Settings settings = session.getService(SettingsBuilder.class)
.build(
session,
mavenSystemHome != null ? mavenSystemHome.resolve("settings.xml") : null,
mavenUserHome.resolve("settings.xml"))
.getEffectiveSettings();
settings.getProfiles();
// local repository
String localRepository = settings.getLocalRepository() != null
? settings.getLocalRepository()
: mavenUserHome.resolve("repository").toString();
LocalRepositoryManager llm =
system.newLocalRepositoryManager(rsession, new LocalRepository(localRepository));
rsession.setLocalRepositoryManager(llm);
// active proxies
// TODO
// active profiles
// DefaultSession defaultSession = new DefaultSession(
// rsession,
// system,
// List.of(lookup.lookup(RepositoryFactory.class)
// .createRemote("central", "https://repo.maven.apache.org/maven2")),
// null,
// lookup);
Profile profile = session.getService(SettingsBuilder.class)
.convert(org.apache.maven.api.settings.Profile.newBuilder()
.repositories(settings.getRepositories())
.pluginRepositories(settings.getPluginRepositories())
.build());
RepositoryFactory repositoryFactory = session.getService(RepositoryFactory.class);
List<RemoteRepository> repositories = profile.getRepositories().stream()
.map(repositoryFactory::createRemote)
.toList();
InternalSession s = (InternalSession) session.withRemoteRepositories(repositories);
InternalSession.associate(rsession, s);
return s;
// List<RemoteRepository> repositories = repositoryFactory.createRemote();
// session.getService(SettingsBuilder.class).convert()
// settings.getDelegate().getRepositories().stream()
// .map(r -> SettingsUtilsV4.)
// defaultSession.getService(RepositoryFactory.class).createRemote()
// return defaultSession;
}
}
static class UnsupportedInStandaloneModeException extends MavenException {}
record DumbPackaging(String id, Type type, Map<String, PluginContainer> plugins) implements Packaging {}
}

View File

@ -51,15 +51,9 @@ public class ResidentMavenContext extends MavenContext {
shadow.interactive = interactive;
shadow.localRepositoryPath = localRepositoryPath;
shadow.installationSettingsPath = installationSettingsPath;
shadow.projectSettingsPath = projectSettingsPath;
shadow.userSettingsPath = userSettingsPath;
shadow.effectiveSettings = effectiveSettings;
shadow.mavenExecutionRequest = mavenExecutionRequest;
shadow.eventSpyDispatcher = eventSpyDispatcher;
shadow.mavenExecutionRequestPopulator = mavenExecutionRequestPopulator;
shadow.modelProcessor = modelProcessor;
shadow.maven = maven;
return shadow;

View File

@ -0,0 +1,42 @@
/*
* 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.cling.invoker.spi;
import java.util.Map;
import org.apache.maven.api.di.Inject;
import org.apache.maven.api.di.Named;
import org.apache.maven.api.spi.PropertyContributor;
/**
* Hack: to circumvent sisu/plexus/di stuff.
*/
@Named
public final class PropertyContributorsHolder {
private final Map<String, PropertyContributor> propertyContributors;
@Inject
public PropertyContributorsHolder(Map<String, PropertyContributor> propertyContributors) {
this.propertyContributors = propertyContributors;
}
public Map<String, PropertyContributor> getPropertyContributors() {
return propertyContributors;
}
}

View File

@ -127,8 +127,6 @@ public class DefaultRepositorySystemSessionFactory implements RepositorySystemSe
private final VersionScheme versionScheme;
private final Map<String, MavenExecutionRequestExtender> requestExtenders;
private final Map<String, RepositorySystemSessionExtender> sessionExtenders;
@SuppressWarnings("checkstyle:ParameterNumber")
@ -139,14 +137,12 @@ public class DefaultRepositorySystemSessionFactory implements RepositorySystemSe
RuntimeInformation runtimeInformation,
TypeRegistry typeRegistry,
VersionScheme versionScheme,
Map<String, MavenExecutionRequestExtender> requestExtenders,
Map<String, RepositorySystemSessionExtender> sessionExtenders) {
this.repoSystem = repoSystem;
this.eventSpyDispatcher = eventSpyDispatcher;
this.runtimeInformation = runtimeInformation;
this.typeRegistry = typeRegistry;
this.versionScheme = versionScheme;
this.requestExtenders = requestExtenders;
this.sessionExtenders = sessionExtenders;
}
@ -159,11 +155,6 @@ public class DefaultRepositorySystemSessionFactory implements RepositorySystemSe
public SessionBuilder newRepositorySessionBuilder(MavenExecutionRequest request) {
requireNonNull(request, "request");
// apply MavenExecutionRequestExtenders
for (MavenExecutionRequestExtender requestExtender : requestExtenders.values()) {
requestExtender.extend(request);
}
MavenSessionBuilderSupplier supplier = new MavenSessionBuilderSupplier(repoSystem);
SessionBuilder sessionBuilder = supplier.get();
sessionBuilder.setArtifactTypeRegistry(new TypeRegistryAdapter(typeRegistry)); // dynamic

View File

@ -1,62 +0,0 @@
/*
* 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.services.Lookup;
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 Lookup lookup;
@Inject
PropertyContributorExtender(Lookup lookup) {
this.lookup = lookup;
}
@SuppressWarnings({"rawtypes", "unchecked"})
@Override
public void extend(MavenExecutionRequest mavenExecutionRequest) {
Map<String, PropertyContributor> effectivePropertyContributors = lookup.lookupMap(PropertyContributor.class);
if (!effectivePropertyContributors.isEmpty()) {
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

@ -88,7 +88,6 @@ public class DefaultRepositorySystemSessionFactoryTest {
information,
defaultTypeRegistry,
versionScheme,
Collections.emptyMap(),
Collections.emptyMap());
MavenExecutionRequest request = new DefaultMavenExecutionRequest();
@ -111,7 +110,6 @@ public class DefaultRepositorySystemSessionFactoryTest {
information,
defaultTypeRegistry,
versionScheme,
Collections.emptyMap(),
Collections.emptyMap());
MavenExecutionRequest request = new DefaultMavenExecutionRequest();
@ -146,7 +144,6 @@ public class DefaultRepositorySystemSessionFactoryTest {
information,
defaultTypeRegistry,
versionScheme,
Collections.emptyMap(),
Collections.emptyMap());
PlexusConfiguration plexusConfiguration = (PlexusConfiguration) systemSessionFactory
@ -189,7 +186,6 @@ public class DefaultRepositorySystemSessionFactoryTest {
information,
defaultTypeRegistry,
versionScheme,
Collections.emptyMap(),
Collections.emptyMap());
Map<String, String> headers = (Map<String, String>) systemSessionFactory
@ -226,7 +222,6 @@ public class DefaultRepositorySystemSessionFactoryTest {
information,
defaultTypeRegistry,
versionScheme,
Collections.emptyMap(),
Collections.emptyMap());
int connectionTimeout = (Integer) systemSessionFactory
@ -267,7 +262,6 @@ public class DefaultRepositorySystemSessionFactoryTest {
information,
defaultTypeRegistry,
versionScheme,
Collections.emptyMap(),
Collections.emptyMap());
int connectionTimeout = (Integer) systemSessionFactory
@ -302,7 +296,6 @@ public class DefaultRepositorySystemSessionFactoryTest {
information,
defaultTypeRegistry,
versionScheme,
Collections.emptyMap(),
Collections.emptyMap());
int requestTimeout = (Integer) systemSessionFactory
@ -343,7 +336,6 @@ public class DefaultRepositorySystemSessionFactoryTest {
information,
defaultTypeRegistry,
versionScheme,
Collections.emptyMap(),
Collections.emptyMap());
int requestTimeout = (Integer) systemSessionFactory
@ -361,7 +353,6 @@ public class DefaultRepositorySystemSessionFactoryTest {
information,
defaultTypeRegistry,
versionScheme,
Collections.emptyMap(),
Collections.emptyMap());
MavenExecutionRequest request = new DefaultMavenExecutionRequest();
@ -407,7 +398,6 @@ public class DefaultRepositorySystemSessionFactoryTest {
information,
defaultTypeRegistry,
versionScheme,
Collections.emptyMap(),
Collections.emptyMap());
MavenExecutionRequest request = new DefaultMavenExecutionRequest();

View File

@ -64,6 +64,8 @@ public class DefaultSettingsBuilder implements SettingsBuilder {
private final SettingsMerger settingsMerger = new SettingsMerger();
private final SettingsXmlFactory settingsXmlFactory;
private final Interpolator interpolator;
private final SecDispatcher secDispatcher;
@ -73,14 +75,16 @@ public class DefaultSettingsBuilder implements SettingsBuilder {
* Maven3 exposes decryption with other means.
*/
public DefaultSettingsBuilder() {
this(new DefaultInterpolator(), null);
this(new DefaultSettingsXmlFactory(), new DefaultInterpolator(), null);
}
/**
* In Maven4 the {@link SecDispatcher} is injected and build settings are fully decrypted as well.
*/
@Inject
public DefaultSettingsBuilder(Interpolator interpolator, SecDispatcher secDispatcher) {
public DefaultSettingsBuilder(
SettingsXmlFactory settingsXmlFactory, Interpolator interpolator, SecDispatcher secDispatcher) {
this.settingsXmlFactory = settingsXmlFactory;
this.interpolator = interpolator;
this.secDispatcher = secDispatcher;
}
@ -161,22 +165,18 @@ public class DefaultSettingsBuilder implements SettingsBuilder {
try {
try (InputStream is = settingsSource.openStream()) {
settings = request.getSession()
.getService(SettingsXmlFactory.class)
.read(XmlReaderRequest.builder()
.inputStream(is)
.location(settingsSource.getLocation())
.strict(true)
.build());
settings = settingsXmlFactory.read(XmlReaderRequest.builder()
.inputStream(is)
.location(settingsSource.getLocation())
.strict(true)
.build());
} catch (XmlReaderException e) {
try (InputStream is = settingsSource.openStream()) {
settings = request.getSession()
.getService(SettingsXmlFactory.class)
.read(XmlReaderRequest.builder()
.inputStream(is)
.location(settingsSource.getLocation())
.strict(false)
.build());
settings = settingsXmlFactory.read(XmlReaderRequest.builder()
.inputStream(is)
.location(settingsSource.getLocation())
.strict(false)
.build());
Location loc = e.getCause() instanceof XMLStreamException xe ? xe.getLocation() : null;
problems.add(new DefaultBuilderProblem(
settingsSource.getLocation(),

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.it;
import java.io.File;
import org.apache.maven.shared.verifier.util.ResourceExtractor;
import org.junit.jupiter.api.Test;
/**
* This is a test set for <a href="https://issues.apache.org/jira/browse/MNG-8385">MNG-8385</a>.
*/
class MavenITmng8385PropertyContributoSPITest extends AbstractMavenIntegrationTestCase {
MavenITmng8385PropertyContributoSPITest() {
super("[4.0.0-beta-6,)");
}
/**
* Verify that PropertyContributorSPI is used and does it's job
*/
@Test
void testIt() throws Exception {
File testDir = ResourceExtractor.simpleExtractResources(getClass(), "/mng-8385")
.getAbsoluteFile();
Verifier verifier;
verifier = newVerifier(new File(testDir, "spi-extension").getAbsolutePath());
verifier.addCliArgument("install");
verifier.execute();
verifier.verifyErrorFreeLog();
verifier = newVerifier(new File(testDir, "spi-consumer").getAbsolutePath());
verifier.addCliArgument("validate");
verifier.addCliArgument("-X");
verifier.setForkJvm(true); // TODO: remove when we updated MavenCLI+Invoker
verifier.execute();
verifier.verifyErrorFreeLog();
verifier.verifyTextInLog("washere!");
}
}

View File

@ -100,6 +100,7 @@ public class TestSuiteOrdering implements ClassOrderer {
* the tests are to finishing. Newer tests are also more likely to fail, so this is
* a fail fast technique as well.
*/
suite.addTestSuite(MavenITmng8385PropertyContributoSPITest.class);
suite.addTestSuite(MavenITmng8383UnknownTypeDependenciesTest.class);
suite.addTestSuite(MavenITmng8379SettingsDecryptTest.class);
suite.addTestSuite(MavenITmng8336UnknownPackagingTest.class);

View File

@ -0,0 +1,7 @@
<extensions>
<extension>
<groupId>org.apache.maven.its.mng8385</groupId>
<artifactId>spi-extension</artifactId>
<version>1.0.0-SNAPSHOT</version>
</extension>
</extensions>

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.1.0" root="true">
<groupId>org.apache.maven.its.mng8385</groupId>
<artifactId>spi-consumer</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>test</id>
<goals>
<goal>run</goal>
</goals>
<phase>validate</phase>
<configuration>
<target>
<echo message="${mng8385}" />
</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.1.0" root="true">
<groupId>org.apache.maven.its.mng8385</groupId>
<artifactId>spi-extension</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-api-spi</artifactId>
<version>4.0.0-beta-5</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<proc>full</proc>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -16,16 +16,17 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.internal.aether;
package org.apache.maven.its.mng8385;
import org.apache.maven.execution.MavenExecutionRequest;
import java.util.Map;
/**
* 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);
import org.apache.maven.api.di.Named;
import org.apache.maven.api.spi.PropertyContributor;
@Named
public class CustomPropertyContributor implements PropertyContributor {
@Override
public void contribute(Map<String, String> userProperties) {
userProperties.put("mng8385", "washere!");
}
}