[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; package org.apache.maven.api;
import java.nio.file.Path; import java.nio.file.Path;
import java.time.Instant;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -46,7 +45,15 @@ import org.apache.maven.api.settings.Settings;
*/ */
@Experimental @Experimental
@ThreadSafe @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. * Retrieves the settings for the current session.
@ -80,25 +87,6 @@ public interface Session {
@Nonnull @Nonnull
SessionData getData(); 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. * Each invocation computes a new map of effective properties. To be used in interpolation.
* <p> * <p>
@ -121,14 +109,6 @@ public interface Session {
@Nonnull @Nonnull
Map<String, String> getEffectiveProperties(@Nullable Project project); 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. * Returns the degree of concurrency for the build.
* *
@ -136,37 +116,6 @@ public interface Session {
*/ */
int getDegreeOfConcurrency(); 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. * 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); session, groupId, artifactId, version, classifier, extension, type, coordinateString);
} }
private static class DefaultArtifactFactoryRequestArtifact extends BaseRequest private static class DefaultArtifactFactoryRequestArtifact extends BaseRequest<Session>
implements ArtifactCoordinatesFactoryRequest { implements ArtifactCoordinatesFactoryRequest {
private final String groupId; private final String groupId;
private final String artifactId; private final String artifactId;

View File

@ -101,7 +101,8 @@ public interface ArtifactDeployerRequest {
return new DefaultArtifactDeployerRequest(session, repository, artifacts, retryFailedDeploymentCount); 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 RemoteRepository repository;
private final Collection<ProducedArtifact> artifacts; private final Collection<ProducedArtifact> artifacts;

View File

@ -136,7 +136,8 @@ public interface ArtifactFactoryRequest {
session, groupId, artifactId, version, classifier, extension, type); 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 groupId;
private final String artifactId; private final String artifactId;
private final String version; private final String version;

View File

@ -83,7 +83,7 @@ public interface ArtifactInstallerRequest {
return new DefaultArtifactInstallerRequest(session, artifacts); 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; private final Collection<ProducedArtifact> artifacts;

View File

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

View File

@ -22,7 +22,7 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; 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.Experimental;
import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.annotations.Nonnull;
@ -32,16 +32,16 @@ import org.apache.maven.api.annotations.Nonnull;
* @since 4.0.0 * @since 4.0.0
*/ */
@Experimental @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"); this.session = nonNull(session, "session cannot be null");
} }
@Nonnull @Nonnull
public Session getSession() { public S getSession() {
return session; return session;
} }

View File

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

View File

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

View File

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

View File

@ -125,7 +125,8 @@ public interface ProjectBuilderRequest {
session, path, source, allowStubModel, recursive, processPlugins, repositories); 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 Path path;
private final Source source; private final Source source;
private final boolean allowStubModel; private final boolean allowStubModel;

View File

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

View File

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

View File

@ -94,7 +94,8 @@ public interface VersionRangeResolverRequest {
return new DefaultVersionResolverRequest(session, artifactCoordinates, repositories); 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 ArtifactCoordinates artifactCoordinates;
private final List<RemoteRepository> repositories; private final List<RemoteRepository> repositories;

View File

@ -96,7 +96,8 @@ public interface VersionResolverRequest {
return new DefaultVersionResolverRequest(session, artifactCoordinates, repositories); 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 ArtifactCoordinates artifactCoordinates;
private final List<RemoteRepository> repositories; private final List<RemoteRepository> repositories;

View File

@ -18,8 +18,10 @@
*/ */
package org.apache.maven.api.spi; package org.apache.maven.api.spi;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.apache.maven.api.ProtoSession;
import org.apache.maven.api.annotations.Consumer; import org.apache.maven.api.annotations.Consumer;
import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.di.Named; 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. * 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}. * @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.Consumer;
import java.util.function.Function; 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.InvokerException;
import org.apache.maven.api.cli.InvokerRequest; import org.apache.maven.api.cli.InvokerRequest;
import org.apache.maven.api.cli.Logger; import org.apache.maven.api.cli.Logger;
import org.apache.maven.api.services.Lookup; import org.apache.maven.api.services.Lookup;
import org.apache.maven.api.settings.Settings; import org.apache.maven.api.settings.Settings;
import org.apache.maven.cling.invoker.mvn.ProtoSession;
import org.apache.maven.cling.logging.Slf4jConfiguration; import org.apache.maven.cling.logging.Slf4jConfiguration;
import org.jline.terminal.Terminal; import org.jline.terminal.Terminal;
import org.slf4j.ILoggerFactory; import org.slf4j.ILoggerFactory;
@ -46,7 +45,6 @@ public class LookupContext implements AutoCloseable {
public final Function<String, Path> cwdResolver; public final Function<String, Path> cwdResolver;
public final Function<String, Path> installationResolver; public final Function<String, Path> installationResolver;
public final Function<String, Path> userResolver; public final Function<String, Path> userResolver;
public final Session session;
protected LookupContext(InvokerRequest invokerRequest) { protected LookupContext(InvokerRequest invokerRequest) {
this.invokerRequest = requireNonNull(invokerRequest); this.invokerRequest = requireNonNull(invokerRequest);
@ -58,12 +56,23 @@ public class LookupContext implements AutoCloseable {
this.logger = invokerRequest.parserRequest().logger(); this.logger = invokerRequest.parserRequest().logger();
Map<String, String> user = new HashMap<>(invokerRequest.userProperties()); Map<String, String> user = new HashMap<>(invokerRequest.userProperties());
user.put("session.rootDirectory", invokerRequest.rootDirectory().toString());
user.put("session.topDirectory", invokerRequest.topDirectory().toString()); user.put("session.topDirectory", invokerRequest.topDirectory().toString());
Map<String, String> system = new HashMap<>(invokerRequest.systemProperties()); if (invokerRequest.rootDirectory().isEmpty()) {
this.session = ProtoSession.create(user, system); 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 Logger logger;
public ILoggerFactory loggerFactory; public ILoggerFactory loggerFactory;
public Slf4jConfiguration slf4jConfiguration; public Slf4jConfiguration slf4jConfiguration;
@ -76,9 +85,6 @@ public class LookupContext implements AutoCloseable {
public boolean interactive; public boolean interactive;
public Path localRepositoryPath; public Path localRepositoryPath;
public Path installationSettingsPath;
public Path projectSettingsPath;
public Path userSettingsPath;
public Settings effectiveSettings; public Settings effectiveSettings;
public final List<AutoCloseable> closeables = new ArrayList<>(); public final List<AutoCloseable> closeables = new ArrayList<>();

View File

@ -33,6 +33,7 @@ import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import org.apache.maven.api.Constants; 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.Invoker;
import org.apache.maven.api.cli.InvokerException; import org.apache.maven.api.cli.InvokerException;
import org.apache.maven.api.cli.InvokerRequest; 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.cli.Options;
import org.apache.maven.api.services.BuilderProblem; import org.apache.maven.api.services.BuilderProblem;
import org.apache.maven.api.services.Interpolator; 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.MavenException;
import org.apache.maven.api.services.MessageBuilder; import org.apache.maven.api.services.MessageBuilder;
import org.apache.maven.api.services.SettingsBuilder; 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.Repository;
import org.apache.maven.api.settings.Server; import org.apache.maven.api.settings.Server;
import org.apache.maven.api.settings.Settings; 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.InvalidRepositoryException;
import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy; import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
import org.apache.maven.artifact.repository.MavenArtifactRepository; import org.apache.maven.artifact.repository.MavenArtifactRepository;
import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout; import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
import org.apache.maven.bridge.MavenRepositorySystem; 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.Slf4jConfiguration;
import org.apache.maven.cling.logging.Slf4jConfigurationFactory; import org.apache.maven.cling.logging.Slf4jConfigurationFactory;
import org.apache.maven.cling.transfer.ConsoleMavenTransferListener; 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 { protected int doInvoke(C context) throws Exception {
pushProperties(context); pushCoreProperties(context);
validate(context); validate(context);
prepare(context); prepare(context);
configureLogging(context); configureLogging(context);
@ -132,6 +136,8 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
helpOrVersionAndMayExit(context); helpOrVersionAndMayExit(context);
preCommands(context); preCommands(context);
container(context); container(context);
postContainer(context);
pushUserProperties(context);
lookup(context); lookup(context);
init(context); init(context);
postCommands(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 abstract C createContext(InvokerRequest invokerRequest) throws InvokerException;
protected void pushProperties(C context) throws Exception { protected void pushCoreProperties(C context) throws Exception {
InvokerRequest invokerRequest = context.invokerRequest; System.setProperty(
HashSet<String> sys = new HashSet<>(invokerRequest.systemProperties().keySet()); Constants.MAVEN_HOME,
invokerRequest.userProperties().entrySet().stream() 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())) .filter(k -> !sys.contains(k.getKey()))
.forEach(k -> System.setProperty(k.getKey(), k.getValue())); .forEach(k -> System.setProperty(k.getKey(), k.getValue()));
System.setProperty(
Constants.MAVEN_HOME, invokerRequest.installationDirectory().toString());
} }
protected void validate(C context) throws Exception {} 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 prepare(C context) throws Exception {}
protected void configureLogging(C context) throws Exception { protected void configureLogging(C context) throws Exception {
InvokerRequest invokerRequest = context.invokerRequest;
// LOG COLOR // LOG COLOR
Options mavenOptions = invokerRequest.options(); Options mavenOptions = context.invokerRequest.options();
Map<String, String> userProperties = invokerRequest.userProperties(); Map<String, String> userProperties = context.protoSession.getUserProperties();
String styleColor = mavenOptions String styleColor = mavenOptions
.color() .color()
.orElse(userProperties.getOrDefault( .orElse(userProperties.getOrDefault(
@ -381,6 +390,19 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
return new PlexusContainerCapsuleFactory<>(); 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 lookup(C context) throws Exception {}
protected void init(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); throw new FileNotFoundException("The specified user settings file does not exist: " + userSettingsFile);
} }
} else { } else {
String userSettingsFileStr = context.invokerRequest.userProperties().get(Constants.MAVEN_USER_SETTINGS); String userSettingsFileStr =
context.protoSession.getUserProperties().get(Constants.MAVEN_USER_SETTINGS);
if (userSettingsFileStr != null) { if (userSettingsFileStr != null) {
userSettingsFile = context.userResolver.apply(userSettingsFileStr); userSettingsFile = context.userResolver.apply(userSettingsFileStr);
} }
@ -445,7 +468,7 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
} }
} else { } else {
String projectSettingsFileStr = String projectSettingsFileStr =
context.invokerRequest.userProperties().get(Constants.MAVEN_PROJECT_SETTINGS); context.protoSession.getUserProperties().get(Constants.MAVEN_PROJECT_SETTINGS);
if (projectSettingsFileStr != null) { if (projectSettingsFileStr != null) {
projectSettingsFile = context.cwdResolver.apply(projectSettingsFileStr); projectSettingsFile = context.cwdResolver.apply(projectSettingsFileStr);
} }
@ -463,20 +486,16 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
} }
} else { } else {
String installationSettingsFileStr = String installationSettingsFileStr =
context.invokerRequest.userProperties().get(Constants.MAVEN_INSTALLATION_SETTINGS); context.protoSession.getUserProperties().get(Constants.MAVEN_INSTALLATION_SETTINGS);
if (installationSettingsFileStr != null) { if (installationSettingsFileStr != null) {
installationSettingsFile = context.installationResolver.apply(installationSettingsFileStr); installationSettingsFile = context.installationResolver.apply(installationSettingsFileStr);
} }
} }
context.installationSettingsPath = installationSettingsFile;
context.projectSettingsPath = projectSettingsFile;
context.userSettingsPath = userSettingsFile;
Function<String, String> interpolationSource = Interpolator.chain( 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() SettingsBuilderRequest settingsRequest = SettingsBuilderRequest.builder()
.session(context.session) .session(context.protoSession)
.installationSettingsSource( .installationSettingsSource(
installationSettingsFile != null && Files.exists(installationSettingsFile) installationSettingsFile != null && Files.exists(installationSettingsFile)
? Source.fromPath(installationSettingsFile) ? Source.fromPath(installationSettingsFile)
@ -540,9 +559,9 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
protected Path localRepositoryPath(C context) { protected Path localRepositoryPath(C context) {
// user override // 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) { if (userDefinedLocalRepo == null) {
userDefinedLocalRepo = context.invokerRequest.systemProperties().get(Constants.MAVEN_REPO_LOCAL); userDefinedLocalRepo = context.protoSession.getUserProperties().get(Constants.MAVEN_REPO_LOCAL);
if (userDefinedLocalRepo != null) { if (userDefinedLocalRepo != null) {
context.logger.warn("The property '" + Constants.MAVEN_REPO_LOCAL context.logger.warn("The property '" + Constants.MAVEN_REPO_LOCAL
+ "' has been set using a JVM system property which is deprecated. " + "' 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 // defaults
return context.userResolver return context.userResolver
.apply(context.invokerRequest.userProperties().get(Constants.MAVEN_USER_CONF)) .apply(context.protoSession.getUserProperties().get(Constants.MAVEN_USER_CONF))
.resolve("repository"); .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); populateRequestFromSettings(request, context.effectiveSettings);
Options options = context.invokerRequest.options(); Options options = context.invokerRequest.options();
@ -575,8 +594,8 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
request.setInteractiveMode(context.interactive); request.setInteractiveMode(context.interactive);
request.setShowErrors(options.showErrors().orElse(false)); request.setShowErrors(options.showErrors().orElse(false));
request.setBaseDirectory(context.invokerRequest.topDirectory().toFile()); request.setBaseDirectory(context.invokerRequest.topDirectory().toFile());
request.setSystemProperties(toProperties(context.invokerRequest.systemProperties())); request.setSystemProperties(toProperties(context.protoSession.getSystemProperties()));
request.setUserProperties(toProperties(context.invokerRequest.userProperties())); request.setUserProperties(toProperties(context.protoSession.getUserProperties()));
request.setTopDirectory(context.invokerRequest.topDirectory()); request.setTopDirectory(context.invokerRequest.topDirectory());
if (context.invokerRequest.rootDirectory().isPresent()) { if (context.invokerRequest.rootDirectory().isPresent()) {
@ -720,7 +739,7 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
} }
protected boolean isRunningOnCI(C context) { 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); 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.AbstractModule;
import com.google.inject.Module; import com.google.inject.Module;
import org.apache.maven.api.Constants; 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.InvokerException;
import org.apache.maven.api.cli.InvokerRequest; import org.apache.maven.api.cli.InvokerRequest;
import org.apache.maven.api.cli.Logger; 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.execution.scope.internal.MojoExecutionScopeModule;
import org.apache.maven.extension.internal.CoreExports; import org.apache.maven.extension.internal.CoreExports;
import org.apache.maven.extension.internal.CoreExtensionEntry; 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.SessionScope;
import org.apache.maven.session.scope.internal.SessionScopeModule; import org.apache.maven.session.scope.internal.SessionScopeModule;
import org.codehaus.plexus.ContainerConfiguration; import org.codehaus.plexus.ContainerConfiguration;
@ -108,11 +110,11 @@ public class PlexusContainerCapsuleFactory<C extends LookupContext> implements C
Thread.currentThread().setContextClassLoader(container.getContainerRealm()); Thread.currentThread().setContextClassLoader(container.getContainerRealm());
container.setLoggerManager(createLoggerManager()); container.setLoggerManager(createLoggerManager());
InvokerRequest invokerRequest = context.invokerRequest; ProtoSession protoSession = context.protoSession;
Function<String, String> extensionSource = expression -> { Function<String, String> extensionSource = expression -> {
String value = invokerRequest.userProperties().get(expression); String value = protoSession.getUserProperties().get(expression);
if (value == null) { if (value == null) {
value = invokerRequest.systemProperties().get(expression); value = protoSession.getSystemProperties().get(expression);
} }
return value; return value;
}; };
@ -189,10 +191,10 @@ public class PlexusContainerCapsuleFactory<C extends LookupContext> implements C
protected void customizeContainer(C context, PlexusContainer container) throws Exception {} protected void customizeContainer(C context, PlexusContainer container) throws Exception {}
protected List<Path> parseExtClasspath(C context) throws Exception { protected List<Path> parseExtClasspath(C context) throws Exception {
InvokerRequest invokerRequest = context.invokerRequest; ProtoSession protoSession = context.protoSession;
String extClassPath = invokerRequest.userProperties().get(Constants.MAVEN_EXT_CLASS_PATH); String extClassPath = protoSession.getUserProperties().get(Constants.MAVEN_EXT_CLASS_PATH);
if (extClassPath == null) { if (extClassPath == null) {
extClassPath = invokerRequest.systemProperties().get(Constants.MAVEN_EXT_CLASS_PATH); extClassPath = protoSession.getSystemProperties().get(Constants.MAVEN_EXT_CLASS_PATH);
if (extClassPath != null) { if (extClassPath != null) {
context.logger.warn("The property '" + Constants.MAVEN_EXT_CLASS_PATH context.logger.warn("The property '" + Constants.MAVEN_EXT_CLASS_PATH
+ "' has been set using a JVM system property which is deprecated. " + "' 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() { DefaultPlexusContainer container = new DefaultPlexusContainer(cc, new AbstractModule() {
@Override @Override
protected void configure() { 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)); invoker.settings(context, container.lookup(SettingsBuilder.class));
MavenExecutionRequest mer = new DefaultMavenExecutionRequest(); MavenExecutionRequest mer = new DefaultMavenExecutionRequest();
invoker.populateRequest(context, mer); invoker.populateRequest(context, new DefaultLookup(container), mer);
mer = container.lookup(MavenExecutionRequestPopulator.class).populateDefaults(mer); mer = container.lookup(MavenExecutionRequestPopulator.class).populateDefaults(mer);
return Collections.unmodifiableList(container return Collections.unmodifiableList(container
.lookup(BootstrapCoreExtensionManager.class) .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.Maven;
import org.apache.maven.api.cli.InvokerRequest; 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.cling.invoker.LookupContext;
import org.apache.maven.eventspy.internal.EventSpyDispatcher; 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; import org.apache.maven.logging.BuildEventListener;
@SuppressWarnings("VisibilityModifier") @SuppressWarnings("VisibilityModifier")
@ -34,9 +31,7 @@ public class MavenContext extends LookupContext {
} }
public BuildEventListener buildEventListener; public BuildEventListener buildEventListener;
public MavenExecutionRequest mavenExecutionRequest;
public EventSpyDispatcher eventSpyDispatcher; public EventSpyDispatcher eventSpyDispatcher;
public MavenExecutionRequestPopulator mavenExecutionRequestPopulator;
public ModelProcessor modelProcessor;
public Maven maven; 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.Logger;
import org.apache.maven.api.cli.mvn.MavenOptions; import org.apache.maven.api.cli.mvn.MavenOptions;
import org.apache.maven.api.services.BuilderProblem; 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.SettingsBuilderRequest;
import org.apache.maven.api.services.SettingsBuilderResult; import org.apache.maven.api.services.SettingsBuilderResult;
import org.apache.maven.api.services.Source; import org.apache.maven.api.services.Source;
@ -88,13 +89,13 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
@Override @Override
protected int execute(C context) throws Exception { protected int execute(C context) throws Exception {
toolchains(context); MavenExecutionRequest request = prepareMavenExecutionRequest();
populateRequest(context, context.mavenExecutionRequest); toolchains(context, request);
return doExecute(context); populateRequest(context, context.lookup, request);
return doExecute(context, request);
} }
@Override protected MavenExecutionRequest prepareMavenExecutionRequest() throws Exception {
protected void prepare(C context) throws Exception {
// explicitly fill in "defaults"? // explicitly fill in "defaults"?
DefaultMavenExecutionRequest mavenExecutionRequest = new DefaultMavenExecutionRequest(); DefaultMavenExecutionRequest mavenExecutionRequest = new DefaultMavenExecutionRequest();
mavenExecutionRequest.setRepositoryCache(new DefaultRepositoryCache()); mavenExecutionRequest.setRepositoryCache(new DefaultRepositoryCache());
@ -108,26 +109,24 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
mavenExecutionRequest.setLoggingLevel(MavenExecutionRequest.LOGGING_LEVEL_INFO); mavenExecutionRequest.setLoggingLevel(MavenExecutionRequest.LOGGING_LEVEL_INFO);
mavenExecutionRequest.setDegreeOfConcurrency(1); mavenExecutionRequest.setDegreeOfConcurrency(1);
mavenExecutionRequest.setBuilderId("singlethreaded"); mavenExecutionRequest.setBuilderId("singlethreaded");
return mavenExecutionRequest;
context.mavenExecutionRequest = mavenExecutionRequest;
} }
@Override @Override
protected void lookup(C context) throws Exception { protected void lookup(C context) throws Exception {
context.eventSpyDispatcher = context.lookup.lookup(EventSpyDispatcher.class); 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); context.maven = context.lookup.lookup(Maven.class);
} }
@Override @Override
protected void init(C context) throws Exception { protected void init(C context) throws Exception {
super.init(context);
InvokerRequest invokerRequest = context.invokerRequest; InvokerRequest invokerRequest = context.invokerRequest;
Map<String, Object> data = new HashMap<>(); Map<String, Object> data = new HashMap<>();
data.put("plexus", context.lookup.lookup(PlexusContainer.class)); data.put("plexus", context.lookup.lookup(PlexusContainer.class));
data.put("workingDirectory", invokerRequest.cwd().toString()); data.put("workingDirectory", invokerRequest.cwd().toString());
data.put("systemProperties", toProperties(invokerRequest.systemProperties())); data.put("systemProperties", toProperties(context.protoSession.getSystemProperties()));
data.put("userProperties", toProperties(invokerRequest.userProperties())); data.put("userProperties", toProperties(context.protoSession.getUserProperties()));
data.put("versionProperties", CLIReportingUtils.getBuildProperties()); data.put("versionProperties", CLIReportingUtils.getBuildProperties());
context.eventSpyDispatcher.init(() -> data); 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; Path userToolchainsFile = null;
if (context.invokerRequest.options().altUserToolchains().isPresent()) { if (context.invokerRequest.options().altUserToolchains().isPresent()) {
@ -194,7 +193,7 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
} }
} else { } else {
String userToolchainsFileStr = String userToolchainsFileStr =
context.invokerRequest.userProperties().get(Constants.MAVEN_USER_TOOLCHAINS); context.protoSession.getUserProperties().get(Constants.MAVEN_USER_TOOLCHAINS);
if (userToolchainsFileStr != null) { if (userToolchainsFileStr != null) {
userToolchainsFile = context.cwdResolver.apply(userToolchainsFileStr); userToolchainsFile = context.cwdResolver.apply(userToolchainsFileStr);
} }
@ -212,19 +211,18 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
} }
} else { } else {
String installationToolchainsFileStr = String installationToolchainsFileStr =
context.invokerRequest.userProperties().get(Constants.MAVEN_INSTALLATION_TOOLCHAINS); context.protoSession.getUserProperties().get(Constants.MAVEN_INSTALLATION_TOOLCHAINS);
if (installationToolchainsFileStr != null) { if (installationToolchainsFileStr != null) {
installationToolchainsFile = context.cwdResolver.apply(installationToolchainsFileStr); installationToolchainsFile = context.cwdResolver.apply(installationToolchainsFileStr);
} }
} }
context.mavenExecutionRequest.setInstallationToolchainsFile( request.setInstallationToolchainsFile(
installationToolchainsFile != null ? installationToolchainsFile.toFile() : null); installationToolchainsFile != null ? installationToolchainsFile.toFile() : null);
context.mavenExecutionRequest.setUserToolchainsFile( request.setUserToolchainsFile(userToolchainsFile != null ? userToolchainsFile.toFile() : null);
userToolchainsFile != null ? userToolchainsFile.toFile() : null);
ToolchainsBuilderRequest toolchainsRequest = ToolchainsBuilderRequest.builder() ToolchainsBuilderRequest toolchainsRequest = ToolchainsBuilderRequest.builder()
.session(context.session) .session(context.protoSession)
.installationToolchainsSource( .installationToolchainsSource(
installationToolchainsFile != null && Files.isRegularFile(installationToolchainsFile) installationToolchainsFile != null && Files.isRegularFile(installationToolchainsFile)
? Source.fromPath(installationToolchainsFile) ? Source.fromPath(installationToolchainsFile)
@ -245,9 +243,12 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
context.eventSpyDispatcher.onEvent(toolchainsResult); context.eventSpyDispatcher.onEvent(toolchainsResult);
context.mavenExecutionRequestPopulator.populateFromToolchains( context.lookup
context.mavenExecutionRequest, .lookup(MavenExecutionRequestPopulator.class)
new org.apache.maven.toolchain.model.PersistedToolchains(toolchainsResult.getEffectiveToolchains())); .populateFromToolchains(
request,
new org.apache.maven.toolchain.model.PersistedToolchains(
toolchainsResult.getEffectiveToolchains()));
if (!toolchainsResult.getProblems().isEmpty()) { if (!toolchainsResult.getProblems().isEmpty()) {
context.logger.warn(""); context.logger.warn("");
@ -262,8 +263,8 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
} }
@Override @Override
protected void populateRequest(C context, MavenExecutionRequest request) throws Exception { protected void populateRequest(C context, Lookup lookup, MavenExecutionRequest request) throws Exception {
super.populateRequest(context, request); super.populateRequest(context, lookup, request);
if (context.invokerRequest.rootDirectory().isEmpty()) { if (context.invokerRequest.rootDirectory().isEmpty()) {
// maven requires this to be set; so default it (and see below at POM) // maven requires this to be set; so default it (and see below at POM)
request.setMultiModuleProjectDirectory( request.setMultiModuleProjectDirectory(
@ -280,7 +281,7 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
request.setUpdateSnapshots(options.updateSnapshots().orElse(false)); request.setUpdateSnapshots(options.updateSnapshots().orElse(false));
request.setGlobalChecksumPolicy(determineGlobalChecksumPolicy(context)); request.setGlobalChecksumPolicy(determineGlobalChecksumPolicy(context));
Path pom = determinePom(context); Path pom = determinePom(context, lookup);
if (pom != null) { if (pom != null) {
request.setPom(pom.toFile()); request.setPom(pom.toFile());
if (pom.getParent() != null) { 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(); Path current = context.invokerRequest.cwd();
MavenOptions options = (MavenOptions) context.invokerRequest.options(); MavenOptions options = (MavenOptions) context.invokerRequest.options();
if (options.alternatePomFile().isPresent()) { if (options.alternatePomFile().isPresent()) {
current = context.cwdResolver.apply(options.alternatePomFile().get()); current = context.cwdResolver.apply(options.alternatePomFile().get());
} }
if (context.modelProcessor != null) { ModelProcessor modelProcessor =
return context.modelProcessor.locateExistingPom(current); lookup.lookupOptional(ModelProcessor.class).orElse(null);
if (modelProcessor != null) {
return modelProcessor.locateExistingPom(current);
} else { } else {
return Files.isRegularFile(current) ? current : null; 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 { protected int doExecute(C context, MavenExecutionRequest request) throws Exception {
MavenExecutionRequest request = context.mavenExecutionRequest;
context.eventSpyDispatcher.onEvent(request); context.eventSpyDispatcher.onEvent(request);
MavenExecutionResult result; 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.interactive = interactive;
shadow.localRepositoryPath = localRepositoryPath; shadow.localRepositoryPath = localRepositoryPath;
shadow.installationSettingsPath = installationSettingsPath;
shadow.projectSettingsPath = projectSettingsPath;
shadow.userSettingsPath = userSettingsPath;
shadow.effectiveSettings = effectiveSettings; shadow.effectiveSettings = effectiveSettings;
shadow.mavenExecutionRequest = mavenExecutionRequest;
shadow.eventSpyDispatcher = eventSpyDispatcher; shadow.eventSpyDispatcher = eventSpyDispatcher;
shadow.mavenExecutionRequestPopulator = mavenExecutionRequestPopulator;
shadow.modelProcessor = modelProcessor;
shadow.maven = maven; shadow.maven = maven;
return shadow; 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 VersionScheme versionScheme;
private final Map<String, MavenExecutionRequestExtender> requestExtenders;
private final Map<String, RepositorySystemSessionExtender> sessionExtenders; private final Map<String, RepositorySystemSessionExtender> sessionExtenders;
@SuppressWarnings("checkstyle:ParameterNumber") @SuppressWarnings("checkstyle:ParameterNumber")
@ -139,14 +137,12 @@ public class DefaultRepositorySystemSessionFactory implements RepositorySystemSe
RuntimeInformation runtimeInformation, RuntimeInformation runtimeInformation,
TypeRegistry typeRegistry, TypeRegistry typeRegistry,
VersionScheme versionScheme, VersionScheme versionScheme,
Map<String, MavenExecutionRequestExtender> requestExtenders,
Map<String, RepositorySystemSessionExtender> sessionExtenders) { Map<String, RepositorySystemSessionExtender> sessionExtenders) {
this.repoSystem = repoSystem; this.repoSystem = repoSystem;
this.eventSpyDispatcher = eventSpyDispatcher; this.eventSpyDispatcher = eventSpyDispatcher;
this.runtimeInformation = runtimeInformation; this.runtimeInformation = runtimeInformation;
this.typeRegistry = typeRegistry; this.typeRegistry = typeRegistry;
this.versionScheme = versionScheme; this.versionScheme = versionScheme;
this.requestExtenders = requestExtenders;
this.sessionExtenders = sessionExtenders; this.sessionExtenders = sessionExtenders;
} }
@ -159,11 +155,6 @@ public class DefaultRepositorySystemSessionFactory implements RepositorySystemSe
public SessionBuilder newRepositorySessionBuilder(MavenExecutionRequest request) { public SessionBuilder newRepositorySessionBuilder(MavenExecutionRequest request) {
requireNonNull(request, "request"); requireNonNull(request, "request");
// apply MavenExecutionRequestExtenders
for (MavenExecutionRequestExtender requestExtender : requestExtenders.values()) {
requestExtender.extend(request);
}
MavenSessionBuilderSupplier supplier = new MavenSessionBuilderSupplier(repoSystem); MavenSessionBuilderSupplier supplier = new MavenSessionBuilderSupplier(repoSystem);
SessionBuilder sessionBuilder = supplier.get(); SessionBuilder sessionBuilder = supplier.get();
sessionBuilder.setArtifactTypeRegistry(new TypeRegistryAdapter(typeRegistry)); // dynamic 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, information,
defaultTypeRegistry, defaultTypeRegistry,
versionScheme, versionScheme,
Collections.emptyMap(),
Collections.emptyMap()); Collections.emptyMap());
MavenExecutionRequest request = new DefaultMavenExecutionRequest(); MavenExecutionRequest request = new DefaultMavenExecutionRequest();
@ -111,7 +110,6 @@ public class DefaultRepositorySystemSessionFactoryTest {
information, information,
defaultTypeRegistry, defaultTypeRegistry,
versionScheme, versionScheme,
Collections.emptyMap(),
Collections.emptyMap()); Collections.emptyMap());
MavenExecutionRequest request = new DefaultMavenExecutionRequest(); MavenExecutionRequest request = new DefaultMavenExecutionRequest();
@ -146,7 +144,6 @@ public class DefaultRepositorySystemSessionFactoryTest {
information, information,
defaultTypeRegistry, defaultTypeRegistry,
versionScheme, versionScheme,
Collections.emptyMap(),
Collections.emptyMap()); Collections.emptyMap());
PlexusConfiguration plexusConfiguration = (PlexusConfiguration) systemSessionFactory PlexusConfiguration plexusConfiguration = (PlexusConfiguration) systemSessionFactory
@ -189,7 +186,6 @@ public class DefaultRepositorySystemSessionFactoryTest {
information, information,
defaultTypeRegistry, defaultTypeRegistry,
versionScheme, versionScheme,
Collections.emptyMap(),
Collections.emptyMap()); Collections.emptyMap());
Map<String, String> headers = (Map<String, String>) systemSessionFactory Map<String, String> headers = (Map<String, String>) systemSessionFactory
@ -226,7 +222,6 @@ public class DefaultRepositorySystemSessionFactoryTest {
information, information,
defaultTypeRegistry, defaultTypeRegistry,
versionScheme, versionScheme,
Collections.emptyMap(),
Collections.emptyMap()); Collections.emptyMap());
int connectionTimeout = (Integer) systemSessionFactory int connectionTimeout = (Integer) systemSessionFactory
@ -267,7 +262,6 @@ public class DefaultRepositorySystemSessionFactoryTest {
information, information,
defaultTypeRegistry, defaultTypeRegistry,
versionScheme, versionScheme,
Collections.emptyMap(),
Collections.emptyMap()); Collections.emptyMap());
int connectionTimeout = (Integer) systemSessionFactory int connectionTimeout = (Integer) systemSessionFactory
@ -302,7 +296,6 @@ public class DefaultRepositorySystemSessionFactoryTest {
information, information,
defaultTypeRegistry, defaultTypeRegistry,
versionScheme, versionScheme,
Collections.emptyMap(),
Collections.emptyMap()); Collections.emptyMap());
int requestTimeout = (Integer) systemSessionFactory int requestTimeout = (Integer) systemSessionFactory
@ -343,7 +336,6 @@ public class DefaultRepositorySystemSessionFactoryTest {
information, information,
defaultTypeRegistry, defaultTypeRegistry,
versionScheme, versionScheme,
Collections.emptyMap(),
Collections.emptyMap()); Collections.emptyMap());
int requestTimeout = (Integer) systemSessionFactory int requestTimeout = (Integer) systemSessionFactory
@ -361,7 +353,6 @@ public class DefaultRepositorySystemSessionFactoryTest {
information, information,
defaultTypeRegistry, defaultTypeRegistry,
versionScheme, versionScheme,
Collections.emptyMap(),
Collections.emptyMap()); Collections.emptyMap());
MavenExecutionRequest request = new DefaultMavenExecutionRequest(); MavenExecutionRequest request = new DefaultMavenExecutionRequest();
@ -407,7 +398,6 @@ public class DefaultRepositorySystemSessionFactoryTest {
information, information,
defaultTypeRegistry, defaultTypeRegistry,
versionScheme, versionScheme,
Collections.emptyMap(),
Collections.emptyMap()); Collections.emptyMap());
MavenExecutionRequest request = new DefaultMavenExecutionRequest(); MavenExecutionRequest request = new DefaultMavenExecutionRequest();

View File

@ -64,6 +64,8 @@ public class DefaultSettingsBuilder implements SettingsBuilder {
private final SettingsMerger settingsMerger = new SettingsMerger(); private final SettingsMerger settingsMerger = new SettingsMerger();
private final SettingsXmlFactory settingsXmlFactory;
private final Interpolator interpolator; private final Interpolator interpolator;
private final SecDispatcher secDispatcher; private final SecDispatcher secDispatcher;
@ -73,14 +75,16 @@ public class DefaultSettingsBuilder implements SettingsBuilder {
* Maven3 exposes decryption with other means. * Maven3 exposes decryption with other means.
*/ */
public DefaultSettingsBuilder() { 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. * In Maven4 the {@link SecDispatcher} is injected and build settings are fully decrypted as well.
*/ */
@Inject @Inject
public DefaultSettingsBuilder(Interpolator interpolator, SecDispatcher secDispatcher) { public DefaultSettingsBuilder(
SettingsXmlFactory settingsXmlFactory, Interpolator interpolator, SecDispatcher secDispatcher) {
this.settingsXmlFactory = settingsXmlFactory;
this.interpolator = interpolator; this.interpolator = interpolator;
this.secDispatcher = secDispatcher; this.secDispatcher = secDispatcher;
} }
@ -161,22 +165,18 @@ public class DefaultSettingsBuilder implements SettingsBuilder {
try { try {
try (InputStream is = settingsSource.openStream()) { try (InputStream is = settingsSource.openStream()) {
settings = request.getSession() settings = settingsXmlFactory.read(XmlReaderRequest.builder()
.getService(SettingsXmlFactory.class) .inputStream(is)
.read(XmlReaderRequest.builder() .location(settingsSource.getLocation())
.inputStream(is) .strict(true)
.location(settingsSource.getLocation()) .build());
.strict(true)
.build());
} catch (XmlReaderException e) { } catch (XmlReaderException e) {
try (InputStream is = settingsSource.openStream()) { try (InputStream is = settingsSource.openStream()) {
settings = request.getSession() settings = settingsXmlFactory.read(XmlReaderRequest.builder()
.getService(SettingsXmlFactory.class) .inputStream(is)
.read(XmlReaderRequest.builder() .location(settingsSource.getLocation())
.inputStream(is) .strict(false)
.location(settingsSource.getLocation()) .build());
.strict(false)
.build());
Location loc = e.getCause() instanceof XMLStreamException xe ? xe.getLocation() : null; Location loc = e.getCause() instanceof XMLStreamException xe ? xe.getLocation() : null;
problems.add(new DefaultBuilderProblem( problems.add(new DefaultBuilderProblem(
settingsSource.getLocation(), 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 * the tests are to finishing. Newer tests are also more likely to fail, so this is
* a fail fast technique as well. * a fail fast technique as well.
*/ */
suite.addTestSuite(MavenITmng8385PropertyContributoSPITest.class);
suite.addTestSuite(MavenITmng8383UnknownTypeDependenciesTest.class); suite.addTestSuite(MavenITmng8383UnknownTypeDependenciesTest.class);
suite.addTestSuite(MavenITmng8379SettingsDecryptTest.class); suite.addTestSuite(MavenITmng8379SettingsDecryptTest.class);
suite.addTestSuite(MavenITmng8336UnknownPackagingTest.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 * specific language governing permissions and limitations
* under the License. * 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;
/** import org.apache.maven.api.di.Named;
* Strictly internal component able to "extend" {@link MavenExecutionRequest} in some way before it is used to import org.apache.maven.api.spi.PropertyContributor;
* construct resolver session.
* @Named
* @since 4.0.0 public class CustomPropertyContributor implements PropertyContributor {
*/ @Override
interface MavenExecutionRequestExtender { public void contribute(Map<String, String> userProperties) {
void extend(MavenExecutionRequest mavenExecutionRequest); userProperties.put("mng8385", "washere!");
}
} }