[MNG-8120] Refactor ModelBuilder and ProjectBuilder (#1700)

With the introduction of the build pom and raw -> build pom transformation, the construction of the effective poms in two steps become very problematic. Over the time, multiple caches have been added to the ProjectBuilder and ModelBuilder related classes which are often redundant.

This PR thus changes things and move the recursive construction of the models fully into the ModelBuilder in a single call. When building build poms, a first step is done by parsing the file models from the root, then building all needed effective models from those. All the inference can be cleanly done because the builder has all the file models ready. The result will be used by the ProjectBuilder to build the projects.
This commit is contained in:
Guillaume Nodet 2024-09-28 11:03:24 +02:00 committed by GitHub
parent 2c6846b09b
commit 2d224623a3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
105 changed files with 2787 additions and 3942 deletions

View File

@ -39,7 +39,7 @@ import org.apache.maven.api.annotations.Nonnull;
@Immutable
public interface Artifact {
/**
* {@return a unique identifier for this artifact}.
* {@return a unique identifier for this artifact}
* The identifier is composed of groupId, artifactId, extension, classifier, and version.
*
* @see ArtifactCoordinates#getId()
@ -58,7 +58,7 @@ public interface Artifact {
}
/**
* {@return the group identifier of the artifact}.
* {@return the group identifier of the artifact}
*
* @see ArtifactCoordinates#getGroupId()
*/
@ -66,7 +66,7 @@ public interface Artifact {
String getGroupId();
/**
* {@return the identifier of the artifact}.
* {@return the identifier of the artifact}
*
* @see ArtifactCoordinates#getArtifactId()
*/
@ -74,7 +74,8 @@ public interface Artifact {
String getArtifactId();
/**
* {@return the version of the artifact}. Contrarily to {@link ArtifactCoordinates},
* {@return the version of the artifact}
* Contrarily to {@link ArtifactCoordinates},
* each {@code Artifact} is associated to a specific version instead of a range of versions.
* If the {@linkplain #getBaseVersion() base version} contains a meta-version such as {@code SNAPSHOT},
* those keywords are replaced by, for example, the actual timestamp.
@ -85,7 +86,7 @@ public interface Artifact {
Version getVersion();
/**
* {@return the version or meta-version of the artifact}.
* {@return the version or meta-version of the artifact}
* A meta-version is a version suffixed with the {@code SNAPSHOT} keyword.
* Meta-versions are represented in a base version by their symbols (e.g., {@code SNAPSHOT}),
* while they are replaced by, for example, the actual timestamp in the {@linkplain #getVersion() version}.
@ -121,7 +122,7 @@ public interface Artifact {
boolean isSnapshot();
/**
* {@return coordinates with the same identifiers as this artifact}.
* {@return coordinates with the same identifiers as this artifact}
* This is a shortcut for {@code session.createArtifactCoordinates(artifact)}.
*
* @see org.apache.maven.api.Session#createArtifactCoordinates(Artifact)

View File

@ -33,13 +33,13 @@ import org.apache.maven.api.annotations.Nonnull;
@Immutable
public interface ArtifactCoordinates {
/**
* {@return the group identifier of the artifact}.
* {@return the group identifier of the artifact}
*/
@Nonnull
String getGroupId();
/**
* {@return the identifier of the artifact}.
* {@return the identifier of the artifact}
*/
@Nonnull
String getArtifactId();
@ -53,7 +53,7 @@ public interface ArtifactCoordinates {
String getClassifier();
/**
* {@return the specific version, range of versions or meta-version of the artifact}.
* {@return the specific version, range of versions or meta-version of the artifact}
* A meta-version is a version suffixed with the {@code SNAPSHOT} keyword.
*/
@Nonnull

View File

@ -271,7 +271,7 @@ public final class Constants {
* @since 4.0.0
*/
@Config(type = "java.lang.Integer", defaultValue = "cores/2 + 1")
public static final String MAVEN_PROJECT_BUILDER_PARALLELISM = "maven.projectBuilder.parallelism";
public static final String MAVEN_MODEL_BUILDER_PARALLELISM = "maven.modelBuilder.parallelism";
/**
* User property for enabling/disabling the consumer POM feature.

View File

@ -36,7 +36,8 @@ import org.apache.maven.api.annotations.Nonnull;
@Immutable
public interface Dependency extends Artifact {
/**
* {@return the type of the dependency}. A dependency can be a <abbr>JAR</abbr> file,
* {@return the type of the dependency}
* A dependency can be a <abbr>JAR</abbr> file,
* a modular-<abbr>JAR</abbr> if it is intended to be placed on the module-path,
* a <abbr>JAR</abbr> containing test classes, <i>etc.</i>
*
@ -46,7 +47,7 @@ public interface Dependency extends Artifact {
Type getType();
/**
* {@return the time at which the dependency will be used}.
* {@return the time at which the dependency will be used}
* If may be, for example, at compile time only, at run time or at test time.
*
* @see DependencyCoordinates#getScope()

View File

@ -39,7 +39,8 @@ import org.apache.maven.api.annotations.Nullable;
@Immutable
public interface DependencyCoordinates extends ArtifactCoordinates {
/**
* {@return the type of the dependency}. A dependency can be a <abbr>JAR</abbr> file,
* {@return the type of the dependency}
* A dependency can be a <abbr>JAR</abbr> file,
* a modular-<abbr>JAR</abbr> if it is intended to be placed on the module-path,
* a <abbr>JAR</abbr> containing test classes, <i>etc.</i>
*/
@ -47,7 +48,7 @@ public interface DependencyCoordinates extends ArtifactCoordinates {
Type getType();
/**
* {@return the time at which the dependency will be used}.
* {@return the time at which the dependency will be used}
* If may be, for example, at compile time only, at run time or at test time.
*/
@Nonnull
@ -62,7 +63,7 @@ public interface DependencyCoordinates extends ArtifactCoordinates {
Boolean getOptional();
/**
* {@return transitive dependencies to exclude}.
* {@return transitive dependencies to exclude}
*/
@Nonnull
Collection<Exclusion> getExclusions();

View File

@ -123,7 +123,7 @@ public interface PathType {
String name();
/**
* {@return a string representation for this extensible enum describing a path type}.
* {@return a string representation for this extensible enum describing a path type}
* For example {@code "PathType[PATCH_MODULE:foo.bar]"}.
*/
@Nonnull

View File

@ -224,6 +224,13 @@ public interface Project {
/**
* Returns project parent project, if any.
* <p>
* Note that the model may have a parent defined, but an empty parent
* project may be returned if the parent comes from a remote repository,
* as a {@code Project} must refer to a buildable project.
*
* @return an optional containing the parent project
* @see Model#getParent()
*/
@Nonnull
Optional<Project> getParent();

View File

@ -37,7 +37,7 @@ import org.apache.maven.api.annotations.Provider;
@Provider
public interface Log {
/**
* {@return true if the <b>debug</b> error level is enabled}.
* {@return true if the <b>debug</b> error level is enabled}
*/
boolean isDebugEnabled();
@ -70,7 +70,7 @@ public interface Log {
void debug(Supplier<String> content, Throwable error);
/**
* {@return true if the <b>info</b> error level is enabled}.
* {@return true if the <b>info</b> error level is enabled}
*/
boolean isInfoEnabled();
@ -103,7 +103,7 @@ public interface Log {
void info(Supplier<String> content, Throwable error);
/**
* {@return true if the <b>warn</b> error level is enabled}.
* {@return true if the <b>warn</b> error level is enabled}
*/
boolean isWarnEnabled();
@ -136,7 +136,7 @@ public interface Log {
void warn(Supplier<String> content, Throwable error);
/**
* {@return true if the <b>error</b> error level is enabled}.
* {@return true if the <b>error</b> error level is enabled}
*/
boolean isErrorEnabled();

View File

@ -97,7 +97,7 @@ public interface DependencyResolverResult {
Map<PathType, List<Path>> getDispatchedPaths();
/**
* {@return all dependencies associated to their paths}.
* {@return all dependencies associated to their paths}
* Some dependencies may be associated to a null value if there is no path available.
*/
@Nonnull

View File

@ -31,9 +31,12 @@ public interface ModelBuilder extends Service {
List<String> VALID_MODEL_VERSIONS = List.of(MODEL_VERSION_4_0_0, MODEL_VERSION_4_1_0);
ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilderException;
ModelBuilderSession newSession();
ModelTransformerContextBuilder newTransformerContextBuilder();
interface ModelBuilderSession {
ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilderException;
}
Model buildRawModel(ModelBuilderRequest request);
}

View File

@ -60,10 +60,17 @@ public class ModelBuilderException extends MavenException {
* @return The identifier of the POM or an empty string if not known, never {@code null}.
*/
public String getModelId() {
if (result == null || result.getModelIds().isEmpty()) {
if (result == null) {
return "";
} else if (result.getEffectiveModel() != null) {
return result.getEffectiveModel().getId();
} else if (result.getRawModel() != null) {
return result.getRawModel().getId();
} else if (result.getFileModel() != null) {
return result.getFileModel().getId();
} else {
return "";
}
return result.getModelIds().get(0);
}
/**

View File

@ -38,9 +38,6 @@ import static org.apache.maven.api.services.BaseRequest.nonNull;
* Request used to build a {@link org.apache.maven.api.Project} using
* the {@link ProjectBuilder} service.
*
* TODO: replace ModelRepositoryHolder with just the enum for the strategy
* TODO: replace validation level with an enum (though, we usually need just a boolean)
*
* @since 4.0.0
*/
@Experimental
@ -48,36 +45,38 @@ import static org.apache.maven.api.services.BaseRequest.nonNull;
public interface ModelBuilderRequest {
/**
* Denotes minimal validation of POMs. This validation level is meant for processing of POMs from repositories
* during metadata retrieval.
* The possible request types for building a model.
*/
int VALIDATION_LEVEL_MINIMAL = 0;
enum RequestType {
/**
* The request is for building a model from a POM file in a project on the filesystem.
*/
BUILD_POM,
/**
* The request is for building a model from a parent POM file from a downloaded artifact.
*/
PARENT_POM,
/**
* The request is for building a model from a dependency POM file from a downloaded artifact.
*/
DEPENDENCY
}
/**
* Denotes validation as performed by Maven 2.0. This validation level is meant as a compatibility mode to allow
* users to migrate their projects.
* The possible merge modes for combining remote repositories.
*/
int VALIDATION_LEVEL_MAVEN_2_0 = 20;
enum RepositoryMerging {
/**
* Denotes validation as performed by Maven 3.0. This validation level is meant for existing projects.
*/
int VALIDATION_LEVEL_MAVEN_3_0 = 30;
/**
* The repositories declared in the POM have precedence over the repositories specified in the request.
*/
POM_DOMINANT,
/**
* Denotes validation as performed by Maven 3.1. This validation level is meant for existing projects.
*/
int VALIDATION_LEVEL_MAVEN_3_1 = 31;
/**
* Denotes validation as performed by Maven 4.0. This validation level is meant for new projects.
*/
int VALIDATION_LEVEL_MAVEN_4_0 = 40;
/**
* Denotes strict validation as recommended by the current Maven version.
*/
int VALIDATION_LEVEL_STRICT = VALIDATION_LEVEL_MAVEN_4_0;
/**
* The repositories specified in the request have precedence over the repositories declared in the POM.
*/
REQUEST_DOMINANT,
}
@Nonnull
Session getSession();
@ -85,28 +84,12 @@ public interface ModelBuilderRequest {
@Nonnull
ModelSource getSource();
int getValidationLevel();
boolean isTwoPhaseBuilding();
@Nonnull
RequestType getRequestType();
boolean isLocationTracking();
/**
* Indicates if the model to be built is a local project or a dependency.
* In case the project is loaded externally from a remote repository (as a dependency or
* even as an external parent), the POM will be parsed in a lenient way. Local POMs
* are parsed more strictly.
*/
boolean isProjectBuild();
/**
* Specifies whether plugin processing should take place for the built model.
* This involves merging plugins specified by the {@link org.apache.maven.api.Packaging},
* configuration expansion (merging configuration defined globally for a given plugin
* using {@link org.apache.maven.api.model.Plugin#getConfiguration()}
* into the configuration for each {@link org.apache.maven.api.model.PluginExecution}.
*/
boolean isProcessPlugins();
boolean isRecursive();
/**
* Defines external profiles that may be activated for the given model.
@ -141,23 +124,14 @@ public interface ModelBuilderRequest {
Map<String, String> getUserProperties();
@Nonnull
ModelResolver getModelResolver();
@Nonnull
ModelRepositoryHolder getModelRepositoryHolder();
@Nullable
Object getListener();
@Nullable
ModelBuilderResult getInterimResult();
@Nullable
ModelTransformerContextBuilder getTransformerContextBuilder();
RepositoryMerging getRepositoryMerging();
@Nullable
List<RemoteRepository> getRepositories();
@Nullable
ModelTransformer getLifecycleBindingsInjector();
@Nonnull
static ModelBuilderRequest build(@Nonnull ModelBuilderRequest request, @Nonnull ModelSource source) {
return builder(nonNull(request, "request cannot be null"))
@ -194,45 +168,35 @@ public interface ModelBuilderRequest {
@NotThreadSafe
class ModelBuilderRequestBuilder {
Session session;
int validationLevel;
RequestType requestType;
boolean locationTracking;
boolean twoPhaseBuilding;
boolean recursive;
ModelSource source;
boolean projectBuild;
boolean processPlugins = true;
Collection<Profile> profiles;
List<String> activeProfileIds;
List<String> inactiveProfileIds;
Map<String, String> systemProperties;
Map<String, String> userProperties;
ModelResolver modelResolver;
ModelRepositoryHolder modelRepositoryHolder;
Object listener;
ModelBuilderResult interimResult;
ModelTransformerContextBuilder transformerContextBuilder;
RepositoryMerging repositoryMerging;
List<RemoteRepository> repositories;
ModelTransformer lifecycleBindingsInjector;
ModelBuilderRequestBuilder() {}
ModelBuilderRequestBuilder(ModelBuilderRequest request) {
this.session = request.getSession();
this.validationLevel = request.getValidationLevel();
this.requestType = request.getRequestType();
this.locationTracking = request.isLocationTracking();
this.twoPhaseBuilding = request.isTwoPhaseBuilding();
this.recursive = request.isRecursive();
this.source = request.getSource();
this.projectBuild = request.isProjectBuild();
this.processPlugins = request.isProcessPlugins();
this.profiles = request.getProfiles();
this.activeProfileIds = request.getActiveProfileIds();
this.inactiveProfileIds = request.getInactiveProfileIds();
this.systemProperties = request.getSystemProperties();
this.userProperties = request.getUserProperties();
this.modelResolver = request.getModelResolver();
this.modelRepositoryHolder = request.getModelRepositoryHolder();
this.listener = request.getListener();
this.interimResult = request.getInterimResult();
this.transformerContextBuilder = request.getTransformerContextBuilder();
this.repositoryMerging = request.getRepositoryMerging();
this.repositories = request.getRepositories();
this.lifecycleBindingsInjector = request.getLifecycleBindingsInjector();
}
public ModelBuilderRequestBuilder session(Session session) {
@ -240,13 +204,8 @@ public interface ModelBuilderRequest {
return this;
}
public ModelBuilderRequestBuilder validationLevel(int validationLevel) {
this.validationLevel = validationLevel;
return this;
}
public ModelBuilderRequestBuilder twoPhaseBuilding(boolean twoPhaseBuilding) {
this.twoPhaseBuilding = twoPhaseBuilding;
public ModelBuilderRequestBuilder requestType(RequestType requestType) {
this.requestType = requestType;
return this;
}
@ -255,21 +214,16 @@ public interface ModelBuilderRequest {
return this;
}
public ModelBuilderRequestBuilder recursive(boolean recursive) {
this.recursive = recursive;
return this;
}
public ModelBuilderRequestBuilder source(ModelSource source) {
this.source = source;
return this;
}
public ModelBuilderRequestBuilder projectBuild(boolean projectBuild) {
this.projectBuild = projectBuild;
return this;
}
public ModelBuilderRequestBuilder processPlugins(boolean processPlugins) {
this.processPlugins = processPlugins;
return this;
}
public ModelBuilderRequestBuilder profiles(List<Profile> profiles) {
this.profiles = profiles;
return this;
@ -295,29 +249,8 @@ public interface ModelBuilderRequest {
return this;
}
public ModelBuilderRequestBuilder modelResolver(ModelResolver modelResolver) {
this.modelResolver = modelResolver;
return this;
}
public ModelBuilderRequestBuilder modelRepositoryHolder(ModelRepositoryHolder modelRepositoryHolder) {
this.modelRepositoryHolder = modelRepositoryHolder;
return this;
}
public ModelBuilderRequestBuilder listener(Object listener) {
this.listener = listener;
return this;
}
public ModelBuilderRequestBuilder interimResult(ModelBuilderResult interimResult) {
this.interimResult = interimResult;
return this;
}
public ModelBuilderRequestBuilder transformerContextBuilder(
ModelTransformerContextBuilder transformerContextBuilder) {
this.transformerContextBuilder = transformerContextBuilder;
public ModelBuilderRequestBuilder repositoryMerging(RepositoryMerging repositoryMerging) {
this.repositoryMerging = repositoryMerging;
return this;
}
@ -326,96 +259,76 @@ public interface ModelBuilderRequest {
return this;
}
public ModelBuilderRequestBuilder lifecycleBindingsInjector(ModelTransformer lifecycleBindingsInjector) {
this.lifecycleBindingsInjector = lifecycleBindingsInjector;
return this;
}
public ModelBuilderRequest build() {
return new DefaultModelBuilderRequest(
session,
validationLevel,
requestType,
locationTracking,
twoPhaseBuilding,
recursive,
source,
projectBuild,
processPlugins,
profiles,
activeProfileIds,
inactiveProfileIds,
systemProperties,
userProperties,
modelResolver,
modelRepositoryHolder,
listener,
interimResult,
transformerContextBuilder,
repositories);
repositoryMerging,
repositories,
lifecycleBindingsInjector);
}
private static class DefaultModelBuilderRequest extends BaseRequest implements ModelBuilderRequest {
private final int validationLevel;
private final RequestType requestType;
private final boolean locationTracking;
private final boolean twoPhaseBuilding;
private final boolean recursive;
private final ModelSource source;
private final boolean projectBuild;
private final boolean processPlugins;
private final Collection<Profile> profiles;
private final List<String> activeProfileIds;
private final List<String> inactiveProfileIds;
private final Map<String, String> systemProperties;
private final Map<String, String> userProperties;
private final ModelResolver modelResolver;
private final ModelRepositoryHolder modelRepositoryHolder;
private final Object listener;
private final ModelBuilderResult interimResult;
private final ModelTransformerContextBuilder transformerContextBuilder;
private final RepositoryMerging repositoryMerging;
private final List<RemoteRepository> repositories;
private final ModelTransformer lifecycleBindingsInjector;
@SuppressWarnings("checkstyle:ParameterNumber")
DefaultModelBuilderRequest(
@Nonnull Session session,
int validationLevel,
@Nonnull RequestType requestType,
boolean locationTracking,
boolean twoPhaseBuilding,
boolean recursive,
@Nonnull ModelSource source,
boolean projectBuild,
boolean processPlugins,
Collection<Profile> profiles,
List<String> activeProfileIds,
List<String> inactiveProfileIds,
Map<String, String> systemProperties,
Map<String, String> userProperties,
ModelResolver modelResolver,
ModelRepositoryHolder modelRepositoryHolder,
Object listener,
ModelBuilderResult interimResult,
ModelTransformerContextBuilder transformerContextBuilder,
List<RemoteRepository> repositories) {
RepositoryMerging repositoryMerging,
List<RemoteRepository> repositories,
ModelTransformer lifecycleBindingsInjector) {
super(session);
this.validationLevel = validationLevel;
this.requestType = nonNull(requestType, "requestType cannot be null");
this.locationTracking = locationTracking;
this.twoPhaseBuilding = twoPhaseBuilding;
this.recursive = recursive;
this.source = source;
this.projectBuild = projectBuild;
this.processPlugins = processPlugins;
this.profiles = profiles != null ? List.copyOf(profiles) : List.of();
this.activeProfileIds = activeProfileIds != null ? List.copyOf(activeProfileIds) : List.of();
this.inactiveProfileIds = inactiveProfileIds != null ? List.copyOf(inactiveProfileIds) : List.of();
this.systemProperties =
systemProperties != null ? Map.copyOf(systemProperties) : session.getSystemProperties();
this.userProperties = userProperties != null ? Map.copyOf(userProperties) : session.getUserProperties();
this.modelResolver = modelResolver;
this.modelRepositoryHolder = modelRepositoryHolder;
this.listener = listener;
this.interimResult = interimResult;
this.transformerContextBuilder = transformerContextBuilder;
this.repositoryMerging = repositoryMerging;
this.repositories = repositories != null ? List.copyOf(repositories) : null;
this.lifecycleBindingsInjector = lifecycleBindingsInjector;
}
@Override
public int getValidationLevel() {
return validationLevel;
}
@Override
public boolean isTwoPhaseBuilding() {
return twoPhaseBuilding;
public RequestType getRequestType() {
return requestType;
}
@Override
@ -423,21 +336,17 @@ public interface ModelBuilderRequest {
return locationTracking;
}
@Override
public boolean isRecursive() {
return recursive;
}
@Nonnull
@Override
public ModelSource getSource() {
return source;
}
public boolean isProjectBuild() {
return projectBuild;
}
@Override
public boolean isProcessPlugins() {
return processPlugins;
}
@Override
public Collection<Profile> getProfiles() {
return profiles;
@ -464,32 +373,19 @@ public interface ModelBuilderRequest {
}
@Override
public ModelResolver getModelResolver() {
return modelResolver;
}
@Override
public ModelRepositoryHolder getModelRepositoryHolder() {
return modelRepositoryHolder;
}
public Object getListener() {
return listener;
}
@Override
public ModelBuilderResult getInterimResult() {
return interimResult;
}
public ModelTransformerContextBuilder getTransformerContextBuilder() {
return transformerContextBuilder;
public RepositoryMerging getRepositoryMerging() {
return repositoryMerging;
}
@Override
public List<RemoteRepository> getRepositories() {
return repositories;
}
@Override
public ModelTransformer getLifecycleBindingsInjector() {
return lifecycleBindingsInjector;
}
}
}
}

View File

@ -19,7 +19,6 @@
package org.apache.maven.api.services;
import java.util.List;
import java.util.Optional;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.annotations.Nonnull;
@ -35,15 +34,12 @@ import org.apache.maven.api.model.Profile;
public interface ModelBuilderResult {
/**
* Gets the sequence of model identifiers that denote the lineage of models from which the effective model was
* constructed. Model identifiers should be handled as "opaque strings" and this method should be used as source
* if navigating the linage. The first identifier from the list denotes the model on which the model builder
* was originally invoked. The last identifier will always be the super POM.
* Gets the source from which the model was read.
*
* @return The model identifiers from the lineage of models, never {@code null}.
* @return The source from which the model was read, never {@code null}.
*/
@Nonnull
List<String> getModelIds();
ModelSource getSource();
/**
* Gets the file model.
@ -53,14 +49,6 @@ public interface ModelBuilderResult {
@Nonnull
Model getFileModel();
/**
* Returns the file model + profile injection.
*
* @return the activated file model, never {@code null}.
*/
@Nonnull
Model getActivatedFileModel();
/**
* Gets the file model + build pom transformation, without inheritance nor interpolation.
*
@ -69,6 +57,14 @@ public interface ModelBuilderResult {
@Nonnull
Model getRawModel();
/**
* Gets the effective model of the parent POM.
*
* @return the effective model of the parent POM, never {@code null}
*/
@Nonnull
Model getParentModel();
/**
* Gets the assembled model with inheritance, interpolation and profile injection.
*
@ -78,28 +74,12 @@ public interface ModelBuilderResult {
Model getEffectiveModel();
/**
* Gets the specified raw model as it was read from a model source. Apart from basic validation, a raw model has not
* undergone any updates by the model builder, e.g. reflects neither inheritance nor interpolation. The model
* identifier should be from the collection obtained by {@link #getModelIds()}.
* Gets the profiles that were active during model building.
*
* @see #getModelIds()
* @param modelId The identifier of the desired raw model, must not be {@code null}.
* @return The raw model or {@code null} if the specified model id does not refer to a known model.
* @return The active profiles of the model or an empty list if the model has no active profiles.
*/
@Nonnull
Optional<Model> getRawModel(@Nonnull String modelId);
/**
* Gets the profiles from the specified model that were active during model building. The model identifier should be
* from the collection obtained by {@link #getModelIds()}.
*
* @see #getModelIds()
* @param modelId The identifier of the model whose active profiles should be retrieved, must not be {@code null}.
* @return The active profiles of the model or an empty list if the specified model id does
* not refer to a known model or has no active profiles.
*/
@Nonnull
List<Profile> getActivePomProfiles(@Nonnull String modelId);
List<Profile> getActivePomProfiles();
/**
* Gets the external profiles that were active during model building. External profiles are those that were
@ -118,6 +98,14 @@ public interface ModelBuilderResult {
@Nonnull
List<ModelProblem> getProblems();
/**
* Gets the children of this result.
*
* @return the children of this result, can be empty but never {@code null}
*/
@Nonnull
List<? extends ModelBuilderResult> getChildren();
/**
* Creates a human-readable representation of these errors.
*/

View File

@ -18,6 +18,8 @@
*/
package org.apache.maven.api.services;
import org.apache.maven.api.annotations.Nonnull;
/**
* Describes a problem that was encountered during model building. A problem can either be an exception that was thrown
* or a simple string message. In addition, a problem carries a hint about its source, e.g. the POM file that exhibits
@ -44,15 +46,16 @@ public interface ModelProblem extends BuilderProblem {
* information that is available at the point the problem occurs and as such merely serves as best effort
* to provide information to the user to track the problem back to its origin.
*
* @see ModelBuilderResult#getModelIds()
* @return The identifier of the model from which the problem originated or an empty string if unknown, never
* {@code null}.
*/
@Nonnull
String getModelId();
/**
* Gets the applicable maven version/validation level of this problem
* @return The version, never {@code null}.
*/
@Nonnull
Version getVersion();
}

View File

@ -21,6 +21,7 @@ package org.apache.maven.api.services;
import java.util.List;
import org.apache.maven.api.model.InputLocation;
import org.apache.maven.api.model.Model;
/**
* Collects problems that are encountered during model building. The primary purpose of this component is to account for
@ -64,4 +65,16 @@ public interface ModelProblemCollector {
Exception exception);
void add(ModelProblem problem);
ModelBuilderException newModelBuilderException();
void setSource(String location);
void setSource(Model model);
String getSource();
void setRootModel(Model model);
Model getRootModel();
}

View File

@ -1,33 +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.api.services;
import java.util.List;
import org.apache.maven.api.RemoteRepository;
import org.apache.maven.api.model.Repository;
public interface ModelRepositoryHolder {
void merge(List<Repository> repos, boolean replace);
List<RemoteRepository> getRepositories();
ModelRepositoryHolder copy();
}

View File

@ -18,27 +18,26 @@
*/
package org.apache.maven.api.services;
import java.nio.file.Path;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.annotations.Nonnull;
import org.apache.maven.api.model.Model;
/**
* The ModelTransformer is a way to transform the local pom while streaming the input.
*
* The {@link #transform(ModelTransformerContext, Model, Path)} method uses a Path on purpose, to ensure the
* local pom is the original source.
* A model transformer.
*
* @since 4.0.0
*/
@Experimental
public interface ModelTransformer {
/**
* @param context the context, cannot be null
* @param model the model to transform
* @param path the pom file, cannot be null
* @throws ModelTransformerException if the transformation fails
* Apply a transformation on the file model.
*
* @param model the input model
* @param problems the problem collector to report any issues encountered during transformation
* @return the transformed model, or the input model if no transformation is needed
*/
@Nonnull
Model transform(@Nonnull ModelTransformerContext context, @Nonnull Model model, @Nonnull Path path)
throws ModelTransformerException;
Model transform(
@Nonnull Model model, @Nonnull ModelBuilderRequest request, @Nonnull ModelProblemCollector problems);
}

View File

@ -1,66 +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.api.services;
import java.nio.file.Path;
import org.apache.maven.api.model.Model;
/**
* Context used to transform a pom file.
*
* @since 4.0.0
*/
public interface ModelTransformerContext {
/**
* Key to get the TransformerContext from the SessionData
*/
Object KEY = ModelTransformerContext.class;
/**
* Get the value of the Maven user property.
*/
String getUserProperty(String key);
/**
* Get the model based on the path when resolving the parent based on relativePath.
*
* @param from the requiring model
* @param pomFile the path to the pomFile
* @return the model, otherwise {@code null}
*/
Model getRawModel(Path from, Path pomFile);
/**
* Get the model from the reactor based on the groupId and artifactId when resolving reactor dependencies.
*
* @param from the requiring model
* @param groupId the groupId
* @param artifactId the artifactId
* @return the model, otherwise {@code null}
* @throws IllegalStateException if multiple versions of the same GA are part of the reactor
*/
Model getRawModel(Path from, String groupId, String artifactId);
/**
* Locate the POM file inside the given directory.
*/
Path locate(Path path);
}

View File

@ -1,43 +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.api.services;
/**
* The transformerContextBuilder is responsible for initializing the TransformerContext.
* In case rawModels are missing, it could do new buildingRequests on the ModelBuilder.
*
* @since 4.0.0
*/
public interface ModelTransformerContextBuilder {
/**
* This method is used to initialize the TransformerContext
*
* @param request the modelBuildingRequest
* @param problems the problemCollector
* @return the mutable transformerContext
*/
ModelTransformerContext initialize(ModelBuilderRequest request, ModelProblemCollector problems);
/**
* The immutable transformerContext, can be used after the buildplan is finished.
*
* @return the immutable transformerContext
*/
ModelTransformerContext build();
}

View File

@ -1,38 +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.api.services;
import org.apache.maven.api.annotations.Experimental;
/**
* Exception thrown when a {@link ModelTransformer} fails.
*
* @since 4.0.0
*/
@Experimental
public class ModelTransformerException extends MavenException {
public ModelTransformerException(Exception e) {
super(e);
}
public ModelTransformerException(String message, Throwable exception) {
super(message, exception);
}
}

View File

@ -23,7 +23,6 @@ import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.annotations.Nonnull;
import org.apache.maven.api.di.Named;
import org.apache.maven.api.model.Model;
import org.apache.maven.api.services.ModelTransformerException;
/**
* Marker interface for model transformers.

View File

@ -1,55 +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.api.services.model;
import java.util.function.Consumer;
import org.apache.maven.api.model.Model;
import org.apache.maven.api.services.ModelBuilderRequest;
import org.apache.maven.api.services.ModelProblemCollector;
/**
* Holds data relevant for a model building event.
*
*/
public interface ModelBuildingEvent {
/**
* Gets the model being built. The precise state of this model depends on the event being fired.
*
* @return The model being built, never {@code null}.
*/
Model model();
Consumer<Model> update();
/**
* Gets the model building request being processed.
*
* @return The model building request being processed, never {@code null}.
*/
ModelBuilderRequest request();
/**
* Gets the container used to collect problems that were encountered while processing the event.
*
* @return The container used to collect problems that were encountered, never {@code null}.
*/
ModelProblemCollector problems();
}

View File

@ -1,33 +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.api.services.model;
/**
* Defines events that the model builder fires during construction of the effective model. When a listener encounters
* errors while processing the event, it can report these problems via {@link ModelBuildingEvent#problems()}.
*/
public interface ModelBuildingListener {
/**
* Notifies the listener that the model has been constructed to the extent where build extensions can be processed.
*
* @param event The details about the event.
*/
default void buildExtensionsAssembled(ModelBuildingEvent event) {}
}

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.api.services;
package org.apache.maven.api.services.model;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
@ -29,6 +29,7 @@ import org.apache.maven.api.annotations.Nonnull;
import org.apache.maven.api.annotations.Nullable;
import org.apache.maven.api.model.Dependency;
import org.apache.maven.api.model.Parent;
import org.apache.maven.api.services.ModelSource;
/**
* Resolves a POM from its coordinates.

View File

@ -16,7 +16,9 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.api.services;
package org.apache.maven.api.services.model;
import org.apache.maven.api.services.MavenException;
/**
* Signals an error when resolving the path to an external model.

View File

@ -27,15 +27,44 @@ import org.apache.maven.api.services.ModelProblemCollector;
*
*/
public interface ModelValidator {
/**
* Denotes minimal validation of POMs. This validation level is meant for processing of POMs from repositories
* during metadata retrieval.
*/
int VALIDATION_LEVEL_MINIMAL = 0;
/**
* Denotes validation as performed by Maven 2.0. This validation level is meant as a compatibility mode to allow
* users to migrate their projects.
*/
int VALIDATION_LEVEL_MAVEN_2_0 = 20;
/**
* Denotes validation as performed by Maven 3.0. This validation level is meant for existing projects.
*/
int VALIDATION_LEVEL_MAVEN_3_0 = 30;
/**
* Denotes validation as performed by Maven 3.1. This validation level is meant for existing projects.
*/
int VALIDATION_LEVEL_MAVEN_3_1 = 31;
/**
* Denotes validation as performed by Maven 4.0. This validation level is meant for new projects.
*/
int VALIDATION_LEVEL_MAVEN_4_0 = 40;
/**
* Denotes strict validation as recommended by the current Maven version.
*/
int VALIDATION_LEVEL_STRICT = VALIDATION_LEVEL_MAVEN_4_0;
/**
* Checks the specified file model for missing or invalid values. This model is directly created from the POM
* file and has not been subjected to inheritance, interpolation or profile/default injection.
*
* @param model The model to validate, must not be {@code null}.
* @param validationLevel The validation level.
* @param request The model building request that holds further settings, must not be {@code null}.
* @param problems The container used to collect problems that were encountered, must not be {@code null}.
*/
default void validateFileModel(Model model, ModelBuilderRequest request, ModelProblemCollector problems) {
default void validateFileModel(
Model model, int validationLevel, ModelBuilderRequest request, ModelProblemCollector problems) {
// do nothing
}
@ -44,18 +73,22 @@ public interface ModelValidator {
* transformation and has not been subjected to inheritance, interpolation or profile/default injection.
*
* @param model The model to validate, must not be {@code null}.
* @param validationLevel The validation level.
* @param request The model building request that holds further settings, must not be {@code null}.
* @param problems The container used to collect problems that were encountered, must not be {@code null}.
*/
void validateRawModel(Model model, ModelBuilderRequest request, ModelProblemCollector problems);
void validateRawModel(
Model model, int validationLevel, ModelBuilderRequest request, ModelProblemCollector problems);
/**
* Checks the specified (effective) model for missing or invalid values. The effective model is fully assembled and
* has undergone inheritance, interpolation and other model operations.
*
* @param model The model to validate, must not be {@code null}.
* @param validationLevel The validation level.
* @param request The model building request that holds further settings, must not be {@code null}.
* @param problems The container used to collect problems that were encountered, must not be {@code null}.
*/
void validateEffectiveModel(Model model, ModelBuilderRequest request, ModelProblemCollector problems);
void validateEffectiveModel(
Model model, int validationLevel, ModelBuilderRequest request, ModelProblemCollector problems);
}

View File

@ -20,6 +20,7 @@ package org.apache.maven.api.services.model;
import java.nio.file.Path;
import org.apache.maven.api.Service;
import org.apache.maven.api.annotations.Nonnull;
import org.apache.maven.api.annotations.Nullable;
@ -34,7 +35,7 @@ import org.apache.maven.api.annotations.Nullable;
* The default implementation will look for a {@code .mvn} child directory
* or a {@code pom.xml} containing the {@code root="true"} attribute.
*/
public interface RootLocator {
public interface RootLocator extends Service {
String UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE = "Unable to find the root directory. "
+ "Create a .mvn directory in the root directory or add the root=\"true\""

View File

@ -1,31 +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.api.services.model;
import org.apache.maven.api.model.Model;
/**
* WorkspaceModelResolver
*/
public interface WorkspaceModelResolver {
Model resolveRawModel(String groupId, String artifactId, String versionConstraint);
Model resolveEffectiveModel(String groupId, String artifactId, String versionConstraint);
}

View File

@ -297,9 +297,7 @@ public abstract class AbstractSession implements InternalSession {
try {
return lookup.lookup(c);
} catch (LookupException e) {
NoSuchElementException nsee = new NoSuchElementException(c.getName());
e.initCause(e);
throw nsee;
throw new NoSuchElementException(c.getName(), e);
}
}

View File

@ -58,7 +58,7 @@ abstract class AetherDependencyWrapper {
}
/**
* {@return the group identifier of the wrapped dependency}.
* {@return the group identifier of the wrapped dependency}
* The default implementation delegates to the Eclipse Aether artifact.
*/
public String getGroupId() {
@ -66,7 +66,7 @@ abstract class AetherDependencyWrapper {
}
/**
* {@return the artifact identifier of the wrapped dependency}.
* {@return the artifact identifier of the wrapped dependency}
* The default implementation delegates to the Eclipse Aether artifact.
*/
public String getArtifactId() {
@ -74,7 +74,7 @@ abstract class AetherDependencyWrapper {
}
/**
* {@return the file extension of the wrapped dependency}.
* {@return the file extension of the wrapped dependency}
* The default implementation delegates to the Eclipse Aether artifact.
*/
public String getExtension() {
@ -82,7 +82,7 @@ abstract class AetherDependencyWrapper {
}
/**
* {@return the type of the wrapped dependency}.
* {@return the type of the wrapped dependency}
* The default implementation infers the type from the properties associated to the Eclipse Aether artifact.
*/
public Type getType() {
@ -91,7 +91,7 @@ abstract class AetherDependencyWrapper {
}
/**
* {@return the classifier ("jar", "test-jar", ) of the wrapped dependency}.
* {@return the classifier ("jar", "test-jar", ) of the wrapped dependency}
* The default implementation first delegates to the Eclipse Aether artifact.
* If the latter does not provide a non-empty classifier,
* then the default value is determined by {@linkplain #getType() type}.
@ -109,7 +109,7 @@ abstract class AetherDependencyWrapper {
}
/**
* {@return the scope (compile, test, ) of this dependency}.
* {@return the scope (compile, test, ) of this dependency}
*/
@Nonnull
public DependencyScope getScope() {
@ -117,7 +117,7 @@ abstract class AetherDependencyWrapper {
}
/**
* {@return a string representation of this dependency}.
* {@return a string representation of this dependency}
* This is for debugging purposes only and may change in any future version.
*/
@Override

View File

@ -222,7 +222,8 @@ class PathModularization {
}
/**
* {@return the type of path detected}. The return value is {@link JavaPathType#MODULES}
* {@return the type of path detected}
* The return value is {@link JavaPathType#MODULES}
* if the dependency is a modular JAR file or a directory containing module descriptor(s),
* or {@link JavaPathType#CLASSES} otherwise. A JAR file without module descriptor but with
* an "Automatic-Module-Name" manifest attribute is considered modular.
@ -246,14 +247,14 @@ class PathModularization {
}
/**
* {@return whether the dependency contains a module of the given name}.
* {@return whether the dependency contains a module of the given name}
*/
public boolean containsModule(String name) {
return descriptors.containsValue(name);
}
/**
* {@return a string representation of this object for debugging purposes}.
* {@return a string representation of this object for debugging purposes}
* This string representation may change in any future version.
*/
@Override

View File

@ -20,6 +20,7 @@ package org.apache.maven.internal.impl;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -49,6 +50,6 @@ class Utils {
}
static <U, V> List<V> map(Collection<U> list, Function<U, V> mapper) {
return list.stream().map(mapper).collect(Collectors.toList());
return list.stream().map(mapper).filter(Objects::nonNull).collect(Collectors.toList());
}
}

View File

@ -1,188 +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.impl.model;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import org.apache.maven.api.di.Named;
import org.apache.maven.api.di.Singleton;
import org.apache.maven.api.model.Dependency;
import org.apache.maven.api.model.InputLocation;
import org.apache.maven.api.model.Model;
import org.apache.maven.api.model.Parent;
import org.apache.maven.api.services.ModelTransformer;
import org.apache.maven.api.services.ModelTransformerContext;
/**
* ModelSourceTransformer for the build pom
*
* @since 4.0.0
*/
@Named
@Singleton
public class BuildModelTransformer implements ModelTransformer {
@Override
public Model transform(ModelTransformerContext context, Model model, Path path) {
Model.Builder builder = Model.newBuilder(model);
handleParent(context, model, path, builder);
handleReactorDependencies(context, model, path, builder);
handleCiFriendlyVersion(context, model, path, builder);
return builder.build();
}
//
// Infer parent information
//
void handleParent(ModelTransformerContext context, Model model, Path pomFile, Model.Builder builder) {
Parent parent = model.getParent();
if (parent != null) {
String version = parent.getVersion();
// CI Friendly version for parent
String modVersion = replaceCiFriendlyVersion(context, version);
// Update parent
builder.parent(parent.with().version(modVersion).build());
}
}
//
// CI friendly versions
//
void handleCiFriendlyVersion(ModelTransformerContext context, Model model, Path pomFile, Model.Builder builder) {
String version = model.getVersion();
String modVersion = replaceCiFriendlyVersion(context, version);
builder.version(modVersion);
}
//
// Infer inner reactor dependencies version
//
void handleReactorDependencies(ModelTransformerContext context, Model model, Path pomFile, Model.Builder builder) {
List<Dependency> newDeps = new ArrayList<>();
boolean modified = false;
for (Dependency dep : model.getDependencies()) {
Dependency.Builder depBuilder = null;
if (dep.getVersion() == null) {
Model depModel = context.getRawModel(model.getPomFile(), dep.getGroupId(), dep.getArtifactId());
if (depModel != null) {
String version = depModel.getVersion();
InputLocation versionLocation = depModel.getLocation("version");
if (version == null && depModel.getParent() != null) {
version = depModel.getParent().getVersion();
versionLocation = depModel.getParent().getLocation("version");
}
depBuilder = Dependency.newBuilder(dep);
depBuilder.version(version).location("version", versionLocation);
if (dep.getGroupId() == null) {
String depGroupId = depModel.getGroupId();
InputLocation groupIdLocation = depModel.getLocation("groupId");
if (depGroupId == null && depModel.getParent() != null) {
depGroupId = depModel.getParent().getGroupId();
groupIdLocation = depModel.getParent().getLocation("groupId");
}
depBuilder.groupId(depGroupId).location("groupId", groupIdLocation);
}
}
}
if (depBuilder != null) {
newDeps.add(depBuilder.build());
modified = true;
} else {
newDeps.add(dep);
}
}
if (modified) {
builder.dependencies(newDeps);
}
}
protected String replaceCiFriendlyVersion(ModelTransformerContext context, String version) {
if (version != null) {
for (String key : Arrays.asList("changelist", "revision", "sha1")) {
String val = context.getUserProperty(key);
if (val != null) {
version = version.replace("${" + key + "}", val);
}
}
}
return version;
}
protected Optional<RelativeProject> resolveRelativePath(
Path pomFile, ModelTransformerContext context, Path relativePath, String groupId, String artifactId) {
Path pomPath = pomFile.resolveSibling(relativePath).normalize();
if (Files.isDirectory(pomPath)) {
pomPath = context.locate(pomPath);
}
if (pomPath == null || !Files.isRegularFile(pomPath)) {
return Optional.empty();
}
return Optional.ofNullable(context.getRawModel(pomFile, pomPath.normalize()))
.map(BuildModelTransformer::toRelativeProject);
}
private static RelativeProject toRelativeProject(final Model m) {
String groupId = m.getGroupId();
if (groupId == null && m.getParent() != null) {
groupId = m.getParent().getGroupId();
}
String version = m.getVersion();
if (version == null && m.getParent() != null) {
version = m.getParent().getVersion();
}
return new RelativeProject(groupId, m.getArtifactId(), version);
}
protected static class RelativeProject {
private final String groupId;
private final String artifactId;
private final String version;
protected RelativeProject(String groupId, String artifactId, String version) {
this.groupId = groupId;
this.artifactId = artifactId;
this.version = version;
}
public String getGroupId() {
return groupId;
}
public String getArtifactId() {
return artifactId;
}
public String getVersion() {
return version;
}
}
}

View File

@ -24,6 +24,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.maven.api.di.Inject;
import org.apache.maven.api.di.Named;
import org.apache.maven.api.di.Singleton;
import org.apache.maven.api.model.InputLocation;
@ -36,6 +37,7 @@ import org.apache.maven.api.model.Reporting;
import org.apache.maven.api.services.ModelBuilderRequest;
import org.apache.maven.api.services.ModelProblemCollector;
import org.apache.maven.api.services.model.InheritanceAssembler;
import org.apache.maven.model.v4.MavenMerger;
/**
* Handles inheritance of model values.
@ -50,7 +52,16 @@ public class DefaultInheritanceAssembler implements InheritanceAssembler {
private static final String CHILD_DIRECTORY_PROPERTY = "project.directory";
private final InheritanceModelMerger merger = new InheritanceModelMerger();
private final MavenMerger merger;
@Inject
public DefaultInheritanceAssembler() {
this(new InheritanceModelMerger());
}
public DefaultInheritanceAssembler(MavenMerger merger) {
this.merger = merger;
}
@Override
public Model assembleModelInheritance(
@ -134,17 +145,11 @@ public class DefaultInheritanceAssembler implements InheritanceAssembler {
Object childDirectory = context.get(CHILD_DIRECTORY);
Object childPathAdjustment = context.get(CHILD_PATH_ADJUSTMENT);
boolean isBlankParentUrl = true;
if (parentUrl != null) {
for (int i = 0; i < parentUrl.length(); i++) {
if (!Character.isWhitespace(parentUrl.charAt(i))) {
isBlankParentUrl = false;
}
}
}
if (isBlankParentUrl || childDirectory == null || childPathAdjustment == null || !appendPath) {
if (parentUrl == null
|| parentUrl.isBlank()
|| childDirectory == null
|| childPathAdjustment == null
|| !appendPath) {
return parentUrl;
}

View File

@ -19,11 +19,9 @@
package org.apache.maven.internal.impl.model;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -31,47 +29,38 @@ import org.apache.maven.api.model.Model;
import org.apache.maven.api.model.Profile;
import org.apache.maven.api.services.ModelBuilderResult;
import org.apache.maven.api.services.ModelProblem;
import org.apache.maven.api.services.ModelSource;
/**
* Collects the output of the model builder.
*
*/
class DefaultModelBuilderResult implements ModelBuilderResult {
private ModelSource source;
private Model fileModel;
private Model activatedFileModel;
private Model rawModel;
private Model parentModel;
private Model effectiveModel;
private List<String> modelIds;
private Map<String, Model> rawModels;
private Map<String, List<Profile>> activePomProfiles;
private List<Profile> activePomProfiles;
private List<Profile> activeExternalProfiles;
private final List<ModelProblem> problems = new CopyOnWriteArrayList<>();
private final DefaultModelBuilderResult problemHolder;
private List<ModelProblem> problems;
private final List<DefaultModelBuilderResult> children = new ArrayList<>();
DefaultModelBuilderResult() {
modelIds = new ArrayList<>();
rawModels = new HashMap<>();
activePomProfiles = new HashMap<>();
activeExternalProfiles = new ArrayList<>();
problems = new ArrayList<>();
this(null);
}
DefaultModelBuilderResult(ModelBuilderResult result) {
this();
this.activeExternalProfiles.addAll(result.getActiveExternalProfiles());
this.effectiveModel = result.getEffectiveModel();
this.fileModel = result.getFileModel();
this.problems.addAll(result.getProblems());
DefaultModelBuilderResult(DefaultModelBuilderResult problemHolder) {
this.problemHolder = problemHolder;
}
for (String modelId : result.getModelIds()) {
this.modelIds.add(modelId);
this.rawModels.put(modelId, result.getRawModel(modelId).orElseThrow());
this.activePomProfiles.put(modelId, result.getActivePomProfiles(modelId));
}
public ModelSource getSource() {
return source;
}
public void setSource(ModelSource source) {
this.source = source;
}
@Override
@ -79,18 +68,26 @@ class DefaultModelBuilderResult implements ModelBuilderResult {
return fileModel;
}
public DefaultModelBuilderResult setFileModel(Model fileModel) {
public void setFileModel(Model fileModel) {
this.fileModel = fileModel;
return this;
}
public Model getActivatedFileModel() {
return activatedFileModel;
@Override
public Model getRawModel() {
return rawModel;
}
public DefaultModelBuilderResult setActivatedFileModel(Model activatedFileModel) {
this.activatedFileModel = activatedFileModel;
return this;
public void setRawModel(Model rawModel) {
this.rawModel = rawModel;
}
@Override
public Model getParentModel() {
return parentModel;
}
public void setParentModel(Model parentModel) {
this.parentModel = parentModel;
}
@Override
@ -98,61 +95,17 @@ class DefaultModelBuilderResult implements ModelBuilderResult {
return effectiveModel;
}
public DefaultModelBuilderResult setEffectiveModel(Model model) {
public void setEffectiveModel(Model model) {
this.effectiveModel = model;
return this;
}
@Override
public List<String> getModelIds() {
return modelIds;
public List<Profile> getActivePomProfiles() {
return activePomProfiles;
}
public DefaultModelBuilderResult addModelId(String modelId) {
// Intentionally notNull because Super POM may not contain a modelId
Objects.requireNonNull(modelId, "modelId cannot be null");
modelIds.add(modelId);
return this;
}
@Override
public Model getRawModel() {
return rawModels.get(modelIds.get(0));
}
@Override
public Optional<Model> getRawModel(String modelId) {
return Optional.ofNullable(rawModels.get(modelId));
}
public DefaultModelBuilderResult setRawModel(String modelId, Model rawModel) {
// Intentionally notNull because Super POM may not contain a modelId
Objects.requireNonNull(modelId, "modelId cannot be null");
rawModels.put(modelId, rawModel);
return this;
}
@Override
public List<Profile> getActivePomProfiles(String modelId) {
List<Profile> profiles = activePomProfiles.get(modelId);
return profiles != null ? profiles : List.of();
}
public DefaultModelBuilderResult setActivePomProfiles(String modelId, List<Profile> activeProfiles) {
// Intentionally notNull because Super POM may not contain a modelId
Objects.requireNonNull(modelId, "modelId cannot be null");
if (activeProfiles != null) {
this.activePomProfiles.put(modelId, new ArrayList<>(activeProfiles));
} else {
this.activePomProfiles.remove(modelId);
}
return this;
public void setActivePomProfiles(List<Profile> activeProfiles) {
this.activePomProfiles = activeProfiles;
}
@Override
@ -160,34 +113,50 @@ class DefaultModelBuilderResult implements ModelBuilderResult {
return activeExternalProfiles;
}
public DefaultModelBuilderResult setActiveExternalProfiles(List<Profile> activeProfiles) {
if (activeProfiles != null) {
this.activeExternalProfiles = new ArrayList<>(activeProfiles);
} else {
this.activeExternalProfiles.clear();
}
public void setActiveExternalProfiles(List<Profile> activeProfiles) {
this.activeExternalProfiles = activeProfiles;
}
return this;
/**
* Returns an unmodifiable list of problems encountered during the model building process.
*
* @return a list of ModelProblem instances representing the encountered problems,
* guaranteed to be non-null but possibly empty.
*/
@Override
public List<ModelProblem> getProblems() {
return Collections.unmodifiableList(problems);
}
/**
* Adds a given problem to the list of problems and propagates it to the parent result if present.
*
* @param problem The problem to be added. It must be an instance of ModelProblem.
*/
public void addProblem(ModelProblem problem) {
problems.add(problem);
if (problemHolder != null) {
problemHolder.addProblem(problem);
}
}
@Override
public List<ModelProblem> getProblems() {
return problems;
}
public DefaultModelBuilderResult setProblems(List<ModelProblem> problems) {
if (problems != null) {
this.problems = new ArrayList<>(problems);
} else {
this.problems.clear();
}
return this;
public List<DefaultModelBuilderResult> getChildren() {
return children;
}
public String toString() {
if (!modelIds.isEmpty()) {
String modelId = modelIds.get(0);
String modelId;
if (effectiveModel != null) {
modelId = effectiveModel.getId();
} else if (rawModel != null) {
modelId = rawModel.getId();
} else if (fileModel != null) {
modelId = fileModel.getId();
} else {
modelId = null;
}
if (!problems.isEmpty()) {
StringBuilder sb = new StringBuilder();
sb.append(problems.size())
.append(
@ -203,7 +172,11 @@ class DefaultModelBuilderResult implements ModelBuilderResult {
sb.append(" - [");
sb.append(problem.getSeverity());
sb.append("] ");
sb.append(problem.getMessage());
if (problem.getMessage() != null && !problem.getMessage().isEmpty()) {
sb.append(problem.getMessage());
} else if (problem.getException() != null) {
sb.append(problem.getException().toString());
}
String loc = Stream.of(
problem.getModelId().equals(modelId) ? problem.getModelId() : "",
problem.getModelId().equals(modelId) ? problem.getSource() : "",
@ -217,6 +190,6 @@ class DefaultModelBuilderResult implements ModelBuilderResult {
}
return sb.toString();
}
return null;
return modelId;
}
}

View File

@ -1,33 +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.impl.model;
import java.util.function.Consumer;
import org.apache.maven.api.model.Model;
import org.apache.maven.api.services.ModelBuilderRequest;
import org.apache.maven.api.services.ModelProblemCollector;
import org.apache.maven.api.services.model.ModelBuildingEvent;
/**
* Holds data relevant for a model building event.
*/
record DefaultModelBuildingEvent(
Model model, Consumer<Model> update, ModelBuilderRequest request, ModelProblemCollector problems)
implements ModelBuildingEvent {}

View File

@ -148,7 +148,7 @@ public class DefaultModelInterpolator implements ModelInterpolator {
}
protected List<String> getProjectPrefixes(ModelBuilderRequest request) {
return request.getValidationLevel() >= ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_4_0
return request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM
? PROJECT_PREFIXES_4_0
: PROJECT_PREFIXES_3_1;
}
@ -159,21 +159,17 @@ public class DefaultModelInterpolator implements ModelInterpolator {
ValueSource projectPrefixValueSource;
ValueSource prefixlessObjectBasedValueSource;
if (request.getValidationLevel() >= ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_4_0) {
if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) {
projectPrefixValueSource = new PrefixedObjectValueSource(PROJECT_PREFIXES_4_0, model, false);
prefixlessObjectBasedValueSource = new ObjectBasedValueSource(model);
} else {
projectPrefixValueSource = new PrefixedObjectValueSource(PROJECT_PREFIXES_3_1, model, false);
if (request.getValidationLevel() >= ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_2_0) {
projectPrefixValueSource =
new ProblemDetectingValueSource(projectPrefixValueSource, PREFIX_POM, PREFIX_PROJECT, problems);
}
projectPrefixValueSource =
new ProblemDetectingValueSource(projectPrefixValueSource, PREFIX_POM, PREFIX_PROJECT, problems);
prefixlessObjectBasedValueSource = new ObjectBasedValueSource(model);
if (request.getValidationLevel() >= ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_2_0) {
prefixlessObjectBasedValueSource =
new ProblemDetectingValueSource(prefixlessObjectBasedValueSource, "", PREFIX_PROJECT, problems);
}
prefixlessObjectBasedValueSource =
new ProblemDetectingValueSource(prefixlessObjectBasedValueSource, "", PREFIX_PROJECT, problems);
}
// NOTE: Order counts here!

View File

@ -107,7 +107,7 @@ public class DefaultModelProblem implements ModelProblem {
this.columnNumber = columnNumber;
this.modelId = (modelId != null) ? modelId : "";
this.exception = exception;
this.version = version;
this.version = version != null ? version : Version.BASE;
}
@Override

View File

@ -1,198 +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.impl.model;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import org.apache.maven.api.model.InputLocation;
import org.apache.maven.api.model.Model;
import org.apache.maven.api.services.BuilderProblem;
import org.apache.maven.api.services.ModelBuilderException;
import org.apache.maven.api.services.ModelBuilderResult;
import org.apache.maven.api.services.ModelProblem;
import org.apache.maven.api.services.ModelProblemCollector;
import org.apache.maven.api.spi.ModelParserException;
/**
* Collects problems that are encountered during model building. The primary purpose of this component is to account for
* the fact that the problem reporter has/should not have information about the calling context and hence cannot provide
* an expressive source hint for the model problem. Instead, the source hint is configured by the model builder before
* it delegates to other components that potentially encounter problems. Then, the problem reporter can focus on
* providing a simple error message, leaving the donkey work of creating a nice model problem to this component.
*
*/
class DefaultModelProblemCollector implements ModelProblemCollector {
private final ModelBuilderResult result;
private List<ModelProblem> problems;
private String source;
private Model sourceModel;
private Model rootModel;
private Set<ModelProblem.Severity> severities = EnumSet.noneOf(ModelProblem.Severity.class);
DefaultModelProblemCollector(ModelBuilderResult result) {
this.result = result;
this.problems = result.getProblems();
for (ModelProblem problem : this.problems) {
severities.add(problem.getSeverity());
}
}
public boolean hasFatalErrors() {
return severities.contains(ModelProblem.Severity.FATAL);
}
public boolean hasErrors() {
return severities.contains(ModelProblem.Severity.ERROR) || severities.contains(ModelProblem.Severity.FATAL);
}
@Override
public List<ModelProblem> getProblems() {
return problems;
}
public void setSource(String source) {
this.source = source;
this.sourceModel = null;
}
public void setSource(Model source) {
this.sourceModel = source;
this.source = null;
if (rootModel == null) {
rootModel = source;
}
}
private String getSource() {
if (source == null && sourceModel != null) {
source = ModelProblemUtils.toPath(sourceModel);
}
return source;
}
private String getModelId() {
return ModelProblemUtils.toId(sourceModel);
}
public void setRootModel(Model rootModel) {
this.rootModel = rootModel;
}
public Model getRootModel() {
return rootModel;
}
public String getRootModelId() {
return ModelProblemUtils.toId(rootModel);
}
@Override
public void add(ModelProblem problem) {
problems.add(problem);
severities.add(problem.getSeverity());
}
public void addAll(Collection<ModelProblem> problems) {
this.problems.addAll(problems);
for (ModelProblem problem : problems) {
severities.add(problem.getSeverity());
}
}
@Override
public void add(BuilderProblem.Severity severity, ModelProblem.Version version, String message) {
add(severity, version, message, null, null);
}
@Override
public void add(
BuilderProblem.Severity severity, ModelProblem.Version version, String message, InputLocation location) {
add(severity, version, message, location, null);
}
@Override
public void add(
BuilderProblem.Severity severity, ModelProblem.Version version, String message, Exception exception) {
add(severity, version, message, null, exception);
}
public void add(
BuilderProblem.Severity severity,
ModelProblem.Version version,
String message,
InputLocation location,
Exception exception) {
int line = -1;
int column = -1;
String source = null;
String modelId = null;
if (location != null) {
line = location.getLineNumber();
column = location.getColumnNumber();
if (location.getSource() != null) {
modelId = location.getSource().getModelId();
source = location.getSource().getLocation();
}
}
if (modelId == null) {
modelId = getModelId();
source = getSource();
}
if (line <= 0 && column <= 0 && exception instanceof ModelParserException e) {
line = e.getLineNumber();
column = e.getColumnNumber();
}
ModelProblem problem =
new DefaultModelProblem(message, severity, version, source, line, column, modelId, exception);
add(problem);
}
public ModelBuilderException newModelBuilderException() {
ModelBuilderResult result = this.result;
if (result.getModelIds().isEmpty()) {
DefaultModelBuilderResult tmp = new DefaultModelBuilderResult();
tmp.setEffectiveModel(result.getEffectiveModel());
tmp.setProblems(getProblems());
tmp.setActiveExternalProfiles(result.getActiveExternalProfiles());
String id = getRootModelId();
tmp.addModelId(id);
tmp.setRawModel(id, getRootModel());
result = tmp;
}
return new ModelBuilderException(result);
}
}

View File

@ -1,141 +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.impl.model;
import java.nio.file.Path;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import org.apache.maven.api.model.Model;
import org.apache.maven.api.services.ModelTransformerContext;
import org.apache.maven.api.services.model.ModelProcessor;
/**
*
* @since 4.0.0
*/
class DefaultModelTransformerContext implements ModelTransformerContext {
final ModelProcessor modelLocator;
final Map<String, String> userProperties = new ConcurrentHashMap<>();
final Map<Path, Holder> modelByPath = new ConcurrentHashMap<>();
final Map<GAKey, Holder> modelByGA = new ConcurrentHashMap<>();
public static class Holder {
private volatile boolean set;
private volatile Model model;
Holder() {}
Holder(Model model) {
this.model = Objects.requireNonNull(model);
this.set = true;
}
public static Model deref(Holder holder) {
return holder != null ? holder.get() : null;
}
public Model get() {
if (!set) {
synchronized (this) {
if (!set) {
try {
this.wait();
} catch (InterruptedException e) {
// Ignore
}
}
}
}
return model;
}
public Model computeIfAbsent(Supplier<Model> supplier) {
if (!set) {
synchronized (this) {
if (!set) {
this.set = true;
this.model = supplier.get();
this.notifyAll();
}
}
}
return model;
}
}
DefaultModelTransformerContext(ModelProcessor modelLocator) {
this.modelLocator = modelLocator;
}
@Override
public String getUserProperty(String key) {
return userProperties.get(key);
}
@Override
public Model getRawModel(Path from, Path p) {
return Holder.deref(modelByPath.get(p));
}
@Override
public Model getRawModel(Path from, String groupId, String artifactId) {
return Holder.deref(modelByGA.get(new GAKey(groupId, artifactId)));
}
@Override
public Path locate(Path path) {
return modelLocator.locateExistingPom(path);
}
static class GAKey {
private final String groupId;
private final String artifactId;
private final int hashCode;
GAKey(String groupId, String artifactId) {
this.groupId = groupId;
this.artifactId = artifactId;
this.hashCode = Objects.hash(groupId, artifactId);
}
@Override
public int hashCode() {
return hashCode;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof GAKey)) {
return false;
}
GAKey other = (GAKey) obj;
return Objects.equals(artifactId, other.artifactId) && Objects.equals(groupId, other.groupId);
}
}
}

View File

@ -1,247 +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.impl.model;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.maven.api.model.Model;
import org.apache.maven.api.services.ModelBuilderException;
import org.apache.maven.api.services.ModelBuilderRequest;
import org.apache.maven.api.services.ModelProblem;
import org.apache.maven.api.services.ModelProblemCollector;
import org.apache.maven.api.services.ModelSource;
import org.apache.maven.api.services.ModelTransformerContext;
import org.apache.maven.api.services.ModelTransformerContextBuilder;
import org.apache.maven.internal.impl.model.DefaultModelTransformerContext.GAKey;
import org.apache.maven.internal.impl.model.DefaultModelTransformerContext.Holder;
/**
* Builds up the transformer context.
* After the buildplan is ready, the build()-method returns the immutable context useful during distribution.
* This is an inner class, as it must be able to call readRawModel()
*
* @since 4.0.0
*/
class DefaultModelTransformerContextBuilder implements ModelTransformerContextBuilder {
private final Graph dag = new Graph();
private final DefaultModelBuilder defaultModelBuilder;
private final DefaultModelTransformerContext context;
private final Map<String, Set<ModelSource>> mappedSources = new ConcurrentHashMap<>(64);
private volatile boolean fullReactorLoaded;
DefaultModelTransformerContextBuilder(DefaultModelBuilder defaultModelBuilder) {
this.defaultModelBuilder = defaultModelBuilder;
this.context = new DefaultModelTransformerContext(defaultModelBuilder.getModelProcessor());
}
/**
* If an interface could be extracted, DefaultModelProblemCollector should be ModelProblemCollectorExt
*/
@Override
public ModelTransformerContext initialize(ModelBuilderRequest request, ModelProblemCollector collector) {
// We must assume the TransformerContext was created using this.newTransformerContextBuilder()
DefaultModelProblemCollector problems = (DefaultModelProblemCollector) collector;
return new ModelTransformerContext() {
@Override
public Path locate(Path path) {
return context.locate(path);
}
@Override
public String getUserProperty(String key) {
return context.userProperties.computeIfAbsent(
key, k -> request.getUserProperties().get(key));
}
@Override
public Model getRawModel(Path from, String gId, String aId) {
Model model = findRawModel(from, gId, aId);
if (model != null) {
String groupId = DefaultModelBuilder.getGroupId(model);
context.modelByGA.put(new GAKey(groupId, model.getArtifactId()), new Holder(model));
context.modelByPath.put(model.getPomFile(), new Holder(model));
}
return model;
}
@Override
public Model getRawModel(Path from, Path path) {
Model model = findRawModel(from, path);
if (model != null) {
String groupId = DefaultModelBuilder.getGroupId(model);
context.modelByGA.put(
new DefaultModelTransformerContext.GAKey(groupId, model.getArtifactId()),
new Holder(model));
context.modelByPath.put(path, new Holder(model));
}
return model;
}
private Model findRawModel(Path from, String groupId, String artifactId) {
ModelSource source = getSource(groupId, artifactId);
if (source == null) {
// we need to check the whole reactor in case it's a dependency
loadFullReactor();
source = getSource(groupId, artifactId);
}
if (source != null) {
if (!addEdge(from, source.getPath(), problems)) {
return null;
}
try {
ModelBuilderRequest gaBuildingRequest = ModelBuilderRequest.build(request, source);
return defaultModelBuilder.readRawModel(gaBuildingRequest, problems);
} catch (ModelBuilderException e) {
// gathered with problem collector
}
}
return null;
}
private void loadFullReactor() {
if (!fullReactorLoaded) {
synchronized (DefaultModelTransformerContextBuilder.this) {
if (!fullReactorLoaded) {
doLoadFullReactor();
fullReactorLoaded = true;
}
}
}
}
private void doLoadFullReactor() {
Path rootDirectory;
try {
rootDirectory = request.getSession().getRootDirectory();
} catch (IllegalStateException e) {
// if no root directory, bail out
return;
}
List<Path> toLoad = new ArrayList<>();
Path root = defaultModelBuilder.getModelProcessor().locateExistingPom(rootDirectory);
toLoad.add(root);
while (!toLoad.isEmpty()) {
Path pom = toLoad.remove(0);
try {
ModelBuilderRequest gaBuildingRequest =
ModelBuilderRequest.build(request, ModelSource.fromPath(pom));
Model rawModel = defaultModelBuilder.readFileModel(gaBuildingRequest, problems);
List<String> subprojects = rawModel.getSubprojects();
if (subprojects.isEmpty()) {
subprojects = rawModel.getModules();
}
for (String subproject : subprojects) {
Path subprojectFile = defaultModelBuilder
.getModelProcessor()
.locateExistingPom(pom.getParent().resolve(subproject));
if (subprojectFile != null) {
toLoad.add(subprojectFile);
}
}
} catch (ModelBuilderException e) {
// gathered with problem collector
}
}
}
private Model findRawModel(Path from, Path p) {
if (!Files.isRegularFile(p)) {
throw new IllegalArgumentException("Not a regular file: " + p);
}
if (!addEdge(from, p, problems)) {
return null;
}
ModelBuilderRequest req = ModelBuilderRequest.build(request, ModelSource.fromPath(p));
try {
return defaultModelBuilder.readRawModel(req, problems);
} catch (ModelBuilderException e) {
// gathered with problem collector
}
return null;
}
};
}
private boolean addEdge(Path from, Path p, DefaultModelProblemCollector problems) {
try {
dag.addEdge(from.toString(), p.toString());
return true;
} catch (Graph.CycleDetectedException e) {
problems.add(new DefaultModelProblem(
"Cycle detected between models at " + from + " and " + p,
ModelProblem.Severity.FATAL,
null,
null,
0,
0,
null,
e));
return false;
}
}
@Override
public ModelTransformerContext build() {
return context;
}
public ModelSource getSource(String groupId, String artifactId) {
Set<ModelSource> sources;
if (groupId != null) {
sources = mappedSources.get(groupId + ":" + artifactId);
if (sources == null) {
return null;
}
} else if (artifactId != null) {
sources = mappedSources.get(artifactId);
if (sources == null) {
return null;
}
} else {
return null;
}
return sources.stream()
.reduce((a, b) -> {
throw new IllegalStateException(String.format(
"No unique Source for %s:%s: %s and %s",
groupId, artifactId, a.getLocation(), b.getLocation()));
})
.orElse(null);
}
public void putSource(String groupId, String artifactId, ModelSource source) {
mappedSources
.computeIfAbsent(groupId + ":" + artifactId, k -> new HashSet<>())
.add(source);
mappedSources.computeIfAbsent(artifactId, k -> new HashSet<>()).add(source);
}
}

View File

@ -66,6 +66,7 @@ import org.apache.maven.api.model.Resource;
import org.apache.maven.api.services.BuilderProblem.Severity;
import org.apache.maven.api.services.ModelBuilder;
import org.apache.maven.api.services.ModelBuilderRequest;
import org.apache.maven.api.services.ModelProblem;
import org.apache.maven.api.services.ModelProblem.Version;
import org.apache.maven.api.services.ModelProblemCollector;
import org.apache.maven.api.services.model.ModelValidator;
@ -298,10 +299,42 @@ public class DefaultModelValidator implements ModelValidator {
@Override
@SuppressWarnings("checkstyle:MethodLength")
public void validateFileModel(Model m, ModelBuilderRequest request, ModelProblemCollector problems) {
public void validateFileModel(
Model m, int validationLevel, ModelBuilderRequest request, ModelProblemCollector problems) {
Parent parent = m.getParent();
if (request.getValidationLevel() == ModelBuilderRequest.VALIDATION_LEVEL_MINIMAL) {
if (parent != null) {
validateStringNotEmpty(
"parent.groupId", problems, Severity.FATAL, Version.BASE, parent.getGroupId(), parent);
validateStringNotEmpty(
"parent.artifactId", problems, Severity.FATAL, Version.BASE, parent.getArtifactId(), parent);
if (equals(parent.getGroupId(), m.getGroupId()) && equals(parent.getArtifactId(), m.getArtifactId())) {
addViolation(
problems,
Severity.FATAL,
Version.BASE,
"parent.artifactId",
null,
"must be changed"
+ ", the parent element cannot have the same groupId:artifactId as the project.",
parent);
}
if (equals("LATEST", parent.getVersion()) || equals("RELEASE", parent.getVersion())) {
addViolation(
problems,
Severity.WARNING,
Version.BASE,
"parent.version",
null,
"is either LATEST or RELEASE (both of them are being deprecated)",
parent);
}
}
if (validationLevel == ModelValidator.VALIDATION_LEVEL_MINIMAL) {
// profiles: they are essential for proper model building (may contribute profiles, dependencies...)
HashSet<String> minProfileIds = new HashSet<>();
for (Profile profile : m.getProfiles()) {
@ -316,7 +349,7 @@ public class DefaultModelValidator implements ModelValidator {
profile);
}
}
} else if (request.getValidationLevel() >= ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_2_0) {
} else if (validationLevel >= ModelValidator.VALIDATION_LEVEL_MAVEN_2_0) {
Set<String> modules = new HashSet<>();
for (int i = 0, n = m.getModules().size(); i < n; i++) {
String module = m.getModules().get(i);
@ -387,7 +420,7 @@ public class DefaultModelValidator implements ModelValidator {
}
}
Severity errOn30 = getSeverity(request, ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_3_0);
Severity errOn30 = getSeverity(validationLevel, ModelValidator.VALIDATION_LEVEL_MAVEN_3_0);
// The file pom may not contain the modelVersion yet, as it may be set later by the
// ModelVersionXMLFilter.
@ -408,7 +441,8 @@ public class DefaultModelValidator implements ModelValidator {
validateStringNotEmpty("version", problems, Severity.FATAL, Version.V20, m.getVersion(), m);
}
validate20RawDependencies(problems, m.getDependencies(), "dependencies.dependency.", EMPTY, request);
validate20RawDependencies(
problems, m.getDependencies(), "dependencies.dependency.", EMPTY, validationLevel, request);
validate20RawDependenciesSelfReferencing(
problems, m, m.getDependencies(), "dependencies.dependency", request);
@ -419,22 +453,35 @@ public class DefaultModelValidator implements ModelValidator {
m.getDependencyManagement().getDependencies(),
"dependencyManagement.dependencies.dependency.",
EMPTY,
validationLevel,
request);
}
validateRawRepositories(problems, m.getRepositories(), "repositories.repository.", EMPTY, request);
validateRawRepositories(
problems, m.getRepositories(), "repositories.repository.", EMPTY, validationLevel, request);
validateRawRepositories(
problems, m.getPluginRepositories(), "pluginRepositories.pluginRepository.", EMPTY, request);
problems,
m.getPluginRepositories(),
"pluginRepositories.pluginRepository.",
EMPTY,
validationLevel,
request);
Build build = m.getBuild();
if (build != null) {
validate20RawPlugins(problems, build.getPlugins(), "build.plugins.plugin.", EMPTY, request);
validate20RawPlugins(
problems, build.getPlugins(), "build.plugins.plugin.", EMPTY, validationLevel, request);
PluginManagement mgmt = build.getPluginManagement();
if (mgmt != null) {
validate20RawPlugins(
problems, mgmt.getPlugins(), "build.pluginManagement.plugins.plugin.", EMPTY, request);
problems,
mgmt.getPlugins(),
"build.pluginManagement.plugins.plugin.",
EMPTY,
validationLevel,
request);
}
}
@ -459,7 +506,12 @@ public class DefaultModelValidator implements ModelValidator {
validate30RawProfileActivation(problems, profile.getActivation(), prefix);
validate20RawDependencies(
problems, profile.getDependencies(), prefix, "dependencies.dependency.", request);
problems,
profile.getDependencies(),
prefix,
"dependencies.dependency.",
validationLevel,
request);
if (profile.getDependencyManagement() != null) {
validate20RawDependencies(
@ -467,27 +519,40 @@ public class DefaultModelValidator implements ModelValidator {
profile.getDependencyManagement().getDependencies(),
prefix,
"dependencyManagement.dependencies.dependency.",
validationLevel,
request);
}
validateRawRepositories(
problems, profile.getRepositories(), prefix, "repositories.repository.", request);
problems,
profile.getRepositories(),
prefix,
"repositories.repository.",
validationLevel,
request);
validateRawRepositories(
problems,
profile.getPluginRepositories(),
prefix,
"pluginRepositories.pluginRepository.",
validationLevel,
request);
BuildBase buildBase = profile.getBuild();
if (buildBase != null) {
validate20RawPlugins(problems, buildBase.getPlugins(), prefix, "plugins.plugin.", request);
validate20RawPlugins(
problems, buildBase.getPlugins(), prefix, "plugins.plugin.", validationLevel, request);
PluginManagement mgmt = buildBase.getPluginManagement();
if (mgmt != null) {
validate20RawPlugins(
problems, mgmt.getPlugins(), prefix, "pluginManagement.plugins.plugin.", request);
problems,
mgmt.getPlugins(),
prefix,
"pluginManagement.plugins.plugin.",
validationLevel,
request);
}
}
}
@ -495,7 +560,8 @@ public class DefaultModelValidator implements ModelValidator {
}
@Override
public void validateRawModel(Model m, ModelBuilderRequest request, ModelProblemCollector problems) {
public void validateRawModel(
Model m, int validationLevel, ModelBuilderRequest request, ModelProblemCollector problems) {
// [MNG-6074] Maven should produce an error if no model version has been set in a POM file used to build an
// effective model.
//
@ -610,8 +676,9 @@ public class DefaultModelValidator implements ModelValidator {
List<Plugin> plugins,
String prefix,
String prefix2,
int validationLevel,
ModelBuilderRequest request) {
Severity errOn31 = getSeverity(request, ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_3_1);
Severity errOn31 = getSeverity(validationLevel, ModelValidator.VALIDATION_LEVEL_MAVEN_3_1);
Map<String, Plugin> index = new HashMap<>();
@ -690,7 +757,8 @@ public class DefaultModelValidator implements ModelValidator {
@Override
@SuppressWarnings("checkstyle:MethodLength")
public void validateEffectiveModel(Model m, ModelBuilderRequest request, ModelProblemCollector problems) {
public void validateEffectiveModel(
Model m, int validationLevel, ModelBuilderRequest request, ModelProblemCollector problems) {
validateStringNotEmpty("modelVersion", problems, Severity.ERROR, Version.BASE, m.getModelVersion(), m);
validateCoordinatesId("groupId", problems, m.getGroupId(), m);
@ -739,17 +807,17 @@ public class DefaultModelValidator implements ModelValidator {
validateStringNotEmpty("version", problems, Severity.ERROR, Version.BASE, m.getVersion(), m);
Severity errOn30 = getSeverity(request, ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_3_0);
Severity errOn30 = getSeverity(validationLevel, ModelValidator.VALIDATION_LEVEL_MAVEN_3_0);
validateEffectiveDependencies(problems, m, m.getDependencies(), false, request);
validateEffectiveDependencies(problems, m, m.getDependencies(), false, validationLevel, request);
DependencyManagement mgmt = m.getDependencyManagement();
if (mgmt != null) {
validateEffectiveDependencies(problems, m, mgmt.getDependencies(), true, request);
validateEffectiveDependencies(problems, m, mgmt.getDependencies(), true, validationLevel, request);
}
if (request.getValidationLevel() >= ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_2_0) {
Severity errOn31 = getSeverity(request, ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_3_1);
if (validationLevel >= ModelValidator.VALIDATION_LEVEL_MAVEN_2_0) {
Severity errOn31 = getSeverity(validationLevel, ModelValidator.VALIDATION_LEVEL_MAVEN_3_1);
validateBannedCharacters(
EMPTY, "version", problems, errOn31, Version.V20, m.getVersion(), null, m, ILLEGAL_VERSION_CHARS);
@ -786,7 +854,13 @@ public class DefaultModelValidator implements ModelValidator {
"build.plugins.plugin.groupId", problems, Severity.ERROR, Version.V20, p.getGroupId(), p);
validate20PluginVersion(
"build.plugins.plugin.version", problems, p.getVersion(), p.getKey(), p, request);
"build.plugins.plugin.version",
problems,
p.getVersion(),
p.getKey(),
p,
validationLevel,
request);
validateBoolean(
"build.plugins.plugin.inherited",
@ -808,13 +882,18 @@ public class DefaultModelValidator implements ModelValidator {
p.getKey(),
p);
validate20EffectivePluginDependencies(problems, p, request);
validate20EffectivePluginDependencies(problems, p, validationLevel, request);
}
validate20RawResources(problems, build.getResources(), "build.resources.resource.", request);
validate20RawResources(
problems, build.getResources(), "build.resources.resource.", validationLevel, request);
validate20RawResources(
problems, build.getTestResources(), "build.testResources.testResource.", request);
problems,
build.getTestResources(),
"build.testResources.testResource.",
validationLevel,
request);
}
Reporting reporting = m.getReporting();
@ -839,11 +918,13 @@ public class DefaultModelValidator implements ModelValidator {
}
for (Repository repository : m.getRepositories()) {
validate20EffectiveRepository(problems, repository, "repositories.repository.", request);
validate20EffectiveRepository(
problems, repository, "repositories.repository.", validationLevel, request);
}
for (Repository repository : m.getPluginRepositories()) {
validate20EffectiveRepository(problems, repository, "pluginRepositories.pluginRepository.", request);
validate20EffectiveRepository(
problems, repository, "pluginRepositories.pluginRepository.", validationLevel, request);
}
DistributionManagement distMgmt = m.getDistributionManagement();
@ -860,11 +941,16 @@ public class DefaultModelValidator implements ModelValidator {
}
validate20EffectiveRepository(
problems, distMgmt.getRepository(), "distributionManagement.repository.", request);
problems,
distMgmt.getRepository(),
"distributionManagement.repository.",
validationLevel,
request);
validate20EffectiveRepository(
problems,
distMgmt.getSnapshotRepository(),
"distributionManagement.snapshotRepository.",
validationLevel,
request);
}
}
@ -875,9 +961,10 @@ public class DefaultModelValidator implements ModelValidator {
List<Dependency> dependencies,
String prefix,
String prefix2,
int validationLevel,
ModelBuilderRequest request) {
Severity errOn30 = getSeverity(request, ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_3_0);
Severity errOn31 = getSeverity(request, ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_3_1);
Severity errOn30 = getSeverity(validationLevel, ModelValidator.VALIDATION_LEVEL_MAVEN_3_0);
Severity errOn31 = getSeverity(validationLevel, ModelValidator.VALIDATION_LEVEL_MAVEN_3_1);
Map<String, Dependency> index = new HashMap<>();
@ -907,7 +994,7 @@ public class DefaultModelValidator implements ModelValidator {
}
} else if ("system".equals(dependency.getScope())) {
if (request.getValidationLevel() >= ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_3_1) {
if (validationLevel >= ModelValidator.VALIDATION_LEVEL_MAVEN_3_1) {
addViolation(
problems,
Severity.WARNING,
@ -1015,15 +1102,16 @@ public class DefaultModelValidator implements ModelValidator {
Model m,
List<Dependency> dependencies,
boolean management,
int validationLevel,
ModelBuilderRequest request) {
Severity errOn30 = getSeverity(request, ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_3_0);
Severity errOn30 = getSeverity(validationLevel, ModelValidator.VALIDATION_LEVEL_MAVEN_3_0);
String prefix = management ? "dependencyManagement.dependencies.dependency." : "dependencies.dependency.";
for (Dependency d : dependencies) {
validateEffectiveDependency(problems, d, management, prefix, request);
validateEffectiveDependency(problems, d, management, prefix, validationLevel, request);
if (request.getValidationLevel() >= ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_2_0) {
if (validationLevel >= ModelValidator.VALIDATION_LEVEL_MAVEN_2_0) {
validateBoolean(
prefix, "optional", problems, errOn30, Version.V20, d.getOptional(), d.getManagementKey(), d);
@ -1087,16 +1175,16 @@ public class DefaultModelValidator implements ModelValidator {
}
private void validate20EffectivePluginDependencies(
ModelProblemCollector problems, Plugin plugin, ModelBuilderRequest request) {
ModelProblemCollector problems, Plugin plugin, int validationLevel, ModelBuilderRequest request) {
List<Dependency> dependencies = plugin.getDependencies();
if (!dependencies.isEmpty()) {
String prefix = "build.plugins.plugin[" + plugin.getKey() + "].dependencies.dependency.";
Severity errOn30 = getSeverity(request, ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_3_0);
Severity errOn30 = getSeverity(validationLevel, ModelValidator.VALIDATION_LEVEL_MAVEN_3_0);
for (Dependency d : dependencies) {
validateEffectiveDependency(problems, d, false, prefix, request);
validateEffectiveDependency(problems, d, false, prefix, validationLevel, request);
validateVersion(
prefix, "version", problems, errOn30, Version.BASE, d.getVersion(), d.getManagementKey(), d);
@ -1122,6 +1210,7 @@ public class DefaultModelValidator implements ModelValidator {
Dependency d,
boolean management,
String prefix,
int validationLevel,
ModelBuilderRequest request) {
validateCoordinatesId(
prefix,
@ -1194,9 +1283,9 @@ public class DefaultModelValidator implements ModelValidator {
d);
}
if (request.getValidationLevel() >= ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_2_0) {
if (validationLevel >= ModelValidator.VALIDATION_LEVEL_MAVEN_2_0) {
for (Exclusion exclusion : d.getExclusions()) {
if (request.getValidationLevel() < ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_3_0) {
if (validationLevel < ModelValidator.VALIDATION_LEVEL_MAVEN_3_0) {
validateCoordinatesId(
prefix,
"exclusions.exclusion.groupId",
@ -1254,6 +1343,7 @@ public class DefaultModelValidator implements ModelValidator {
List<Repository> repositories,
String prefix,
String prefix2,
int validationLevel,
ModelBuilderRequest request) {
Map<String, Repository> index = new HashMap<>();
@ -1292,7 +1382,7 @@ public class DefaultModelValidator implements ModelValidator {
Repository existing = index.get(key);
if (existing != null) {
Severity errOn30 = getSeverity(request, ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_3_0);
Severity errOn30 = getSeverity(validationLevel, ModelValidator.VALIDATION_LEVEL_MAVEN_3_0);
addViolation(
problems,
@ -1310,9 +1400,13 @@ public class DefaultModelValidator implements ModelValidator {
}
private void validate20EffectiveRepository(
ModelProblemCollector problems, Repository repository, String prefix, ModelBuilderRequest request) {
ModelProblemCollector problems,
Repository repository,
String prefix,
int validationLevel,
ModelBuilderRequest request) {
if (repository != null) {
Severity errOn31 = getSeverity(request, ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_3_1);
Severity errOn31 = getSeverity(validationLevel, ModelValidator.VALIDATION_LEVEL_MAVEN_3_1);
validateBannedCharacters(
prefix,
@ -1351,8 +1445,12 @@ public class DefaultModelValidator implements ModelValidator {
}
private void validate20RawResources(
ModelProblemCollector problems, List<Resource> resources, String prefix, ModelBuilderRequest request) {
Severity errOn30 = getSeverity(request, ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_3_0);
ModelProblemCollector problems,
List<Resource> resources,
String prefix,
int validationLevel,
ModelBuilderRequest request) {
Severity errOn30 = getSeverity(validationLevel, ModelValidator.VALIDATION_LEVEL_MAVEN_3_0);
for (Resource resource : resources) {
validateStringNotEmpty(
@ -1940,13 +2038,21 @@ public class DefaultModelValidator implements ModelValidator {
String string,
String sourceHint,
InputLocationTracker tracker,
int validationLevel,
ModelBuilderRequest request) {
if (string == null) {
// NOTE: The check for missing plugin versions is handled directly by the model builder
return true;
addViolation(
problems,
Severity.WARNING,
ModelProblem.Version.V20,
fieldName,
sourceHint,
" is missing.",
tracker);
return false;
}
Severity errOn30 = getSeverity(request, ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_3_0);
Severity errOn30 = getSeverity(validationLevel, ModelValidator.VALIDATION_LEVEL_MAVEN_3_0);
if (!validateVersion(EMPTY, fieldName, problems, errOn30, Version.V20, string, sourceHint, tracker)) {
return false;
@ -2026,10 +2132,6 @@ public class DefaultModelValidator implements ModelValidator {
return c1.equals(c2);
}
private static Severity getSeverity(ModelBuilderRequest request, int errorThreshold) {
return getSeverity(request.getValidationLevel(), errorThreshold);
}
private static Severity getSeverity(int validationLevel, int errorThreshold) {
if (validationLevel < errorThreshold) {
return Severity.WARNING;

View File

@ -27,12 +27,24 @@ import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import org.apache.maven.api.annotations.Nullable;
import org.apache.maven.api.di.Named;
import org.apache.maven.api.services.model.RootLocator;
@Named
public class DefaultRootLocator implements RootLocator {
@Override
@Nullable
public Path findRoot(Path basedir) {
Path rootDirectory = basedir;
while (rootDirectory != null && !isRootDirectory(rootDirectory)) {
rootDirectory = rootDirectory.getParent();
}
return rootDirectory;
}
@Override
public boolean isRootDirectory(Path dir) {
if (Files.isDirectory(dir.resolve(".mvn"))) {
return true;

View File

@ -33,6 +33,7 @@ record ModelData(ModelSource source, Model model) {
* @return The effective identifier of the model, never {@code null}.
*/
public String id() {
// TODO: this should be model.getId() but it fails for some reason
// if source is null, it is the super model, which can be accessed via empty string
return source != null ? source.getLocation() : "";
}

View File

@ -34,10 +34,8 @@ import org.apache.maven.api.services.ModelBuilderException;
import org.apache.maven.api.services.ModelBuilderRequest;
import org.apache.maven.api.services.ModelBuilderResult;
import org.apache.maven.api.services.ModelProblem;
import org.apache.maven.api.services.ModelRepositoryHolder;
import org.apache.maven.api.services.ModelResolver;
import org.apache.maven.api.services.ModelResolverException;
import org.apache.maven.api.services.ModelSource;
import org.apache.maven.api.services.model.ModelResolverException;
import org.apache.maven.internal.impl.InternalSession;
import org.apache.maven.internal.impl.model.ModelProblemUtils;
import org.eclipse.aether.RepositoryEvent;
@ -48,9 +46,7 @@ import org.eclipse.aether.RequestTrace;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.impl.ArtifactDescriptorReader;
import org.eclipse.aether.impl.ArtifactResolver;
import org.eclipse.aether.impl.RemoteRepositoryManager;
import org.eclipse.aether.impl.RepositoryEventDispatcher;
import org.eclipse.aether.impl.VersionRangeResolver;
import org.eclipse.aether.impl.VersionResolver;
import org.eclipse.aether.repository.WorkspaceReader;
import org.eclipse.aether.resolution.ArtifactDescriptorException;
@ -74,9 +70,7 @@ import org.slf4j.LoggerFactory;
@Named
@Singleton
public class DefaultArtifactDescriptorReader implements ArtifactDescriptorReader {
private final RemoteRepositoryManager remoteRepositoryManager;
private final VersionResolver versionResolver;
private final VersionRangeResolver versionRangeResolver;
private final ArtifactResolver artifactResolver;
private final RepositoryEventDispatcher repositoryEventDispatcher;
private final ModelBuilder modelBuilder;
@ -86,17 +80,12 @@ public class DefaultArtifactDescriptorReader implements ArtifactDescriptorReader
@Inject
public DefaultArtifactDescriptorReader(
RemoteRepositoryManager remoteRepositoryManager,
VersionResolver versionResolver,
VersionRangeResolver versionRangeResolver,
ArtifactResolver artifactResolver,
ModelBuilder modelBuilder,
RepositoryEventDispatcher repositoryEventDispatcher,
Map<String, MavenArtifactRelocationSource> artifactRelocationSources) {
this.remoteRepositoryManager =
Objects.requireNonNull(remoteRepositoryManager, "remoteRepositoryManager cannot be null");
this.versionResolver = Objects.requireNonNull(versionResolver, "versionResolver cannot be null");
this.versionRangeResolver = Objects.requireNonNull(versionRangeResolver, "versionRangeResolver cannot be null");
this.artifactResolver = Objects.requireNonNull(artifactResolver, "artifactResolver cannot be null");
this.modelBuilder = Objects.requireNonNull(modelBuilder, "modelBuilder cannot be null");
this.repositoryEventDispatcher =
@ -203,25 +192,19 @@ public class DefaultArtifactDescriptorReader implements ArtifactDescriptorReader
.toList();
String gav =
pomArtifact.getGroupId() + ":" + pomArtifact.getArtifactId() + ":" + pomArtifact.getVersion();
ModelResolver modelResolver = new DefaultModelResolver();
ModelRepositoryHolder modelRepositoryHolder = new DefaultModelRepositoryHolder(
iSession, DefaultModelRepositoryHolder.RepositoryMerging.REQUEST_DOMINANT, repositories);
ModelBuilderRequest modelRequest = ModelBuilderRequest.builder()
.session(iSession)
.projectBuild(false)
.processPlugins(false)
.twoPhaseBuilding(false)
.requestType(ModelBuilderRequest.RequestType.DEPENDENCY)
.source(ModelSource.fromPath(pomArtifact.getPath(), gav))
// This merge is on purpose because otherwise user properties would override model
// properties in dependencies the user does not know. See MNG-7563 for details.
.systemProperties(toProperties(session.getUserProperties(), session.getSystemProperties()))
.userProperties(Map.of())
.modelResolver(modelResolver)
.modelRepositoryHolder(modelRepositoryHolder)
.repositoryMerging(ModelBuilderRequest.RepositoryMerging.REQUEST_DOMINANT)
.repositories(repositories)
.build();
ModelBuilderResult modelResult = modelBuilder.build(modelRequest);
ModelBuilderResult modelResult = modelBuilder.newSession().build(modelRequest);
// ModelBuildingEx is thrown only on FATAL and ERROR severities, but we still can have WARNs
// that may lead to unexpected build failure, log them
if (!modelResult.getProblems().isEmpty()) {

View File

@ -1,112 +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.impl.resolver;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.maven.api.RemoteRepository;
import org.apache.maven.api.Session;
import org.apache.maven.api.model.Repository;
import org.apache.maven.api.services.ModelRepositoryHolder;
import org.apache.maven.api.services.RepositoryFactory;
public class DefaultModelRepositoryHolder implements ModelRepositoryHolder {
/**
* The possible merge modes for combining remote repositories.
*/
public enum RepositoryMerging {
/**
* The repositories declared in the POM have precedence over the repositories specified in the request.
*/
POM_DOMINANT,
/**
* The repositories specified in the request have precedence over the repositories declared in the POM.
*/
REQUEST_DOMINANT,
}
final Session session;
final RepositoryMerging repositoryMerging;
List<RemoteRepository> pomRepositories;
List<RemoteRepository> repositories;
List<RemoteRepository> externalRepositories;
Set<String> ids;
public DefaultModelRepositoryHolder(
Session session, RepositoryMerging repositoryMerging, List<RemoteRepository> externalRepositories) {
this.session = session;
this.repositoryMerging = repositoryMerging;
this.pomRepositories = List.of();
this.externalRepositories = List.copyOf(externalRepositories);
this.repositories = List.copyOf(externalRepositories);
this.ids = new HashSet<>();
}
protected DefaultModelRepositoryHolder(DefaultModelRepositoryHolder holder) {
this.session = holder.session;
this.repositoryMerging = holder.repositoryMerging;
this.pomRepositories = List.copyOf(holder.pomRepositories);
this.externalRepositories = List.copyOf(holder.externalRepositories);
this.repositories = List.copyOf(holder.repositories);
}
@Override
public void merge(List<Repository> toAdd, boolean replace) {
List<RemoteRepository> repos =
toAdd.stream().map(session::createRemoteRepository).toList();
if (replace) {
Set<String> ids = repos.stream().map(RemoteRepository::getId).collect(Collectors.toSet());
repositories =
repositories.stream().filter(r -> !ids.contains(r.getId())).toList();
pomRepositories = pomRepositories.stream()
.filter(r -> !ids.contains(r.getId()))
.toList();
} else {
Set<String> ids =
pomRepositories.stream().map(RemoteRepository::getId).collect(Collectors.toSet());
repos = repos.stream().filter(r -> !ids.contains(r.getId())).toList();
}
RepositoryFactory repositoryFactory = session.getService(RepositoryFactory.class);
if (repositoryMerging == RepositoryMerging.REQUEST_DOMINANT) {
repositories = repositoryFactory.aggregate(session, repositories, repos, true);
pomRepositories = repositories;
} else {
pomRepositories = repositoryFactory.aggregate(session, pomRepositories, repos, true);
repositories = repositoryFactory.aggregate(session, pomRepositories, externalRepositories, false);
}
}
@Override
public List<org.apache.maven.api.RemoteRepository> getRepositories() {
return List.copyOf(repositories);
}
@Override
public ModelRepositoryHolder copy() {
return new DefaultModelRepositoryHolder(this);
}
}

View File

@ -24,6 +24,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@ -32,14 +33,19 @@ import org.apache.maven.api.DownloadedArtifact;
import org.apache.maven.api.RemoteRepository;
import org.apache.maven.api.Session;
import org.apache.maven.api.Version;
import org.apache.maven.api.annotations.Nonnull;
import org.apache.maven.api.annotations.Nullable;
import org.apache.maven.api.di.Named;
import org.apache.maven.api.di.Singleton;
import org.apache.maven.api.model.Dependency;
import org.apache.maven.api.model.InputLocation;
import org.apache.maven.api.model.Parent;
import org.apache.maven.api.services.ArtifactResolverException;
import org.apache.maven.api.services.ModelResolver;
import org.apache.maven.api.services.ModelResolverException;
import org.apache.maven.api.services.ModelSource;
import org.apache.maven.api.services.Source;
import org.apache.maven.api.services.VersionRangeResolverException;
import org.apache.maven.api.services.model.ModelResolver;
import org.apache.maven.api.services.model.ModelResolverException;
/**
* A model resolver to assist building of dependency POMs.
@ -50,13 +56,64 @@ import org.apache.maven.api.services.VersionRangeResolverException;
@Singleton
public class DefaultModelResolver implements ModelResolver {
@Nonnull
@Override
public ModelSource resolveModel(
@Nonnull Session session,
@Nullable List<RemoteRepository> repositories,
@Nonnull Parent parent,
@Nonnull AtomicReference<Parent> modified)
throws ModelResolverException {
return resolveModel(
session,
repositories,
parent.getGroupId(),
parent.getArtifactId(),
parent.getVersion(),
"parent",
parent.getLocation("version"),
version -> modified.set(parent.withVersion(version)));
}
@Nonnull
public ModelSource resolveModel(
@Nonnull Session session,
@Nullable List<RemoteRepository> repositories,
@Nonnull Dependency dependency,
@Nonnull AtomicReference<Dependency> modified)
throws ModelResolverException {
return resolveModel(
session,
repositories,
dependency.getGroupId(),
dependency.getArtifactId(),
dependency.getVersion(),
"dependency",
dependency.getLocation("version"),
version -> modified.set(dependency.withVersion(version)));
}
@Override
public ModelSource resolveModel(
@Nonnull Session session,
@Nullable List<RemoteRepository> repositories,
@Nonnull String groupId,
@Nonnull String artifactId,
@Nonnull String version,
@Nonnull Consumer<String> resolvedVersion)
throws ModelResolverException {
return resolveModel(session, repositories, groupId, artifactId, version, null, null, resolvedVersion);
}
@SuppressWarnings("checkstyle:ParameterNumber")
public ModelSource resolveModel(
Session session,
List<RemoteRepository> repositories,
String groupId,
String artifactId,
String version,
String type,
InputLocation location,
Consumer<String> resolvedVersion)
throws ModelResolverException {
try {
@ -65,7 +122,9 @@ public class DefaultModelResolver implements ModelResolver {
&& coords.getVersionConstraint().getVersionRange().getUpperBoundary() == null) {
// Message below is checked for in the MNG-2199 core IT.
throw new ModelResolverException(
String.format("The requested version range '%s' does not specify an upper bound", version),
"The requested " + (type != null ? type + " " : "") + "version range '" + version + "'"
+ (location != null ? " (at " + location + ")" : "")
+ " does not specify an upper bound",
groupId,
artifactId,
version);
@ -73,7 +132,8 @@ public class DefaultModelResolver implements ModelResolver {
List<Version> versions = session.resolveVersionRange(coords, repositories);
if (versions.isEmpty()) {
throw new ModelResolverException(
String.format("No versions matched the requested version range '%s'", version),
"No versions matched the requested " + (type != null ? type + " " : "") + "version range '"
+ version + "'",
groupId,
artifactId,
version);
@ -83,11 +143,8 @@ public class DefaultModelResolver implements ModelResolver {
resolvedVersion.accept(newVersion);
}
DownloadedArtifact resolved = session.resolveArtifact(
session.createArtifactCoordinates(groupId, artifactId, newVersion, "pom"), repositories);
Path path = resolved.getPath();
String location = groupId + ":" + artifactId + ":" + newVersion;
return new ResolverModelSource(path, location);
Path path = getPath(session, repositories, groupId, artifactId, newVersion);
return new ResolverModelSource(path, groupId + ":" + artifactId + ":" + newVersion);
} catch (VersionRangeResolverException | ArtifactResolverException e) {
throw new ModelResolverException(
e.getMessage() + " (remote repositories: "
@ -101,7 +158,18 @@ public class DefaultModelResolver implements ModelResolver {
}
}
private static class ResolverModelSource implements ModelSource {
protected Path getPath(
Session session,
List<RemoteRepository> repositories,
String groupId,
String artifactId,
String newVersion) {
DownloadedArtifact resolved = session.resolveArtifact(
session.createArtifactCoordinates(groupId, artifactId, newVersion, "pom"), repositories);
return resolved.getPath();
}
protected static class ResolverModelSource implements ModelSource {
private final Path path;
private final String location;

View File

@ -16,12 +16,22 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.lifecycle.internal.concurrent;
package org.apache.maven.internal.impl.util;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Phaser;
/**
* The phasing executor is a simple executor that allows to execute tasks in parallel
* and wait for all tasks to be executed before closing the executor. The tasks that are
* currently being executed are allowed to submit new tasks while the executor is closed.
* The executor implements {@link AutoCloseable} to allow using the executor with
* a try-with-resources statement.
*
* The {@link #phase()} method can be used to submit tasks and wait for them to be executed
* without closing the executor.
*/
public class PhasingExecutor implements Executor, AutoCloseable {
private final ExecutorService executor;
private final Phaser phaser = new Phaser();
@ -43,12 +53,14 @@ public class PhasingExecutor implements Executor, AutoCloseable {
});
}
public void await() {
phaser.arriveAndAwaitAdvance();
public AutoCloseable phase() {
phaser.register();
return () -> phaser.awaitAdvance(phaser.arriveAndDeregister());
}
@Override
public void close() {
phaser.arriveAndAwaitAdvance();
executor.shutdownNow();
}
}

View File

@ -28,8 +28,8 @@ import org.apache.maven.api.RemoteRepository;
import org.apache.maven.api.Session;
import org.apache.maven.api.model.Dependency;
import org.apache.maven.api.model.Parent;
import org.apache.maven.api.services.ModelResolver;
import org.apache.maven.api.services.ModelResolverException;
import org.apache.maven.api.services.model.ModelResolver;
import org.apache.maven.api.services.model.ModelResolverException;
import org.apache.maven.internal.impl.standalone.ApiRunner;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -87,7 +87,7 @@ class DefaultModelResolverTest {
ModelResolverException.class,
() -> newModelResolver().resolveModel(session, null, parent, new AtomicReference<>()),
"Expected 'ModelResolverException' not thrown.");
assertEquals("No versions matched the requested version range '[2.0,2.1)'", e.getMessage());
assertEquals("No versions matched the requested parent version range '[2.0,2.1)'", e.getMessage());
}
@Test
@ -102,7 +102,7 @@ class DefaultModelResolverTest {
ModelResolverException.class,
() -> newModelResolver().resolveModel(session, null, parent, new AtomicReference<>()),
"Expected 'ModelResolverException' not thrown.");
assertEquals("The requested version range '[1,)' does not specify an upper bound", e.getMessage());
assertEquals("The requested parent version range '[1,)' does not specify an upper bound", e.getMessage());
}
@Test
@ -158,7 +158,7 @@ class DefaultModelResolverTest {
ModelResolverException.class,
() -> newModelResolver().resolveModel(session, null, dependency, new AtomicReference<>()),
"Expected 'ModelResolverException' not thrown.");
assertEquals("No versions matched the requested version range '[2.0,2.1)'", e.getMessage());
assertEquals("No versions matched the requested dependency version range '[2.0,2.1)'", e.getMessage());
}
@Test
@ -173,7 +173,7 @@ class DefaultModelResolverTest {
ModelResolverException.class,
() -> newModelResolver().resolveModel(session, null, dependency, new AtomicReference<>()),
"Expected 'ModelResolverException' not thrown.");
assertEquals("The requested version range '[1,)' does not specify an upper bound", e.getMessage());
assertEquals("The requested dependency version range '[1,)' does not specify an upper bound", e.getMessage());
}
@Test

View File

@ -158,7 +158,7 @@ public class ApiRunner {
@Override
public Path getRootDirectory() {
return null;
throw new IllegalStateException();
}
@Override

View File

@ -32,7 +32,6 @@ import org.apache.maven.internal.impl.DefaultModelXmlFactory;
import org.apache.maven.internal.impl.DefaultPluginConfigurationExpander;
import org.apache.maven.internal.impl.DefaultSuperPomProvider;
import org.apache.maven.internal.impl.DefaultUrlNormalizer;
import org.apache.maven.internal.impl.model.BuildModelTransformer;
import org.apache.maven.internal.impl.model.DefaultDependencyManagementImporter;
import org.apache.maven.internal.impl.model.DefaultDependencyManagementInjector;
import org.apache.maven.internal.impl.model.DefaultInheritanceAssembler;
@ -51,6 +50,7 @@ import org.apache.maven.internal.impl.model.DefaultProfileSelector;
import org.apache.maven.internal.impl.model.DefaultRootLocator;
import org.apache.maven.internal.impl.model.ProfileActivationFilePathInterpolator;
import org.apache.maven.internal.impl.resolver.DefaultArtifactDescriptorReader;
import org.apache.maven.internal.impl.resolver.DefaultModelResolver;
import org.apache.maven.internal.impl.resolver.DefaultVersionRangeResolver;
import org.apache.maven.internal.impl.resolver.DefaultVersionResolver;
import org.apache.maven.internal.impl.resolver.MavenArtifactRelocationSource;
@ -987,9 +987,7 @@ public class RepositorySystemSupplier implements Supplier<RepositorySystem> {
protected ArtifactDescriptorReader createArtifactDescriptorReader() {
// from maven-resolver-provider
return new DefaultArtifactDescriptorReader(
getRemoteRepositoryManager(),
getVersionResolver(),
getVersionRangeResolver(),
getArtifactResolver(),
getModelBuilder(),
getRepositoryEventDispatcher(),
@ -1056,13 +1054,12 @@ public class RepositorySystemSupplier implements Supplier<RepositorySystem> {
new DefaultPluginManagementInjector(),
new DefaultDependencyManagementInjector(),
new DefaultDependencyManagementImporter(),
(m, r, b) -> m,
new DefaultPluginConfigurationExpander(),
new ProfileActivationFilePathInterpolator(new DefaultPathTranslator(), new DefaultRootLocator()),
new BuildModelTransformer(),
new DefaultModelVersionParser(getVersionScheme()),
List.of(),
new DefaultModelCacheFactory());
new DefaultModelCacheFactory(),
new DefaultModelResolver());
}
private RepositorySystem repositorySystem;

View File

@ -42,11 +42,13 @@ class TestApiStandalone {
Session session = ApiRunner.createSession();
ModelBuilder builder = session.getService(ModelBuilder.class);
ModelBuilderResult result = builder.build(ModelBuilderRequest.builder()
.session(session)
.source(ModelSource.fromPath(Paths.get("pom.xml").toAbsolutePath()))
.projectBuild(true)
.build());
ModelBuilderResult result = builder.newSession()
.build(ModelBuilderRequest.builder()
.session(session)
.source(ModelSource.fromPath(Paths.get("pom.xml").toAbsolutePath()))
.requestType(ModelBuilderRequest.RequestType.BUILD_POM)
.recursive(true)
.build());
assertNotNull(result.getEffectiveModel());
ArtifactCoordinates coords =

View File

@ -16,20 +16,20 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.lifecycle.internal.concurrent;
package org.apache.maven.internal.impl.util;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import org.junit.jupiter.api.Test;
public class PhasingExecutorTest {
class PhasingExecutorTest {
@Test
void testPhaser() {
PhasingExecutor p = new PhasingExecutor(Executors.newFixedThreadPool(4));
p.execute(() -> waitSomeTime(p, 2));
p.await();
try (PhasingExecutor p = new PhasingExecutor(Executors.newFixedThreadPool(4))) {
p.execute(() -> waitSomeTime(p, 2));
}
}
private void waitSomeTime(Executor executor, int nb) {

View File

@ -26,6 +26,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import org.apache.maven.api.Session;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.InvalidRepositoryException;
import org.apache.maven.artifact.repository.ArtifactRepository;
@ -34,8 +35,9 @@ import org.apache.maven.execution.DefaultMavenExecutionRequest;
import org.apache.maven.execution.DefaultMavenExecutionResult;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.internal.impl.DefaultRepositoryFactory;
import org.apache.maven.internal.impl.DefaultSession;
import org.apache.maven.internal.impl.DefaultLookup;
import org.apache.maven.internal.impl.DefaultSessionFactory;
import org.apache.maven.internal.impl.InternalMavenSession;
import org.apache.maven.internal.impl.InternalSession;
import org.apache.maven.model.Build;
import org.apache.maven.model.Dependency;
@ -48,19 +50,15 @@ import org.apache.maven.project.DefaultProjectBuildingRequest;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuildingRequest;
import org.apache.maven.repository.RepositorySystem;
import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
import org.apache.maven.repository.internal.MavenSessionBuilderSupplier;
import org.apache.maven.session.scope.internal.SessionScope;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.testing.PlexusTest;
import org.codehaus.plexus.util.FileUtils;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.internal.impl.DefaultChecksumPolicyProvider;
import org.eclipse.aether.internal.impl.DefaultRemoteRepositoryManager;
import org.eclipse.aether.internal.impl.DefaultUpdatePolicyAnalyzer;
import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.repository.LocalRepository;
import static org.codehaus.plexus.testing.PlexusExtension.getBasedir;
import static org.mockito.Mockito.mock;
@PlexusTest
@Deprecated
@ -70,7 +68,10 @@ public abstract class AbstractCoreMavenComponentTestCase {
protected PlexusContainer container;
@Inject
protected RepositorySystem repositorySystem;
protected org.eclipse.aether.RepositorySystem repositorySystem;
@Inject
protected RepositorySystem mavenRepositorySystem;
@Inject
protected org.apache.maven.project.ProjectBuilder projectBuilder;
@ -128,20 +129,7 @@ public abstract class AbstractCoreMavenComponentTestCase {
.setSystemProperties(executionProperties)
.setUserProperties(new Properties());
initRepoSession(configuration);
MavenSession session = new MavenSession(
getContainer(), configuration.getRepositorySession(), request, new DefaultMavenExecutionResult());
DefaultSession iSession = new DefaultSession(
session,
mock(org.eclipse.aether.RepositorySystem.class),
null,
null,
new SimpleLookup(List.of(new DefaultRepositoryFactory(new DefaultRemoteRepositoryManager(
new DefaultUpdatePolicyAnalyzer(), new DefaultChecksumPolicyProvider())))),
null);
InternalSession.associate(session.getRepositorySession(), iSession);
session.setSession(iSession);
initRepoSession(request, configuration);
List<MavenProject> projects = new ArrayList<>();
@ -165,18 +153,45 @@ public abstract class AbstractCoreMavenComponentTestCase {
projects.add(project);
}
InternalSession iSession = InternalSession.from(configuration.getRepositorySession());
InternalMavenSession mSession = InternalMavenSession.from(iSession);
MavenSession session = mSession.getMavenSession();
session.setProjects(projects);
session.setAllProjects(session.getProjects());
return session;
}
protected void initRepoSession(ProjectBuildingRequest request) throws Exception {
File localRepoDir = new File(request.getLocalRepository().getBasedir());
LocalRepository localRepo = new LocalRepository(localRepoDir);
DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
session.setLocalRepositoryManager(new SimpleLocalRepositoryManagerFactory().newInstance(session, localRepo));
request.setRepositorySession(session);
protected void initRepoSession(
MavenExecutionRequest mavenExecutionRequest, ProjectBuildingRequest projectBuildingRequest)
throws Exception {
File localRepoDir = new File(projectBuildingRequest.getLocalRepository().getBasedir());
LocalRepository localRepo = new LocalRepository(localRepoDir, "simple");
RepositorySystemSession session = new MavenSessionBuilderSupplier(repositorySystem)
.get()
.withLocalRepositories(localRepo)
.build();
projectBuildingRequest.setRepositorySession(session);
DefaultSessionFactory defaultSessionFactory =
new DefaultSessionFactory(repositorySystem, null, new DefaultLookup(container), null);
MavenSession mSession = new MavenSession(
container,
projectBuildingRequest.getRepositorySession(),
mavenExecutionRequest,
new DefaultMavenExecutionResult());
InternalSession iSession = defaultSessionFactory.newSession(mSession);
mSession.setSession(iSession);
SessionScope sessionScope = getContainer().lookup(SessionScope.class);
sessionScope.enter();
sessionScope.seed(MavenSession.class, mSession);
sessionScope.seed(Session.class, iSession);
sessionScope.seed(InternalMavenSession.class, InternalMavenSession.from(iSession));
}
protected MavenProject createStubMavenProject() {
@ -201,7 +216,7 @@ public abstract class AbstractCoreMavenComponentTestCase {
repository.setReleases(policy);
repository.setSnapshots(policy);
return Arrays.asList(repositorySystem.buildArtifactRepository(repository));
return Arrays.asList(mavenRepositorySystem.buildArtifactRepository(repository));
}
protected List<ArtifactRepository> getPluginArtifactRepositories() throws InvalidRepositoryException {
@ -211,7 +226,7 @@ public abstract class AbstractCoreMavenComponentTestCase {
protected ArtifactRepository getLocalRepository() throws InvalidRepositoryException {
File repoDir = new File(getBasedir(), "target/local-repo").getAbsoluteFile();
return repositorySystem.createLocalRepository(repoDir);
return mavenRepositorySystem.createLocalRepository(repoDir);
}
protected class ProjectBuilder {

View File

@ -26,25 +26,28 @@ import java.net.URISyntaxException;
import java.net.URL;
import java.util.Arrays;
import org.apache.maven.api.Session;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
import org.apache.maven.bridge.MavenRepositorySystem;
import org.apache.maven.execution.DefaultMavenExecutionRequest;
import org.apache.maven.execution.DefaultMavenExecutionResult;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.internal.impl.DefaultLookup;
import org.apache.maven.internal.impl.DefaultSession;
import org.apache.maven.internal.impl.InternalMavenSession;
import org.apache.maven.internal.impl.InternalSession;
import org.apache.maven.model.building.ModelBuildingException;
import org.apache.maven.model.building.ModelProblem;
import org.apache.maven.repository.RepositorySystem;
import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
import org.apache.maven.session.scope.internal.SessionScope;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.testing.PlexusTest;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.junit.jupiter.api.BeforeEach;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.Mockito.mock;
/**
*/
@ -56,6 +59,12 @@ public abstract class AbstractMavenProjectTestCase {
@Inject
protected RepositorySystem repositorySystem;
@Inject
protected org.eclipse.aether.RepositorySystem resolverRepositorySystem;
@Inject
protected MavenRepositorySystem mavenRepositorySystem;
@Inject
protected PlexusContainer container;
@ -117,7 +126,7 @@ public abstract class AbstractMavenProjectTestCase {
ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
configuration.setLocalRepository(getLocalRepository());
configuration.setRemoteRepositories(Arrays.asList(new ArtifactRepository[] {}));
configuration.setProcessPlugins(false);
configuration.setProcessPlugins(true);
configuration.setResolveDependencies(true);
initRepoSession(configuration);
@ -146,7 +155,7 @@ public abstract class AbstractMavenProjectTestCase {
return projectBuilder.build(pom, configuration).getProject();
}
protected void initRepoSession(ProjectBuildingRequest request) {
protected void initRepoSession(ProjectBuildingRequest request) throws Exception {
File localRepo = new File(request.getLocalRepository().getBasedir());
DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
session.setLocalRepositoryManager(new LegacyLocalRepositoryManager(localRepo));
@ -156,12 +165,13 @@ public abstract class AbstractMavenProjectTestCase {
MavenSession msession =
new MavenSession(getContainer(), session, mavenExecutionRequest, new DefaultMavenExecutionResult());
DefaultSession iSession = new DefaultSession(
msession,
mock(org.eclipse.aether.RepositorySystem.class),
null,
null,
new DefaultLookup(container),
null);
msession, resolverRepositorySystem, null, mavenRepositorySystem, new DefaultLookup(container), null);
InternalSession.associate(session, iSession);
SessionScope sessionScope = container.lookup(SessionScope.class);
sessionScope.enter();
sessionScope.seed(MavenSession.class, msession);
sessionScope.seed(InternalMavenSession.class, iSession);
sessionScope.seed(Session.class, iSession);
}
}

View File

@ -26,12 +26,10 @@ import java.io.File;
import java.util.Collections;
import org.apache.maven.api.services.ModelBuilder;
import org.apache.maven.api.services.model.ModelProcessor;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.api.services.model.LifecycleBindingsInjector;
import org.apache.maven.bridge.MavenRepositorySystem;
import org.apache.maven.model.root.RootLocator;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.impl.RemoteRepositoryManager;
@Named("classpath")
@Singleton
@ -40,22 +38,20 @@ public class TestProjectBuilder extends DefaultProjectBuilder {
@Inject
public TestProjectBuilder(
ModelBuilder modelBuilder,
ModelProcessor modelProcessor,
ProjectBuildingHelper projectBuildingHelper,
MavenRepositorySystem repositorySystem,
RepositorySystem repoSystem,
RemoteRepositoryManager repositoryManager,
ProjectDependenciesResolver dependencyResolver,
RootLocator rootLocator) {
RootLocator rootLocator,
LifecycleBindingsInjector lifecycleBindingsInjector) {
super(
modelBuilder,
modelProcessor,
projectBuildingHelper,
repositorySystem,
repoSystem,
repositoryManager,
dependencyResolver,
rootLocator);
rootLocator,
lifecycleBindingsInjector);
}
@Override
@ -63,7 +59,7 @@ public class TestProjectBuilder extends DefaultProjectBuilder {
throws ProjectBuildingException {
ProjectBuildingResult result = super.build(pomFile, configuration);
result.getProject().setRemoteArtifactRepositories(Collections.<ArtifactRepository>emptyList());
result.getProject().setRemoteArtifactRepositories(Collections.emptyList());
return result;
}

View File

@ -48,7 +48,7 @@ public class DefaultEvent implements Event {
@Override
public Optional<Project> getProject() {
return Optional.ofNullable(delegate.getProject()).map(session::getProject);
return Optional.ofNullable(session.getProject(delegate.getProject()));
}
@Override

View File

@ -159,7 +159,7 @@ public class DefaultProject implements Project {
@Override
public Optional<Project> getParent() {
MavenProject parent = project.getParent();
return parent != null ? Optional.of(session.getProject(parent)) : Optional.empty();
return Optional.ofNullable(session.getProject(parent));
}
@Nonnull

View File

@ -100,7 +100,7 @@ public class DefaultProjectBuilder implements ProjectBuilder {
@Nonnull
@Override
public Optional<Project> getProject() {
return Optional.ofNullable(res.getProject()).map(session::getProject);
return Optional.ofNullable(session.getProject(res.getProject()));
}
@Nonnull

View File

@ -93,7 +93,9 @@ public class DefaultSession extends AbstractSession implements InternalMavenSess
@Override
public Project getProject(MavenProject project) {
return allProjects.computeIfAbsent(project.getId(), id -> new DefaultProject(this, project));
return project != null && project.getBasedir() != null
? allProjects.computeIfAbsent(project.getId(), id -> new DefaultProject(this, project))
: null;
}
@Override

View File

@ -23,6 +23,7 @@ import java.util.List;
import org.apache.maven.api.Project;
import org.apache.maven.api.RemoteRepository;
import org.apache.maven.api.Session;
import org.apache.maven.api.annotations.Nullable;
import org.apache.maven.execution.MavenSession;
import static org.apache.maven.internal.impl.Utils.cast;
@ -33,8 +34,16 @@ public interface InternalMavenSession extends InternalSession {
return cast(InternalMavenSession.class, session, "session should be an " + InternalMavenSession.class);
}
static InternalMavenSession from(org.eclipse.aether.RepositorySystemSession session) {
return cast(InternalMavenSession.class, session.getData().get(InternalSession.class), "session");
}
List<Project> getProjects(List<org.apache.maven.project.MavenProject> projects);
/**
* May return null if the input project is null or is not part of the reactor.
*/
@Nullable
Project getProject(org.apache.maven.project.MavenProject project);
List<org.apache.maven.artifact.repository.ArtifactRepository> toArtifactRepositories(

View File

@ -20,7 +20,6 @@ package org.apache.maven.internal.transformation.impl;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import java.nio.file.Path;
import java.util.ArrayList;
@ -36,13 +35,12 @@ import org.apache.maven.api.model.Model;
import org.apache.maven.api.model.ModelBase;
import org.apache.maven.api.model.Profile;
import org.apache.maven.api.model.Repository;
import org.apache.maven.api.services.ModelBuilder;
import org.apache.maven.api.services.ModelBuilderException;
import org.apache.maven.api.services.ModelBuilderRequest;
import org.apache.maven.api.services.ModelBuilderResult;
import org.apache.maven.api.services.ModelProblemCollector;
import org.apache.maven.api.services.ModelResolver;
import org.apache.maven.api.services.ModelSource;
import org.apache.maven.api.services.ModelTransformer;
import org.apache.maven.api.services.SuperPomProvider;
import org.apache.maven.api.services.model.DependencyManagementImporter;
import org.apache.maven.api.services.model.DependencyManagementInjector;
@ -53,6 +51,7 @@ import org.apache.maven.api.services.model.ModelInterpolator;
import org.apache.maven.api.services.model.ModelNormalizer;
import org.apache.maven.api.services.model.ModelPathTranslator;
import org.apache.maven.api.services.model.ModelProcessor;
import org.apache.maven.api.services.model.ModelResolver;
import org.apache.maven.api.services.model.ModelUrlNormalizer;
import org.apache.maven.api.services.model.ModelValidator;
import org.apache.maven.api.services.model.ModelVersionParser;
@ -61,15 +60,14 @@ import org.apache.maven.api.services.model.PluginManagementInjector;
import org.apache.maven.api.services.model.ProfileActivationContext;
import org.apache.maven.api.services.model.ProfileInjector;
import org.apache.maven.api.services.model.ProfileSelector;
import org.apache.maven.api.spi.ModelTransformer;
import org.apache.maven.internal.impl.InternalSession;
import org.apache.maven.internal.impl.model.DefaultModelBuilder;
import org.apache.maven.internal.impl.model.DefaultProfileSelector;
import org.apache.maven.internal.impl.model.ProfileActivationFilePathInterpolator;
import org.apache.maven.model.v4.MavenModelVersion;
import org.apache.maven.project.MavenProject;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.impl.RemoteRepositoryManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -79,71 +77,70 @@ class DefaultConsumerPomBuilder implements ConsumerPomBuilder {
public static final String POM_PACKAGING = "pom";
@Inject
private ProfileInjector profileInjector;
private final ProfileInjector profileInjector;
private final InheritanceAssembler inheritanceAssembler;
private final DependencyManagementImporter dependencyManagementImporter;
private final DependencyManagementInjector dependencyManagementInjector;
private final LifecycleBindingsInjector lifecycleBindingsInjector;
private final ModelInterpolator modelInterpolator;
private final ModelNormalizer modelNormalizer;
private final ModelPathTranslator modelPathTranslator;
private final ModelProcessor modelProcessor;
private final ModelUrlNormalizer modelUrlNormalizer;
private final ModelValidator modelValidator;
private final PluginConfigurationExpander pluginConfigurationExpander;
private final PluginManagementInjector pluginManagementInjector;
private final SuperPomProvider superPomProvider;
private final ModelVersionParser versionParser;
private final ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator;
private final List<ModelTransformer> transformers;
private final ModelCacheFactory modelCacheFactory;
private final ModelResolver modelResolver;
@Inject
private InheritanceAssembler inheritanceAssembler;
@SuppressWarnings("checkstyle:ParameterNumber")
DefaultConsumerPomBuilder(
ProfileInjector profileInjector,
InheritanceAssembler inheritanceAssembler,
DependencyManagementImporter dependencyManagementImporter,
DependencyManagementInjector dependencyManagementInjector,
LifecycleBindingsInjector lifecycleBindingsInjector,
ModelInterpolator modelInterpolator,
ModelNormalizer modelNormalizer,
ModelPathTranslator modelPathTranslator,
ModelProcessor modelProcessor,
ModelUrlNormalizer modelUrlNormalizer,
ModelValidator modelValidator,
PluginConfigurationExpander pluginConfigurationExpander,
PluginManagementInjector pluginManagementInjector,
SuperPomProvider superPomProvider,
ModelVersionParser versionParser,
ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator,
List<ModelTransformer> transformers,
ModelCacheFactory modelCacheFactory,
ModelResolver modelResolver) {
this.profileInjector = profileInjector;
this.inheritanceAssembler = inheritanceAssembler;
this.dependencyManagementImporter = dependencyManagementImporter;
this.dependencyManagementInjector = dependencyManagementInjector;
this.lifecycleBindingsInjector = lifecycleBindingsInjector;
this.modelInterpolator = modelInterpolator;
this.modelNormalizer = modelNormalizer;
this.modelPathTranslator = modelPathTranslator;
this.modelProcessor = modelProcessor;
this.modelUrlNormalizer = modelUrlNormalizer;
this.modelValidator = modelValidator;
this.pluginConfigurationExpander = pluginConfigurationExpander;
this.pluginManagementInjector = pluginManagementInjector;
this.superPomProvider = superPomProvider;
this.versionParser = versionParser;
this.profileActivationFilePathInterpolator = profileActivationFilePathInterpolator;
this.transformers = transformers;
this.modelCacheFactory = modelCacheFactory;
this.modelResolver = modelResolver;
}
@Inject
private DependencyManagementImporter dependencyManagementImporter;
@Inject
private DependencyManagementInjector dependencyManagementInjector;
@Inject
private LifecycleBindingsInjector lifecycleBindingsInjector;
@Inject
private ModelInterpolator modelInterpolator;
@Inject
private ModelNormalizer modelNormalizer;
@Inject
private ModelPathTranslator modelPathTranslator;
@Inject
private ModelProcessor modelProcessor;
@Inject
private ModelUrlNormalizer modelUrlNormalizer;
@Inject
private ModelValidator modelValidator;
@Inject
private PluginConfigurationExpander pluginConfigurationExpander;
@Inject
private PluginManagementInjector pluginManagementInjector;
@Inject
private SuperPomProvider superPomProvider;
@Inject
private ModelVersionParser versionParser;
@Inject
private ModelTransformer modelTransformer;
// To break circular dependency
@Inject
private Provider<RepositorySystem> repositorySystem;
@Inject
private RemoteRepositoryManager remoteRepositoryManager;
@Inject
private ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator;
@Inject
private List<org.apache.maven.api.spi.ModelTransformer> transformers;
@Inject
private ModelCacheFactory modelCacheFactory;
Logger logger = LoggerFactory.getLogger(getClass());
private final Logger logger = LoggerFactory.getLogger(getClass());
@Override
public Model build(RepositorySystemSession session, MavenProject project, Path src) throws ModelBuilderException {
@ -180,6 +177,7 @@ class DefaultConsumerPomBuilder implements ConsumerPomBuilder {
return new ArrayList<>();
}
};
// TODO: the custom selector should be used as a flag on the request
DefaultModelBuilder modelBuilder = new DefaultModelBuilder(
modelProcessor,
modelValidator,
@ -194,25 +192,27 @@ class DefaultConsumerPomBuilder implements ConsumerPomBuilder {
pluginManagementInjector,
dependencyManagementInjector,
dependencyManagementImporter,
lifecycleBindingsInjector,
pluginConfigurationExpander,
profileActivationFilePathInterpolator,
modelTransformer,
versionParser,
transformers,
modelCacheFactory);
modelCacheFactory,
modelResolver);
InternalSession iSession = InternalSession.from(session);
ModelBuilderRequest.ModelBuilderRequestBuilder request = ModelBuilderRequest.builder();
request.projectBuild(true);
request.requestType(ModelBuilderRequest.RequestType.BUILD_POM);
request.session(iSession);
request.source(ModelSource.fromPath(src));
request.validationLevel(ModelBuilderRequest.VALIDATION_LEVEL_MINIMAL);
request.locationTracking(false);
request.modelResolver(iSession.getData().get(SessionData.key(ModelResolver.class)));
request.transformerContextBuilder(modelBuilder.newTransformerContextBuilder());
request.systemProperties(session.getSystemProperties());
request.userProperties(session.getUserProperties());
return modelBuilder.build(request.build());
request.lifecycleBindingsInjector(lifecycleBindingsInjector::injectLifecycleBindings);
ModelBuilder.ModelBuilderSession mbSession =
iSession.getData().get(SessionData.key(ModelBuilder.ModelBuilderSession.class));
if (mbSession == null) {
mbSession = modelBuilder.newSession();
}
return mbSession.build(request.build());
}
static Model transform(Model model, MavenProject project) {

View File

@ -53,6 +53,7 @@ import org.apache.maven.execution.ProjectDependencyGraph;
import org.apache.maven.execution.ProjectExecutionEvent;
import org.apache.maven.execution.ProjectExecutionListener;
import org.apache.maven.internal.MultilineMessageHelper;
import org.apache.maven.internal.impl.util.PhasingExecutor;
import org.apache.maven.internal.transformation.ConsumerPomArtifactTransformer;
import org.apache.maven.internal.xml.XmlNodeImpl;
import org.apache.maven.lifecycle.LifecycleExecutionException;
@ -301,10 +302,9 @@ public class BuildPlanExecutor {
}
void execute() {
try {
try (var phase = executor.phase()) {
plan();
executePlan();
executor.await();
} catch (Exception e) {
session.getResult().addException(e);
}

View File

@ -1,126 +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.project;
import java.util.List;
import java.util.Objects;
import org.apache.maven.api.services.BuilderProblem;
import org.apache.maven.api.services.ModelProblem;
import org.apache.maven.api.services.model.ModelBuildingEvent;
import org.apache.maven.api.services.model.ModelBuildingListener;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.model.Model;
import org.apache.maven.plugin.PluginManagerException;
import org.apache.maven.plugin.PluginResolutionException;
import org.apache.maven.plugin.version.PluginVersionResolutionException;
/**
* Processes events from the model builder while building the effective model for a {@link MavenProject} instance.
*
*/
public class DefaultModelBuildingListener implements ModelBuildingListener {
private final MavenProject project;
private final ProjectBuildingHelper projectBuildingHelper;
private final ProjectBuildingRequest projectBuildingRequest;
private List<ArtifactRepository> remoteRepositories;
private List<ArtifactRepository> pluginRepositories;
public DefaultModelBuildingListener(
MavenProject project,
ProjectBuildingHelper projectBuildingHelper,
ProjectBuildingRequest projectBuildingRequest) {
this.project = Objects.requireNonNull(project, "project cannot be null");
this.projectBuildingHelper =
Objects.requireNonNull(projectBuildingHelper, "projectBuildingHelper cannot be null");
this.projectBuildingRequest =
Objects.requireNonNull(projectBuildingRequest, "projectBuildingRequest cannot be null");
this.remoteRepositories = projectBuildingRequest.getRemoteRepositories();
this.pluginRepositories = projectBuildingRequest.getPluginArtifactRepositories();
}
/**
* Gets the project whose model is being built.
*
* @return The project, never {@code null}.
*/
public MavenProject getProject() {
return project;
}
@Override
public void buildExtensionsAssembled(ModelBuildingEvent event) {
Model model = new Model(event.model());
try {
pluginRepositories = projectBuildingHelper.createArtifactRepositories(
model.getPluginRepositories(), pluginRepositories, projectBuildingRequest);
} catch (Exception e) {
event.problems()
.add(
BuilderProblem.Severity.ERROR,
ModelProblem.Version.BASE,
"Invalid plugin repository: " + e.getMessage(),
e);
}
project.setPluginArtifactRepositories(pluginRepositories);
if (event.request().isProcessPlugins()) {
try {
ProjectRealmCache.CacheRecord record =
projectBuildingHelper.createProjectRealm(project, model, projectBuildingRequest);
project.setClassRealm(record.getRealm());
project.setExtensionDependencyFilter(record.getExtensionArtifactFilter());
} catch (PluginResolutionException | PluginManagerException | PluginVersionResolutionException e) {
event.problems()
.add(
BuilderProblem.Severity.ERROR,
ModelProblem.Version.BASE,
"Unresolvable build extension: " + e.getMessage(),
e);
}
projectBuildingHelper.selectProjectRealm(project);
}
// build the regular repos after extensions are loaded to allow for custom layouts
try {
remoteRepositories = projectBuildingHelper.createArtifactRepositories(
model.getRepositories(), remoteRepositories, projectBuildingRequest);
} catch (Exception e) {
event.problems()
.add(
BuilderProblem.Severity.ERROR,
ModelProblem.Version.BASE,
"Invalid artifact repository: " + e.getMessage(),
e);
}
project.setRemoteArtifactRepositories(remoteRepositories);
if (model.getDelegate() != event.model()) {
event.update().accept(model.getDelegate());
}
}
}

View File

@ -66,7 +66,9 @@ class ReactorModelPool {
}
void put(Path pomFile, Model model) {
modelsByPath.put(pomFile, model);
if (pomFile != null) {
modelsByPath.put(pomFile, model);
}
modelsByGa
.computeIfAbsent(new GAKey(getGroupId(model), model.getArtifactId()), k -> new HashSet<>())
.add(model);

View File

@ -38,6 +38,7 @@ import org.apache.maven.execution.MavenSession;
import org.apache.maven.internal.impl.DefaultLookup;
import org.apache.maven.internal.impl.DefaultSessionFactory;
import org.apache.maven.internal.impl.InternalMavenSession;
import org.apache.maven.internal.impl.InternalSession;
import org.apache.maven.model.Build;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Exclusion;
@ -89,6 +90,7 @@ public abstract class AbstractCoreMavenComponentTestCase {
protected MavenExecutionRequest createMavenExecutionRequest(File pom) throws Exception {
MavenExecutionRequest request = new DefaultMavenExecutionRequest()
.setRootDirectory(pom != null ? pom.toPath().getParent() : null)
.setPom(pom)
.setProjectPresent(true)
.setShowErrors(true)
@ -119,16 +121,16 @@ public abstract class AbstractCoreMavenComponentTestCase {
protected MavenSession createMavenSession(File pom, Properties executionProperties, boolean includeModules)
throws Exception {
MavenExecutionRequest request = createMavenExecutionRequest(pom);
RepositorySystemSession rsession = MavenTestHelper.createSession(mavenRepositorySystem);
ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest()
.setRepositorySession(rsession)
.setLocalRepository(request.getLocalRepository())
.setRemoteRepositories(request.getRemoteRepositories())
.setPluginArtifactRepositories(request.getPluginArtifactRepositories())
.setSystemProperties(executionProperties)
.setUserProperties(new Properties());
initRepoSession(request, configuration);
List<MavenProject> projects = new ArrayList<>();
if (pom != null) {
@ -151,34 +153,45 @@ public abstract class AbstractCoreMavenComponentTestCase {
projects.add(project);
}
initRepoSession(configuration);
InternalSession iSession = InternalSession.from(configuration.getRepositorySession());
InternalMavenSession mSession = InternalMavenSession.from(iSession);
MavenSession session = mSession.getMavenSession();
DefaultSessionFactory defaultSessionFactory =
new DefaultSessionFactory(repositorySystem, null, new DefaultLookup(container), null);
MavenSession session = new MavenSession(
getContainer(), configuration.getRepositorySession(), request, new DefaultMavenExecutionResult());
session.setProjects(projects);
session.setAllProjects(session.getProjects());
session.setSession(defaultSessionFactory.newSession(session));
SessionScope sessionScope = getContainer().lookup(SessionScope.class);
sessionScope.enter();
sessionScope.seed(MavenSession.class, session);
sessionScope.seed(Session.class, session.getSession());
sessionScope.seed(InternalMavenSession.class, InternalMavenSession.from(session.getSession()));
return session;
}
protected void initRepoSession(ProjectBuildingRequest request) throws Exception {
File localRepoDir = new File(request.getLocalRepository().getBasedir());
protected void initRepoSession(
MavenExecutionRequest mavenExecutionRequest, ProjectBuildingRequest projectBuildingRequest)
throws Exception {
File localRepoDir = new File(projectBuildingRequest.getLocalRepository().getBasedir());
LocalRepository localRepo = new LocalRepository(localRepoDir, "simple");
RepositorySystemSession session = new MavenSessionBuilderSupplier(repositorySystem)
.get()
.withLocalRepositories(localRepo)
.build();
request.setRepositorySession(session);
projectBuildingRequest.setRepositorySession(session);
DefaultSessionFactory defaultSessionFactory =
new DefaultSessionFactory(repositorySystem, null, new DefaultLookup(container), null);
MavenSession mSession = new MavenSession(
container,
projectBuildingRequest.getRepositorySession(),
mavenExecutionRequest,
new DefaultMavenExecutionResult());
InternalSession iSession = defaultSessionFactory.newSession(mSession);
mSession.setSession(iSession);
SessionScope sessionScope = getContainer().lookup(SessionScope.class);
sessionScope.enter();
sessionScope.seed(MavenSession.class, mSession);
sessionScope.seed(Session.class, iSession);
sessionScope.seed(InternalMavenSession.class, InternalMavenSession.from(iSession));
}
protected MavenProject createStubMavenProject() {

View File

@ -18,33 +18,24 @@
*/
package org.apache.maven;
import java.util.List;
import org.apache.maven.bridge.MavenRepositorySystem;
import org.apache.maven.execution.DefaultMavenExecutionRequest;
import org.apache.maven.execution.DefaultMavenExecutionResult;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.internal.impl.DefaultRepositoryFactory;
import org.apache.maven.internal.impl.DefaultLookup;
import org.apache.maven.internal.impl.DefaultSession;
import org.apache.maven.internal.impl.InternalSession;
import org.codehaus.plexus.PlexusContainer;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.internal.impl.DefaultChecksumPolicyProvider;
import org.eclipse.aether.internal.impl.DefaultRemoteRepositoryManager;
import org.eclipse.aether.internal.impl.DefaultUpdatePolicyAnalyzer;
public class MavenTestHelper {
public static DefaultRepositorySystemSession createSession(MavenRepositorySystem repositorySystem) {
public static DefaultRepositorySystemSession createSession(
MavenRepositorySystem repositorySystem, PlexusContainer container) {
DefaultRepositorySystemSession repoSession = new DefaultRepositorySystemSession(h -> false);
DefaultMavenExecutionRequest request = new DefaultMavenExecutionRequest();
MavenSession mavenSession = new MavenSession(repoSession, request, new DefaultMavenExecutionResult());
DefaultSession session = new DefaultSession(
mavenSession,
null,
null,
repositorySystem,
new SimpleLookup(List.of(new DefaultRepositoryFactory(new DefaultRemoteRepositoryManager(
new DefaultUpdatePolicyAnalyzer(), new DefaultChecksumPolicyProvider())))),
null);
DefaultSession session =
new DefaultSession(mavenSession, null, null, repositorySystem, new DefaultLookup(container), null);
InternalSession.associate(repoSession, session);
return repoSession;
}

View File

@ -19,32 +19,35 @@
package org.apache.maven.internal.transformation.impl;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import org.apache.maven.api.RemoteRepository;
import org.apache.maven.api.Session;
import org.apache.maven.api.SessionData;
import org.apache.maven.api.model.Model;
import org.apache.maven.api.services.ModelResolver;
import org.apache.maven.api.services.ModelResolverException;
import org.apache.maven.api.model.Parent;
import org.apache.maven.api.services.ModelBuilder;
import org.apache.maven.api.services.ModelSource;
import org.apache.maven.artifact.repository.MavenArtifactRepository;
import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
import org.apache.maven.api.services.model.ModelResolver;
import org.apache.maven.api.services.model.ModelResolverException;
import org.apache.maven.api.spi.ModelTransformer;
import org.apache.maven.api.spi.ModelTransformerException;
import org.apache.maven.di.Injector;
import org.apache.maven.internal.impl.InternalMavenSession;
import org.apache.maven.internal.impl.InternalSession;
import org.apache.maven.internal.impl.model.DefaultModelBuilder;
import org.apache.maven.internal.transformation.AbstractRepositoryTestCase;
import org.apache.maven.model.v4.MavenStaxReader;
import org.apache.maven.project.MavenProject;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.sisu.Priority;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@ -55,6 +58,32 @@ public class ConsumerPomBuilderTest extends AbstractRepositoryTestCase {
@Inject
ConsumerPomBuilder builder;
@BeforeEach
void setupTransformerContext() throws Exception {
// We need to hack things a bit here to get the transformer context to work
// * we cannot use the CIFriendlyVersionModelTransformer directly because
// it's a session scoped bean and all tests using a model builder would have
// to use a session and initialize the scope in order for DI to start
// * the transformer context is supposed to be immutable but in this case
// we don't build the full projects before, so we need to pass a mutable
// context to the model builder
// * we also need to bind the model resolver explicitly to avoid going
// to maven central
getContainer().lookup(Injector.class).bindImplicit(MyModelResolver.class);
InternalSession iSession = InternalSession.from(session);
// set up the transformers
List<ModelTransformer> transformers = List.of(new CIFriendlyVersionModelTransformer(iSession));
Field transformersField = DefaultModelBuilder.class.getDeclaredField("transformers");
transformersField.setAccessible(true);
DefaultModelBuilder modelBuilder = (DefaultModelBuilder) getContainer().lookup(ModelBuilder.class);
transformersField.set(modelBuilder, transformers);
transformersField = DefaultConsumerPomBuilder.class.getDeclaredField("transformers");
transformersField.setAccessible(true);
transformersField.set(builder, transformers);
// set up the model resolver
iSession.getData().set(SessionData.key(ModelResolver.class), new MyModelResolver());
}
@Test
void testTrivialConsumer() throws Exception {
MavenProject project;
@ -63,11 +92,12 @@ public class ConsumerPomBuilderTest extends AbstractRepositoryTestCase {
org.apache.maven.model.Model model =
new org.apache.maven.model.Model(new MavenStaxReader().read(inputStream));
project = new MavenProject(model);
project.setRootDirectory(Paths.get("src/test/resources/consumer/trivial"));
project.setOriginalModel(model);
project.setRemoteArtifactRepositories(Collections.singletonList(new MavenArtifactRepository(
"central", "http://repo.maven.apache.org/", new DefaultRepositoryLayout(), null, null)));
}
InternalMavenSession.from(InternalSession.from(session))
.getMavenSession()
.getRequest()
.setRootDirectory(Paths.get("src/test/resources/consumer/trivial"));
Model model = builder.build(session, project, file);
assertNotNull(model);
@ -77,14 +107,16 @@ public class ConsumerPomBuilderTest extends AbstractRepositoryTestCase {
void testSimpleConsumer() throws Exception {
MavenProject project;
Path file = Paths.get("src/test/resources/consumer/simple/simple-parent/simple-weather/pom.xml");
((DefaultRepositorySystemSession) session).setUserProperty("changelist", "MNG6957");
InternalMavenSession.from(InternalSession.from(session))
.getMavenSession()
.getRequest()
.getUserProperties()
.setProperty("changelist", "MNG6957");
try (InputStream inputStream = Files.newInputStream(file)) {
org.apache.maven.model.Model model =
new org.apache.maven.model.Model(new MavenStaxReader().read(inputStream));
project = new MavenProject(model);
project.setRootDirectory(Paths.get("src/test/resources/consumer/simple"));
project.setRemoteArtifactRepositories(Collections.singletonList(new MavenArtifactRepository(
"central", "http://repo.maven.apache.org/", new DefaultRepositoryLayout(), null, null)));
project.setOriginalModel(model);
}
InternalMavenSession.from(InternalSession.from(session))
@ -97,10 +129,7 @@ public class ConsumerPomBuilderTest extends AbstractRepositoryTestCase {
assertTrue(model.getProfiles().isEmpty());
}
@Named
@Singleton
@Priority(10)
public static class MyModelResolver implements ModelResolver {
static class MyModelResolver implements ModelResolver {
@Override
public ModelSource resolveModel(
Session session,
@ -121,4 +150,39 @@ public class ConsumerPomBuilderTest extends AbstractRepositoryTestCase {
return null;
}
}
static class CIFriendlyVersionModelTransformer implements ModelTransformer {
private static final String SHA1_PROPERTY = "sha1";
private static final String CHANGELIST_PROPERTY = "changelist";
private static final String REVISION_PROPERTY = "revision";
private final Session session;
CIFriendlyVersionModelTransformer(Session session) {
this.session = session;
}
@Override
public Model transformFileModel(Model model) throws ModelTransformerException {
return model.with()
.version(replaceCiFriendlyVersion(model.getVersion()))
.parent(replaceParent(model.getParent()))
.build();
}
Parent replaceParent(Parent parent) {
return parent != null ? parent.withVersion(replaceCiFriendlyVersion(parent.getVersion())) : null;
}
String replaceCiFriendlyVersion(String version) {
if (version != null) {
for (String key : Arrays.asList(SHA1_PROPERTY, CHANGELIST_PROPERTY, REVISION_PROPERTY)) {
String val = session.getUserProperties().get(key);
if (val != null) {
version = version.replace("${" + key + "}", val);
}
}
}
return version;
}
}
}

View File

@ -21,6 +21,7 @@ package org.apache.maven.model;
import javax.inject.Inject;
import java.io.File;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
@ -66,6 +67,7 @@ public class ModelBuilderTest {
void testModelBuilder() throws Exception {
MavenExecutionRequest mavenRequest = new DefaultMavenExecutionRequest();
mavenRequest.setLocalRepository(mavenRepositorySystem.createLocalRepository(new File("target/test-repo/")));
mavenRequest.setRootDirectory(Paths.get("src/test/resources/projects/tree"));
DefaultProjectBuildingRequest request = new DefaultProjectBuildingRequest();
RepositorySystemSession.CloseableSession rsession = repositorySessionFactory

View File

@ -26,6 +26,7 @@ import java.net.URISyntaxException;
import java.net.URL;
import java.util.Arrays;
import org.apache.maven.api.Session;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.bridge.MavenRepositorySystem;
import org.apache.maven.execution.DefaultMavenExecutionRequest;
@ -34,17 +35,18 @@ import org.apache.maven.execution.MavenSession;
import org.apache.maven.internal.impl.DefaultLookup;
import org.apache.maven.internal.impl.DefaultSession;
import org.apache.maven.internal.impl.DefaultSessionFactory;
import org.apache.maven.internal.impl.InternalMavenSession;
import org.apache.maven.model.building.ModelBuildingException;
import org.apache.maven.model.building.ModelProblem;
import org.apache.maven.session.scope.internal.SessionScope;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.testing.PlexusTest;
import org.eclipse.aether.DefaultRepositoryCache;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositorySystem;
import org.junit.jupiter.api.BeforeEach;
import static org.mockito.Mockito.mock;
/**
*/
@PlexusTest
@ -54,6 +56,9 @@ public abstract class AbstractMavenProjectTestCase {
@Inject
protected MavenRepositorySystem repositorySystem;
@Inject
protected RepositorySystem repoSystem;
@Inject
protected PlexusContainer container;
@ -151,18 +156,22 @@ public abstract class AbstractMavenProjectTestCase {
return configuration;
}
protected void initRepoSession(ProjectBuildingRequest request) {
protected void initRepoSession(ProjectBuildingRequest request) throws ComponentLookupException {
File localRepo = new File(request.getLocalRepository().getBasedir());
DefaultRepositorySystemSession repoSession = new DefaultRepositorySystemSession(h -> false);
DefaultSessionFactory defaultSessionFactory =
new DefaultSessionFactory(mock(RepositorySystem.class), null, new DefaultLookup(container), null);
new DefaultSessionFactory(repoSystem, repositorySystem, new DefaultLookup(container), null);
MavenSession session = new MavenSession(
getContainer(), repoSession, new DefaultMavenExecutionRequest(), new DefaultMavenExecutionResult());
session.setSession(defaultSessionFactory.newSession(session));
new DefaultSession(session, null, null, null, null, null);
DefaultSession s = new DefaultSession(session, null, null, null, null, null);
SessionScope scope = container.lookup(SessionScope.class);
scope.enter();
scope.seed(Session.class, s);
scope.seed(InternalMavenSession.class, s);
repoSession.setCache(new DefaultRepositoryCache());
repoSession.setLocalRepositoryManager(new LegacyLocalRepositoryManager(localRepo));

View File

@ -29,6 +29,7 @@ import org.apache.maven.api.SessionData;
import org.apache.maven.api.services.model.ModelCache;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.internal.impl.InternalMavenSession;
import org.apache.maven.internal.impl.InternalSession;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
@ -323,6 +324,11 @@ class DefaultMavenProjectBuilderTest extends AbstractMavenProjectTestCase {
final Path pom = projectRoot.resolve("pom.xml");
final ProjectBuildingRequest buildingRequest = newBuildingRequest();
InternalMavenSession.from(InternalSession.from(buildingRequest.getRepositorySession()))
.getMavenSession()
.getRequest()
.setRootDirectory(projectRoot);
try (InputStream pomResource =
DefaultMavenProjectBuilderTest.class.getResourceAsStream("/projects/reread/pom1.xml")) {
Files.copy(pomResource, pom, StandardCopyOption.REPLACE_EXISTING);
@ -419,6 +425,12 @@ class DefaultMavenProjectBuilderTest extends AbstractMavenProjectTestCase {
public void testSubprojectDiscovery() throws Exception {
File pom = getTestFile("src/test/resources/projects/subprojects-discover/pom.xml");
ProjectBuildingRequest configuration = newBuildingRequest();
InternalSession internalSession = InternalSession.from(configuration.getRepositorySession());
InternalMavenSession mavenSession = InternalMavenSession.from(internalSession);
mavenSession
.getMavenSession()
.getRequest()
.setRootDirectory(pom.toPath().getParent());
List<ProjectBuildingResult> results = projectBuilder.build(List.of(pom), true, configuration);
assertEquals(2, results.size());

View File

@ -21,6 +21,8 @@ package org.apache.maven.project;
import javax.inject.Inject;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -30,6 +32,8 @@ import java.util.Properties;
import org.apache.maven.MavenTestHelper;
import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
import org.apache.maven.bridge.MavenRepositorySystem;
import org.apache.maven.internal.impl.InternalMavenSession;
import org.apache.maven.internal.impl.InternalSession;
import org.apache.maven.model.Model;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginExecution;
@ -38,6 +42,7 @@ import org.apache.maven.model.ReportPlugin;
import org.apache.maven.model.ReportSet;
import org.apache.maven.model.building.ModelBuildingRequest;
import org.apache.maven.project.harness.PomTestWrapper;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.testing.PlexusTest;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory;
@ -73,6 +78,9 @@ class PomConstructionTest {
@Inject
private MavenRepositorySystem repositorySystem;
@Inject
private PlexusContainer container;
private File testDirectory;
@BeforeEach
@ -1226,7 +1234,7 @@ class PomConstructionTest {
@Test
void testPomInheritance() throws Exception {
PomTestWrapper pom = buildPom("pom-inheritance/sub");
PomTestWrapper pom = buildPom("pom-inheritance/child-1");
assertEquals("parent-description", pom.getValue("description"));
assertEquals("jar", pom.getValue("packaging"));
}
@ -1888,13 +1896,23 @@ class PomConstructionTest {
? ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0
: ModelBuildingRequest.VALIDATION_LEVEL_STRICT);
DefaultRepositorySystemSession repoSession = MavenTestHelper.createSession(repositorySystem);
DefaultRepositorySystemSession repoSession = MavenTestHelper.createSession(repositorySystem, container);
LocalRepository localRepo =
new LocalRepository(config.getLocalRepository().getBasedir());
repoSession.setLocalRepositoryManager(
new SimpleLocalRepositoryManagerFactory().newInstance(repoSession, localRepo));
config.setRepositorySession(repoSession);
InternalSession iSession = InternalSession.from(repoSession);
InternalMavenSession mSession = InternalMavenSession.from(iSession);
Path root = pomFile.getParentFile().toPath();
while (root != null
&& !Files.isDirectory(root.resolve(".mvn"))
&& Files.isRegularFile(root.resolve("../pom.xml"))) {
root = root.getParent();
}
mSession.getMavenSession().getRequest().setRootDirectory(root);
return new PomTestWrapper(pomFile, projectBuilder.build(pomFile, config).getProject());
}

View File

@ -35,10 +35,8 @@ import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.InputLocation;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.building.FileModelSource;
import org.apache.maven.model.building.ModelBuildingRequest;
import org.apache.maven.model.building.ModelProblem;
import org.apache.maven.model.building.ModelSource;
import org.codehaus.plexus.util.FileUtils;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
@ -85,10 +83,9 @@ class ProjectBuilderTest extends AbstractCoreMavenComponentTestCase {
MavenSession mavenSession = createMavenSession(pomFile);
ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
configuration.setRepositorySession(mavenSession.getRepositorySession());
ModelSource modelSource = new FileModelSource(pomFile);
ProjectBuildingResult result = getContainer()
.lookup(org.apache.maven.project.ProjectBuilder.class)
.build(modelSource, configuration);
.build(pomFile, configuration);
assertNotNull(result.getProject().getParentFile());
}
@ -174,6 +171,7 @@ class ProjectBuilderTest extends AbstractCoreMavenComponentTestCase {
FileUtils.copyDirectoryStructure(new File("src/test/resources/projects/grandchild-check"), tempDir.toFile());
MavenSession mavenSession = createMavenSession(null);
mavenSession.getRequest().setRootDirectory(tempDir);
ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
configuration.setRepositorySession(mavenSession.getRepositorySession());
org.apache.maven.project.ProjectBuilder projectBuilder =
@ -223,7 +221,7 @@ class ProjectBuilderTest extends AbstractCoreMavenComponentTestCase {
// multi projects build entry point
ProjectBuildingException ex2 = assertThrows(
ProjectBuildingException.class,
() -> projectBuilder.build(Collections.singletonList(pomFile), false, configuration));
() -> projectBuilder.build(Collections.singletonList(pomFile), true, configuration));
assertEquals(1, ex2.getResults().size());
MavenProject project2 = ex2.getResults().get(0).getProject();
@ -319,7 +317,8 @@ class ProjectBuilderTest extends AbstractCoreMavenComponentTestCase {
ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
configuration.setRepositorySession(mavenSession.getRepositorySession());
configuration.setResolveDependencies(true);
List<ProjectBuildingResult> result = projectBuilder.build(Collections.singletonList(file), true, configuration);
List<ProjectBuildingResult> result =
projectBuilder.build(Collections.singletonList(file), false, configuration);
MavenProject project = result.get(0).getProject();
// verify a few typical parameters are not duplicated
assertEquals(1, project.getTestCompileSourceRoots().size());
@ -346,10 +345,9 @@ class ProjectBuilderTest extends AbstractCoreMavenComponentTestCase {
MavenSession mavenSession = createMavenSession(null);
ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
configuration.setRepositorySession(mavenSession.getRepositorySession());
ModelSource modelSource = new FileModelSource(pomFile);
ProjectBuildingResult result = getContainer()
.lookup(org.apache.maven.project.ProjectBuilder.class)
.build(modelSource, configuration);
.build(pomFile, configuration);
assertEquals(
pomFile.getAbsoluteFile(),

View File

@ -36,6 +36,7 @@ import org.apache.maven.project.DefaultProjectBuildingRequest;
import org.apache.maven.project.ProjectBuildingRequest;
import org.apache.maven.project.harness.PomTestWrapper;
import org.apache.maven.settings.v4.SettingsStaxReader;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.testing.PlexusTest;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory;
@ -58,6 +59,9 @@ class PomConstructionWithSettingsTest {
@Inject
private MavenRepositorySystem repositorySystem;
@Inject
private PlexusContainer container;
private File testDirectory;
@BeforeEach
@ -111,7 +115,7 @@ class PomConstructionWithSettingsTest {
"local", localRepoUrl, new DefaultRepositoryLayout(), null, null));
config.setActiveProfileIds(settings.getActiveProfiles());
DefaultRepositorySystemSession repoSession = MavenTestHelper.createSession(repositorySystem);
DefaultRepositorySystemSession repoSession = MavenTestHelper.createSession(repositorySystem, container);
LocalRepository localRepo =
new LocalRepository(config.getLocalRepository().getBasedir());
repoSession.setLocalRepositoryManager(

View File

@ -28,4 +28,7 @@ under the License.
<packaging>pom</packaging>
<!-- minimal parent just to have one more level of inheritance -->
<modules>
<module>sub</module>
</modules>
</project>

View File

@ -0,0 +1,11 @@
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.maven.its.mng</groupId>
<artifactId>test</artifactId>
<version>0.2</version>
</parent>
<artifactId>sub</artifactId>
</project>

View File

@ -0,0 +1,11 @@
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.maven.its.mng</groupId>
<artifactId>test</artifactId>
<version>0.2</version>
</parent>
<artifactId>sub</artifactId>
</project>

View File

@ -33,8 +33,8 @@ under the License.
</description>
<modules>
<module>child-1</module>
<module>child-2</module>
<module>w-merge</module>
<module>wo-merge</module>
</modules>
<build>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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
https://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.
-->
<project>
<modelVersion>4.0.0</modelVersion>
<!--
This minimalist POM tests mere inheritance from its parent.
-->
<parent>
<groupId>org.apache.maven.its.mng3843</groupId>
<artifactId>parent-1</artifactId>
<version>0.1</version>
</parent>
<artifactId>child-2</artifactId>
</project>

View File

@ -0,0 +1,12 @@
<project>
<parent>
<groupId>org.ops4j.pax</groupId>
<artifactId>construct</artifactId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.ops4j</groupId>
<artifactId>maven-inherit-plugin</artifactId>
<version>1.1</version>
</project>

View File

@ -0,0 +1,12 @@
<project>
<parent>
<groupId>org.ops4j.pax</groupId>
<artifactId>construct</artifactId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.ops4j</groupId>
<artifactId>maven-pax-plugin</artifactId>
<version>1.1</version>
</project>

View File

@ -7,6 +7,6 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.ops4j</groupId>
<artifactId>maven-inherit-plugin</artifactId>
<artifactId>sub</artifactId>
<version>1.1</version>
</project>

View File

@ -0,0 +1,9 @@
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>gid</groupId>
<artifactId>aid</artifactId>
<version>1.0</version>
</parent>
<artifactId>module-1</artifactId>
</project>

View File

@ -0,0 +1,9 @@
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>gid</groupId>
<artifactId>aid</artifactId>
<version>1.0</version>
</parent>
<artifactId>module-2</artifactId>
</project>

View File

@ -0,0 +1,9 @@
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>gid</groupId>
<artifactId>aid</artifactId>
<version>1.0</version>
</parent>
<artifactId>module-3</artifactId>
</project>

View File

@ -0,0 +1,9 @@
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>gid</groupId>
<artifactId>aid</artifactId>
<version>1.0</version>
</parent>
<artifactId>module-4</artifactId>
</project>

View File

@ -0,0 +1,9 @@
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>gid</groupId>
<artifactId>aid</artifactId>
<version>1.0</version>
</parent>
<artifactId>module-5</artifactId>
</project>

View File

@ -29,7 +29,7 @@
<description>Test inheritance of reporting plugin configuration</description>
<modules>
<module>child</module>
<module>sub</module>
</modules>
<reporting>

View File

@ -29,7 +29,7 @@
<description>Test inheritance of UNC paths</description>
<modules>
<module>child</module>
<module>sub</module>
</modules>
<distributionManagement>

View File

@ -5,7 +5,7 @@
<packaging>pom</packaging>
<subprojects>
<subproject>child.xml</subproject>
<subproject>child</subproject>
</subprojects>
<dependencyManagement>

View File

@ -1,4 +1,4 @@
<project xmlns="http://maven.apache.org/POM/4.0.0">
<project xmlns="http://maven.apache.org/POM/4.1.0">
<parent>
<groupId>org.apache.maven.ut</groupId>

View File

@ -1,4 +1,4 @@
<project xmlns="http://maven.apache.org/POM/4.0.0">
<project xmlns="http://maven.apache.org/POM/4.1.0">
<parent>
<groupId>org.apache.maven.ut</groupId>

View File

@ -1,10 +1,10 @@
<project xmlns="http://maven.apache.org/POM/4.0.0">
<project xmlns="http://maven.apache.org/POM/4.1.0" root="true">
<groupId>org.apache.maven.ut</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>dep</module>
<module>consumer</module>
</modules>
<subprojects>
<subproject>dep</subproject>
<subproject>consumer</subproject>
</subprojects>
</project>

View File

@ -201,7 +201,7 @@ class DefaultTransformerContextBuilder implements TransformerContextBuilder {
}
public FileModelSource getSource(String groupId, String artifactId) {
Set<FileModelSource> sources = mappedSources.get(groupId + ":" + artifactId);
Set<FileModelSource> sources = mappedSources.get(groupId != null ? groupId + ":" + artifactId : artifactId);
if (sources == null) {
return null;
}
@ -218,5 +218,8 @@ class DefaultTransformerContextBuilder implements TransformerContextBuilder {
mappedSources
.computeIfAbsent(groupId + ":" + artifactId, k -> new HashSet<>())
.add(source);
if (groupId != null) {
mappedSources.computeIfAbsent(artifactId, k -> new HashSet<>()).add(source);
}
}
}

View File

@ -18,8 +18,6 @@
*/
package org.apache.maven.model.building;
import org.apache.maven.api.services.ModelBuilderResult;
/**
* Describes a problem that was encountered during model building. A problem can either be an exception that was thrown
* or a simple string message. In addition, a problem carries a hint about its source, e.g. the POM file that exhibits
@ -55,7 +53,6 @@ public interface ModelProblem {
* information that is available at the point the problem occurs and as such merely serves as best effort
* to provide information to the user to track the problem back to its origin.
*
* @see ModelBuilderResult#getModelIds()
* @return The hint about the source of the problem or an empty string if unknown, never {@code null}.
*/
String getSource();

View File

@ -20,6 +20,8 @@ package org.apache.maven.model;
import java.io.Serializable;
import static java.util.Objects.requireNonNull;
public abstract class BaseObject implements Serializable, Cloneable, InputLocationTracker {
protected transient ChildrenTracking childrenTracking;
@ -28,12 +30,12 @@ public abstract class BaseObject implements Serializable, Cloneable, InputLocati
public BaseObject() {}
public BaseObject(Object delegate, BaseObject parent) {
this.delegate = delegate;
this.delegate = requireNonNull(delegate, "delegate cannot be null");
this.childrenTracking = parent != null ? parent::replace : null;
}
public BaseObject(Object delegate, ChildrenTracking parent) {
this.delegate = delegate;
this.delegate = requireNonNull(delegate, "delegate cannot be null");
this.childrenTracking = parent;
}

Some files were not shown because too many files have changed in this diff Show More