From eb9b69f8128e7ce15858c13f0e28c5e59077d37d Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Sat, 31 Aug 2024 07:41:19 +0200 Subject: [PATCH 01/63] [MNG-8120] Remove WorkspaceModelResolver # Conflicts: # maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java --- .../model/WorkspaceModelResolver.java | 31 ---- .../impl/model/DefaultModelBuilder.java | 157 +++++++----------- 2 files changed, 60 insertions(+), 128 deletions(-) delete mode 100644 maven-api-impl/src/main/java/org/apache/maven/api/services/model/WorkspaceModelResolver.java diff --git a/maven-api-impl/src/main/java/org/apache/maven/api/services/model/WorkspaceModelResolver.java b/maven-api-impl/src/main/java/org/apache/maven/api/services/model/WorkspaceModelResolver.java deleted file mode 100644 index 4dd18968d567..000000000000 --- a/maven-api-impl/src/main/java/org/apache/maven/api/services/model/WorkspaceModelResolver.java +++ /dev/null @@ -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); -} diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index a7a578659c24..c5b59e4be1c8 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -100,7 +100,6 @@ 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.services.model.WorkspaceModelResolver; import org.apache.maven.api.services.xml.XmlReaderException; import org.apache.maven.api.services.xml.XmlReaderRequest; import org.apache.maven.internal.impl.resolver.DefaultModelRepositoryHolder; @@ -1038,33 +1037,14 @@ private ModelData readParentLocally( ModelBuilderRequest request, DefaultModelProblemCollector problems) throws ModelBuilderException { - final Parent parent = childModel.getParent(); - final ModelSource candidateSource; - final Model candidateModel; - final WorkspaceModelResolver resolver = getWorkspaceModelResolver(request); - if (resolver == null) { - candidateSource = getParentPomFile(childModel, childSource); - - if (candidateSource == null) { - return null; - } + ModelSource candidateSource = getParentPomFile(childModel, childSource); + if (candidateSource == null) { + return null; + } - ModelBuilderRequest candidateBuildRequest = ModelBuilderRequest.build(request, candidateSource); + ModelBuilderRequest candidateBuildRequest = ModelBuilderRequest.build(request, candidateSource); - candidateModel = readRawModel(candidateBuildRequest, problems); - } else { - try { - candidateModel = - resolver.resolveRawModel(parent.getGroupId(), parent.getArtifactId(), parent.getVersion()); - } catch (ModelBuilderException e) { - problems.add(Severity.FATAL, ModelProblem.Version.BASE, e.getMessage(), parent.getLocation(""), e); - throw problems.newModelBuilderException(); - } - if (candidateModel == null) { - return null; - } - candidateSource = ModelSource.fromPath(candidateModel.getPomFile()); - } + Model candidateModel = readRawModel(candidateBuildRequest, problems); // // TODO jvz Why isn't all this checking the job of the duty of the workspace resolver, we know that we @@ -1075,6 +1055,7 @@ private ModelData readParentLocally( String groupId = getGroupId(candidateModel); String artifactId = candidateModel.getArtifactId(); + Parent parent = childModel.getParent(); if (groupId == null || !groupId.equals(parent.getGroupId()) || artifactId == null @@ -1427,87 +1408,73 @@ private Model doLoadDependencyManagement( String artifactId, String version, Collection importIds) { - final WorkspaceModelResolver workspaceResolver = getWorkspaceModelResolver(request); final ModelResolver modelResolver = getModelResolver(request); - if (workspaceResolver == null && modelResolver == null) { + if (modelResolver == null) { throw new NullPointerException(String.format( "request.workspaceModelResolver and request.modelResolver cannot be null (parent POM %s and POM %s)", ModelProblemUtils.toId(groupId, artifactId, version), ModelProblemUtils.toSourceHint(model))); } - Model importModel = null; - if (workspaceResolver != null) { - try { - importModel = workspaceResolver.resolveEffectiveModel(groupId, artifactId, version); - } catch (ModelBuilderException e) { - problems.add(Severity.FATAL, ModelProblem.Version.BASE, null, e); - return null; + Model importModel; + // no workspace resolver or workspace resolver returned null (i.e. model not in workspace) + final ModelSource importSource; + try { + importSource = modelResolver.resolveModel( + request.getSession(), + request.getModelRepositoryHolder().getRepositories(), + dependency, + new AtomicReference<>()); + } catch (ModelBuilderException e) { + StringBuilder buffer = new StringBuilder(256); + buffer.append("Non-resolvable import POM"); + if (!containsCoordinates(e.getMessage(), groupId, artifactId, version)) { + buffer.append(' ').append(ModelProblemUtils.toId(groupId, artifactId, version)); } - } + buffer.append(": ").append(e.getMessage()); - // no workspace resolver or workspace resolver returned null (i.e. model not in workspace) - if (importModel == null) { - final ModelSource importSource; - try { - importSource = modelResolver.resolveModel( - request.getSession(), - request.getModelRepositoryHolder().getRepositories(), - dependency, - new AtomicReference<>()); - } catch (ModelBuilderException e) { - StringBuilder buffer = new StringBuilder(256); - buffer.append("Non-resolvable import POM"); - if (!containsCoordinates(e.getMessage(), groupId, artifactId, version)) { - buffer.append(' ').append(ModelProblemUtils.toId(groupId, artifactId, version)); - } - buffer.append(": ").append(e.getMessage()); + problems.add(Severity.ERROR, ModelProblem.Version.BASE, buffer.toString(), dependency.getLocation(""), e); + return null; + } + Path rootDirectory; + try { + rootDirectory = request.getSession().getRootDirectory(); + } catch (IllegalStateException e) { + rootDirectory = null; + } + if (importSource.getPath() != null && rootDirectory != null) { + Path sourcePath = importSource.getPath(); + if (sourcePath.startsWith(rootDirectory)) { problems.add( - Severity.ERROR, ModelProblem.Version.BASE, buffer.toString(), dependency.getLocation(""), e); - return null; - } - - Path rootDirectory; - try { - rootDirectory = request.getSession().getRootDirectory(); - } catch (IllegalStateException e) { - rootDirectory = null; - } - if (importSource.getPath() != null && rootDirectory != null) { - Path sourcePath = importSource.getPath(); - if (sourcePath.startsWith(rootDirectory)) { - problems.add( - Severity.WARNING, - ModelProblem.Version.BASE, - "BOM imports from within reactor should be avoided", - dependency.getLocation("")); - } + Severity.WARNING, + ModelProblem.Version.BASE, + "BOM imports from within reactor should be avoided", + dependency.getLocation("")); } + } - final ModelBuilderResult importResult; - try { - ModelBuilderRequest importRequest = ModelBuilderRequest.builder() - .session(request.getSession()) - .repositories(request.getModelRepositoryHolder().getRepositories()) - .validationLevel(ModelBuilderRequest.VALIDATION_LEVEL_MINIMAL) - .systemProperties(request.getSystemProperties()) - .userProperties(request.getUserProperties()) - .source(importSource) - .modelResolver(modelResolver) - .modelRepositoryHolder( - request.getModelRepositoryHolder().copy()) - .twoPhaseBuilding(false) - .build(); - importResult = build(importRequest, importIds); - } catch (ModelBuilderException e) { - e.getResult().getProblems().forEach(problems::add); - return null; - } + final ModelBuilderResult importResult; + try { + ModelBuilderRequest importRequest = ModelBuilderRequest.builder() + .session(request.getSession()) + .repositories(request.getModelRepositoryHolder().getRepositories()) + .validationLevel(ModelBuilderRequest.VALIDATION_LEVEL_MINIMAL) + .systemProperties(request.getSystemProperties()) + .userProperties(request.getUserProperties()) + .source(importSource) + .modelResolver(modelResolver) + .modelRepositoryHolder(request.getModelRepositoryHolder().copy()) + .twoPhaseBuilding(false) + .build(); + importResult = build(importRequest, importIds); + } catch (ModelBuilderException e) { + e.getResult().getProblems().forEach(problems::add); + return null; + } - importResult.getProblems().forEach(problems::add); + importResult.getProblems().forEach(problems::add); - importModel = importResult.getEffectiveModel(); - } + importModel = importResult.getEffectiveModel(); return importModel; } @@ -1585,10 +1552,6 @@ private static ModelBuildingListener getModelBuildingListener(ModelBuilderReques return (ModelBuildingListener) request.getListener(); } - private static WorkspaceModelResolver getWorkspaceModelResolver(ModelBuilderRequest request) { - return null; // request.getWorkspaceModelResolver(); - } - private static ModelResolver getModelResolver(ModelBuilderRequest request) { return request.getModelResolver(); } From 281977dd0832b7a5f2eadf60f8e95bd38986ad59 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Sat, 31 Aug 2024 07:41:44 +0200 Subject: [PATCH 02/63] [MNG-8120] Deprecate some API --- .../org/apache/maven/api/services/ModelRepositoryHolder.java | 5 +++++ .../java/org/apache/maven/api/services/ModelTransformer.java | 3 +++ .../apache/maven/api/services/ModelTransformerContext.java | 3 +++ .../maven/api/services/ModelTransformerContextBuilder.java | 3 +++ 4 files changed, 14 insertions(+) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelRepositoryHolder.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelRepositoryHolder.java index 3be93256bebc..5d309d3a48d0 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelRepositoryHolder.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelRepositoryHolder.java @@ -23,6 +23,11 @@ import org.apache.maven.api.RemoteRepository; import org.apache.maven.api.model.Repository; +/** + * @deprecated this should not be exposed + * TODO refactor in MNG-8120 + */ +@Deprecated public interface ModelRepositoryHolder { void merge(List repos, boolean replace); diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformer.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformer.java index 0c17ae41bc3a..89cde693e8d8 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformer.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformer.java @@ -30,7 +30,10 @@ * local pom is the original source. * * @since 4.0.0 + * @deprecated this should not be exposed + * TODO refactor in MNG-8120 */ +@Deprecated public interface ModelTransformer { /** * @param context the context, cannot be null diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerContext.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerContext.java index a6e31720fae6..e40ee241f98e 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerContext.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerContext.java @@ -25,8 +25,11 @@ /** * Context used to transform a pom file. * + * @deprecated this should not be exposed * @since 4.0.0 + * TODO refactor in MNG-8120 */ +@Deprecated public interface ModelTransformerContext { /** diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerContextBuilder.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerContextBuilder.java index 9efb6e63eeb8..4c852c90b961 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerContextBuilder.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerContextBuilder.java @@ -23,7 +23,10 @@ * In case rawModels are missing, it could do new buildingRequests on the ModelBuilder. * * @since 4.0.0 + * @deprecated this should not be exposed + * TODO refactor in MNG-8120 */ +@Deprecated public interface ModelTransformerContextBuilder { /** * This method is used to initialize the TransformerContext From 5b8c56ba58c4ba75d012c9ff7e2cf9aa2f0a6acf Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 4 Sep 2024 07:47:14 +0200 Subject: [PATCH 03/63] Record problems during reactor loading --- .../api/services/ModelProblemCollector.java | 13 +++++ .../impl/model/DefaultModelBuilder.java | 52 +++++++------------ .../model/DefaultModelProblemCollector.java | 2 +- ...DefaultModelTransformerContextBuilder.java | 10 ++-- 4 files changed, 41 insertions(+), 36 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelProblemCollector.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelProblemCollector.java index 06d68b09d28d..9ef9aa861ed3 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelProblemCollector.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelProblemCollector.java @@ -21,6 +21,7 @@ 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 @@ void add( Exception exception); void add(ModelProblem problem); + + ModelBuilderException newModelBuilderException(); + + void setSource(String location); + + void setSource(Model model); + + String getSource(); + + void setRootModel(Model model); + + Model getRootModel(); } diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index c5b59e4be1c8..a4e1911222a8 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -227,7 +227,7 @@ protected ModelBuilderResult build(ModelBuilderRequest request, Collection interpolateActivations( - List profiles, DefaultProfileActivationContext context, DefaultModelProblemCollector problems) { + List profiles, DefaultProfileActivationContext context, ModelProblemCollector problems) { if (profiles.stream() .map(org.apache.maven.api.model.Profile::getActivation) .noneMatch(Objects::nonNull)) { @@ -519,7 +519,7 @@ private String transformPath(String path, ActivationFile target, String location } private static void addInterpolationProblem( - DefaultModelProblemCollector problems, + ModelProblemCollector problems, InputLocationTracker target, String path, InterpolationException e, @@ -543,7 +543,7 @@ public ModelBuilderResult build(final ModelBuilderRequest request, final ModelBu public Model buildRawModel(ModelBuilderRequest request) throws ModelBuilderException { request = fillRequestDefaults(request); - DefaultModelProblemCollector problems = new DefaultModelProblemCollector(new DefaultModelBuilderResult()); + ModelProblemCollector problems = new DefaultModelProblemCollector(new DefaultModelBuilderResult()); Model model = readRawModel(request, problems); if (hasModelErrors(problems)) { throw problems.newModelBuilderException(); @@ -556,7 +556,7 @@ private ModelBuilderResult build( throws ModelBuilderException { DefaultModelBuilderResult result = asDefaultModelBuilderResult(phaseOneResult); - DefaultModelProblemCollector problems = new DefaultModelProblemCollector(result); + ModelProblemCollector problems = new DefaultModelProblemCollector(result); // phase 2 Model resultModel = readEffectiveModel(request, result, problems); @@ -628,7 +628,7 @@ public Result buildRawModel( .locationTracking(locationTracking) .source(ModelSource.fromPath(pomFile)) .build(); - DefaultModelProblemCollector problems = new DefaultModelProblemCollector(new DefaultModelBuilderResult()); + ModelProblemCollector problems = new DefaultModelProblemCollector(new DefaultModelBuilderResult()); try { Model model = readFileModel(request, problems); @@ -646,8 +646,7 @@ public Result buildRawModel( } } - Model readFileModel(ModelBuilderRequest request, DefaultModelProblemCollector problems) - throws ModelBuilderException { + Model readFileModel(ModelBuilderRequest request, ModelProblemCollector problems) throws ModelBuilderException { ModelSource modelSource = request.getSource(); Model model = cache(getModelCache(request), modelSource, FILE, () -> doReadFileModel(modelSource, request, problems)); @@ -662,8 +661,7 @@ Model readFileModel(ModelBuilderRequest request, DefaultModelProblemCollector pr } @SuppressWarnings("checkstyle:methodlength") - private Model doReadFileModel( - ModelSource modelSource, ModelBuilderRequest request, DefaultModelProblemCollector problems) + private Model doReadFileModel(ModelSource modelSource, ModelBuilderRequest request, ModelProblemCollector problems) throws ModelBuilderException { Model model; problems.setSource(modelSource.getLocation()); @@ -823,8 +821,7 @@ private Model doReadFileModel( return model; } - Model readRawModel(ModelBuilderRequest request, DefaultModelProblemCollector problems) - throws ModelBuilderException { + Model readRawModel(ModelBuilderRequest request, ModelProblemCollector problems) throws ModelBuilderException { ModelSource modelSource = request.getSource(); ModelData modelData = @@ -834,7 +831,7 @@ Model readRawModel(ModelBuilderRequest request, DefaultModelProblemCollector pro } private ModelData doReadRawModel( - ModelSource modelSource, ModelBuilderRequest request, DefaultModelProblemCollector problems) + ModelSource modelSource, ModelBuilderRequest request, ModelProblemCollector problems) throws ModelBuilderException { Model rawModel = readFileModel(request, problems); if (!MODEL_VERSION_4_0_0.equals(rawModel.getModelVersion()) && modelSource.getPath() != null) { @@ -1003,10 +1000,7 @@ private Model interpolateModel(Model model, ModelBuilderRequest request, ModelPr } private ModelData readParent( - Model childModel, - ModelSource childSource, - ModelBuilderRequest request, - DefaultModelProblemCollector problems) + Model childModel, ModelSource childSource, ModelBuilderRequest request, ModelProblemCollector problems) throws ModelBuilderException { ModelData parentData = null; @@ -1032,10 +1026,7 @@ private ModelData readParent( } private ModelData readParentLocally( - Model childModel, - ModelSource childSource, - ModelBuilderRequest request, - DefaultModelProblemCollector problems) + Model childModel, ModelSource childSource, ModelBuilderRequest request, ModelProblemCollector problems) throws ModelBuilderException { ModelSource candidateSource = getParentPomFile(childModel, childSource); if (candidateSource == null) { @@ -1141,7 +1132,7 @@ private ModelSource getParentPomFile(Model childModel, ModelSource source) { } private ModelData readParentExternally( - Model childModel, ModelBuilderRequest request, DefaultModelProblemCollector problems) + Model childModel, ModelBuilderRequest request, ModelProblemCollector problems) throws ModelBuilderException { problems.setSource(childModel); @@ -1227,13 +1218,13 @@ private ModelData readParentExternally( return new ModelData(modelSource, parentModel); } - Model readParentModel(ModelBuilderRequest request, DefaultModelProblemCollector problems) { + Model readParentModel(ModelBuilderRequest request, ModelProblemCollector problems) { ModelSource modelSource = request.getSource(); Model model = cache(getModelCache(request), modelSource, PARENT, () -> doReadParentModel(request, problems)); return model; } - private Model doReadParentModel(ModelBuilderRequest request, DefaultModelProblemCollector problems) { + private Model doReadParentModel(ModelBuilderRequest request, ModelProblemCollector problems) { Model raw = readRawModel(request, problems); ModelData parentData; @@ -1259,10 +1250,7 @@ private Model getSuperModel(String modelVersion) { } private Model importDependencyManagement( - Model model, - ModelBuilderRequest request, - DefaultModelProblemCollector problems, - Collection importIds) { + Model model, ModelBuilderRequest request, ModelProblemCollector problems, Collection importIds) { DependencyManagement depMgmt = model.getDependencyManagement(); if (depMgmt == null) { @@ -1307,7 +1295,7 @@ private Model importDependencyManagement( private DependencyManagement loadDependencyManagement( Model model, ModelBuilderRequest request, - DefaultModelProblemCollector problems, + ModelProblemCollector problems, Dependency dependency, Collection importIds) { String groupId = dependency.getGroupId(); @@ -1402,7 +1390,7 @@ private boolean match(String match, String text) { private Model doLoadDependencyManagement( Model model, ModelBuilderRequest request, - DefaultModelProblemCollector problems, + ModelProblemCollector problems, Dependency dependency, String groupId, String artifactId, diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelProblemCollector.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelProblemCollector.java index 8df01905227a..23f26f3c2395 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelProblemCollector.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelProblemCollector.java @@ -90,7 +90,7 @@ public void setSource(Model source) { } } - private String getSource() { + public String getSource() { if (source == null && sourceModel != null) { source = ModelProblemUtils.toPath(sourceModel); } diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContextBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContextBuilder.java index 76d94a6d3130..318bfd68b237 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContextBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContextBuilder.java @@ -63,9 +63,8 @@ class DefaultModelTransformerContextBuilder implements ModelTransformerContextBu * If an interface could be extracted, DefaultModelProblemCollector should be ModelProblemCollectorExt */ @Override - public ModelTransformerContext initialize(ModelBuilderRequest request, ModelProblemCollector collector) { + public ModelTransformerContext initialize(ModelBuilderRequest request, ModelProblemCollector problems) { // We must assume the TransformerContext was created using this.newTransformerContextBuilder() - DefaultModelProblemCollector problems = (DefaultModelProblemCollector) collector; return new ModelTransformerContext() { @Override @@ -166,6 +165,11 @@ private void doLoadFullReactor() { } } catch (ModelBuilderException e) { // gathered with problem collector + problems.add( + ModelProblem.Severity.ERROR, + ModelProblem.Version.V40, + "Failed to load project " + pom, + e); } } } @@ -191,7 +195,7 @@ private Model findRawModel(Path from, Path p) { }; } - private boolean addEdge(Path from, Path p, DefaultModelProblemCollector problems) { + private boolean addEdge(Path from, Path p, ModelProblemCollector problems) { try { dag.addEdge(from.toString(), p.toString()); return true; From 0cafe794d21e7405c90e2a592e09fb67bb02a23e Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 4 Sep 2024 08:14:02 +0200 Subject: [PATCH 04/63] Move mappedSources into the ModelTransformerContext and use GAKey --- .../model/DefaultModelTransformerContext.java | 4 ++++ .../DefaultModelTransformerContextBuilder.java | 17 +++++++---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContext.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContext.java index 28c61d962a08..3ec4701edd74 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContext.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContext.java @@ -21,10 +21,12 @@ import java.nio.file.Path; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; import org.apache.maven.api.model.Model; +import org.apache.maven.api.services.ModelSource; import org.apache.maven.api.services.ModelTransformerContext; import org.apache.maven.api.services.model.ModelProcessor; @@ -41,6 +43,8 @@ class DefaultModelTransformerContext implements ModelTransformerContext { final Map modelByGA = new ConcurrentHashMap<>(); + final Map> mappedSources = new ConcurrentHashMap<>(64); + public static class Holder { private volatile boolean set; private volatile Model model; diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContextBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContextBuilder.java index 318bfd68b237..990f1f6e8c3e 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContextBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContextBuilder.java @@ -23,9 +23,7 @@ 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; @@ -49,9 +47,6 @@ class DefaultModelTransformerContextBuilder implements ModelTransformerContextBu private final Graph dag = new Graph(); private final DefaultModelBuilder defaultModelBuilder; private final DefaultModelTransformerContext context; - - private final Map> mappedSources = new ConcurrentHashMap<>(64); - private volatile boolean fullReactorLoaded; DefaultModelTransformerContextBuilder(DefaultModelBuilder defaultModelBuilder) { @@ -221,12 +216,12 @@ public ModelTransformerContext build() { public ModelSource getSource(String groupId, String artifactId) { Set sources; if (groupId != null) { - sources = mappedSources.get(groupId + ":" + artifactId); + sources = context.mappedSources.get(new GAKey(groupId, artifactId)); if (sources == null) { return null; } } else if (artifactId != null) { - sources = mappedSources.get(artifactId); + sources = context.mappedSources.get(new GAKey(null, artifactId)); if (sources == null) { return null; } @@ -243,9 +238,11 @@ public ModelSource getSource(String groupId, String artifactId) { } public void putSource(String groupId, String artifactId, ModelSource source) { - mappedSources - .computeIfAbsent(groupId + ":" + artifactId, k -> new HashSet<>()) + context.mappedSources + .computeIfAbsent(new GAKey(groupId, artifactId), k -> new HashSet<>()) + .add(source); + context.mappedSources + .computeIfAbsent(new GAKey(null, artifactId), k -> new HashSet<>()) .add(source); - mappedSources.computeIfAbsent(artifactId, k -> new HashSet<>()).add(source); } } From 622ba9e5d351b062bbf13d1384df6c85d0feb4b5 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 4 Sep 2024 08:09:39 +0200 Subject: [PATCH 05/63] Inline ModelTransformer inside DefaultModelBuilder --- .../maven/api/services/ModelTransformer.java | 47 ----- .../ModelTransformerContextBuilder.java | 7 - .../services/ModelTransformerException.java | 38 ---- .../maven/api/spi/ModelTransformer.java | 1 - .../impl/model/BuildModelTransformer.java | 188 ------------------ .../impl/model/DefaultModelBuilder.java | 123 ++++++++++-- ...DefaultModelTransformerContextBuilder.java | 5 - .../standalone/RepositorySystemSupplier.java | 2 - .../impl/DefaultConsumerPomBuilder.java | 5 - .../maven/project/DefaultProjectBuilder.java | 6 - .../DefaultTransformerContextBuilder.java | 5 +- .../MavenRepositorySystemSupplier.java | 2 - 12 files changed, 111 insertions(+), 318 deletions(-) delete mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformer.java delete mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerException.java delete mode 100644 maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/BuildModelTransformer.java diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformer.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformer.java deleted file mode 100644 index 89cde693e8d8..000000000000 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformer.java +++ /dev/null @@ -1,47 +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.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. - * - * @since 4.0.0 - * @deprecated this should not be exposed - * TODO refactor in MNG-8120 - */ -@Deprecated -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 - */ - @Nonnull - Model transform(@Nonnull ModelTransformerContext context, @Nonnull Model model, @Nonnull Path path) - throws ModelTransformerException; -} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerContextBuilder.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerContextBuilder.java index 4c852c90b961..29a8c6686da1 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerContextBuilder.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerContextBuilder.java @@ -36,11 +36,4 @@ public interface ModelTransformerContextBuilder { * @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(); } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerException.java deleted file mode 100644 index c68456beb433..000000000000 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerException.java +++ /dev/null @@ -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); - } -} diff --git a/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ModelTransformer.java b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ModelTransformer.java index d37982993f2a..525b353c6a5c 100644 --- a/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ModelTransformer.java +++ b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ModelTransformer.java @@ -23,7 +23,6 @@ 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. diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/BuildModelTransformer.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/BuildModelTransformer.java deleted file mode 100644 index b879649dfeb7..000000000000 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/BuildModelTransformer.java +++ /dev/null @@ -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 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 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; - } - } -} diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index a4e1911222a8..64fbd1e62480 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -25,6 +25,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; @@ -73,10 +74,8 @@ 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.ModelTransformer; import org.apache.maven.api.services.ModelTransformerContext; import org.apache.maven.api.services.ModelTransformerContextBuilder; -import org.apache.maven.api.services.ModelTransformerException; import org.apache.maven.api.services.Source; import org.apache.maven.api.services.SuperPomProvider; import org.apache.maven.api.services.VersionParserException; @@ -102,6 +101,8 @@ import org.apache.maven.api.services.model.ProfileSelector; import org.apache.maven.api.services.xml.XmlReaderException; import org.apache.maven.api.services.xml.XmlReaderRequest; +import org.apache.maven.api.spi.ModelTransformer; +import org.apache.maven.api.spi.ModelTransformerException; import org.apache.maven.internal.impl.resolver.DefaultModelRepositoryHolder; import org.apache.maven.internal.impl.resolver.DefaultModelResolver; import org.apache.maven.model.v4.MavenTransformer; @@ -143,9 +144,9 @@ public class DefaultModelBuilder implements ModelBuilder { private final LifecycleBindingsInjector lifecycleBindingsInjector; private final PluginConfigurationExpander pluginConfigurationExpander; private final ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator; - private final ModelTransformer transformer; + private final BuildModelTransformer buildModelTransformer; private final ModelVersionParser versionParser; - private final List transformers; + private final List transformers; private final ModelCacheFactory modelCacheFactory; @SuppressWarnings("checkstyle:ParameterNumber") @@ -167,9 +168,8 @@ public DefaultModelBuilder( @Nullable LifecycleBindingsInjector lifecycleBindingsInjector, PluginConfigurationExpander pluginConfigurationExpander, ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator, - ModelTransformer transformer, ModelVersionParser versionParser, - List transformers, + List transformers, ModelCacheFactory modelCacheFactory) { this.modelProcessor = modelProcessor; this.modelValidator = modelValidator; @@ -187,7 +187,7 @@ public DefaultModelBuilder( this.lifecycleBindingsInjector = lifecycleBindingsInjector; this.pluginConfigurationExpander = pluginConfigurationExpander; this.profileActivationFilePathInterpolator = profileActivationFilePathInterpolator; - this.transformer = transformer; + this.buildModelTransformer = new BuildModelTransformer(); this.versionParser = versionParser; this.transformers = transformers; this.modelCacheFactory = modelCacheFactory; @@ -633,8 +633,8 @@ public Result buildRawModel( Model model = readFileModel(request, problems); try { - if (transformer != null && context != null) { - transformer.transform(context, model, pomFile); + if (buildModelTransformer != null && context != null) { + buildModelTransformer.transform(context, model, pomFile); } } catch (ModelBuilderException e) { problems.add(Severity.FATAL, ModelProblem.Version.V40, null, e); @@ -651,12 +651,6 @@ Model readFileModel(ModelBuilderRequest request, ModelProblemCollector problems) Model model = cache(getModelCache(request), modelSource, FILE, () -> doReadFileModel(modelSource, request, problems)); - if (modelSource.getPath() != null) { - if (getTransformerContextBuilder(request) instanceof DefaultModelTransformerContextBuilder contextBuilder) { - contextBuilder.putSource(getGroupId(model), model.getArtifactId(), modelSource); - } - } - return model; } @@ -818,6 +812,12 @@ private Model doReadFileModel(ModelSource modelSource, ModelBuilderRequest reque throw problems.newModelBuilderException(); } + if (modelSource.getPath() != null) { + if (getTransformerContextBuilder(request) instanceof DefaultModelTransformerContextBuilder contextBuilder) { + contextBuilder.putSource(getGroupId(model), model.getArtifactId(), modelSource); + } + } + return model; } @@ -841,7 +841,7 @@ private ModelData doReadRawModel( ModelTransformerContextBuilder transformerContextBuilder = getTransformerContextBuilder(request); if (transformerContextBuilder != null) { ModelTransformerContext context = transformerContextBuilder.initialize(request, problems); - rawModel = this.transformer.transform(context, rawModel, pomFile); + rawModel = this.buildModelTransformer.transform(context, rawModel, pomFile); } } catch (ModelTransformerException e) { problems.add(Severity.FATAL, ModelProblem.Version.V40, null, e); @@ -1547,4 +1547,95 @@ private static ModelResolver getModelResolver(ModelBuilderRequest request) { private static ModelTransformerContextBuilder getTransformerContextBuilder(ModelBuilderRequest request) { return request.getTransformerContextBuilder(); } + + /** + * ModelSourceTransformer for the build pom + */ + public static class BuildModelTransformer { + + 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(); + String modVersion = replaceCiFriendlyVersion(context, version); + builder.parent(parent.withVersion(modVersion)); + } + } + + // + // 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 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; + } + } } diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContextBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContextBuilder.java index 990f1f6e8c3e..80f42c52309b 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContextBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContextBuilder.java @@ -208,11 +208,6 @@ private boolean addEdge(Path from, Path p, ModelProblemCollector problems) { } } - @Override - public ModelTransformerContext build() { - return context; - } - public ModelSource getSource(String groupId, String artifactId) { Set sources; if (groupId != null) { diff --git a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/RepositorySystemSupplier.java b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/RepositorySystemSupplier.java index 558dea7f7271..e5f47d86cd3f 100644 --- a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/RepositorySystemSupplier.java +++ b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/RepositorySystemSupplier.java @@ -32,7 +32,6 @@ 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; @@ -1059,7 +1058,6 @@ protected ModelBuilder createModelBuilder() { (m, r, b) -> m, new DefaultPluginConfigurationExpander(), new ProfileActivationFilePathInterpolator(new DefaultPathTranslator(), new DefaultRootLocator()), - new BuildModelTransformer(), new DefaultModelVersionParser(getVersionScheme()), List.of(), new DefaultModelCacheFactory()); diff --git a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java index ab2463adc6d5..cf592af809f7 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java @@ -42,7 +42,6 @@ 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; @@ -124,9 +123,6 @@ class DefaultConsumerPomBuilder implements ConsumerPomBuilder { @Inject private ModelVersionParser versionParser; - @Inject - private ModelTransformer modelTransformer; - // To break circular dependency @Inject private Provider repositorySystem; @@ -197,7 +193,6 @@ public List getActiveProfiles( lifecycleBindingsInjector, pluginConfigurationExpander, profileActivationFilePathInterpolator, - modelTransformer, versionParser, transformers, modelCacheFactory); diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index d90f09a5a126..eb3ba82962e4 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -80,7 +80,6 @@ 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.ModelTransformerContext; import org.apache.maven.api.services.ModelTransformerContextBuilder; import org.apache.maven.api.services.Source; import org.apache.maven.api.services.model.ModelBuildingListener; @@ -613,11 +612,6 @@ List doBuild(List pomFiles, boolean recursive) { try { // Phase 2: get effective models from the reactor List results = build(projectIndex, interimResults); - - request.getRepositorySession() - .getData() - .set(ModelTransformerContext.KEY, transformerContextBuilder.build()); - return results; } finally { Thread.currentThread().setContextClassLoader(oldContextClassLoader); diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultTransformerContextBuilder.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultTransformerContextBuilder.java index da0da3b78a53..2e31d40c6321 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultTransformerContextBuilder.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultTransformerContextBuilder.java @@ -201,7 +201,7 @@ public TransformerContext build() { } public FileModelSource getSource(String groupId, String artifactId) { - Set sources = mappedSources.get(groupId + ":" + artifactId); + Set sources = mappedSources.get(groupId != null ? groupId + ":" + artifactId : artifactId); if (sources == null) { return null; } @@ -218,5 +218,8 @@ public void putSource(String groupId, String artifactId, FileModelSource source) mappedSources .computeIfAbsent(groupId + ":" + artifactId, k -> new HashSet<>()) .add(source); + if (groupId != null) { + mappedSources.computeIfAbsent(artifactId, k -> new HashSet<>()).add(source); + } } } diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemSupplier.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemSupplier.java index 50daaf95fff2..0790720dc2c4 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemSupplier.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemSupplier.java @@ -32,7 +32,6 @@ 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; @@ -1061,7 +1060,6 @@ protected ModelBuilder createModelBuilder() { (m, r, b) -> m, new DefaultPluginConfigurationExpander(), new ProfileActivationFilePathInterpolator(new DefaultPathTranslator(), new DefaultRootLocator()), - new BuildModelTransformer(), new DefaultModelVersionParser(getVersionScheme()), List.of(), new DefaultModelCacheFactory()); From f5f4d85de856d9d8d44212ea4b988e69f021c281 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 4 Sep 2024 08:18:54 +0200 Subject: [PATCH 06/63] Do not return ModelData for readRawModel --- .../maven/internal/impl/model/DefaultModelBuilder.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 64fbd1e62480..4c2940bb0c29 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -824,14 +824,13 @@ private Model doReadFileModel(ModelSource modelSource, ModelBuilderRequest reque Model readRawModel(ModelBuilderRequest request, ModelProblemCollector problems) throws ModelBuilderException { ModelSource modelSource = request.getSource(); - ModelData modelData = + Model model = cache(getModelCache(request), modelSource, RAW, () -> doReadRawModel(modelSource, request, problems)); - return modelData.model(); + return model; } - private ModelData doReadRawModel( - ModelSource modelSource, ModelBuilderRequest request, ModelProblemCollector problems) + private Model doReadRawModel(ModelSource modelSource, ModelBuilderRequest request, ModelProblemCollector problems) throws ModelBuilderException { Model rawModel = readFileModel(request, problems); if (!MODEL_VERSION_4_0_0.equals(rawModel.getModelVersion()) && modelSource.getPath() != null) { @@ -863,7 +862,7 @@ private ModelData doReadRawModel( throw problems.newModelBuilderException(); } - return new ModelData(modelSource, rawModel); + return rawModel; } static String getGroupId(Model model) { From adea1c5b55d99983340e26eef54b582d0f5c8ebb Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 4 Sep 2024 08:21:42 +0200 Subject: [PATCH 07/63] Use SessionData.Key, use immutable ModelTransformerContext during consumer pom build --- .../api/services/ModelTransformerContext.java | 3 +- .../impl/model/DefaultModelBuilder.java | 32 ++++-- ...DefaultModelTransformerContextBuilder.java | 1 + .../impl/DefaultConsumerPomBuilder.java | 4 +- .../impl/ConsumerPomBuilderTest.java | 100 +++++++++++++++--- 5 files changed, 115 insertions(+), 25 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerContext.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerContext.java index e40ee241f98e..eb46af0d2530 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerContext.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerContext.java @@ -20,6 +20,7 @@ import java.nio.file.Path; +import org.apache.maven.api.SessionData; import org.apache.maven.api.model.Model; /** @@ -35,7 +36,7 @@ public interface ModelTransformerContext { /** * Key to get the TransformerContext from the SessionData */ - Object KEY = ModelTransformerContext.class; + SessionData.Key KEY = SessionData.key(ModelTransformerContext.class); /** * Get the value of the Maven user property. diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 4c2940bb0c29..314e1cd89500 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -114,6 +114,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static java.util.Objects.requireNonNull; + /** */ @Named @@ -208,6 +210,14 @@ public ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilder } } + public ModelProblemCollector newCollector() { + return newCollector(new DefaultModelBuilderResult()); + } + + DefaultModelProblemCollector newCollector(DefaultModelBuilderResult result) { + return new DefaultModelProblemCollector(result); + } + private static ModelBuilderRequest fillRequestDefaults(ModelBuilderRequest request) { ModelBuilderRequest.ModelBuilderRequestBuilder builder = ModelBuilderRequest.builder(request); if (request.getModelRepositoryHolder() == null) { @@ -227,7 +237,7 @@ protected ModelBuilderResult build(ModelBuilderRequest request, Collection buildRawModel( .locationTracking(locationTracking) .source(ModelSource.fromPath(pomFile)) .build(); - ModelProblemCollector problems = new DefaultModelProblemCollector(new DefaultModelBuilderResult()); + ModelProblemCollector problems = newCollector(new DefaultModelBuilderResult()); try { Model model = readFileModel(request, problems); try { - if (buildModelTransformer != null && context != null) { + if (context != null) { buildModelTransformer.transform(context, model, pomFile); } } catch (ModelBuilderException e) { @@ -840,7 +850,15 @@ private Model doReadRawModel(ModelSource modelSource, ModelBuilderRequest reques ModelTransformerContextBuilder transformerContextBuilder = getTransformerContextBuilder(request); if (transformerContextBuilder != null) { ModelTransformerContext context = transformerContextBuilder.initialize(request, problems); - rawModel = this.buildModelTransformer.transform(context, rawModel, pomFile); + if (context == null) { + problems.add( + Severity.FATAL, + ModelProblem.Version.V40, + "Illegal state: ModelTransformerContextBuilder returned null", + (Exception) null); + } else { + rawModel = this.buildModelTransformer.transform(context, rawModel, pomFile); + } } } catch (ModelTransformerException e) { problems.add(Severity.FATAL, ModelProblem.Version.V40, null, e); @@ -1142,7 +1160,7 @@ private ModelData readParentExternally( String version = parent.getVersion(); ModelResolver modelResolver = getModelResolver(request); - Objects.requireNonNull( + requireNonNull( modelResolver, String.format( "request.modelResolver cannot be null (parent POM %s and POM %s)", diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContextBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContextBuilder.java index 80f42c52309b..4c766ffbe1af 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContextBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContextBuilder.java @@ -60,6 +60,7 @@ class DefaultModelTransformerContextBuilder implements ModelTransformerContextBu @Override public ModelTransformerContext initialize(ModelBuilderRequest request, ModelProblemCollector problems) { // We must assume the TransformerContext was created using this.newTransformerContextBuilder() + request.getSession().getData().set(ModelTransformerContext.KEY, context); return new ModelTransformerContext() { @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java index cf592af809f7..d3ab0cf58faa 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java @@ -42,6 +42,7 @@ 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.ModelTransformerContext; import org.apache.maven.api.services.SuperPomProvider; import org.apache.maven.api.services.model.DependencyManagementImporter; import org.apache.maven.api.services.model.DependencyManagementInjector; @@ -204,7 +205,8 @@ public List getActiveProfiles( request.validationLevel(ModelBuilderRequest.VALIDATION_LEVEL_MINIMAL); request.locationTracking(false); request.modelResolver(iSession.getData().get(SessionData.key(ModelResolver.class))); - request.transformerContextBuilder(modelBuilder.newTransformerContextBuilder()); + ModelTransformerContext context = iSession.getData().get(ModelTransformerContext.KEY); + request.transformerContextBuilder((r, p) -> context); request.systemProperties(session.getSystemProperties()); request.userProperties(session.getUserProperties()); return modelBuilder.build(request.build()); diff --git a/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java b/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java index c21e8902381a..eda7d8d77f53 100644 --- a/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java +++ b/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java @@ -19,32 +19,38 @@ 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.model.Parent; +import org.apache.maven.api.services.ModelBuilder; +import org.apache.maven.api.services.ModelBuilderRequest; 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.artifact.repository.MavenArtifactRepository; -import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout; +import org.apache.maven.api.services.ModelTransformerContext; +import org.apache.maven.api.services.ModelTransformerContextBuilder; +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 +61,35 @@ 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); + DefaultModelBuilder modelBuilder = (DefaultModelBuilder) getContainer().lookup(ModelBuilder.class); + Field transformersField = DefaultModelBuilder.class.getDeclaredField("transformers"); + transformersField.setAccessible(true); + transformersField.set(modelBuilder, List.of(new CIFriendlyVersionModelTransformer(iSession))); + ModelTransformerContextBuilder tcb = modelBuilder.newTransformerContextBuilder(); + ModelTransformerContext context = tcb.initialize( + ModelBuilderRequest.builder() + .session(iSession) + .transformerContextBuilder(tcb) + .build(), + modelBuilder.newCollector()); + iSession.getData().set(ModelTransformerContext.KEY, context); + iSession.getData().set(SessionData.key(ModelResolver.class), new MyModelResolver()); + } + @Test void testTrivialConsumer() throws Exception { MavenProject project; @@ -65,8 +100,6 @@ void testTrivialConsumer() throws Exception { 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))); } Model model = builder.build(session, project, file); @@ -77,14 +110,17 @@ void testTrivialConsumer() throws Exception { 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 +133,7 @@ void testSimpleConsumer() throws Exception { 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 +154,39 @@ public ModelSource resolveModel( 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; + } + } } From ba238635140c50924fb3368d96931a4b1be0027e Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 4 Sep 2024 10:10:44 +0200 Subject: [PATCH 08/63] Fix possible IllegalArgumentException self-causation --- .../java/org/apache/maven/internal/impl/AbstractSession.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/AbstractSession.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/AbstractSession.java index ece39133d3af..b92ec7b8ee08 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/AbstractSession.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/AbstractSession.java @@ -297,9 +297,7 @@ private Service lookup(Class c) { 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); } } From 7920794a499201ba71e1253f90cffcba618afe6d Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 4 Sep 2024 10:32:33 +0200 Subject: [PATCH 09/63] Use constructor injection for DefaultConsumerPomBuilder --- .../impl/DefaultConsumerPomBuilder.java | 124 +++++++++--------- 1 file changed, 63 insertions(+), 61 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java index d3ab0cf58faa..847e98bb3cd6 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java @@ -20,7 +20,6 @@ import javax.inject.Inject; import javax.inject.Named; -import javax.inject.Provider; import java.nio.file.Path; import java.util.ArrayList; @@ -61,13 +60,13 @@ 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; @@ -79,68 +78,71 @@ class DefaultConsumerPomBuilder implements ConsumerPomBuilder { public static final String POM_PACKAGING = "pom"; - @Inject - private ProfileInjector profileInjector; - - @Inject - private InheritanceAssembler inheritanceAssembler; - - @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; + 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; + // To break circular dependency private final Provider repositorySystem; + private final RemoteRepositoryManager remoteRepositoryManager; + private final ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator; + private final List transformers; + private final ModelCacheFactory modelCacheFactory; @Inject - private ModelValidator modelValidator; - - @Inject - private PluginConfigurationExpander pluginConfigurationExpander; - - @Inject - private PluginManagementInjector pluginManagementInjector; - - @Inject - private SuperPomProvider superPomProvider; - - @Inject - private ModelVersionParser versionParser; - - // To break circular dependency - @Inject - private Provider repositorySystem; - - @Inject - private RemoteRepositoryManager remoteRepositoryManager; - - @Inject - private ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator; - - @Inject - private List transformers; - - @Inject - private ModelCacheFactory modelCacheFactory; + @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, + RemoteRepositoryManager remoteRepositoryManager, + ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator, + List transformers, + ModelCacheFactory modelCacheFactory) { + 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.remoteRepositoryManager = remoteRepositoryManager; + this.profileActivationFilePathInterpolator = profileActivationFilePathInterpolator; + this.transformers = transformers; + this.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 { From ae405781f293ed08faae2b5c47d6dc149c6628b6 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 4 Sep 2024 10:42:32 +0200 Subject: [PATCH 10/63] Remove unused fields from DefaultArtifactDescriptorReader --- .../impl/resolver/DefaultArtifactDescriptorReader.java | 9 --------- .../impl/standalone/RepositorySystemSupplier.java | 2 -- .../internal/MavenRepositorySystemSupplier.java | 2 -- 3 files changed, 13 deletions(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java index 3c16120b20b6..f92cc2c2120f 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java @@ -48,9 +48,7 @@ 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 +72,7 @@ @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 +82,12 @@ public class DefaultArtifactDescriptorReader implements ArtifactDescriptorReader @Inject public DefaultArtifactDescriptorReader( - RemoteRepositoryManager remoteRepositoryManager, VersionResolver versionResolver, - VersionRangeResolver versionRangeResolver, ArtifactResolver artifactResolver, ModelBuilder modelBuilder, RepositoryEventDispatcher repositoryEventDispatcher, Map 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 = diff --git a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/RepositorySystemSupplier.java b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/RepositorySystemSupplier.java index e5f47d86cd3f..94d83542f427 100644 --- a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/RepositorySystemSupplier.java +++ b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/RepositorySystemSupplier.java @@ -986,9 +986,7 @@ public final ArtifactDescriptorReader getArtifactDescriptorReader() { protected ArtifactDescriptorReader createArtifactDescriptorReader() { // from maven-resolver-provider return new DefaultArtifactDescriptorReader( - getRemoteRepositoryManager(), getVersionResolver(), - getVersionRangeResolver(), getArtifactResolver(), getModelBuilder(), getRepositoryEventDispatcher(), diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemSupplier.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemSupplier.java index 0790720dc2c4..12ae8c07260e 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemSupplier.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemSupplier.java @@ -988,9 +988,7 @@ public final ArtifactDescriptorReader getArtifactDescriptorReader() { protected ArtifactDescriptorReader createArtifactDescriptorReader() { // from maven-resolver-provider return new DefaultArtifactDescriptorReader( - getRemoteRepositoryManager(), getVersionResolver(), - getVersionRangeResolver(), getArtifactResolver(), getModelBuilder(), getRepositoryEventDispatcher(), From 815c8e6ceb952561ed6a1a88440c598bca087286 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 5 Sep 2024 00:58:36 +0200 Subject: [PATCH 11/63] Remove ModelRepositoryHolder interface # Conflicts: # maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java --- .../api/services/ModelBuilderRequest.java | 48 ++++++++++++++++--- .../api/services/ModelRepositoryHolder.java | 38 --------------- .../impl/model/DefaultModelBuilder.java | 36 +++++++++----- .../DefaultArtifactDescriptorReader.java | 5 +- .../DefaultModelRepositoryHolder.java | 25 ++-------- .../maven/project/DefaultProjectBuilder.java | 11 +---- 6 files changed, 71 insertions(+), 92 deletions(-) delete mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelRepositoryHolder.java diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java index a72dd730498c..66f74aeaa322 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java @@ -79,6 +79,22 @@ public interface ModelBuilderRequest { */ int VALIDATION_LEVEL_STRICT = VALIDATION_LEVEL_MAVEN_4_0; + /** + * The possible merge modes for combining remote repositories. + */ + 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, + } + @Nonnull Session getSession(); @@ -144,7 +160,10 @@ public interface ModelBuilderRequest { ModelResolver getModelResolver(); @Nonnull - ModelRepositoryHolder getModelRepositoryHolder(); + Object getModelRepositoryHolder(); + + @Nonnull + RepositoryMerging getRepositoryMerging(); @Nullable Object getListener(); @@ -206,7 +225,8 @@ class ModelBuilderRequestBuilder { Map systemProperties; Map userProperties; ModelResolver modelResolver; - ModelRepositoryHolder modelRepositoryHolder; + Object modelRepositoryHolder; + RepositoryMerging repositoryMerging; Object listener; ModelBuilderResult interimResult; ModelTransformerContextBuilder transformerContextBuilder; @@ -229,6 +249,7 @@ class ModelBuilderRequestBuilder { this.userProperties = request.getUserProperties(); this.modelResolver = request.getModelResolver(); this.modelRepositoryHolder = request.getModelRepositoryHolder(); + this.repositoryMerging = request.getRepositoryMerging(); this.listener = request.getListener(); this.interimResult = request.getInterimResult(); this.transformerContextBuilder = request.getTransformerContextBuilder(); @@ -300,11 +321,16 @@ public ModelBuilderRequestBuilder modelResolver(ModelResolver modelResolver) { return this; } - public ModelBuilderRequestBuilder modelRepositoryHolder(ModelRepositoryHolder modelRepositoryHolder) { + public ModelBuilderRequestBuilder modelRepositoryHolder(Object modelRepositoryHolder) { this.modelRepositoryHolder = modelRepositoryHolder; return this; } + public ModelBuilderRequestBuilder repositoryMerging(RepositoryMerging repositoryMerging) { + this.repositoryMerging = repositoryMerging; + return this; + } + public ModelBuilderRequestBuilder listener(Object listener) { this.listener = listener; return this; @@ -342,6 +368,7 @@ public ModelBuilderRequest build() { userProperties, modelResolver, modelRepositoryHolder, + repositoryMerging, listener, interimResult, transformerContextBuilder, @@ -361,7 +388,8 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M private final Map systemProperties; private final Map userProperties; private final ModelResolver modelResolver; - private final ModelRepositoryHolder modelRepositoryHolder; + private final Object modelRepositoryHolder; + private final RepositoryMerging repositoryMerging; private final Object listener; private final ModelBuilderResult interimResult; private final ModelTransformerContextBuilder transformerContextBuilder; @@ -382,7 +410,8 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M Map systemProperties, Map userProperties, ModelResolver modelResolver, - ModelRepositoryHolder modelRepositoryHolder, + Object modelRepositoryHolder, + RepositoryMerging repositoryMerging, Object listener, ModelBuilderResult interimResult, ModelTransformerContextBuilder transformerContextBuilder, @@ -402,6 +431,7 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M this.userProperties = userProperties != null ? Map.copyOf(userProperties) : session.getUserProperties(); this.modelResolver = modelResolver; this.modelRepositoryHolder = modelRepositoryHolder; + this.repositoryMerging = repositoryMerging; this.listener = listener; this.interimResult = interimResult; this.transformerContextBuilder = transformerContextBuilder; @@ -469,10 +499,16 @@ public ModelResolver getModelResolver() { } @Override - public ModelRepositoryHolder getModelRepositoryHolder() { + public Object getModelRepositoryHolder() { return modelRepositoryHolder; } + @Override + public RepositoryMerging getRepositoryMerging() { + return repositoryMerging; + } + + @Override public Object getListener() { return listener; } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelRepositoryHolder.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelRepositoryHolder.java deleted file mode 100644 index 5d309d3a48d0..000000000000 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelRepositoryHolder.java +++ /dev/null @@ -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 java.util.List; - -import org.apache.maven.api.RemoteRepository; -import org.apache.maven.api.model.Repository; - -/** - * @deprecated this should not be exposed - * TODO refactor in MNG-8120 - */ -@Deprecated -public interface ModelRepositoryHolder { - - void merge(List repos, boolean replace); - - List getRepositories(); - - ModelRepositoryHolder copy(); -} diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 314e1cd89500..ce00003abb2b 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -220,11 +220,15 @@ DefaultModelProblemCollector newCollector(DefaultModelBuilderResult result) { private static ModelBuilderRequest fillRequestDefaults(ModelBuilderRequest request) { ModelBuilderRequest.ModelBuilderRequestBuilder builder = ModelBuilderRequest.builder(request); - if (request.getModelRepositoryHolder() == null) { + if (getModelRepositoryHolder(request) == null) { builder.modelRepositoryHolder(new DefaultModelRepositoryHolder( request.getSession(), - DefaultModelRepositoryHolder.RepositoryMerging.POM_DOMINANT, - request.getSession().getRemoteRepositories())); + request.getRepositoryMerging() != null + ? request.getRepositoryMerging() + : ModelBuilderRequest.RepositoryMerging.POM_DOMINANT, + request.getRepositories() != null + ? request.getRepositories() + : request.getSession().getRemoteRepositories())); } if (request.getModelResolver() == null) { builder.modelResolver(new DefaultModelResolver()); @@ -378,11 +382,12 @@ private Model readEffectiveModel( // add repositories specified by the current model so that we can resolve the parent if (!model.getRepositories().isEmpty()) { - List oldRepos = request.getModelRepositoryHolder().getRepositories().stream() + DefaultModelRepositoryHolder modelRepositoryHolder = getModelRepositoryHolder(request); + List oldRepos = modelRepositoryHolder.getRepositories().stream() .map(Object::toString) .toList(); - request.getModelRepositoryHolder().merge(model.getRepositories(), false); - List newRepos = request.getModelRepositoryHolder().getRepositories().stream() + modelRepositoryHolder.merge(model.getRepositories(), false); + List newRepos = modelRepositoryHolder.getRepositories().stream() .map(Object::toString) .toList(); if (!Objects.equals(oldRepos, newRepos)) { @@ -444,11 +449,12 @@ private Model readEffectiveModel( // Now the fully interpolated model is available: reconfigure the resolver if (!resultModel.getRepositories().isEmpty()) { - List oldRepos = request.getModelRepositoryHolder().getRepositories().stream() + DefaultModelRepositoryHolder modelRepositoryHolder = getModelRepositoryHolder(request); + List oldRepos = modelRepositoryHolder.getRepositories().stream() .map(Object::toString) .toList(); - request.getModelRepositoryHolder().merge(resultModel.getRepositories(), true); - List newRepos = request.getModelRepositoryHolder().getRepositories().stream() + modelRepositoryHolder.merge(resultModel.getRepositories(), true); + List newRepos = modelRepositoryHolder.getRepositories().stream() .map(Object::toString) .toList(); if (!Objects.equals(oldRepos, newRepos)) { @@ -1171,7 +1177,7 @@ private ModelData readParentExternally( try { AtomicReference modified = new AtomicReference<>(); modelSource = modelResolver.resolveModel( - request.getSession(), request.getModelRepositoryHolder().getRepositories(), parent, modified); + request.getSession(), getModelRepositoryHolder(request).getRepositories(), parent, modified); if (modified.get() != null) { parent = modified.get(); } @@ -1426,7 +1432,7 @@ private Model doLoadDependencyManagement( try { importSource = modelResolver.resolveModel( request.getSession(), - request.getModelRepositoryHolder().getRepositories(), + getModelRepositoryHolder(request).getRepositories(), dependency, new AtomicReference<>()); } catch (ModelBuilderException e) { @@ -1462,14 +1468,14 @@ private Model doLoadDependencyManagement( try { ModelBuilderRequest importRequest = ModelBuilderRequest.builder() .session(request.getSession()) - .repositories(request.getModelRepositoryHolder().getRepositories()) .validationLevel(ModelBuilderRequest.VALIDATION_LEVEL_MINIMAL) .systemProperties(request.getSystemProperties()) .userProperties(request.getUserProperties()) .source(importSource) .modelResolver(modelResolver) - .modelRepositoryHolder(request.getModelRepositoryHolder().copy()) + .modelRepositoryHolder(getModelRepositoryHolder(request).copy()) .twoPhaseBuilding(false) + .repositories(getModelRepositoryHolder(request).getRepositories()) .build(); importResult = build(importRequest, importIds); } catch (ModelBuilderException e) { @@ -1484,6 +1490,10 @@ private Model doLoadDependencyManagement( return importModel; } + private static DefaultModelRepositoryHolder getModelRepositoryHolder(ModelBuilderRequest request) { + return (DefaultModelRepositoryHolder) request.getModelRepositoryHolder(); + } + private static T cache( ModelCache cache, String groupId, String artifactId, String version, String tag, Callable supplier) { return cache.computeIfAbsent(groupId, artifactId, version, tag, asSupplier(supplier)); diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java index f92cc2c2120f..3c5ebfdbf586 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java @@ -34,7 +34,6 @@ 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; @@ -195,8 +194,6 @@ private Model loadPom( 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) @@ -208,7 +205,7 @@ private Model loadPom( .systemProperties(toProperties(session.getUserProperties(), session.getSystemProperties())) .userProperties(Map.of()) .modelResolver(modelResolver) - .modelRepositoryHolder(modelRepositoryHolder) + .repositoryMerging(ModelBuilderRequest.RepositoryMerging.REQUEST_DOMINANT) .repositories(repositories) .build(); diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelRepositoryHolder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelRepositoryHolder.java index 155825408bcd..cb9f6bd2aa9e 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelRepositoryHolder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelRepositoryHolder.java @@ -26,26 +26,10 @@ 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.ModelBuilderRequest.RepositoryMerging; 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, - } +public class DefaultModelRepositoryHolder { final Session session; final RepositoryMerging repositoryMerging; @@ -73,7 +57,6 @@ protected DefaultModelRepositoryHolder(DefaultModelRepositoryHolder holder) { this.repositories = List.copyOf(holder.repositories); } - @Override public void merge(List toAdd, boolean replace) { List repos = toAdd.stream().map(session::createRemoteRepository).toList(); @@ -100,13 +83,11 @@ public void merge(List toAdd, boolean replace) { } } - @Override public List getRepositories() { return List.copyOf(repositories); } - @Override - public ModelRepositoryHolder copy() { + public DefaultModelRepositoryHolder copy() { return new DefaultModelRepositoryHolder(this); } } diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index eb3ba82962e4..e116f46c6566 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -90,7 +90,6 @@ import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.bridge.MavenRepositorySystem; import org.apache.maven.internal.impl.InternalSession; -import org.apache.maven.internal.impl.resolver.DefaultModelRepositoryHolder; import org.apache.maven.model.building.DefaultModelProblem; import org.apache.maven.model.building.FileModelSource; import org.apache.maven.model.building.ModelSource2; @@ -1191,14 +1190,8 @@ private ModelBuilderRequest.ModelBuilderRequestBuilder getModelBuildingRequest() modelBuildingRequest.userProperties(toMap(request.getUserProperties())); // bv4: modelBuildingRequest.setBuildStartTime(request.getBuildStartTime()); modelBuildingRequest.modelResolver(modelResolver); - DefaultModelRepositoryHolder holder = new DefaultModelRepositoryHolder( - internalSession, - DefaultModelRepositoryHolder.RepositoryMerging.valueOf( - request.getRepositoryMerging().name()), - repositories.stream() - .map(internalSession::getRemoteRepository) - .toList()); - modelBuildingRequest.modelRepositoryHolder(holder); + modelBuildingRequest.repositoryMerging(ModelBuilderRequest.RepositoryMerging.valueOf( + request.getRepositoryMerging().name())); modelBuildingRequest.transformerContextBuilder(transformerContextBuilder); modelBuildingRequest.repositories(request.getRemoteRepositories().stream() .map(r -> internalSession.getRemoteRepository(RepositoryUtils.toRepo(r))) From 3d6533f6f90019f18a3fb20faae0cff9c82b7e31 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 5 Sep 2024 11:45:13 +0200 Subject: [PATCH 12/63] Use request.isProjectBuild() instead of source.getPath() != null # Conflicts: # maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java --- .../maven/internal/impl/model/DefaultModelBuilder.java | 8 ++++---- .../transformation/impl/ConsumerPomBuilderTest.java | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index ce00003abb2b..bfb18760eb31 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -754,7 +754,7 @@ private Model doReadFileModel(ModelSource modelSource, ModelBuilderRequest reque throw problems.newModelBuilderException(); } - if (modelSource.getPath() != null) { + if (request.isProjectBuild()) { model = model.withPomFile(modelSource.getPath()); Parent parent = model.getParent(); @@ -828,7 +828,7 @@ private Model doReadFileModel(ModelSource modelSource, ModelBuilderRequest reque throw problems.newModelBuilderException(); } - if (modelSource.getPath() != null) { + if (request.isProjectBuild()) { if (getTransformerContextBuilder(request) instanceof DefaultModelTransformerContextBuilder contextBuilder) { contextBuilder.putSource(getGroupId(model), model.getArtifactId(), modelSource); } @@ -849,7 +849,7 @@ Model readRawModel(ModelBuilderRequest request, ModelProblemCollector problems) private Model doReadRawModel(ModelSource modelSource, ModelBuilderRequest request, ModelProblemCollector problems) throws ModelBuilderException { Model rawModel = readFileModel(request, problems); - if (!MODEL_VERSION_4_0_0.equals(rawModel.getModelVersion()) && modelSource.getPath() != null) { + if (!MODEL_VERSION_4_0_0.equals(rawModel.getModelVersion()) && request.isProjectBuild()) { Path pomFile = modelSource.getPath(); try { @@ -1453,7 +1453,7 @@ private Model doLoadDependencyManagement( } catch (IllegalStateException e) { rootDirectory = null; } - if (importSource.getPath() != null && rootDirectory != null) { + if (request.isProjectBuild() && rootDirectory != null) { Path sourcePath = importSource.getPath(); if (sourcePath.startsWith(rootDirectory)) { problems.add( diff --git a/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java b/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java index eda7d8d77f53..3c4711de303f 100644 --- a/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java +++ b/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java @@ -82,6 +82,7 @@ void setupTransformerContext() throws Exception { ModelTransformerContextBuilder tcb = modelBuilder.newTransformerContextBuilder(); ModelTransformerContext context = tcb.initialize( ModelBuilderRequest.builder() + .projectBuild(true) .session(iSession) .transformerContextBuilder(tcb) .build(), From 86738c07909cdf690d887dc824b102c752b23980 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 5 Sep 2024 14:59:28 +0200 Subject: [PATCH 13/63] Remove ModelTransformerContextBuilder and ModelTransformerContext interfaces # Conflicts: # maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContextBuilder.java # maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java --- .../maven/api/services/ModelBuilder.java | 2 - .../api/services/ModelBuilderRequest.java | 19 -- .../api/services/ModelTransformerContext.java | 70 ----- .../ModelTransformerContextBuilder.java | 39 --- .../impl/model/DefaultModelBuilder.java | 62 ++--- .../model/DefaultModelTransformerContext.java | 215 +++++++++++---- ...DefaultModelTransformerContextBuilder.java | 244 ------------------ .../internal/impl/standalone/ApiRunner.java | 2 +- .../impl/DefaultConsumerPomBuilder.java | 3 - .../maven/project/DefaultProjectBuilder.java | 8 +- .../impl/ConsumerPomBuilderTest.java | 21 +- .../maven/project/ProjectBuilderTest.java | 8 +- 12 files changed, 210 insertions(+), 483 deletions(-) delete mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerContext.java delete mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerContextBuilder.java delete mode 100644 maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContextBuilder.java diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilder.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilder.java index dc502aeeb97b..f2e4f5702c97 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilder.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilder.java @@ -33,7 +33,5 @@ public interface ModelBuilder extends Service { ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilderException; - ModelTransformerContextBuilder newTransformerContextBuilder(); - Model buildRawModel(ModelBuilderRequest request); } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java index 66f74aeaa322..be216084e77b 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java @@ -171,9 +171,6 @@ enum RepositoryMerging { @Nullable ModelBuilderResult getInterimResult(); - @Nullable - ModelTransformerContextBuilder getTransformerContextBuilder(); - @Nullable List getRepositories(); @@ -229,7 +226,6 @@ class ModelBuilderRequestBuilder { RepositoryMerging repositoryMerging; Object listener; ModelBuilderResult interimResult; - ModelTransformerContextBuilder transformerContextBuilder; List repositories; ModelBuilderRequestBuilder() {} @@ -252,7 +248,6 @@ class ModelBuilderRequestBuilder { this.repositoryMerging = request.getRepositoryMerging(); this.listener = request.getListener(); this.interimResult = request.getInterimResult(); - this.transformerContextBuilder = request.getTransformerContextBuilder(); this.repositories = request.getRepositories(); } @@ -341,12 +336,6 @@ public ModelBuilderRequestBuilder interimResult(ModelBuilderResult interimResult return this; } - public ModelBuilderRequestBuilder transformerContextBuilder( - ModelTransformerContextBuilder transformerContextBuilder) { - this.transformerContextBuilder = transformerContextBuilder; - return this; - } - public ModelBuilderRequestBuilder repositories(List repositories) { this.repositories = repositories; return this; @@ -371,7 +360,6 @@ public ModelBuilderRequest build() { repositoryMerging, listener, interimResult, - transformerContextBuilder, repositories); } @@ -392,7 +380,6 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M private final RepositoryMerging repositoryMerging; private final Object listener; private final ModelBuilderResult interimResult; - private final ModelTransformerContextBuilder transformerContextBuilder; private final List repositories; @SuppressWarnings("checkstyle:ParameterNumber") @@ -414,7 +401,6 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M RepositoryMerging repositoryMerging, Object listener, ModelBuilderResult interimResult, - ModelTransformerContextBuilder transformerContextBuilder, List repositories) { super(session); this.validationLevel = validationLevel; @@ -434,7 +420,6 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M this.repositoryMerging = repositoryMerging; this.listener = listener; this.interimResult = interimResult; - this.transformerContextBuilder = transformerContextBuilder; this.repositories = repositories != null ? List.copyOf(repositories) : null; } @@ -518,10 +503,6 @@ public ModelBuilderResult getInterimResult() { return interimResult; } - public ModelTransformerContextBuilder getTransformerContextBuilder() { - return transformerContextBuilder; - } - @Override public List getRepositories() { return repositories; diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerContext.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerContext.java deleted file mode 100644 index eb46af0d2530..000000000000 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerContext.java +++ /dev/null @@ -1,70 +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.SessionData; -import org.apache.maven.api.model.Model; - -/** - * Context used to transform a pom file. - * - * @deprecated this should not be exposed - * @since 4.0.0 - * TODO refactor in MNG-8120 - */ -@Deprecated -public interface ModelTransformerContext { - - /** - * Key to get the TransformerContext from the SessionData - */ - SessionData.Key KEY = SessionData.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); -} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerContextBuilder.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerContextBuilder.java deleted file mode 100644 index 29a8c6686da1..000000000000 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformerContextBuilder.java +++ /dev/null @@ -1,39 +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 - * @deprecated this should not be exposed - * TODO refactor in MNG-8120 - */ -@Deprecated -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); -} diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index bfb18760eb31..8a5a2b0acb38 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -74,8 +74,6 @@ 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.ModelTransformerContext; -import org.apache.maven.api.services.ModelTransformerContextBuilder; import org.apache.maven.api.services.Source; import org.apache.maven.api.services.SuperPomProvider; import org.apache.maven.api.services.VersionParserException; @@ -195,11 +193,6 @@ public DefaultModelBuilder( this.modelCacheFactory = modelCacheFactory; } - @Override - public ModelTransformerContextBuilder newTransformerContextBuilder() { - return new DefaultModelTransformerContextBuilder(this); - } - @Override public ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilderException { request = fillRequestDefaults(request); @@ -638,7 +631,7 @@ public Result buildRawModel(Path pomFile, int validationLevel, } public Result buildRawModel( - Path pomFile, int validationLevel, boolean locationTracking, ModelTransformerContext context) { + Path pomFile, int validationLevel, boolean locationTracking, DefaultModelTransformerContext context) { final ModelBuilderRequest request = ModelBuilderRequest.builder() .validationLevel(validationLevel) .locationTracking(locationTracking) @@ -649,7 +642,7 @@ public Result buildRawModel( Model model = readFileModel(request, problems); try { - if (context != null) { + if (context != null && request.isProjectBuild()) { buildModelTransformer.transform(context, model, pomFile); } } catch (ModelBuilderException e) { @@ -829,9 +822,8 @@ private Model doReadFileModel(ModelSource modelSource, ModelBuilderRequest reque } if (request.isProjectBuild()) { - if (getTransformerContextBuilder(request) instanceof DefaultModelTransformerContextBuilder contextBuilder) { - contextBuilder.putSource(getGroupId(model), model.getArtifactId(), modelSource); - } + DefaultModelTransformerContext context = getTransformerContext(request, problems); + context.putSource(getGroupId(model), model.getArtifactId(), modelSource); } return model; @@ -852,19 +844,16 @@ private Model doReadRawModel(ModelSource modelSource, ModelBuilderRequest reques if (!MODEL_VERSION_4_0_0.equals(rawModel.getModelVersion()) && request.isProjectBuild()) { Path pomFile = modelSource.getPath(); + DefaultModelTransformerContext context = getTransformerContext(request, problems); try { - ModelTransformerContextBuilder transformerContextBuilder = getTransformerContextBuilder(request); - if (transformerContextBuilder != null) { - ModelTransformerContext context = transformerContextBuilder.initialize(request, problems); - if (context == null) { - problems.add( - Severity.FATAL, - ModelProblem.Version.V40, - "Illegal state: ModelTransformerContextBuilder returned null", - (Exception) null); - } else { - rawModel = this.buildModelTransformer.transform(context, rawModel, pomFile); - } + if (context == null) { + problems.add( + Severity.FATAL, + ModelProblem.Version.V40, + "Illegal state: ModelTransformerContextBuilder returned null", + (Exception) null); + } else { + rawModel = this.buildModelTransformer.transform(context, rawModel, pomFile); } } catch (ModelTransformerException e) { problems.add(Severity.FATAL, ModelProblem.Version.V40, null, e); @@ -889,6 +878,15 @@ private Model doReadRawModel(ModelSource modelSource, ModelBuilderRequest reques return rawModel; } + private DefaultModelTransformerContext getTransformerContext( + ModelBuilderRequest request, ModelProblemCollector problems) { + return (DefaultModelTransformerContext) request.getSession() + .getData() + .computeIfAbsent( + SessionData.key(DefaultModelTransformerContext.class), + () -> new DefaultModelTransformerContext(this, request, problems)); + } + static String getGroupId(Model model) { String groupId = model.getGroupId(); if (groupId == null && model.getParent() != null) { @@ -1455,7 +1453,7 @@ private Model doLoadDependencyManagement( } if (request.isProjectBuild() && rootDirectory != null) { Path sourcePath = importSource.getPath(); - if (sourcePath.startsWith(rootDirectory)) { + if (sourcePath != null && sourcePath.startsWith(rootDirectory)) { problems.add( Severity.WARNING, ModelProblem.Version.BASE, @@ -1571,16 +1569,12 @@ private static ModelResolver getModelResolver(ModelBuilderRequest request) { return request.getModelResolver(); } - private static ModelTransformerContextBuilder getTransformerContextBuilder(ModelBuilderRequest request) { - return request.getTransformerContextBuilder(); - } - /** * ModelSourceTransformer for the build pom */ public static class BuildModelTransformer { - public Model transform(ModelTransformerContext context, Model model, Path path) { + public Model transform(DefaultModelTransformerContext context, Model model, Path path) { Model.Builder builder = Model.newBuilder(model); handleParent(context, model, path, builder); handleReactorDependencies(context, model, path, builder); @@ -1591,7 +1585,7 @@ public Model transform(ModelTransformerContext context, Model model, Path path) // // Infer parent information // - void handleParent(ModelTransformerContext context, Model model, Path pomFile, Model.Builder builder) { + void handleParent(DefaultModelTransformerContext context, Model model, Path pomFile, Model.Builder builder) { Parent parent = model.getParent(); if (parent != null) { String version = parent.getVersion(); @@ -1604,7 +1598,7 @@ void handleParent(ModelTransformerContext context, Model model, Path pomFile, Mo // CI friendly versions // void handleCiFriendlyVersion( - ModelTransformerContext context, Model model, Path pomFile, Model.Builder builder) { + DefaultModelTransformerContext context, Model model, Path pomFile, Model.Builder builder) { String version = model.getVersion(); String modVersion = replaceCiFriendlyVersion(context, version); builder.version(modVersion); @@ -1614,7 +1608,7 @@ void handleCiFriendlyVersion( // Infer inner reactor dependencies version // void handleReactorDependencies( - ModelTransformerContext context, Model model, Path pomFile, Model.Builder builder) { + DefaultModelTransformerContext context, Model model, Path pomFile, Model.Builder builder) { List newDeps = new ArrayList<>(); boolean modified = false; for (Dependency dep : model.getDependencies()) { @@ -1653,7 +1647,7 @@ void handleReactorDependencies( } } - protected String replaceCiFriendlyVersion(ModelTransformerContext context, String version) { + String replaceCiFriendlyVersion(DefaultModelTransformerContext context, String version) { if (version != null) { for (String key : Arrays.asList("changelist", "revision", "sha1")) { String val = context.getUserProperty(key); diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContext.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContext.java index 3ec4701edd74..07b25c499650 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContext.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContext.java @@ -18,7 +18,11 @@ */ 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.Objects; import java.util.Set; @@ -26,31 +30,27 @@ import java.util.function.Supplier; 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.model.ModelProcessor; -/** - * - * @since 4.0.0 - */ -class DefaultModelTransformerContext implements ModelTransformerContext { - final ModelProcessor modelLocator; - - final Map userProperties = new ConcurrentHashMap<>(); +class DefaultModelTransformerContext { + final DefaultModelBuilder modelBuilder; + final ModelBuilderRequest request; + final ModelProblemCollector problems; + final Graph dag = new Graph(); final Map modelByPath = new ConcurrentHashMap<>(); - final Map modelByGA = new ConcurrentHashMap<>(); - final Map> mappedSources = new ConcurrentHashMap<>(64); + volatile boolean fullReactorLoaded; - public static class Holder { + static class Holder { private volatile boolean set; private volatile Model model; - Holder() {} - Holder(Model model) { this.model = Objects.requireNonNull(model); this.set = true; @@ -89,57 +89,178 @@ public Model computeIfAbsent(Supplier supplier) { } } - DefaultModelTransformerContext(ModelProcessor modelLocator) { - this.modelLocator = modelLocator; + DefaultModelTransformerContext( + DefaultModelBuilder modelBuilder, ModelBuilderRequest request, ModelProblemCollector problems) { + this.modelBuilder = modelBuilder; + this.request = request; + this.problems = problems; } - @Override public String getUserProperty(String key) { - return userProperties.get(key); + return request.getUserProperties().get(key); } - @Override - public Model getRawModel(Path from, Path p) { - return Holder.deref(modelByPath.get(p)); + public Model getRawModel(Path from, String gId, String aId) { + Model model = findRawModel(from, gId, aId); + if (model != null) { + modelByGA.put(new GAKey(gId, aId), new Holder(model)); + if (model.getPomFile() != null) { + modelByPath.put(model.getPomFile(), new Holder(model)); + } + } + return model; } - @Override - public Model getRawModel(Path from, String groupId, String artifactId) { - return Holder.deref(modelByGA.get(new GAKey(groupId, artifactId))); + public Model getRawModel(Path from, Path path) { + Model model = findRawModel(from, path); + if (model != null) { + String groupId = DefaultModelBuilder.getGroupId(model); + modelByGA.put(new GAKey(groupId, model.getArtifactId()), new Holder(model)); + modelByPath.put(path, new Holder(model)); + } + return model; } - @Override public Path locate(Path path) { - return modelLocator.locateExistingPom(path); + return modelBuilder.getModelProcessor().locateExistingPom(path); + } + + 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 modelBuilder.readRawModel(gaBuildingRequest, problems); + } catch (ModelBuilderException e) { + // gathered with problem collector + } + } + return null; + } + + private void loadFullReactor() { + if (!fullReactorLoaded) { + synchronized (this) { + if (!fullReactorLoaded) { + doLoadFullReactor(); + fullReactorLoaded = true; + } + } + } } - static class GAKey { - private final String groupId; - private final String artifactId; - private final int hashCode; + private void doLoadFullReactor() { + Path rootDirectory; + try { + rootDirectory = request.getSession().getRootDirectory(); + } catch (IllegalStateException e) { + // if no root directory, bail out + return; + } + List toLoad = new ArrayList<>(); + Path root = modelBuilder.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 = modelBuilder.readFileModel(gaBuildingRequest, problems); + List subprojects = rawModel.getSubprojects(); + if (subprojects == null) { + subprojects = rawModel.getModules(); + } + for (String subproject : subprojects) { + Path subprojectFile = modelBuilder + .getModelProcessor() + .locateExistingPom(pom.getParent().resolve(subproject)); + if (subprojectFile != null) { + toLoad.add(subprojectFile); + } + } + } catch (ModelBuilderException e) { + // gathered with problem collector + problems.add(ModelProblem.Severity.ERROR, ModelProblem.Version.V40, "Failed to load project " + pom, e); + } + } + } - GAKey(String groupId, String artifactId) { - this.groupId = groupId; - this.artifactId = artifactId; - this.hashCode = Objects.hash(groupId, artifactId); + private Model findRawModel(Path from, Path p) { + if (!Files.isRegularFile(p)) { + throw new IllegalArgumentException("Not a regular file: " + p); } - @Override - public int hashCode() { - return hashCode; + if (!addEdge(from, p, problems)) { + return null; } - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; + ModelBuilderRequest req = ModelBuilderRequest.build(request, ModelSource.fromPath(p)); + + try { + return modelBuilder.readRawModel(req, problems); + } catch (ModelBuilderException e) { + // gathered with problem collector + } + return null; + } + + private boolean addEdge(Path from, Path p, ModelProblemCollector 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; + } + } + + public ModelSource getSource(String groupId, String artifactId) { + Set sources; + if (groupId != null) { + sources = mappedSources.get(new GAKey(groupId, artifactId)); + if (sources == null) { + return null; } - if (!(obj instanceof GAKey)) { - return false; + } else if (artifactId != null) { + sources = mappedSources.get(new GAKey(null, artifactId)); + if (sources == null) { + return null; } - - GAKey other = (GAKey) obj; - return Objects.equals(artifactId, other.artifactId) && Objects.equals(groupId, other.groupId); + } 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(new GAKey(groupId, artifactId), k -> new HashSet<>()) + .add(source); + mappedSources + .computeIfAbsent(new GAKey(null, artifactId), k -> new HashSet<>()) + .add(source); } + + record GAKey(String groupId, String artifactId) {} } diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContextBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContextBuilder.java deleted file mode 100644 index 4c766ffbe1af..000000000000 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContextBuilder.java +++ /dev/null @@ -1,244 +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.Set; - -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 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 problems) { - // We must assume the TransformerContext was created using this.newTransformerContextBuilder() - request.getSession().getData().set(ModelTransformerContext.KEY, context); - 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 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 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 - problems.add( - ModelProblem.Severity.ERROR, - ModelProblem.Version.V40, - "Failed to load project " + pom, - e); - } - } - } - - 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, ModelProblemCollector 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; - } - } - - public ModelSource getSource(String groupId, String artifactId) { - Set sources; - if (groupId != null) { - sources = context.mappedSources.get(new GAKey(groupId, artifactId)); - if (sources == null) { - return null; - } - } else if (artifactId != null) { - sources = context.mappedSources.get(new GAKey(null, 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) { - context.mappedSources - .computeIfAbsent(new GAKey(groupId, artifactId), k -> new HashSet<>()) - .add(source); - context.mappedSources - .computeIfAbsent(new GAKey(null, artifactId), k -> new HashSet<>()) - .add(source); - } -} diff --git a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/ApiRunner.java b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/ApiRunner.java index 15a605ea20ef..05a3cfaa187b 100644 --- a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/ApiRunner.java +++ b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/ApiRunner.java @@ -158,7 +158,7 @@ public Path getTopDirectory() { @Override public Path getRootDirectory() { - return null; + throw new IllegalStateException(); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java index 847e98bb3cd6..2a8ca38cfbe8 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java @@ -41,7 +41,6 @@ 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.ModelTransformerContext; import org.apache.maven.api.services.SuperPomProvider; import org.apache.maven.api.services.model.DependencyManagementImporter; import org.apache.maven.api.services.model.DependencyManagementInjector; @@ -207,8 +206,6 @@ public List getActiveProfiles( request.validationLevel(ModelBuilderRequest.VALIDATION_LEVEL_MINIMAL); request.locationTracking(false); request.modelResolver(iSession.getData().get(SessionData.key(ModelResolver.class))); - ModelTransformerContext context = iSession.getData().get(ModelTransformerContext.KEY); - request.transformerContextBuilder((r, p) -> context); request.systemProperties(session.getSystemProperties()); request.userProperties(session.getUserProperties()); return modelBuilder.build(request.build()); diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index e116f46c6566..48e2708ec3cf 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -80,7 +80,6 @@ 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.ModelTransformerContextBuilder; import org.apache.maven.api.services.Source; import org.apache.maven.api.services.model.ModelBuildingListener; import org.apache.maven.api.services.model.ModelProcessor; @@ -381,7 +380,6 @@ class BuildSession implements AutoCloseable { private final List repositories; private final ReactorModelPool modelPool; private final ConcurrentMap parentCache; - private final ModelTransformerContextBuilder transformerContextBuilder; private final ExecutorService executor; private final ModelResolver modelResolver; private final Map ciFriendlyVersions = new ConcurrentHashMap<>(); @@ -395,10 +393,8 @@ class BuildSession implements AutoCloseable { this.executor = createExecutor(getParallelism(request)); if (localProjects) { this.modelPool = new ReactorModelPool(); - this.transformerContextBuilder = modelBuilder.newTransformerContextBuilder(); } else { this.modelPool = null; - this.transformerContextBuilder = null; } this.parentCache = new ConcurrentHashMap<>(); this.modelResolver = new ModelResolverWrapper() { @@ -488,7 +484,7 @@ ProjectBuildingResult build(Path pomFile, ModelSource modelSource) throws Projec ModelBuilderRequest.ModelBuilderRequestBuilder builder = getModelBuildingRequest(); ModelBuilderRequest request = builder.projectBuild(modelPool != null) .source(modelSource) - .projectBuild(true) + .projectBuild(pomFile != null) .locationTracking(true) .listener(listener) .build(); @@ -1176,6 +1172,7 @@ private ModelBuilderRequest.ModelBuilderRequestBuilder getModelBuildingRequest() InternalSession internalSession = InternalSession.from(session); modelBuildingRequest.session(internalSession); + modelBuildingRequest.projectBuild(true); modelBuildingRequest.validationLevel(request.getValidationLevel()); modelBuildingRequest.processPlugins(request.isProcessPlugins()); modelBuildingRequest.profiles( @@ -1192,7 +1189,6 @@ private ModelBuilderRequest.ModelBuilderRequestBuilder getModelBuildingRequest() modelBuildingRequest.modelResolver(modelResolver); modelBuildingRequest.repositoryMerging(ModelBuilderRequest.RepositoryMerging.valueOf( request.getRepositoryMerging().name())); - modelBuildingRequest.transformerContextBuilder(transformerContextBuilder); modelBuildingRequest.repositories(request.getRemoteRepositories().stream() .map(r -> internalSession.getRemoteRepository(RepositoryUtils.toRepo(r))) .toList()); diff --git a/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java b/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java index 3c4711de303f..40117047a6d9 100644 --- a/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java +++ b/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java @@ -35,12 +35,9 @@ import org.apache.maven.api.model.Model; import org.apache.maven.api.model.Parent; import org.apache.maven.api.services.ModelBuilder; -import org.apache.maven.api.services.ModelBuilderRequest; 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.ModelTransformerContext; -import org.apache.maven.api.services.ModelTransformerContextBuilder; import org.apache.maven.api.spi.ModelTransformer; import org.apache.maven.api.spi.ModelTransformerException; import org.apache.maven.di.Injector; @@ -79,15 +76,15 @@ void setupTransformerContext() throws Exception { Field transformersField = DefaultModelBuilder.class.getDeclaredField("transformers"); transformersField.setAccessible(true); transformersField.set(modelBuilder, List.of(new CIFriendlyVersionModelTransformer(iSession))); - ModelTransformerContextBuilder tcb = modelBuilder.newTransformerContextBuilder(); - ModelTransformerContext context = tcb.initialize( - ModelBuilderRequest.builder() - .projectBuild(true) - .session(iSession) - .transformerContextBuilder(tcb) - .build(), - modelBuilder.newCollector()); - iSession.getData().set(ModelTransformerContext.KEY, context); + // ModelTransformerContextBuilder tcb = modelBuilder.newTransformerContextBuilder(); + // ModelTransformerContext context = tcb.initialize( + // ModelBuilderRequest.builder() + // .projectBuild(true) + // .session(iSession) + // .transformerContextBuilder(tcb) + // .build(), + // modelBuilder.newCollector()); + // iSession.getData().set(ModelTransformerContext.KEY, context); iSession.getData().set(SessionData.key(ModelResolver.class), new MyModelResolver()); } diff --git a/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java b/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java index b798c39bdf0f..d1d4521c15ec 100644 --- a/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java +++ b/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java @@ -35,10 +35,8 @@ 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 @@ void testBuildFromModelSource() throws Exception { 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()); } @@ -346,10 +343,9 @@ void testBuildFromModelSourceResolvesBasedir() throws Exception { 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(), From b4ac77678924dcbfee7baf9640238247c08fd0ea Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 5 Sep 2024 20:20:29 +0200 Subject: [PATCH 14/63] Replace ModelBuilderRequest validationLevel,projectBuild,processPlugins with a single enum RequestType # Conflicts: # maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java # maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelValidator.java --- .../api/services/ModelBuilderRequest.java | 116 +++-------- .../api/services/model/ModelValidator.java | 39 +++- .../impl/model/DefaultModelBuilder.java | 55 +++-- .../impl/model/DefaultModelInterpolator.java | 16 +- .../impl/model/DefaultModelValidator.java | 192 +++++++++++++----- .../DefaultArtifactDescriptorReader.java | 3 +- .../impl/standalone/TestApiStandalone.java | 2 +- .../project/AbstractMavenProjectTestCase.java | 2 +- .../impl/DefaultConsumerPomBuilder.java | 3 +- .../project/DefaultModelBuildingListener.java | 3 +- .../maven/project/DefaultProjectBuilder.java | 18 +- .../impl/ConsumerPomBuilderTest.java | 20 +- 12 files changed, 274 insertions(+), 195 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java index be216084e77b..815dea0c0bea 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java @@ -39,7 +39,6 @@ * 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 */ @@ -48,36 +47,22 @@ 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; - - /** - * 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; + 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 + } /** * The possible merge modes for combining remote repositories. @@ -101,29 +86,13 @@ enum RepositoryMerging { @Nonnull ModelSource getSource(); - int getValidationLevel(); + @Nonnull + RequestType getRequestType(); boolean isTwoPhaseBuilding(); 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(); - /** * Defines external profiles that may be activated for the given model. * Those are external profiles usually defined in {@link org.apache.maven.api.settings.Settings#getProfiles()}. @@ -210,12 +179,10 @@ static ModelBuilderRequestBuilder builder(ModelBuilderRequest request) { @NotThreadSafe class ModelBuilderRequestBuilder { Session session; - int validationLevel; + RequestType requestType; boolean locationTracking; boolean twoPhaseBuilding; ModelSource source; - boolean projectBuild; - boolean processPlugins = true; Collection profiles; List activeProfileIds; List inactiveProfileIds; @@ -232,12 +199,10 @@ class 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.source = request.getSource(); - this.projectBuild = request.isProjectBuild(); - this.processPlugins = request.isProcessPlugins(); this.profiles = request.getProfiles(); this.activeProfileIds = request.getActiveProfileIds(); this.inactiveProfileIds = request.getInactiveProfileIds(); @@ -256,8 +221,8 @@ public ModelBuilderRequestBuilder session(Session session) { return this; } - public ModelBuilderRequestBuilder validationLevel(int validationLevel) { - this.validationLevel = validationLevel; + public ModelBuilderRequestBuilder requestType(RequestType requestType) { + this.requestType = requestType; return this; } @@ -276,16 +241,6 @@ public ModelBuilderRequestBuilder source(ModelSource 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 profiles) { this.profiles = profiles; return this; @@ -344,12 +299,10 @@ public ModelBuilderRequestBuilder repositories(List repositori public ModelBuilderRequest build() { return new DefaultModelBuilderRequest( session, - validationLevel, + requestType, locationTracking, twoPhaseBuilding, source, - projectBuild, - processPlugins, profiles, activeProfileIds, inactiveProfileIds, @@ -364,12 +317,10 @@ public ModelBuilderRequest build() { } 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 ModelSource source; - private final boolean projectBuild; - private final boolean processPlugins; private final Collection profiles; private final List activeProfileIds; private final List inactiveProfileIds; @@ -385,12 +336,10 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M @SuppressWarnings("checkstyle:ParameterNumber") DefaultModelBuilderRequest( @Nonnull Session session, - int validationLevel, + @Nonnull RequestType requestType, boolean locationTracking, boolean twoPhaseBuilding, @Nonnull ModelSource source, - boolean projectBuild, - boolean processPlugins, Collection profiles, List activeProfileIds, List inactiveProfileIds, @@ -403,12 +352,10 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M ModelBuilderResult interimResult, List repositories) { super(session); - this.validationLevel = validationLevel; + this.requestType = nonNull(requestType, "requestType cannot be null"); this.locationTracking = locationTracking; this.twoPhaseBuilding = twoPhaseBuilding; 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(); @@ -424,8 +371,8 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M } @Override - public int getValidationLevel() { - return validationLevel; + public RequestType getRequestType() { + return requestType; } @Override @@ -444,15 +391,6 @@ public ModelSource getSource() { return source; } - public boolean isProjectBuild() { - return projectBuild; - } - - @Override - public boolean isProcessPlugins() { - return processPlugins; - } - @Override public Collection getProfiles() { return profiles; diff --git a/maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelValidator.java b/maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelValidator.java index de45f9d5a5ba..40a8e813de64 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelValidator.java +++ b/maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelValidator.java @@ -27,15 +27,44 @@ * */ 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 @@ default void validateFileModel(Model model, ModelBuilderRequest request, ModelPr * 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); } diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 8a5a2b0acb38..9932a9b90378 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -580,7 +580,7 @@ private ModelBuilderResult build( resultModel = fireEvent(resultModel, request, problems, ModelBuildingListener::buildExtensionsAssembled); - if (request.isProcessPlugins()) { + if (request.getRequestType() != ModelBuilderRequest.RequestType.DEPENDENCY) { if (lifecycleBindingsInjector == null) { throw new IllegalStateException("lifecycle bindings injector is missing"); } @@ -597,7 +597,7 @@ private ModelBuilderResult build( resultModel = modelNormalizer.injectDefaultValues(resultModel, request, problems); - if (request.isProcessPlugins()) { + if (request.getRequestType() != ModelBuilderRequest.RequestType.DEPENDENCY) { // plugins configuration resultModel = pluginConfigurationExpander.expandPluginConfiguration(resultModel, request, problems); } @@ -609,7 +609,13 @@ private ModelBuilderResult build( result.setEffectiveModel(resultModel); // effective model validation - modelValidator.validateEffectiveModel(resultModel, request, problems); + modelValidator.validateEffectiveModel( + resultModel, + request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM + ? ModelValidator.VALIDATION_LEVEL_STRICT + : ModelValidator.VALIDATION_LEVEL_MINIMAL, + request, + problems); if (hasModelErrors(problems)) { throw problems.newModelBuilderException(); @@ -633,7 +639,7 @@ public Result buildRawModel(Path pomFile, int validationLevel, public Result buildRawModel( Path pomFile, int validationLevel, boolean locationTracking, DefaultModelTransformerContext context) { final ModelBuilderRequest request = ModelBuilderRequest.builder() - .validationLevel(validationLevel) + .requestType(ModelBuilderRequest.RequestType.DEPENDENCY) .locationTracking(locationTracking) .source(ModelSource.fromPath(pomFile)) .build(); @@ -642,7 +648,7 @@ public Result buildRawModel( Model model = readFileModel(request, problems); try { - if (context != null && request.isProjectBuild()) { + if (context != null && request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { buildModelTransformer.transform(context, model, pomFile); } } catch (ModelBuilderException e) { @@ -669,7 +675,7 @@ private Model doReadFileModel(ModelSource modelSource, ModelBuilderRequest reque Model model; problems.setSource(modelSource.getLocation()); try { - boolean strict = request.getValidationLevel() >= ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_2_0; + boolean strict = request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM; Path rootDirectory; try { @@ -702,7 +708,9 @@ private Model doReadFileModel(ModelSource modelSource, ModelBuilderRequest reque throw e; } - Severity severity = request.isProjectBuild() ? Severity.ERROR : Severity.WARNING; + Severity severity = request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM + ? Severity.ERROR + : Severity.WARNING; problems.add( severity, ModelProblem.Version.V20, @@ -747,7 +755,7 @@ private Model doReadFileModel(ModelSource modelSource, ModelBuilderRequest reque throw problems.newModelBuilderException(); } - if (request.isProjectBuild()) { + if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { model = model.withPomFile(modelSource.getPath()); Parent parent = model.getParent(); @@ -816,12 +824,18 @@ private Model doReadFileModel(ModelSource modelSource, ModelBuilderRequest reque } problems.setSource(model); - modelValidator.validateFileModel(model, request, problems); + modelValidator.validateFileModel( + model, + request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM + ? ModelValidator.VALIDATION_LEVEL_STRICT + : ModelValidator.VALIDATION_LEVEL_MINIMAL, + request, + problems); if (hasFatalErrors(problems)) { throw problems.newModelBuilderException(); } - if (request.isProjectBuild()) { + if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { DefaultModelTransformerContext context = getTransformerContext(request, problems); context.putSource(getGroupId(model), model.getArtifactId(), modelSource); } @@ -841,7 +855,8 @@ Model readRawModel(ModelBuilderRequest request, ModelProblemCollector problems) private Model doReadRawModel(ModelSource modelSource, ModelBuilderRequest request, ModelProblemCollector problems) throws ModelBuilderException { Model rawModel = readFileModel(request, problems); - if (!MODEL_VERSION_4_0_0.equals(rawModel.getModelVersion()) && request.isProjectBuild()) { + if (!MODEL_VERSION_4_0_0.equals(rawModel.getModelVersion()) + && request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { Path pomFile = modelSource.getPath(); DefaultModelTransformerContext context = getTransformerContext(request, problems); @@ -869,7 +884,13 @@ private Model doReadRawModel(ModelSource modelSource, ModelBuilderRequest reques rawModel = transformer.transformRawModel(rawModel); } - modelValidator.validateRawModel(rawModel, request, problems); + modelValidator.validateRawModel( + rawModel, + request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM + ? ModelValidator.VALIDATION_LEVEL_STRICT + : ModelValidator.VALIDATION_LEVEL_MINIMAL, + request, + problems); if (hasFatalErrors(problems)) { throw problems.newModelBuilderException(); @@ -921,7 +942,7 @@ private DefaultProfileActivationContext getProfileActivationContext(ModelBuilder } private void checkPluginVersions(List lineage, ModelBuilderRequest request, ModelProblemCollector problems) { - if (request.getValidationLevel() < ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_2_0) { + if (request.getRequestType() != ModelBuilderRequest.RequestType.BUILD_POM) { return; } @@ -1202,10 +1223,8 @@ private ModelData readParentExternally( throw problems.newModelBuilderException(); } - int validationLevel = Math.min(request.getValidationLevel(), ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_2_0); ModelBuilderRequest lenientRequest = ModelBuilderRequest.builder(request) - .validationLevel(validationLevel) - .projectBuild(false) + .requestType(ModelBuilderRequest.RequestType.PARENT_POM) .source(modelSource) .build(); @@ -1451,7 +1470,7 @@ private Model doLoadDependencyManagement( } catch (IllegalStateException e) { rootDirectory = null; } - if (request.isProjectBuild() && rootDirectory != null) { + if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM && rootDirectory != null) { Path sourcePath = importSource.getPath(); if (sourcePath != null && sourcePath.startsWith(rootDirectory)) { problems.add( @@ -1466,7 +1485,7 @@ private Model doLoadDependencyManagement( try { ModelBuilderRequest importRequest = ModelBuilderRequest.builder() .session(request.getSession()) - .validationLevel(ModelBuilderRequest.VALIDATION_LEVEL_MINIMAL) + .requestType(ModelBuilderRequest.RequestType.DEPENDENCY) .systemProperties(request.getSystemProperties()) .userProperties(request.getUserProperties()) .source(importSource) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelInterpolator.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelInterpolator.java index 53262e4b8a0b..ea2eee3ead76 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelInterpolator.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelInterpolator.java @@ -148,7 +148,7 @@ private InnerInterpolator createInterpolator( } protected List 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 @@ protected List createValueSources( 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! diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelValidator.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelValidator.java index 07c26da3c969..db4ec5a64280 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelValidator.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelValidator.java @@ -298,10 +298,42 @@ public DefaultModelValidator(ModelVersionProcessor versionProcessor) { @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 minProfileIds = new HashSet<>(); for (Profile profile : m.getProfiles()) { @@ -316,7 +348,7 @@ public void validateFileModel(Model m, ModelBuilderRequest request, ModelProblem profile); } } - } else if (request.getValidationLevel() >= ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_2_0) { + } else if (validationLevel >= ModelValidator.VALIDATION_LEVEL_MAVEN_2_0) { Set modules = new HashSet<>(); for (int i = 0, n = m.getModules().size(); i < n; i++) { String module = m.getModules().get(i); @@ -387,7 +419,7 @@ public void validateFileModel(Model m, ModelBuilderRequest request, ModelProblem } } - 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 +440,8 @@ public void validateFileModel(Model m, ModelBuilderRequest request, ModelProblem 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 +452,35 @@ public void validateFileModel(Model m, ModelBuilderRequest request, ModelProblem 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 +505,12 @@ public void validateFileModel(Model m, ModelBuilderRequest request, ModelProblem 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 +518,40 @@ public void validateFileModel(Model m, ModelBuilderRequest request, ModelProblem 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 +559,8 @@ public void validateFileModel(Model m, ModelBuilderRequest request, ModelProblem } @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 +675,9 @@ private void validate20RawPlugins( List 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 index = new HashMap<>(); @@ -690,7 +756,8 @@ private void validate20RawPlugins( @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 +806,17 @@ public void validateEffectiveModel(Model m, ModelBuilderRequest request, ModelPr 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 +853,13 @@ public void validateEffectiveModel(Model m, ModelBuilderRequest request, ModelPr "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 +881,18 @@ public void validateEffectiveModel(Model m, ModelBuilderRequest request, ModelPr 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 +917,13 @@ public void validateEffectiveModel(Model m, ModelBuilderRequest request, ModelPr } 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 +940,16 @@ public void validateEffectiveModel(Model m, ModelBuilderRequest request, ModelPr } validate20EffectiveRepository( - problems, distMgmt.getRepository(), "distributionManagement.repository.", request); + problems, + distMgmt.getRepository(), + "distributionManagement.repository.", + validationLevel, + request); validate20EffectiveRepository( problems, distMgmt.getSnapshotRepository(), "distributionManagement.snapshotRepository.", + validationLevel, request); } } @@ -875,9 +960,10 @@ private void validate20RawDependencies( List 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 index = new HashMap<>(); @@ -907,7 +993,7 @@ private void validate20RawDependencies( } } 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 +1101,16 @@ private void validateEffectiveDependencies( Model m, List 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 +1174,16 @@ private void validateEffectiveModelAgainstDependency( } private void validate20EffectivePluginDependencies( - ModelProblemCollector problems, Plugin plugin, ModelBuilderRequest request) { + ModelProblemCollector problems, Plugin plugin, int validationLevel, ModelBuilderRequest request) { List 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 +1209,7 @@ private void validateEffectiveDependency( Dependency d, boolean management, String prefix, + int validationLevel, ModelBuilderRequest request) { validateCoordinatesId( prefix, @@ -1194,9 +1282,9 @@ private void validateEffectiveDependency( 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 +1342,7 @@ private void validateRawRepositories( List repositories, String prefix, String prefix2, + int validationLevel, ModelBuilderRequest request) { Map index = new HashMap<>(); @@ -1292,7 +1381,7 @@ private void validateRawRepositories( 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 +1399,13 @@ private void validateRawRepositories( } 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 +1444,12 @@ private void validate20EffectiveRepository( } private void validate20RawResources( - ModelProblemCollector problems, List resources, String prefix, ModelBuilderRequest request) { - Severity errOn30 = getSeverity(request, ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_3_0); + ModelProblemCollector problems, + List resources, + String prefix, + int validationLevel, + ModelBuilderRequest request) { + Severity errOn30 = getSeverity(validationLevel, ModelValidator.VALIDATION_LEVEL_MAVEN_3_0); for (Resource resource : resources) { validateStringNotEmpty( @@ -1940,13 +2037,14 @@ private boolean validate20PluginVersion( 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; } - 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 +2124,6 @@ private static boolean equals(String s1, String s2) { 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; diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java index 3c5ebfdbf586..972a0d86755a 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java @@ -196,8 +196,7 @@ private Model loadPom( ModelResolver modelResolver = new DefaultModelResolver(); ModelBuilderRequest modelRequest = ModelBuilderRequest.builder() .session(iSession) - .projectBuild(false) - .processPlugins(false) + .requestType(ModelBuilderRequest.RequestType.DEPENDENCY) .twoPhaseBuilding(false) .source(ModelSource.fromPath(pomArtifact.getPath(), gav)) // This merge is on purpose because otherwise user properties would override model diff --git a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/TestApiStandalone.java b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/TestApiStandalone.java index 5eec24147c4b..2d74bb9a9344 100644 --- a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/TestApiStandalone.java +++ b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/TestApiStandalone.java @@ -45,7 +45,7 @@ void testStandalone() { ModelBuilderResult result = builder.build(ModelBuilderRequest.builder() .session(session) .source(ModelSource.fromPath(Paths.get("pom.xml").toAbsolutePath())) - .projectBuild(true) + .requestType(ModelBuilderRequest.RequestType.BUILD_POM) .build()); assertNotNull(result.getEffectiveModel()); diff --git a/maven-compat/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java b/maven-compat/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java index 68d6827b7a7f..b57e953200b7 100644 --- a/maven-compat/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java +++ b/maven-compat/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java @@ -117,7 +117,7 @@ protected MavenProject getProjectWithDependencies(File pom) throws Exception { ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest(); configuration.setLocalRepository(getLocalRepository()); configuration.setRemoteRepositories(Arrays.asList(new ArtifactRepository[] {})); - configuration.setProcessPlugins(false); + configuration.setProcessPlugins(true); configuration.setResolveDependencies(true); initRepoSession(configuration); diff --git a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java index 2a8ca38cfbe8..032b53faa3b7 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java @@ -200,10 +200,9 @@ public List getActiveProfiles( modelCacheFactory); 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.systemProperties(session.getSystemProperties()); diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultModelBuildingListener.java b/maven-core/src/main/java/org/apache/maven/project/DefaultModelBuildingListener.java index eef005b51749..64f8244b944d 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultModelBuildingListener.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultModelBuildingListener.java @@ -22,6 +22,7 @@ import java.util.Objects; import org.apache.maven.api.services.BuilderProblem; +import org.apache.maven.api.services.ModelBuilderRequest; import org.apache.maven.api.services.ModelProblem; import org.apache.maven.api.services.model.ModelBuildingEvent; import org.apache.maven.api.services.model.ModelBuildingListener; @@ -86,7 +87,7 @@ public void buildExtensionsAssembled(ModelBuildingEvent event) { } project.setPluginArtifactRepositories(pluginRepositories); - if (event.request().isProcessPlugins()) { + if (event.request().getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { try { ProjectRealmCache.CacheRecord record = projectBuildingHelper.createProjectRealm(project, model, projectBuildingRequest); diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index 48e2708ec3cf..f840bc4dbb8a 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -91,6 +91,7 @@ import org.apache.maven.internal.impl.InternalSession; import org.apache.maven.model.building.DefaultModelProblem; import org.apache.maven.model.building.FileModelSource; +import org.apache.maven.model.building.ModelBuildingRequest; import org.apache.maven.model.building.ModelSource2; import org.apache.maven.model.building.ModelSource3; import org.apache.maven.model.resolution.UnresolvableModelException; @@ -482,9 +483,14 @@ ProjectBuildingResult build(Path pomFile, ModelSource modelSource) throws Projec new DefaultModelBuildingListener(project, projectBuildingHelper, this.request); ModelBuilderRequest.ModelBuilderRequestBuilder builder = getModelBuildingRequest(); - ModelBuilderRequest request = builder.projectBuild(modelPool != null) - .source(modelSource) - .projectBuild(pomFile != null) + ModelBuilderRequest request = builder.source(modelSource) + .requestType( + pomFile != null + && this.request.isProcessPlugins() + && this.request.getValidationLevel() + == ModelBuildingRequest.VALIDATION_LEVEL_STRICT + ? ModelBuilderRequest.RequestType.BUILD_POM + : ModelBuilderRequest.RequestType.DEPENDENCY) .locationTracking(true) .listener(listener) .build(); @@ -661,7 +667,7 @@ private InterimResult build( ModelBuilderRequest modelBuildingRequest = getModelBuildingRequest() .source(ModelSource.fromPath(pomFile.toPath())) - .projectBuild(true) + .requestType(ModelBuilderRequest.RequestType.BUILD_POM) .twoPhaseBuilding(true) .locationTracking(true) .listener(listener) @@ -1172,9 +1178,7 @@ private ModelBuilderRequest.ModelBuilderRequestBuilder getModelBuildingRequest() InternalSession internalSession = InternalSession.from(session); modelBuildingRequest.session(internalSession); - modelBuildingRequest.projectBuild(true); - modelBuildingRequest.validationLevel(request.getValidationLevel()); - modelBuildingRequest.processPlugins(request.isProcessPlugins()); + modelBuildingRequest.requestType(ModelBuilderRequest.RequestType.BUILD_POM); modelBuildingRequest.profiles( request.getProfiles() != null ? request.getProfiles().stream() diff --git a/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java b/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java index 40117047a6d9..9e0e9a0346f1 100644 --- a/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java +++ b/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java @@ -69,22 +69,18 @@ void setupTransformerContext() throws Exception { // 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); - DefaultModelBuilder modelBuilder = (DefaultModelBuilder) getContainer().lookup(ModelBuilder.class); + // set up the transformers + List transformers = List.of(new CIFriendlyVersionModelTransformer(iSession)); Field transformersField = DefaultModelBuilder.class.getDeclaredField("transformers"); transformersField.setAccessible(true); - transformersField.set(modelBuilder, List.of(new CIFriendlyVersionModelTransformer(iSession))); - // ModelTransformerContextBuilder tcb = modelBuilder.newTransformerContextBuilder(); - // ModelTransformerContext context = tcb.initialize( - // ModelBuilderRequest.builder() - // .projectBuild(true) - // .session(iSession) - // .transformerContextBuilder(tcb) - // .build(), - // modelBuilder.newCollector()); - // iSession.getData().set(ModelTransformerContext.KEY, context); + 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()); } From 4cd8f4ef6b6f4939ffce65d097b384d210f34d1b Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 6 Sep 2024 08:35:25 +0200 Subject: [PATCH 15/63] Restrict `Project` to the buildable projects, i.e. from the filesystem so that getBasedir() and getPomPath() always return a valid directory That means that getParent() will return an empty optional if the parent not in the reactor. --- .../src/main/java/org/apache/maven/api/Project.java | 7 +++++++ .../main/java/org/apache/maven/internal/impl/Utils.java | 3 ++- .../java/org/apache/maven/internal/impl/DefaultEvent.java | 2 +- .../org/apache/maven/internal/impl/DefaultProject.java | 2 +- .../apache/maven/internal/impl/DefaultProjectBuilder.java | 2 +- .../org/apache/maven/internal/impl/DefaultSession.java | 4 +++- .../apache/maven/internal/impl/InternalMavenSession.java | 5 +++++ .../org/apache/maven/project/DefaultProjectBuilder.java | 4 +++- 8 files changed, 23 insertions(+), 6 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Project.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Project.java index 47342ce8a7ec..219e21f2469b 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Project.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Project.java @@ -224,6 +224,13 @@ default String getId() { /** * Returns project parent project, if any. + *

+ * 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 getParent(); diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/Utils.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/Utils.java index 0d0d43c32f93..2fb4ad3d338c 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/Utils.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/Utils.java @@ -20,6 +20,7 @@ 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 @@ static T cast(Class clazz, Object o, String name) { } static List map(Collection list, Function mapper) { - return list.stream().map(mapper).collect(Collectors.toList()); + return list.stream().map(mapper).filter(Objects::nonNull).collect(Collectors.toList()); } } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultEvent.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultEvent.java index 2f4cf648c832..2f03e6654333 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultEvent.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultEvent.java @@ -48,7 +48,7 @@ public Session getSession() { @Override public Optional getProject() { - return Optional.ofNullable(delegate.getProject()).map(session::getProject); + return Optional.ofNullable(session.getProject(delegate.getProject())); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java index ba1c6d708fc8..359f84094a12 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java @@ -159,7 +159,7 @@ public Path getRootDirectory() { @Override public Optional getParent() { MavenProject parent = project.getParent(); - return parent != null ? Optional.of(session.getProject(parent)) : Optional.empty(); + return Optional.ofNullable(session.getProject(parent)); } @Nonnull diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProjectBuilder.java index a446f63b26ee..efc6d3e7855a 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProjectBuilder.java @@ -100,7 +100,7 @@ public Optional getPomFile() { @Nonnull @Override public Optional getProject() { - return Optional.ofNullable(res.getProject()).map(session::getProject); + return Optional.ofNullable(session.getProject(res.getProject())); } @Nonnull diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSession.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSession.java index cd83f7c44921..a931b9874ba7 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSession.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSession.java @@ -93,7 +93,9 @@ public List getProjects(List projects) { @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 diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/InternalMavenSession.java b/maven-core/src/main/java/org/apache/maven/internal/impl/InternalMavenSession.java index 1ee399c6c040..4df67943e8ea 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/InternalMavenSession.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/InternalMavenSession.java @@ -23,6 +23,7 @@ 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; @@ -35,6 +36,10 @@ static InternalMavenSession from(Session session) { List getProjects(List projects); + /** + * May return null if the input projcet is null or is not part of the reactor. + */ + @Nullable Project getProject(org.apache.maven.project.MavenProject project); List toArtifactRepositories( diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index f840bc4dbb8a..4c8c9080dc0b 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -692,7 +692,9 @@ private InterimResult build( // In case the model is using CI friendly versions, at this point, it will contain uninterpolated version // such as ${revision}${changelist}, so we need to take care of it now Model modelWithVersion = getModelWithInterpolatedVersion(model, result.getProblems()::add); - modelPool.put(model.getPomFile(), modelWithVersion); + if (model.getPomFile() != null) { + modelPool.put(model.getPomFile(), modelWithVersion); + } InterimResult interimResult = new InterimResult(pomFile, modelBuildingRequest, result, project, isRoot); From 4abc430825734a1078731f5461d90d4ae14aa32b Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 6 Sep 2024 16:33:17 +0200 Subject: [PATCH 16/63] Introduce ModelBuilderSession # Conflicts: # maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java # Conflicts: # maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContext.java --- .../maven/api/services/ModelBuilder.java | 7 +- .../impl/model/DefaultModelBuilder.java | 1016 ++++++++++++----- .../model/DefaultModelTransformerContext.java | 266 ----- .../DefaultArtifactDescriptorReader.java | 2 +- .../impl/standalone/TestApiStandalone.java | 11 +- .../impl/DefaultConsumerPomBuilder.java | 3 +- .../maven/project/DefaultProjectBuilder.java | 11 +- .../maven/project/ReactorModelPool.java | 4 +- .../apache/maven/model/ModelBuilderTest.java | 2 + .../org/apache/maven/model/BaseObject.java | 4 +- 10 files changed, 730 insertions(+), 596 deletions(-) delete mode 100644 maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContext.java diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilder.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilder.java index f2e4f5702c97..4362353185e0 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilder.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilder.java @@ -31,7 +31,12 @@ public interface ModelBuilder extends Service { List VALID_MODEL_VERSIONS = List.of(MODEL_VERSION_4_0_0, MODEL_VERSION_4_1_0); - ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilderException; + ModelBuilderSession newSession(); + + interface ModelBuilderSession { + + ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilderException; + } Model buildRawModel(ModelBuilderRequest request); } diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 9932a9b90378..ab2e11d105e1 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -27,7 +27,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.EnumSet; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; @@ -35,7 +37,9 @@ import java.util.Objects; import java.util.Optional; import java.util.Properties; +import java.util.Set; import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiConsumer; import java.util.function.Supplier; @@ -43,6 +47,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.maven.api.Session; import org.apache.maven.api.SessionData; import org.apache.maven.api.Type; import org.apache.maven.api.VersionRange; @@ -64,6 +69,7 @@ import org.apache.maven.api.model.Plugin; import org.apache.maven.api.model.PluginManagement; import org.apache.maven.api.model.Profile; +import org.apache.maven.api.services.BuilderProblem; import org.apache.maven.api.services.BuilderProblem.Severity; import org.apache.maven.api.services.ModelBuilder; import org.apache.maven.api.services.ModelBuilderException; @@ -99,6 +105,7 @@ import org.apache.maven.api.services.model.ProfileSelector; import org.apache.maven.api.services.xml.XmlReaderException; import org.apache.maven.api.services.xml.XmlReaderRequest; +import org.apache.maven.api.spi.ModelParserException; import org.apache.maven.api.spi.ModelTransformer; import org.apache.maven.api.spi.ModelTransformerException; import org.apache.maven.internal.impl.resolver.DefaultModelRepositoryHolder; @@ -144,7 +151,6 @@ public class DefaultModelBuilder implements ModelBuilder { private final LifecycleBindingsInjector lifecycleBindingsInjector; private final PluginConfigurationExpander pluginConfigurationExpander; private final ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator; - private final BuildModelTransformer buildModelTransformer; private final ModelVersionParser versionParser; private final List transformers; private final ModelCacheFactory modelCacheFactory; @@ -187,24 +193,478 @@ public DefaultModelBuilder( this.lifecycleBindingsInjector = lifecycleBindingsInjector; this.pluginConfigurationExpander = pluginConfigurationExpander; this.profileActivationFilePathInterpolator = profileActivationFilePathInterpolator; - this.buildModelTransformer = new BuildModelTransformer(); this.versionParser = versionParser; this.transformers = transformers; this.modelCacheFactory = modelCacheFactory; } - @Override - public ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilderException { - request = fillRequestDefaults(request); - if (request.getInterimResult() != null) { - return build(request, request.getInterimResult(), new LinkedHashSet<>()); - } else { - return build(request, new LinkedHashSet<>()); - } + public ModelBuilderSession newSession() { + return new ModelBuilderSession() { + DefaultModelBuilderSession mainSession; + + @Override + public ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilderException { + request = fillRequestDefaults(request); + if (request.getInterimResult() != null) { + if (mainSession == null) { + throw new IllegalStateException("ModelBuilderSession is not initialized"); + } + DefaultModelBuilderResult result = asDefaultModelBuilderResult(request.getInterimResult()); + return DefaultModelBuilder.this.build2(mainSession.derive(request, result), new LinkedHashSet<>()); + } else { + DefaultModelBuilderSession session; + if (mainSession == null) { + mainSession = new DefaultModelBuilderSession(request); + session = mainSession; + } else { + session = mainSession.derive(request, new DefaultModelBuilderResult()); + } + return DefaultModelBuilder.this.build(session, new LinkedHashSet<>()); + } + } + }; } - public ModelProblemCollector newCollector() { - return newCollector(new DefaultModelBuilderResult()); + protected final class DefaultModelBuilderSession implements ModelProblemCollector { + final Session session; + final ModelBuilderRequest request; + final DefaultModelBuilderResult result; + final ModelCache cache; + final Graph dag; + final Map modelByPath; + final Map modelByGA; + final Map> mappedSources; + + private String source; + private Model sourceModel; + private Model rootModel; + + private Set severities = EnumSet.noneOf(ModelProblem.Severity.class); + + volatile boolean fullReactorLoaded; + + DefaultModelBuilderSession(ModelBuilderRequest request) { + this(request, new DefaultModelBuilderResult()); + } + + DefaultModelBuilderSession(ModelBuilderRequest request, DefaultModelBuilderResult result) { + this(request.getSession(), request, result); + } + + DefaultModelBuilderSession(Session session, ModelBuilderRequest request, DefaultModelBuilderResult result) { + this( + session, + request, + result, + session.getData() + .computeIfAbsent(SessionData.key(ModelCache.class), modelCacheFactory::newInstance)); + } + + DefaultModelBuilderSession( + Session session, ModelBuilderRequest request, DefaultModelBuilderResult result, ModelCache cache) { + this( + session, + request, + result, + cache, + new Graph(), + new ConcurrentHashMap<>(64), + new ConcurrentHashMap<>(64), + new ConcurrentHashMap<>(64)); + } + + @SuppressWarnings("checkstyle:ParameterNumber") + private DefaultModelBuilderSession( + Session session, + ModelBuilderRequest request, + DefaultModelBuilderResult result, + ModelCache cache, + Graph dag, + Map modelByPath, + Map modelByGA, + Map> mappedSources) { + this.session = session; + this.request = request; + this.result = result; + this.cache = cache; + this.dag = dag; + this.modelByPath = modelByPath; + this.modelByGA = modelByGA; + this.mappedSources = mappedSources; + this.result.getProblems().forEach(p -> severities.add(p.getSeverity())); + } + + public DefaultModelBuilderSession derive(ModelSource source) { + return derive(ModelBuilderRequest.build(request, source), result); + } + + public DefaultModelBuilderSession derive(ModelBuilderRequest request, DefaultModelBuilderResult result) { + if (session != request.getSession()) { + throw new IllegalArgumentException("Session mismatch"); + } + return new DefaultModelBuilderSession( + session, request, result, cache, dag, modelByPath, modelByGA, mappedSources); + } + + public Session session() { + return session; + } + + public ModelBuilderRequest request() { + return request; + } + + public DefaultModelBuilderResult result() { + return result; + } + + public ModelCache cache() { + return cache; + } + + @Override + public String toString() { + return "ModelBuilderSession[" + "session=" + + session + ", " + "request=" + + request + ", " + "result=" + + result + ", " + "cache=" + + cache + ']'; + } + + static class Holder { + private volatile boolean set; + private volatile Model model; + + Holder(Model model) { + this.model = 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 supplier) { + if (!set) { + synchronized (this) { + if (!set) { + this.set = true; + this.model = supplier.get(); + this.notifyAll(); + } + } + } + return model; + } + } + + public Model getRawModel(Path from, String gId, String aId) { + Model model = findRawModel(from, gId, aId); + if (model != null) { + modelByGA.put(new GAKey(gId, aId), new Holder(model)); + if (model.getPomFile() != null) { + modelByPath.put(model.getPomFile(), new Holder(model)); + } + } + return model; + } + + public Model getRawModel(Path from, Path path) { + Model model = findRawModel(from, path); + if (model != null) { + String groupId = getGroupId(model); + modelByGA.put(new GAKey(groupId, model.getArtifactId()), new Holder(model)); + modelByPath.put(path, new Holder(model)); + } + return model; + } + + public Path locate(Path path) { + return getModelProcessor().locateExistingPom(path); + } + + 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())) { + return null; + } + try { + return readRawModel(derive(source)); + } catch (ModelBuilderException e) { + // gathered with problem collector + } + } + return null; + } + + private void loadFullReactor() { + if (!fullReactorLoaded) { + synchronized (this) { + if (!fullReactorLoaded) { + doLoadFullReactor(); + fullReactorLoaded = true; + } + } + } + } + + private void doLoadFullReactor() { + Path rootDirectory; + try { + rootDirectory = session().getRootDirectory(); + } catch (IllegalStateException e) { + // if no root directory, bail out + return; + } + List toLoad = new ArrayList<>(); + Path root = getModelProcessor().locateExistingPom(rootDirectory); + toLoad.add(root); + while (!toLoad.isEmpty()) { + Path pom = toLoad.remove(0); + try { + Model rawModel = readFileModel(derive(ModelSource.fromPath(pom))); + List subprojects = rawModel.getSubprojects(); + if (subprojects.isEmpty()) { + subprojects = rawModel.getModules(); + } + for (String subproject : subprojects) { + Path subprojectFile = getModelProcessor() + .locateExistingPom(pom.getParent().resolve(subproject)); + if (subprojectFile != null) { + toLoad.add(subprojectFile); + } + } + } catch (ModelBuilderException e) { + // gathered with problem collector + add(Severity.ERROR, ModelProblem.Version.V40, "Failed to load project " + pom, e); + } + } + } + + private Model findRawModel(Path from, Path p) { + if (!Files.isRegularFile(p)) { + throw new IllegalArgumentException("Not a regular file: " + p); + } + if (!addEdge(from, p)) { + return null; + } + try { + return readRawModel(derive(ModelSource.fromPath(p))); + } catch (ModelBuilderException e) { + // gathered with problem collector + } + return null; + } + + private boolean addEdge(Path from, Path p) { + try { + dag.addEdge(from.toString(), p.toString()); + return true; + } catch (Graph.CycleDetectedException e) { + add(new DefaultModelProblem( + "Cycle detected between models at " + from + " and " + p, + Severity.FATAL, + null, + null, + 0, + 0, + null, + e)); + return false; + } + } + + public ModelSource getSource(String groupId, String artifactId) { + Set sources; + if (groupId != null) { + sources = mappedSources.get(new GAKey(groupId, artifactId)); + if (sources == null) { + return null; + } + } else if (artifactId != null) { + sources = mappedSources.get(new GAKey(null, 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(new GAKey(groupId, artifactId), k -> new HashSet<>()) + .add(source); + if (groupId != null) { + mappedSources + .computeIfAbsent(new GAKey(null, artifactId), k -> new HashSet<>()) + .add(source); + } + } + + 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 getProblems() { + return result.getProblems(); + } + + 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; + } + } + + public 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) { + result.getProblems().add(problem); + + severities.add(problem.getSeverity()); + } + + public void addAll(Collection problems) { + this.result.getProblems().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); + } } DefaultModelProblemCollector newCollector(DefaultModelBuilderResult result) { @@ -229,45 +689,40 @@ private static ModelBuilderRequest fillRequestDefaults(ModelBuilderRequest reque return builder.build(); } - protected ModelBuilderResult build(ModelBuilderRequest request, Collection importIds) + protected ModelBuilderResult build(DefaultModelBuilderSession build, Collection importIds) throws ModelBuilderException { // phase 1 - DefaultModelBuilderResult result = new DefaultModelBuilderResult(); - - ModelProblemCollector problems = newCollector(result); + ModelBuilderRequest request = build.request; + DefaultModelBuilderResult result = build.result; // read and validate raw model - Model fileModel = readFileModel(request, problems); + Model fileModel = readFileModel(build); result.setFileModel(fileModel); - Model activatedFileModel = activateFileModel(fileModel, request, result, problems); + Model activatedFileModel = activateFileModel(build, fileModel); result.setActivatedFileModel(activatedFileModel); if (!request.isTwoPhaseBuilding()) { - return build(request, result, importIds); - } else if (hasModelErrors(problems)) { - throw problems.newModelBuilderException(); + return build2(build, importIds); + } else if (hasModelErrors(build)) { + throw build.newModelBuilderException(); } return result; } - private Model activateFileModel( - Model inputModel, - ModelBuilderRequest request, - DefaultModelBuilderResult result, - ModelProblemCollector problems) - throws ModelBuilderException { - problems.setRootModel(inputModel); + private Model activateFileModel(DefaultModelBuilderSession build, Model inputModel) throws ModelBuilderException { + build.setRootModel(inputModel); // profile activation - DefaultProfileActivationContext profileActivationContext = getProfileActivationContext(request, inputModel); + DefaultProfileActivationContext profileActivationContext = + getProfileActivationContext(build.request, inputModel); - problems.setSource("(external profiles)"); + build.setSource("(external profiles)"); List activeExternalProfiles = - profileSelector.getActiveProfiles(request.getProfiles(), profileActivationContext, problems); + profileSelector.getActiveProfiles(build.request.getProfiles(), profileActivationContext, build); - result.setActiveExternalProfiles(activeExternalProfiles); + build.result.setActiveExternalProfiles(activeExternalProfiles); if (!activeExternalProfiles.isEmpty()) { Properties profileProps = new Properties(); @@ -279,38 +734,38 @@ private Model activateFileModel( } profileActivationContext.setProjectProperties(inputModel.getProperties()); - problems.setSource(inputModel); + build.setSource(inputModel); List activePomProfiles = - profileSelector.getActiveProfiles(inputModel.getProfiles(), profileActivationContext, problems); + profileSelector.getActiveProfiles(inputModel.getProfiles(), profileActivationContext, build); // model normalization - problems.setSource(inputModel); - inputModel = modelNormalizer.mergeDuplicates(inputModel, request, problems); + build.setSource(inputModel); + inputModel = modelNormalizer.mergeDuplicates(inputModel, build.request, build); Map interpolatedActivations = getProfileActivations(inputModel); inputModel = injectProfileActivations(inputModel, interpolatedActivations); // profile injection - inputModel = profileInjector.injectProfiles(inputModel, activePomProfiles, request, problems); - inputModel = profileInjector.injectProfiles(inputModel, activeExternalProfiles, request, problems); + inputModel = profileInjector.injectProfiles(inputModel, activePomProfiles, build.request, build); + inputModel = profileInjector.injectProfiles(inputModel, activeExternalProfiles, build.request, build); return inputModel; } @SuppressWarnings("checkstyle:methodlength") - private Model readEffectiveModel( - final ModelBuilderRequest request, - final DefaultModelBuilderResult result, - final ModelProblemCollector problems) - throws ModelBuilderException { - Model inputModel = readRawModel(request, problems); - if (problems.hasFatalErrors()) { - throw problems.newModelBuilderException(); + private Model readEffectiveModel(final DefaultModelBuilderSession build) throws ModelBuilderException { + + ModelBuilderRequest request = build.request; + DefaultModelBuilderResult result = build.result; + + Model inputModel = readRawModel(build); + if (build.hasFatalErrors()) { + throw build.newModelBuilderException(); } - inputModel = activateFileModel(inputModel, request, result, problems); + inputModel = activateFileModel(build, inputModel); - problems.setRootModel(inputModel); + build.setRootModel(inputModel); ModelData resultData = new ModelData(request.getSource(), inputModel); String superModelVersion = @@ -347,24 +802,24 @@ private Model readEffectiveModel( Model model = currentData.model(); result.setRawModel(modelId, model); - problems.setSource(model); + build.setSource(model); // model normalization - model = modelNormalizer.mergeDuplicates(model, request, problems); + model = modelNormalizer.mergeDuplicates(model, request, build); // profile activation profileActivationContext.setProjectProperties(model.getProperties()); List interpolatedProfiles = - interpolateActivations(model.getProfiles(), profileActivationContext, problems); + interpolateActivations(model.getProfiles(), profileActivationContext, build); // profile injection List activePomProfiles = - profileSelector.getActiveProfiles(interpolatedProfiles, profileActivationContext, problems); + profileSelector.getActiveProfiles(interpolatedProfiles, profileActivationContext, build); result.setActivePomProfiles(modelId, activePomProfiles); - model = profileInjector.injectProfiles(model, activePomProfiles, request, problems); + model = profileInjector.injectProfiles(model, activePomProfiles, request, build); if (currentData == resultData) { - model = profileInjector.injectProfiles(model, activeExternalProfiles, request, problems); + model = profileInjector.injectProfiles(model, activeExternalProfiles, request, build); } lineage.add(model); @@ -390,7 +845,7 @@ private Model readEffectiveModel( } // we pass a cloned model, so that resolving the parent version does not affect the returned model - ModelData parentData = readParent(model, currentData.source(), request, problems); + ModelData parentData = readParent(build, model, currentData.source()); if (parentData == null) { currentData = superData; @@ -401,9 +856,9 @@ private Model readEffectiveModel( } message.append(parentData.id()); - problems.add(Severity.FATAL, ModelProblem.Version.BASE, message.toString()); + build.add(Severity.FATAL, ModelProblem.Version.BASE, message.toString()); - throw problems.newModelBuilderException(); + throw build.newModelBuilderException(); } else { currentData = parentData; } @@ -412,28 +867,28 @@ private Model readEffectiveModel( Model tmpModel = lineage.get(0); // inject interpolated activations - List interpolated = interpolateActivations(tmpModel.getProfiles(), profileActivationContext, problems); + List interpolated = interpolateActivations(tmpModel.getProfiles(), profileActivationContext, build); if (interpolated != tmpModel.getProfiles()) { tmpModel = tmpModel.withProfiles(interpolated); } // inject external profile into current model - tmpModel = profileInjector.injectProfiles(tmpModel, activeExternalProfiles, request, problems); + tmpModel = profileInjector.injectProfiles(tmpModel, activeExternalProfiles, request, build); lineage.set(0, tmpModel); - checkPluginVersions(lineage, request, problems); + checkPluginVersions(lineage, request, build); // inheritance assembly - Model resultModel = assembleInheritance(lineage, request, problems); + Model resultModel = assembleInheritance(lineage, request, build); // consider caching inherited model - problems.setSource(resultModel); - problems.setRootModel(resultModel); + build.setSource(resultModel); + build.setRootModel(resultModel); // model interpolation - resultModel = interpolateModel(resultModel, request, problems); + resultModel = interpolateModel(resultModel, request, build); // url normalization resultModel = modelUrlNormalizer.normalize(resultModel, request); @@ -547,38 +1002,37 @@ private static boolean isNotEmpty(String string) { public ModelBuilderResult build(final ModelBuilderRequest request, final ModelBuilderResult result) throws ModelBuilderException { - return build(request, result, new LinkedHashSet<>()); + return build( + new DefaultModelBuilderSession(request, (DefaultModelBuilderResult) result), new LinkedHashSet<>()); } public Model buildRawModel(ModelBuilderRequest request) throws ModelBuilderException { request = fillRequestDefaults(request); - ModelProblemCollector problems = newCollector(new DefaultModelBuilderResult()); - Model model = readRawModel(request, problems); - if (hasModelErrors(problems)) { - throw problems.newModelBuilderException(); + DefaultModelBuilderSession build = new DefaultModelBuilderSession(request); + Model model = readRawModel(build); + if (hasModelErrors(build)) { + throw build.newModelBuilderException(); } return model; } - private ModelBuilderResult build( - ModelBuilderRequest request, final ModelBuilderResult phaseOneResult, Collection importIds) + private ModelBuilderResult build2(DefaultModelBuilderSession build, Collection importIds) throws ModelBuilderException { - DefaultModelBuilderResult result = asDefaultModelBuilderResult(phaseOneResult); - - ModelProblemCollector problems = newCollector(result); + ModelBuilderRequest request = build.request; + DefaultModelBuilderResult result = build.result; // phase 2 - Model resultModel = readEffectiveModel(request, result, problems); - problems.setSource(resultModel); - problems.setRootModel(resultModel); + Model resultModel = readEffectiveModel(build); + build.setSource(resultModel); + build.setRootModel(resultModel); // model path translation resultModel = modelPathTranslator.alignToBaseDirectory(resultModel, resultModel.getProjectDirectory(), request); // plugin management injection - resultModel = pluginManagementInjector.injectManagement(resultModel, request, problems); + resultModel = pluginManagementInjector.injectManagement(resultModel, request, build); - resultModel = fireEvent(resultModel, request, problems, ModelBuildingListener::buildExtensionsAssembled); + resultModel = fireEvent(resultModel, request, build, ModelBuildingListener::buildExtensionsAssembled); if (request.getRequestType() != ModelBuilderRequest.RequestType.DEPENDENCY) { if (lifecycleBindingsInjector == null) { @@ -586,20 +1040,20 @@ private ModelBuilderResult build( } // lifecycle bindings injection - resultModel = lifecycleBindingsInjector.injectLifecycleBindings(resultModel, request, problems); + resultModel = lifecycleBindingsInjector.injectLifecycleBindings(resultModel, request, build); } // dependency management import - resultModel = importDependencyManagement(resultModel, request, problems, importIds); + resultModel = importDependencyManagement(build, resultModel, importIds); // dependency management injection - resultModel = dependencyManagementInjector.injectManagement(resultModel, request, problems); + resultModel = dependencyManagementInjector.injectManagement(resultModel, request, build); - resultModel = modelNormalizer.injectDefaultValues(resultModel, request, problems); + resultModel = modelNormalizer.injectDefaultValues(resultModel, request, build); if (request.getRequestType() != ModelBuilderRequest.RequestType.DEPENDENCY) { // plugins configuration - resultModel = pluginConfigurationExpander.expandPluginConfiguration(resultModel, request, problems); + resultModel = pluginConfigurationExpander.expandPluginConfiguration(resultModel, request, build); } for (var transformer : transformers) { @@ -615,10 +1069,10 @@ private ModelBuilderResult build( ? ModelValidator.VALIDATION_LEVEL_STRICT : ModelValidator.VALIDATION_LEVEL_MINIMAL, request, - problems); + build); - if (hasModelErrors(problems)) { - throw problems.newModelBuilderException(); + if (hasModelErrors(build)) { + throw build.newModelBuilderException(); } return result; @@ -632,48 +1086,20 @@ private DefaultModelBuilderResult asDefaultModelBuilderResult(ModelBuilderResult } } - public Result buildRawModel(Path pomFile, int validationLevel, boolean locationTracking) { - return buildRawModel(pomFile, validationLevel, locationTracking, null); - } - - public Result buildRawModel( - Path pomFile, int validationLevel, boolean locationTracking, DefaultModelTransformerContext context) { - final ModelBuilderRequest request = ModelBuilderRequest.builder() - .requestType(ModelBuilderRequest.RequestType.DEPENDENCY) - .locationTracking(locationTracking) - .source(ModelSource.fromPath(pomFile)) - .build(); - ModelProblemCollector problems = newCollector(new DefaultModelBuilderResult()); - try { - Model model = readFileModel(request, problems); - - try { - if (context != null && request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { - buildModelTransformer.transform(context, model, pomFile); - } - } catch (ModelBuilderException e) { - problems.add(Severity.FATAL, ModelProblem.Version.V40, null, e); - } - - return Result.newResult(model, problems.getProblems()); - } catch (ModelBuilderException e) { - return Result.error(problems.getProblems()); + Model readFileModel(DefaultModelBuilderSession build) throws ModelBuilderException { + Model model = cache(build.cache, build.request.getSource(), FILE, () -> doReadFileModel(build)); + if (build.request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { + build.putSource(getGroupId(model), model.getArtifactId(), build.request.getSource()); } - } - - Model readFileModel(ModelBuilderRequest request, ModelProblemCollector problems) throws ModelBuilderException { - ModelSource modelSource = request.getSource(); - Model model = - cache(getModelCache(request), modelSource, FILE, () -> doReadFileModel(modelSource, request, problems)); - return model; } @SuppressWarnings("checkstyle:methodlength") - private Model doReadFileModel(ModelSource modelSource, ModelBuilderRequest request, ModelProblemCollector problems) - throws ModelBuilderException { + private Model doReadFileModel(DefaultModelBuilderSession build) throws ModelBuilderException { + ModelBuilderRequest request = build.request; + ModelSource modelSource = request.getSource(); Model model; - problems.setSource(modelSource.getLocation()); + build.setSource(modelSource.getLocation()); try { boolean strict = request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM; @@ -711,11 +1137,12 @@ private Model doReadFileModel(ModelSource modelSource, ModelBuilderRequest reque Severity severity = request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM ? Severity.ERROR : Severity.WARNING; - problems.add( - severity, - ModelProblem.Version.V20, - "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage(), - e); + ((ModelProblemCollector) build) + .add( + severity, + ModelProblem.Version.V20, + "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage(), + e); } InputLocation loc = model.getLocation(""); @@ -731,12 +1158,13 @@ private Model doReadFileModel(ModelSource modelSource, ModelBuilderRequest reque } } } catch (XmlReaderException e) { - problems.add( - Severity.FATAL, - ModelProblem.Version.BASE, - "Non-parseable POM " + modelSource.getLocation() + ": " + e.getMessage(), - e); - throw problems.newModelBuilderException(); + ((ModelProblemCollector) build) + .add( + Severity.FATAL, + ModelProblem.Version.BASE, + "Non-parseable POM " + modelSource.getLocation() + ": " + e.getMessage(), + e); + throw ((ModelProblemCollector) build).newModelBuilderException(); } catch (IOException e) { String msg = e.getMessage(); if (msg == null || msg.isEmpty()) { @@ -747,12 +1175,13 @@ private Model doReadFileModel(ModelSource modelSource, ModelBuilderRequest reque msg = e.getClass().getSimpleName(); } } - problems.add( - Severity.FATAL, - ModelProblem.Version.BASE, - "Non-readable POM " + modelSource.getLocation() + ": " + msg, - e); - throw problems.newModelBuilderException(); + ((ModelProblemCollector) build) + .add( + Severity.FATAL, + ModelProblem.Version.BASE, + "Non-readable POM " + modelSource.getLocation() + ": " + msg, + e); + throw ((ModelProblemCollector) build).newModelBuilderException(); } if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { @@ -772,9 +1201,7 @@ private Model doReadFileModel(ModelSource modelSource, ModelBuilderRequest reque pomPath = getModelProcessor().locateExistingPom(pomPath); } if (pomPath != null && Files.isRegularFile(pomPath)) { - ModelBuilderRequest parentRequest = - ModelBuilderRequest.build(request, ModelSource.fromPath(pomPath)); - Model parentModel = readFileModel(parentRequest, problems); + Model parentModel = readFileModel(build.derive(ModelSource.fromPath(pomPath))); if (parentModel != null) { String parentGroupId = getGroupId(parentModel); String parentArtifactId = parentModel.getArtifactId(); @@ -814,7 +1241,8 @@ private Model doReadFileModel(ModelSource modelSource, ModelBuilderRequest reque model = model.withSubprojects(subprojects); } } catch (IOException e) { - problems.add(Severity.FATAL, ModelProblem.Version.V41, "Error discovering subprojects", e); + ((ModelProblemCollector) build) + .add(Severity.FATAL, ModelProblem.Version.V41, "Error discovering subprojects", e); } } } @@ -823,55 +1251,36 @@ private Model doReadFileModel(ModelSource modelSource, ModelBuilderRequest reque model = transformer.transformFileModel(model); } - problems.setSource(model); + ((ModelProblemCollector) build).setSource(model); modelValidator.validateFileModel( model, request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM ? ModelValidator.VALIDATION_LEVEL_STRICT : ModelValidator.VALIDATION_LEVEL_MINIMAL, request, - problems); - if (hasFatalErrors(problems)) { - throw problems.newModelBuilderException(); - } - - if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { - DefaultModelTransformerContext context = getTransformerContext(request, problems); - context.putSource(getGroupId(model), model.getArtifactId(), modelSource); + build); + if (hasFatalErrors(build)) { + throw ((ModelProblemCollector) build).newModelBuilderException(); } return model; } - Model readRawModel(ModelBuilderRequest request, ModelProblemCollector problems) throws ModelBuilderException { - ModelSource modelSource = request.getSource(); - - Model model = - cache(getModelCache(request), modelSource, RAW, () -> doReadRawModel(modelSource, request, problems)); - - return model; + Model readRawModel(DefaultModelBuilderSession build) throws ModelBuilderException { + return cache(build.cache, build.request.getSource(), RAW, () -> doReadRawModel(build)); } - private Model doReadRawModel(ModelSource modelSource, ModelBuilderRequest request, ModelProblemCollector problems) - throws ModelBuilderException { - Model rawModel = readFileModel(request, problems); + private Model doReadRawModel(DefaultModelBuilderSession build) throws ModelBuilderException { + ModelBuilderRequest request = build.request; + ModelSource modelSource = request.getSource(); + Model rawModel = readFileModel(build); if (!MODEL_VERSION_4_0_0.equals(rawModel.getModelVersion()) && request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { Path pomFile = modelSource.getPath(); - - DefaultModelTransformerContext context = getTransformerContext(request, problems); try { - if (context == null) { - problems.add( - Severity.FATAL, - ModelProblem.Version.V40, - "Illegal state: ModelTransformerContextBuilder returned null", - (Exception) null); - } else { - rawModel = this.buildModelTransformer.transform(context, rawModel, pomFile); - } + rawModel = this.transform(build, rawModel, pomFile); } catch (ModelTransformerException e) { - problems.add(Severity.FATAL, ModelProblem.Version.V40, null, e); + build.add(Severity.FATAL, ModelProblem.Version.V40, null, e); } } @@ -890,24 +1299,15 @@ private Model doReadRawModel(ModelSource modelSource, ModelBuilderRequest reques ? ModelValidator.VALIDATION_LEVEL_STRICT : ModelValidator.VALIDATION_LEVEL_MINIMAL, request, - problems); + build); - if (hasFatalErrors(problems)) { - throw problems.newModelBuilderException(); + if (hasFatalErrors(build)) { + throw build.newModelBuilderException(); } return rawModel; } - private DefaultModelTransformerContext getTransformerContext( - ModelBuilderRequest request, ModelProblemCollector problems) { - return (DefaultModelTransformerContext) request.getSession() - .getData() - .computeIfAbsent( - SessionData.key(DefaultModelTransformerContext.class), - () -> new DefaultModelTransformerContext(this, request, problems)); - } - static String getGroupId(Model model) { String groupId = model.getGroupId(); if (groupId == null && model.getParent() != null) { @@ -1041,21 +1441,20 @@ private Model interpolateModel(Model model, ModelBuilderRequest request, ModelPr return interpolatedModel; } - private ModelData readParent( - Model childModel, ModelSource childSource, ModelBuilderRequest request, ModelProblemCollector problems) + private ModelData readParent(DefaultModelBuilderSession build, Model childModel, ModelSource childSource) throws ModelBuilderException { ModelData parentData = null; Parent parent = childModel.getParent(); if (parent != null) { - parentData = readParentLocally(childModel, childSource, request, problems); + parentData = readParentLocally(build, childModel, childSource); if (parentData == null) { - parentData = readParentExternally(childModel, request, problems); + parentData = resolveAndReadParentExternally(build, childModel); } Model parentModel = parentData.model(); if (!"pom".equals(parentModel.getPackaging())) { - problems.add( + build.add( Severity.ERROR, ModelProblem.Version.BASE, "Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint(parentModel) @@ -1067,17 +1466,13 @@ private ModelData readParent( return parentData; } - private ModelData readParentLocally( - Model childModel, ModelSource childSource, ModelBuilderRequest request, ModelProblemCollector problems) + private ModelData readParentLocally(DefaultModelBuilderSession build, Model childModel, ModelSource childSource) throws ModelBuilderException { ModelSource candidateSource = getParentPomFile(childModel, childSource); if (candidateSource == null) { return null; } - - ModelBuilderRequest candidateBuildRequest = ModelBuilderRequest.build(request, candidateSource); - - Model candidateModel = readRawModel(candidateBuildRequest, problems); + final Model candidateModel = readRawModel(build.derive(candidateSource)); // // TODO jvz Why isn't all this checking the job of the duty of the workspace resolver, we know that we @@ -1095,15 +1490,15 @@ private ModelData readParentLocally( || !artifactId.equals(parent.getArtifactId())) { StringBuilder buffer = new StringBuilder(256); buffer.append("'parent.relativePath'"); - if (childModel != problems.getRootModel()) { + if (childModel != build.getRootModel()) { buffer.append(" of POM ").append(ModelProblemUtils.toSourceHint(childModel)); } buffer.append(" points at ").append(groupId).append(':').append(artifactId); buffer.append(" instead of ").append(parent.getGroupId()).append(':'); buffer.append(parent.getArtifactId()).append(", please verify your project structure"); - problems.setSource(childModel); - problems.add(Severity.WARNING, ModelProblem.Version.BASE, buffer.toString(), parent.getLocation("")); + build.setSource(childModel); + build.add(Severity.WARNING, ModelProblem.Version.BASE, buffer.toString(), parent.getLocation("")); return null; } @@ -1121,7 +1516,7 @@ private ModelData readParentLocally( if (rawChildModelVersion == null) { // Message below is checked for in the MNG-2199 core IT. - problems.add( + build.add( Severity.FATAL, ModelProblem.Version.V31, "Version must be a constant", @@ -1130,7 +1525,7 @@ private ModelData readParentLocally( } else { if (rawChildVersionReferencesParent(rawChildModelVersion)) { // Message below is checked for in the MNG-2199 core IT. - problems.add( + build.add( Severity.FATAL, ModelProblem.Version.V31, "Version must be a constant", @@ -1173,10 +1568,10 @@ private ModelSource getParentPomFile(Model childModel, ModelSource source) { } } - private ModelData readParentExternally( - Model childModel, ModelBuilderRequest request, ModelProblemCollector problems) + private ModelData resolveAndReadParentExternally(DefaultModelBuilderSession build, Model childModel) throws ModelBuilderException { - problems.setSource(childModel); + ModelBuilderRequest request = build.request; + build.setSource(childModel); Parent parent = childModel.getParent(); @@ -1207,7 +1602,7 @@ private ModelData readParentExternally( if (!containsCoordinates(e.getMessage(), groupId, artifactId, version)) { buffer.append(' ').append(ModelProblemUtils.toId(groupId, artifactId, version)); } - if (childModel != problems.getRootModel()) { + if (childModel != ((ModelProblemCollector) build).getRootModel()) { buffer.append(" for ").append(ModelProblemUtils.toId(childModel)); } buffer.append(": ").append(e.getMessage()); @@ -1219,8 +1614,9 @@ private ModelData readParentExternally( } } - problems.add(Severity.FATAL, ModelProblem.Version.BASE, buffer.toString(), parent.getLocation(""), e); - throw problems.newModelBuilderException(); + ((ModelProblemCollector) build) + .add(Severity.FATAL, ModelProblem.Version.BASE, buffer.toString(), parent.getLocation(""), e); + throw ((ModelProblemCollector) build).newModelBuilderException(); } ModelBuilderRequest lenientRequest = ModelBuilderRequest.builder(request) @@ -1228,23 +1624,22 @@ private ModelData readParentExternally( .source(modelSource) .build(); - Model parentModel = readParentModel(lenientRequest, problems); + Model parentModel = readParentModel(new DefaultModelBuilderSession(lenientRequest, build.result)); if (!parent.getVersion().equals(version)) { String rawChildModelVersion = childModel.getVersion(); if (rawChildModelVersion == null) { // Message below is checked for in the MNG-2199 core IT. - problems.add( + build.add( Severity.FATAL, ModelProblem.Version.V31, "Version must be a constant", childModel.getLocation("")); - } else { if (rawChildVersionReferencesParent(rawChildModelVersion)) { // Message below is checked for in the MNG-2199 core IT. - problems.add( + build.add( Severity.FATAL, ModelProblem.Version.V31, "Version must be a constant", @@ -1258,18 +1653,16 @@ private ModelData readParentExternally( return new ModelData(modelSource, parentModel); } - Model readParentModel(ModelBuilderRequest request, ModelProblemCollector problems) { - ModelSource modelSource = request.getSource(); - Model model = cache(getModelCache(request), modelSource, PARENT, () -> doReadParentModel(request, problems)); - return model; + Model readParentModel(DefaultModelBuilderSession build) { + return cache(build.cache, build.request.getSource(), PARENT, () -> doReadParentModel(build)); } - private Model doReadParentModel(ModelBuilderRequest request, ModelProblemCollector problems) { - Model raw = readRawModel(request, problems); + private Model doReadParentModel(DefaultModelBuilderSession build) { + Model raw = readRawModel(build); ModelData parentData; if (raw.getParent() != null) { - parentData = readParentExternally(raw, request, problems); + parentData = resolveAndReadParentExternally(build, raw); } else { String superModelVersion = raw.getModelVersion() != null ? raw.getModelVersion() : "4.0.0"; if (!VALID_MODEL_VERSIONS.contains(superModelVersion)) { @@ -1281,7 +1674,7 @@ private Model doReadParentModel(ModelBuilderRequest request, ModelProblemCollect parentData = new ModelData(null, getSuperModel(superModelVersion)); } - Model parent = inheritanceAssembler.assembleModelInheritance(raw, parentData.model(), request, problems); + Model parent = inheritanceAssembler.assembleModelInheritance(raw, parentData.model(), build.request, build); return parent.withParent(null); } @@ -1290,7 +1683,7 @@ private Model getSuperModel(String modelVersion) { } private Model importDependencyManagement( - Model model, ModelBuilderRequest request, ModelProblemCollector problems, Collection importIds) { + DefaultModelBuilderSession build, Model model, Collection importIds) { DependencyManagement depMgmt = model.getDependencyManagement(); if (depMgmt == null) { @@ -1314,7 +1707,7 @@ private Model importDependencyManagement( it.remove(); - DependencyManagement importMgmt = loadDependencyManagement(model, request, problems, dependency, importIds); + DependencyManagement importMgmt = loadDependencyManagement(build, model, dependency, importIds); if (importMgmt != null) { if (importMgmts == null) { @@ -1329,21 +1722,17 @@ private Model importDependencyManagement( model = model.withDependencyManagement(model.getDependencyManagement().withDependencies(deps)); - return dependencyManagementImporter.importManagement(model, importMgmts, request, problems); + return dependencyManagementImporter.importManagement(model, importMgmts, build.request, build); } private DependencyManagement loadDependencyManagement( - Model model, - ModelBuilderRequest request, - ModelProblemCollector problems, - Dependency dependency, - Collection importIds) { + DefaultModelBuilderSession build, Model model, Dependency dependency, Collection importIds) { String groupId = dependency.getGroupId(); String artifactId = dependency.getArtifactId(); String version = dependency.getVersion(); if (groupId == null || groupId.isEmpty()) { - problems.add( + build.add( Severity.ERROR, ModelProblem.Version.BASE, "'dependencyManagement.dependencies.dependency.groupId' for " + dependency.getManagementKey() @@ -1352,7 +1741,7 @@ private DependencyManagement loadDependencyManagement( return null; } if (artifactId == null || artifactId.isEmpty()) { - problems.add( + build.add( Severity.ERROR, ModelProblem.Version.BASE, "'dependencyManagement.dependencies.dependency.artifactId' for " + dependency.getManagementKey() @@ -1361,7 +1750,7 @@ private DependencyManagement loadDependencyManagement( return null; } if (version == null || version.isEmpty()) { - problems.add( + build.add( Severity.ERROR, ModelProblem.Version.BASE, "'dependencyManagement.dependencies.dependency.version' for " + dependency.getManagementKey() @@ -1379,19 +1768,17 @@ private DependencyManagement loadDependencyManagement( message.append(modelId).append(" -> "); } message.append(imported); - problems.add(Severity.ERROR, ModelProblem.Version.BASE, message.toString()); - + build.add(Severity.ERROR, ModelProblem.Version.BASE, message.toString()); return null; } Model importModel = cache( - getModelCache(request), + build.cache, groupId, artifactId, version, IMPORT, - () -> doLoadDependencyManagement( - model, request, problems, dependency, groupId, artifactId, version, importIds)); + () -> doLoadDependencyManagement(build, model, dependency, groupId, artifactId, version, importIds)); DependencyManagement importMgmt = importModel != null ? importModel.getDependencyManagement() : null; if (importMgmt == null) { importMgmt = DependencyManagement.newInstance(); @@ -1428,14 +1815,14 @@ private boolean match(String match, String text) { @SuppressWarnings("checkstyle:parameternumber") private Model doLoadDependencyManagement( + DefaultModelBuilderSession build, Model model, - ModelBuilderRequest request, - ModelProblemCollector problems, Dependency dependency, String groupId, String artifactId, String version, Collection importIds) { + final ModelBuilderRequest request = build.request; final ModelResolver modelResolver = getModelResolver(request); if (modelResolver == null) { throw new NullPointerException(String.format( @@ -1460,7 +1847,7 @@ private Model doLoadDependencyManagement( } buffer.append(": ").append(e.getMessage()); - problems.add(Severity.ERROR, ModelProblem.Version.BASE, buffer.toString(), dependency.getLocation(""), e); + build.add(Severity.ERROR, ModelProblem.Version.BASE, buffer.toString(), dependency.getLocation(""), e); return null; } @@ -1473,7 +1860,7 @@ private Model doLoadDependencyManagement( if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM && rootDirectory != null) { Path sourcePath = importSource.getPath(); if (sourcePath != null && sourcePath.startsWith(rootDirectory)) { - problems.add( + build.add( Severity.WARNING, ModelProblem.Version.BASE, "BOM imports from within reactor should be avoided", @@ -1494,13 +1881,13 @@ private Model doLoadDependencyManagement( .twoPhaseBuilding(false) .repositories(getModelRepositoryHolder(request).getRepositories()) .build(); - importResult = build(importRequest, importIds); + importResult = build(new DefaultModelBuilderSession(importRequest), importIds); } catch (ModelBuilderException e) { - e.getResult().getProblems().forEach(problems::add); + e.getResult().getProblems().forEach(build::add); return null; } - importResult.getProblems().forEach(problems::add); + importResult.getProblems().forEach(build::add); importModel = importResult.getEffectiveModel(); @@ -1591,91 +1978,88 @@ private static ModelResolver getModelResolver(ModelBuilderRequest request) { /** * ModelSourceTransformer for the build pom */ - public static class BuildModelTransformer { - - public Model transform(DefaultModelTransformerContext 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(); - } + Model transform(DefaultModelBuilderSession build, Model model, Path path) { + Model.Builder builder = Model.newBuilder(model); + handleParent(build, model, path, builder); + handleReactorDependencies(build, model, path, builder); + handleCiFriendlyVersion(build, model, path, builder); + return builder.build(); + } - // - // Infer parent information - // - void handleParent(DefaultModelTransformerContext context, Model model, Path pomFile, Model.Builder builder) { - Parent parent = model.getParent(); - if (parent != null) { - String version = parent.getVersion(); - String modVersion = replaceCiFriendlyVersion(context, version); - builder.parent(parent.withVersion(modVersion)); - } + // + // Infer parent information + // + void handleParent(DefaultModelBuilderSession build, Model model, Path pomFile, Model.Builder builder) { + Parent parent = model.getParent(); + if (parent != null) { + String version = parent.getVersion(); + String modVersion = replaceCiFriendlyVersion(build, version); + builder.parent(parent.withVersion(modVersion)); } + } - // - // CI friendly versions - // - void handleCiFriendlyVersion( - DefaultModelTransformerContext context, Model model, Path pomFile, Model.Builder builder) { - String version = model.getVersion(); - String modVersion = replaceCiFriendlyVersion(context, version); - builder.version(modVersion); - } + // + // CI friendly versions + // + void handleCiFriendlyVersion(DefaultModelBuilderSession build, Model model, Path pomFile, Model.Builder builder) { + String version = model.getVersion(); + String modVersion = replaceCiFriendlyVersion(build, version); + builder.version(modVersion); + } - // - // Infer inner reactor dependencies version - // - void handleReactorDependencies( - DefaultModelTransformerContext context, Model model, Path pomFile, Model.Builder builder) { - List 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); + // + // Infer inner reactor dependencies version + // + void handleReactorDependencies(DefaultModelBuilderSession build, Model model, Path pomFile, Model.Builder builder) { + List newDeps = new ArrayList<>(); + boolean modified = false; + for (Dependency dep : model.getDependencies()) { + Dependency.Builder depBuilder = null; + if (dep.getVersion() == null) { + Model depModel = build.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); + if (depBuilder != null) { + newDeps.add(depBuilder.build()); + modified = true; + } else { + newDeps.add(dep); } } + if (modified) { + builder.dependencies(newDeps); + } + } - String replaceCiFriendlyVersion(DefaultModelTransformerContext 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); - } + String replaceCiFriendlyVersion(DefaultModelBuilderSession build, String version) { + if (version != null) { + for (String key : Arrays.asList("changelist", "revision", "sha1")) { + String val = build.request.getUserProperties().get(key); + if (val != null) { + version = version.replace("${" + key + "}", val); } } - return version; } + return version; } + + record GAKey(String groupId, String artifactId) {} } diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContext.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContext.java deleted file mode 100644 index 07b25c499650..000000000000 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelTransformerContext.java +++ /dev/null @@ -1,266 +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.Objects; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Supplier; - -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; - -class DefaultModelTransformerContext { - - final DefaultModelBuilder modelBuilder; - final ModelBuilderRequest request; - final ModelProblemCollector problems; - final Graph dag = new Graph(); - final Map modelByPath = new ConcurrentHashMap<>(); - final Map modelByGA = new ConcurrentHashMap<>(); - final Map> mappedSources = new ConcurrentHashMap<>(64); - volatile boolean fullReactorLoaded; - - static class Holder { - private volatile boolean set; - private volatile Model model; - - 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 supplier) { - if (!set) { - synchronized (this) { - if (!set) { - this.set = true; - this.model = supplier.get(); - this.notifyAll(); - } - } - } - return model; - } - } - - DefaultModelTransformerContext( - DefaultModelBuilder modelBuilder, ModelBuilderRequest request, ModelProblemCollector problems) { - this.modelBuilder = modelBuilder; - this.request = request; - this.problems = problems; - } - - public String getUserProperty(String key) { - return request.getUserProperties().get(key); - } - - public Model getRawModel(Path from, String gId, String aId) { - Model model = findRawModel(from, gId, aId); - if (model != null) { - modelByGA.put(new GAKey(gId, aId), new Holder(model)); - if (model.getPomFile() != null) { - modelByPath.put(model.getPomFile(), new Holder(model)); - } - } - return model; - } - - public Model getRawModel(Path from, Path path) { - Model model = findRawModel(from, path); - if (model != null) { - String groupId = DefaultModelBuilder.getGroupId(model); - modelByGA.put(new GAKey(groupId, model.getArtifactId()), new Holder(model)); - modelByPath.put(path, new Holder(model)); - } - return model; - } - - public Path locate(Path path) { - return modelBuilder.getModelProcessor().locateExistingPom(path); - } - - 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 modelBuilder.readRawModel(gaBuildingRequest, problems); - } catch (ModelBuilderException e) { - // gathered with problem collector - } - } - return null; - } - - private void loadFullReactor() { - if (!fullReactorLoaded) { - synchronized (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 toLoad = new ArrayList<>(); - Path root = modelBuilder.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 = modelBuilder.readFileModel(gaBuildingRequest, problems); - List subprojects = rawModel.getSubprojects(); - if (subprojects == null) { - subprojects = rawModel.getModules(); - } - for (String subproject : subprojects) { - Path subprojectFile = modelBuilder - .getModelProcessor() - .locateExistingPom(pom.getParent().resolve(subproject)); - if (subprojectFile != null) { - toLoad.add(subprojectFile); - } - } - } catch (ModelBuilderException e) { - // gathered with problem collector - problems.add(ModelProblem.Severity.ERROR, ModelProblem.Version.V40, "Failed to load project " + pom, e); - } - } - } - - 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 modelBuilder.readRawModel(req, problems); - } catch (ModelBuilderException e) { - // gathered with problem collector - } - return null; - } - - private boolean addEdge(Path from, Path p, ModelProblemCollector 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; - } - } - - public ModelSource getSource(String groupId, String artifactId) { - Set sources; - if (groupId != null) { - sources = mappedSources.get(new GAKey(groupId, artifactId)); - if (sources == null) { - return null; - } - } else if (artifactId != null) { - sources = mappedSources.get(new GAKey(null, 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(new GAKey(groupId, artifactId), k -> new HashSet<>()) - .add(source); - mappedSources - .computeIfAbsent(new GAKey(null, artifactId), k -> new HashSet<>()) - .add(source); - } - - record GAKey(String groupId, String artifactId) {} -} diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java index 972a0d86755a..7115468c82aa 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java @@ -208,7 +208,7 @@ private Model loadPom( .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()) { diff --git a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/TestApiStandalone.java b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/TestApiStandalone.java index 2d74bb9a9344..05710d116dc4 100644 --- a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/TestApiStandalone.java +++ b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/TestApiStandalone.java @@ -42,11 +42,12 @@ void testStandalone() { 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())) - .requestType(ModelBuilderRequest.RequestType.BUILD_POM) - .build()); + ModelBuilderResult result = builder.newSession() + .build(ModelBuilderRequest.builder() + .session(session) + .source(ModelSource.fromPath(Paths.get("pom.xml").toAbsolutePath())) + .requestType(ModelBuilderRequest.RequestType.BUILD_POM) + .build()); assertNotNull(result.getEffectiveModel()); ArtifactCoordinates coords = diff --git a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java index 032b53faa3b7..ed61363140d4 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java @@ -178,6 +178,7 @@ public List getActiveProfiles( return new ArrayList<>(); } }; + // TODO: the custom selector should be used as a flag on the request DefaultModelBuilder modelBuilder = new DefaultModelBuilder( modelProcessor, modelValidator, @@ -207,7 +208,7 @@ public List getActiveProfiles( request.modelResolver(iSession.getData().get(SessionData.key(ModelResolver.class))); request.systemProperties(session.getSystemProperties()); request.userProperties(session.getUserProperties()); - return modelBuilder.build(request.build()); + return modelBuilder.newSession().build(request.build()); } static Model transform(Model model, MavenProject project) { diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index 4c8c9080dc0b..f7dbac01af45 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -130,7 +130,6 @@ public class DefaultProjectBuilder implements ProjectBuilder { private final org.eclipse.aether.RepositorySystem repoSystem; private final RemoteRepositoryManager repositoryManager; private final ProjectDependenciesResolver dependencyResolver; - private final RootLocator rootLocator; @SuppressWarnings("checkstyle:ParameterNumber") @@ -384,6 +383,7 @@ class BuildSession implements AutoCloseable { private final ExecutorService executor; private final ModelResolver modelResolver; private final Map ciFriendlyVersions = new ConcurrentHashMap<>(); + private final ModelBuilder.ModelBuilderSession modelBuilderSession; BuildSession(ProjectBuildingRequest request, boolean localProjects) { this.request = request; @@ -413,6 +413,7 @@ protected org.apache.maven.model.resolution.ModelResolver getResolver( parentCache); } }; + this.modelBuilderSession = modelBuilder.newSession(); } ExecutorService createExecutor(int parallelism) { @@ -501,7 +502,7 @@ ProjectBuildingResult build(Path pomFile, ModelSource modelSource) throws Projec ModelBuilderResult result; try { - result = modelBuilder.build(request); + result = modelBuilderSession.build(request); } catch (ModelBuilderException e) { result = e.getResult(); if (result == null || result.getEffectiveModel() == null) { @@ -675,7 +676,7 @@ private InterimResult build( ModelBuilderResult result; try { - result = modelBuilder.build(modelBuildingRequest); + result = modelBuilderSession.build(modelBuildingRequest); } catch (ModelBuilderException e) { result = e.getResult(); if (result == null || result.getFileModel() == null) { @@ -832,6 +833,7 @@ private List build( // which may cause some re-entrance in the build() method and can // actually cause deadlocks. In order to workaround the problem, // we do a first pass by reading all rawModels in order. + /* List results = new ArrayList<>(); boolean failure = false; for (InterimResult r : interimResults) { @@ -856,6 +858,7 @@ private List build( if (failure) { return results; } + */ List>> callables = interimResults.stream() .map(interimResult -> @@ -890,7 +893,7 @@ private List doBuild(Map projectIndex } MavenProject project = interimResult.project; try { - ModelBuilderResult result = modelBuilder.build(ModelBuilderRequest.builder(interimResult.request) + ModelBuilderResult result = modelBuilderSession.build(ModelBuilderRequest.builder(interimResult.request) .interimResult(interimResult.result) .build()); diff --git a/maven-core/src/main/java/org/apache/maven/project/ReactorModelPool.java b/maven-core/src/main/java/org/apache/maven/project/ReactorModelPool.java index 183132a5e3e8..078ce850ed8d 100644 --- a/maven-core/src/main/java/org/apache/maven/project/ReactorModelPool.java +++ b/maven-core/src/main/java/org/apache/maven/project/ReactorModelPool.java @@ -66,7 +66,9 @@ private String getVersion(Model model) { } 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); diff --git a/maven-core/src/test/java/org/apache/maven/model/ModelBuilderTest.java b/maven-core/src/test/java/org/apache/maven/model/ModelBuilderTest.java index 4596e6981465..8fecf35980c4 100644 --- a/maven-core/src/test/java/org/apache/maven/model/ModelBuilderTest.java +++ b/maven-core/src/test/java/org/apache/maven/model/ModelBuilderTest.java @@ -21,6 +21,7 @@ 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 diff --git a/maven-model/src/main/java/org/apache/maven/model/BaseObject.java b/maven-model/src/main/java/org/apache/maven/model/BaseObject.java index 355453d39441..22c7a6efc4e1 100644 --- a/maven-model/src/main/java/org/apache/maven/model/BaseObject.java +++ b/maven-model/src/main/java/org/apache/maven/model/BaseObject.java @@ -20,6 +20,8 @@ import java.io.Serializable; +import static java.util.Objects.requireNonNull; + public abstract class BaseObject implements Serializable, Cloneable, InputLocationTracker { protected transient ChildrenTracking childrenTracking; @@ -28,7 +30,7 @@ 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; } From 9aa70994c0024cacaf89b099e51afdaaeb6a92ef Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 6 Sep 2024 16:46:49 +0200 Subject: [PATCH 17/63] Move DefaultModelBuildingListener into DefaultProjectBuilder # Conflicts: # maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java --- .../project/DefaultModelBuildingListener.java | 127 ------------------ .../maven/project/DefaultProjectBuilder.java | 102 +++++++++++++- 2 files changed, 100 insertions(+), 129 deletions(-) delete mode 100644 maven-core/src/main/java/org/apache/maven/project/DefaultModelBuildingListener.java diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultModelBuildingListener.java b/maven-core/src/main/java/org/apache/maven/project/DefaultModelBuildingListener.java deleted file mode 100644 index 64f8244b944d..000000000000 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultModelBuildingListener.java +++ /dev/null @@ -1,127 +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.ModelBuilderRequest; -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 remoteRepositories; - - private List 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().getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { - 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()); - } - } -} diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index f7dbac01af45..5e59fb0b2e30 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -71,6 +71,7 @@ import org.apache.maven.api.model.Plugin; import org.apache.maven.api.model.Profile; import org.apache.maven.api.model.ReportPlugin; +import org.apache.maven.api.services.BuilderProblem; import org.apache.maven.api.services.MavenException; import org.apache.maven.api.services.ModelBuilder; import org.apache.maven.api.services.ModelBuilderException; @@ -81,6 +82,7 @@ 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.model.ModelBuildingEvent; import org.apache.maven.api.services.model.ModelBuildingListener; import org.apache.maven.api.services.model.ModelProcessor; import org.apache.maven.artifact.Artifact; @@ -96,6 +98,9 @@ import org.apache.maven.model.building.ModelSource3; import org.apache.maven.model.resolution.UnresolvableModelException; import org.apache.maven.model.root.RootLocator; +import org.apache.maven.plugin.PluginManagerException; +import org.apache.maven.plugin.PluginResolutionException; +import org.apache.maven.plugin.version.PluginVersionResolutionException; import org.apache.maven.repository.internal.ArtifactDescriptorUtils; import org.apache.maven.utils.Os; import org.codehaus.plexus.interpolation.AbstractValueSource; @@ -663,8 +668,7 @@ private InterimResult build( project.setRootDirectory( rootLocator.findRoot(pomFile.getParentFile().toPath())); - DefaultModelBuildingListener listener = - new DefaultModelBuildingListener(project, projectBuildingHelper, request); + ModelBuildingListener listener = new DefaultModelBuildingListener(project, projectBuildingHelper, request); ModelBuilderRequest modelBuildingRequest = getModelBuildingRequest() .source(ModelSource.fromPath(pomFile.toPath())) @@ -1413,4 +1417,98 @@ public ModelSource resolveModel( } } } + + /** + * Processes events from the model builder while building the effective model for a {@link MavenProject} instance. + * + */ + public static class DefaultModelBuildingListener implements ModelBuildingListener { + + private final MavenProject project; + + private final ProjectBuildingHelper projectBuildingHelper; + + private final ProjectBuildingRequest projectBuildingRequest; + + private List remoteRepositories; + + private List 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) { + org.apache.maven.model.Model model = new org.apache.maven.model.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().getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { + 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()); + } + } + } } From 61cec5b194ddda832eec33195dd096b1515c014d Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 6 Sep 2024 17:13:57 +0200 Subject: [PATCH 18/63] Get rid of DefaultModelRepositoryHolder # Conflicts: # maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java # Conflicts: # maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java --- .../api/services/ModelBuilderRequest.java | 21 --- .../impl/model/DefaultModelBuilder.java | 134 ++++++++++++------ .../DefaultModelRepositoryHolder.java | 93 ------------ 3 files changed, 92 insertions(+), 156 deletions(-) delete mode 100644 maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelRepositoryHolder.java diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java index 815dea0c0bea..9a6616530f88 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java @@ -38,8 +38,6 @@ * 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 - * * @since 4.0.0 */ @Experimental @@ -128,9 +126,6 @@ enum RepositoryMerging { @Nonnull ModelResolver getModelResolver(); - @Nonnull - Object getModelRepositoryHolder(); - @Nonnull RepositoryMerging getRepositoryMerging(); @@ -189,7 +184,6 @@ class ModelBuilderRequestBuilder { Map systemProperties; Map userProperties; ModelResolver modelResolver; - Object modelRepositoryHolder; RepositoryMerging repositoryMerging; Object listener; ModelBuilderResult interimResult; @@ -209,7 +203,6 @@ class ModelBuilderRequestBuilder { this.systemProperties = request.getSystemProperties(); this.userProperties = request.getUserProperties(); this.modelResolver = request.getModelResolver(); - this.modelRepositoryHolder = request.getModelRepositoryHolder(); this.repositoryMerging = request.getRepositoryMerging(); this.listener = request.getListener(); this.interimResult = request.getInterimResult(); @@ -271,11 +264,6 @@ public ModelBuilderRequestBuilder modelResolver(ModelResolver modelResolver) { return this; } - public ModelBuilderRequestBuilder modelRepositoryHolder(Object modelRepositoryHolder) { - this.modelRepositoryHolder = modelRepositoryHolder; - return this; - } - public ModelBuilderRequestBuilder repositoryMerging(RepositoryMerging repositoryMerging) { this.repositoryMerging = repositoryMerging; return this; @@ -309,7 +297,6 @@ public ModelBuilderRequest build() { systemProperties, userProperties, modelResolver, - modelRepositoryHolder, repositoryMerging, listener, interimResult, @@ -327,7 +314,6 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M private final Map systemProperties; private final Map userProperties; private final ModelResolver modelResolver; - private final Object modelRepositoryHolder; private final RepositoryMerging repositoryMerging; private final Object listener; private final ModelBuilderResult interimResult; @@ -346,7 +332,6 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M Map systemProperties, Map userProperties, ModelResolver modelResolver, - Object modelRepositoryHolder, RepositoryMerging repositoryMerging, Object listener, ModelBuilderResult interimResult, @@ -363,7 +348,6 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M systemProperties != null ? Map.copyOf(systemProperties) : session.getSystemProperties(); this.userProperties = userProperties != null ? Map.copyOf(userProperties) : session.getUserProperties(); this.modelResolver = modelResolver; - this.modelRepositoryHolder = modelRepositoryHolder; this.repositoryMerging = repositoryMerging; this.listener = listener; this.interimResult = interimResult; @@ -421,11 +405,6 @@ public ModelResolver getModelResolver() { return modelResolver; } - @Override - public Object getModelRepositoryHolder() { - return modelRepositoryHolder; - } - @Override public RepositoryMerging getRepositoryMerging() { return repositoryMerging; diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index ab2e11d105e1..f0647c036638 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -47,6 +47,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.maven.api.RemoteRepository; import org.apache.maven.api.Session; import org.apache.maven.api.SessionData; import org.apache.maven.api.Type; @@ -69,6 +70,7 @@ import org.apache.maven.api.model.Plugin; import org.apache.maven.api.model.PluginManagement; import org.apache.maven.api.model.Profile; +import org.apache.maven.api.model.Repository; import org.apache.maven.api.services.BuilderProblem; import org.apache.maven.api.services.BuilderProblem.Severity; import org.apache.maven.api.services.ModelBuilder; @@ -80,6 +82,7 @@ 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.RepositoryFactory; import org.apache.maven.api.services.Source; import org.apache.maven.api.services.SuperPomProvider; import org.apache.maven.api.services.VersionParserException; @@ -108,7 +111,6 @@ import org.apache.maven.api.spi.ModelParserException; import org.apache.maven.api.spi.ModelTransformer; import org.apache.maven.api.spi.ModelTransformerException; -import org.apache.maven.internal.impl.resolver.DefaultModelRepositoryHolder; import org.apache.maven.internal.impl.resolver.DefaultModelResolver; import org.apache.maven.model.v4.MavenTransformer; import org.codehaus.plexus.interpolation.InterpolationException; @@ -234,6 +236,7 @@ protected final class DefaultModelBuilderSession implements ModelProblemCollecto final Map modelByPath; final Map modelByGA; final Map> mappedSources; + final RepositoryHolder repositoryHolder; private String source; private Model sourceModel; @@ -270,7 +273,8 @@ protected final class DefaultModelBuilderSession implements ModelProblemCollecto new Graph(), new ConcurrentHashMap<>(64), new ConcurrentHashMap<>(64), - new ConcurrentHashMap<>(64)); + new ConcurrentHashMap<>(64), + null); } @SuppressWarnings("checkstyle:ParameterNumber") @@ -282,7 +286,8 @@ private DefaultModelBuilderSession( Graph dag, Map modelByPath, Map modelByGA, - Map> mappedSources) { + Map> mappedSources, + RepositoryHolder repositoryHolder) { this.session = session; this.request = request; this.result = result; @@ -291,6 +296,12 @@ private DefaultModelBuilderSession( this.modelByPath = modelByPath; this.modelByGA = modelByGA; this.mappedSources = mappedSources; + this.repositoryHolder = repositoryHolder != null + ? repositoryHolder + : new RepositoryHolder( + request.getRepositories() != null + ? request.getRepositories() + : session.getRemoteRepositories()); this.result.getProblems().forEach(p -> severities.add(p.getSeverity())); } @@ -303,7 +314,7 @@ public DefaultModelBuilderSession derive(ModelBuilderRequest request, DefaultMod throw new IllegalArgumentException("Session mismatch"); } return new DefaultModelBuilderSession( - session, request, result, cache, dag, modelByPath, modelByGA, mappedSources); + session, request, result, cache, dag, modelByPath, modelByGA, mappedSources, repositoryHolder); } public Session session() { @@ -665,6 +676,70 @@ public ModelBuilderException newModelBuilderException() { } return new ModelBuilderException(result); } + + List getRepositories() { + return repositoryHolder.getRepositories(); + } + + void mergeRepositories(List repositories, boolean replace) { + repositoryHolder.mergeRepositories(repositories, replace); + } + + class RepositoryHolder { + + List pomRepositories; + List repositories; + List externalRepositories; + + RepositoryHolder(List externalRepositories) { + this.pomRepositories = List.of(); + this.externalRepositories = List.copyOf(externalRepositories); + this.repositories = List.copyOf(externalRepositories); + } + + RepositoryHolder(RepositoryHolder holder) { + this.pomRepositories = List.copyOf(holder.pomRepositories); + this.externalRepositories = List.copyOf(holder.externalRepositories); + this.repositories = List.copyOf(holder.repositories); + } + + public void mergeRepositories(List toAdd, boolean replace) { + List repos = + toAdd.stream().map(session::createRemoteRepository).toList(); + if (replace) { + Set 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 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 (request.getRepositoryMerging() == ModelBuilderRequest.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); + } + } + + public List getRepositories() { + return repositories; + } + + public RepositoryHolder copy() { + return new RepositoryHolder(this); + } + } } DefaultModelProblemCollector newCollector(DefaultModelBuilderResult result) { @@ -673,16 +748,6 @@ DefaultModelProblemCollector newCollector(DefaultModelBuilderResult result) { private static ModelBuilderRequest fillRequestDefaults(ModelBuilderRequest request) { ModelBuilderRequest.ModelBuilderRequestBuilder builder = ModelBuilderRequest.builder(request); - if (getModelRepositoryHolder(request) == null) { - builder.modelRepositoryHolder(new DefaultModelRepositoryHolder( - request.getSession(), - request.getRepositoryMerging() != null - ? request.getRepositoryMerging() - : ModelBuilderRequest.RepositoryMerging.POM_DOMINANT, - request.getRepositories() != null - ? request.getRepositories() - : request.getSession().getRemoteRepositories())); - } if (request.getModelResolver() == null) { builder.modelResolver(new DefaultModelResolver()); } @@ -830,14 +895,11 @@ private Model readEffectiveModel(final DefaultModelBuilderSession build) throws // add repositories specified by the current model so that we can resolve the parent if (!model.getRepositories().isEmpty()) { - DefaultModelRepositoryHolder modelRepositoryHolder = getModelRepositoryHolder(request); - List oldRepos = modelRepositoryHolder.getRepositories().stream() - .map(Object::toString) - .toList(); - modelRepositoryHolder.merge(model.getRepositories(), false); - List newRepos = modelRepositoryHolder.getRepositories().stream() - .map(Object::toString) - .toList(); + List oldRepos = + build.getRepositories().stream().map(Object::toString).toList(); + build.mergeRepositories(model.getRepositories(), false); + List newRepos = + build.getRepositories().stream().map(Object::toString).toList(); if (!Objects.equals(oldRepos, newRepos)) { logger.debug("Merging repositories from " + model.getId() + "\n" + newRepos.stream().map(s -> " " + s).collect(Collectors.joining("\n"))); @@ -897,14 +959,11 @@ private Model readEffectiveModel(final DefaultModelBuilderSession build) throws // Now the fully interpolated model is available: reconfigure the resolver if (!resultModel.getRepositories().isEmpty()) { - DefaultModelRepositoryHolder modelRepositoryHolder = getModelRepositoryHolder(request); - List oldRepos = modelRepositoryHolder.getRepositories().stream() - .map(Object::toString) - .toList(); - modelRepositoryHolder.merge(resultModel.getRepositories(), true); - List newRepos = modelRepositoryHolder.getRepositories().stream() - .map(Object::toString) - .toList(); + List oldRepos = + build.getRepositories().stream().map(Object::toString).toList(); + build.mergeRepositories(resultModel.getRepositories(), true); + List newRepos = + build.getRepositories().stream().map(Object::toString).toList(); if (!Objects.equals(oldRepos, newRepos)) { logger.debug("Replacing repositories from " + resultModel.getId() + "\n" + newRepos.stream().map(s -> " " + s).collect(Collectors.joining("\n"))); @@ -1590,8 +1649,7 @@ private ModelData resolveAndReadParentExternally(DefaultModelBuilderSession buil ModelSource modelSource; try { AtomicReference modified = new AtomicReference<>(); - modelSource = modelResolver.resolveModel( - request.getSession(), getModelRepositoryHolder(request).getRepositories(), parent, modified); + modelSource = modelResolver.resolveModel(request.getSession(), build.getRepositories(), parent, modified); if (modified.get() != null) { parent = modified.get(); } @@ -1835,10 +1893,7 @@ private Model doLoadDependencyManagement( final ModelSource importSource; try { importSource = modelResolver.resolveModel( - request.getSession(), - getModelRepositoryHolder(request).getRepositories(), - dependency, - new AtomicReference<>()); + request.getSession(), build.getRepositories(), dependency, new AtomicReference<>()); } catch (ModelBuilderException e) { StringBuilder buffer = new StringBuilder(256); buffer.append("Non-resolvable import POM"); @@ -1877,9 +1932,8 @@ private Model doLoadDependencyManagement( .userProperties(request.getUserProperties()) .source(importSource) .modelResolver(modelResolver) - .modelRepositoryHolder(getModelRepositoryHolder(request).copy()) .twoPhaseBuilding(false) - .repositories(getModelRepositoryHolder(request).getRepositories()) + .repositories(build.getRepositories()) .build(); importResult = build(new DefaultModelBuilderSession(importRequest), importIds); } catch (ModelBuilderException e) { @@ -1894,10 +1948,6 @@ private Model doLoadDependencyManagement( return importModel; } - private static DefaultModelRepositoryHolder getModelRepositoryHolder(ModelBuilderRequest request) { - return (DefaultModelRepositoryHolder) request.getModelRepositoryHolder(); - } - private static T cache( ModelCache cache, String groupId, String artifactId, String version, String tag, Callable supplier) { return cache.computeIfAbsent(groupId, artifactId, version, tag, asSupplier(supplier)); diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelRepositoryHolder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelRepositoryHolder.java deleted file mode 100644 index cb9f6bd2aa9e..000000000000 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelRepositoryHolder.java +++ /dev/null @@ -1,93 +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.ModelBuilderRequest.RepositoryMerging; -import org.apache.maven.api.services.RepositoryFactory; - -public class DefaultModelRepositoryHolder { - - final Session session; - final RepositoryMerging repositoryMerging; - - List pomRepositories; - List repositories; - List externalRepositories; - Set ids; - - public DefaultModelRepositoryHolder( - Session session, RepositoryMerging repositoryMerging, List 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); - } - - public void merge(List toAdd, boolean replace) { - List repos = - toAdd.stream().map(session::createRemoteRepository).toList(); - if (replace) { - Set 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 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); - } - } - - public List getRepositories() { - return List.copyOf(repositories); - } - - public DefaultModelRepositoryHolder copy() { - return new DefaultModelRepositoryHolder(this); - } -} From 7804f2a1c7a5c32aad12677e31a665bb7eab856d Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 6 Sep 2024 18:37:28 +0200 Subject: [PATCH 19/63] Cleanup # Conflicts: # maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java # Conflicts: # maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java --- .../impl/model/DefaultModelBuilder.java | 416 +++++++----------- 1 file changed, 158 insertions(+), 258 deletions(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index f0647c036638..831c0a99d3c5 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -233,14 +233,15 @@ protected final class DefaultModelBuilderSession implements ModelProblemCollecto final DefaultModelBuilderResult result; final ModelCache cache; final Graph dag; - final Map modelByPath; - final Map modelByGA; final Map> mappedSources; - final RepositoryHolder repositoryHolder; - private String source; - private Model sourceModel; - private Model rootModel; + String source; + Model sourceModel; + Model rootModel; + + List pomRepositories; + List externalRepositories; + List repositories; private Set severities = EnumSet.noneOf(ModelProblem.Severity.class); @@ -265,16 +266,7 @@ protected final class DefaultModelBuilderSession implements ModelProblemCollecto DefaultModelBuilderSession( Session session, ModelBuilderRequest request, DefaultModelBuilderResult result, ModelCache cache) { - this( - session, - request, - result, - cache, - new Graph(), - new ConcurrentHashMap<>(64), - new ConcurrentHashMap<>(64), - new ConcurrentHashMap<>(64), - null); + this(session, request, result, cache, new Graph(), new ConcurrentHashMap<>(64), null, null, null); } @SuppressWarnings("checkstyle:ParameterNumber") @@ -284,24 +276,28 @@ private DefaultModelBuilderSession( DefaultModelBuilderResult result, ModelCache cache, Graph dag, - Map modelByPath, - Map modelByGA, Map> mappedSources, - RepositoryHolder repositoryHolder) { + List pomRepositories, + List externalRepositories, + List repositories) { this.session = session; this.request = request; this.result = result; this.cache = cache; this.dag = dag; - this.modelByPath = modelByPath; - this.modelByGA = modelByGA; this.mappedSources = mappedSources; - this.repositoryHolder = repositoryHolder != null - ? repositoryHolder - : new RepositoryHolder( - request.getRepositories() != null - ? request.getRepositories() - : session.getRemoteRepositories()); + if (pomRepositories == null) { + this.pomRepositories = List.of(); + this.externalRepositories = List.copyOf( + request.getRepositories() != null + ? request.getRepositories() + : session.getRemoteRepositories()); + this.repositories = this.externalRepositories; + } else { + this.pomRepositories = pomRepositories; + this.externalRepositories = externalRepositories; + this.repositories = repositories; + } this.result.getProblems().forEach(p -> severities.add(p.getSeverity())); } @@ -314,7 +310,15 @@ public DefaultModelBuilderSession derive(ModelBuilderRequest request, DefaultMod throw new IllegalArgumentException("Session mismatch"); } return new DefaultModelBuilderSession( - session, request, result, cache, dag, modelByPath, modelByGA, mappedSources, repositoryHolder); + session, + request, + result, + cache, + dag, + mappedSources, + pomRepositories, + externalRepositories, + repositories); } public Session session() { @@ -342,74 +346,7 @@ public String toString() { + cache + ']'; } - static class Holder { - private volatile boolean set; - private volatile Model model; - - Holder(Model model) { - this.model = 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 supplier) { - if (!set) { - synchronized (this) { - if (!set) { - this.set = true; - this.model = supplier.get(); - this.notifyAll(); - } - } - } - return model; - } - } - - public Model getRawModel(Path from, String gId, String aId) { - Model model = findRawModel(from, gId, aId); - if (model != null) { - modelByGA.put(new GAKey(gId, aId), new Holder(model)); - if (model.getPomFile() != null) { - modelByPath.put(model.getPomFile(), new Holder(model)); - } - } - return model; - } - - public Model getRawModel(Path from, Path path) { - Model model = findRawModel(from, path); - if (model != null) { - String groupId = getGroupId(model); - modelByGA.put(new GAKey(groupId, model.getArtifactId()), new Holder(model)); - modelByPath.put(path, new Holder(model)); - } - return model; - } - - public Path locate(Path path) { - return getModelProcessor().locateExistingPom(path); - } - - private Model findRawModel(Path from, String groupId, String artifactId) { + public Model getRawModel(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 @@ -429,6 +366,21 @@ private Model findRawModel(Path from, String groupId, String artifactId) { return null; } + public Model getRawModel(Path from, Path path) { + if (!Files.isRegularFile(path)) { + throw new IllegalArgumentException("Not a regular file: " + path); + } + if (!addEdge(from, path)) { + return null; + } + try { + return readRawModel(derive(ModelSource.fromPath(path))); + } catch (ModelBuilderException e) { + // gathered with problem collector + } + return null; + } + private void loadFullReactor() { if (!fullReactorLoaded) { synchronized (this) { @@ -473,21 +425,6 @@ private void doLoadFullReactor() { } } - private Model findRawModel(Path from, Path p) { - if (!Files.isRegularFile(p)) { - throw new IllegalArgumentException("Not a regular file: " + p); - } - if (!addEdge(from, p)) { - return null; - } - try { - return readRawModel(derive(ModelSource.fromPath(p))); - } catch (ModelBuilderException e) { - // gathered with problem collector - } - return null; - } - private boolean addEdge(Path from, Path p) { try { dag.addEdge(from.toString(), p.toString()); @@ -677,75 +614,130 @@ public ModelBuilderException newModelBuilderException() { return new ModelBuilderException(result); } - List getRepositories() { - return repositoryHolder.getRepositories(); + public List getRepositories() { + return repositories; + } + + /** + * TODO: this is not thread safe and the session is mutated + */ + public void mergeRepositories(List toAdd, boolean replace) { + List repos = + toAdd.stream().map(session::createRemoteRepository).toList(); + if (replace) { + Set 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 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 (request.getRepositoryMerging() == ModelBuilderRequest.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); + } } - void mergeRepositories(List repositories, boolean replace) { - repositoryHolder.mergeRepositories(repositories, replace); + /** + * ModelSourceTransformer for the build pom + * + * @param model + * @param path + */ + public Model transform(Model model, Path path) { + Model.Builder builder = Model.newBuilder(model); + handleParent(model, path, builder); + handleReactorDependencies(model, path, builder); + handleCiFriendlyVersion(model, path, builder); + return builder.build(); } - class RepositoryHolder { + // + // Infer parent information + // + void handleParent(Model model, Path pomFile, Model.Builder builder) { + Parent parent = model.getParent(); + if (parent != null) { + String version = parent.getVersion(); + String modVersion = replaceCiFriendlyVersion(version); + builder.parent(parent.withVersion(modVersion)); + } + } - List pomRepositories; - List repositories; - List externalRepositories; + // + // CI friendly versions + // + void handleCiFriendlyVersion(Model model, Path pomFile, Model.Builder builder) { + String version = model.getVersion(); + String modVersion = replaceCiFriendlyVersion(version); + builder.version(modVersion); + } - RepositoryHolder(List externalRepositories) { - this.pomRepositories = List.of(); - this.externalRepositories = List.copyOf(externalRepositories); - this.repositories = List.copyOf(externalRepositories); - } - - RepositoryHolder(RepositoryHolder holder) { - this.pomRepositories = List.copyOf(holder.pomRepositories); - this.externalRepositories = List.copyOf(holder.externalRepositories); - this.repositories = List.copyOf(holder.repositories); - } - - public void mergeRepositories(List toAdd, boolean replace) { - List repos = - toAdd.stream().map(session::createRemoteRepository).toList(); - if (replace) { - Set 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 ids = pomRepositories.stream() - .map(RemoteRepository::getId) - .collect(Collectors.toSet()); - repos = repos.stream().filter(r -> !ids.contains(r.getId())).toList(); + // + // Infer inner reactor dependencies version + // + void handleReactorDependencies(Model model, Path pomFile, Model.Builder builder) { + List newDeps = new ArrayList<>(); + boolean modified = false; + for (Dependency dep : model.getDependencies()) { + Dependency.Builder depBuilder = null; + if (dep.getVersion() == null) { + Model depModel = 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); + } + } } - - RepositoryFactory repositoryFactory = session.getService(RepositoryFactory.class); - if (request.getRepositoryMerging() == ModelBuilderRequest.RepositoryMerging.REQUEST_DOMINANT) { - repositories = repositoryFactory.aggregate(session, repositories, repos, true); - pomRepositories = repositories; + if (depBuilder != null) { + newDeps.add(depBuilder.build()); + modified = true; } else { - pomRepositories = repositoryFactory.aggregate(session, pomRepositories, repos, true); - repositories = repositoryFactory.aggregate(session, pomRepositories, externalRepositories, false); + newDeps.add(dep); } } - - public List getRepositories() { - return repositories; + if (modified) { + builder.dependencies(newDeps); } + } - public RepositoryHolder copy() { - return new RepositoryHolder(this); + String replaceCiFriendlyVersion(String version) { + if (version != null) { + for (String key : Arrays.asList("changelist", "revision", "sha1")) { + String val = request.getUserProperties().get(key); + if (val != null) { + version = version.replace("${" + key + "}", val); + } + } } + return version; } } - DefaultModelProblemCollector newCollector(DefaultModelBuilderResult result) { - return new DefaultModelProblemCollector(result); - } - private static ModelBuilderRequest fillRequestDefaults(ModelBuilderRequest request) { ModelBuilderRequest.ModelBuilderRequestBuilder builder = ModelBuilderRequest.builder(request); if (request.getModelResolver() == null) { @@ -1319,7 +1311,7 @@ private Model doReadFileModel(DefaultModelBuilderSession build) throws ModelBuil request, build); if (hasFatalErrors(build)) { - throw ((ModelProblemCollector) build).newModelBuilderException(); + throw build.newModelBuilderException(); } return model; @@ -1337,7 +1329,7 @@ private Model doReadRawModel(DefaultModelBuilderSession build) throws ModelBuild && request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { Path pomFile = modelSource.getPath(); try { - rawModel = this.transform(build, rawModel, pomFile); + rawModel = build.transform(rawModel, pomFile); } catch (ModelTransformerException e) { build.add(Severity.FATAL, ModelProblem.Version.V40, null, e); } @@ -2011,12 +2003,6 @@ ModelProcessor getModelProcessor() { return modelProcessor; } - private ModelCache getModelCache(ModelBuilderRequest request) { - return request.getSession() - .getData() - .computeIfAbsent(SessionData.key(ModelCache.class), modelCacheFactory::newInstance); - } - private static ModelBuildingListener getModelBuildingListener(ModelBuilderRequest request) { return (ModelBuildingListener) request.getListener(); } @@ -2025,91 +2011,5 @@ private static ModelResolver getModelResolver(ModelBuilderRequest request) { return request.getModelResolver(); } - /** - * ModelSourceTransformer for the build pom - */ - Model transform(DefaultModelBuilderSession build, Model model, Path path) { - Model.Builder builder = Model.newBuilder(model); - handleParent(build, model, path, builder); - handleReactorDependencies(build, model, path, builder); - handleCiFriendlyVersion(build, model, path, builder); - return builder.build(); - } - - // - // Infer parent information - // - void handleParent(DefaultModelBuilderSession build, Model model, Path pomFile, Model.Builder builder) { - Parent parent = model.getParent(); - if (parent != null) { - String version = parent.getVersion(); - String modVersion = replaceCiFriendlyVersion(build, version); - builder.parent(parent.withVersion(modVersion)); - } - } - - // - // CI friendly versions - // - void handleCiFriendlyVersion(DefaultModelBuilderSession build, Model model, Path pomFile, Model.Builder builder) { - String version = model.getVersion(); - String modVersion = replaceCiFriendlyVersion(build, version); - builder.version(modVersion); - } - - // - // Infer inner reactor dependencies version - // - void handleReactorDependencies(DefaultModelBuilderSession build, Model model, Path pomFile, Model.Builder builder) { - List newDeps = new ArrayList<>(); - boolean modified = false; - for (Dependency dep : model.getDependencies()) { - Dependency.Builder depBuilder = null; - if (dep.getVersion() == null) { - Model depModel = build.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); - } - } - - String replaceCiFriendlyVersion(DefaultModelBuilderSession build, String version) { - if (version != null) { - for (String key : Arrays.asList("changelist", "revision", "sha1")) { - String val = build.request.getUserProperties().get(key); - if (val != null) { - version = version.replace("${" + key + "}", val); - } - } - } - return version; - } - record GAKey(String groupId, String artifactId) {} } From bd8169006b371bb8332aec268af37872ac1ab7b2 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Sat, 7 Sep 2024 08:36:09 +0200 Subject: [PATCH 20/63] Add sanity checks --- .../src/main/java/org/apache/maven/model/BaseObject.java | 2 +- .../maven/artifact/repository/metadata/BaseObject.java | 6 ++++-- .../src/main/java/org/apache/maven/settings/BaseObject.java | 6 ++++-- .../java/org/apache/maven/toolchain/model/BaseObject.java | 6 ++++-- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/maven-model/src/main/java/org/apache/maven/model/BaseObject.java b/maven-model/src/main/java/org/apache/maven/model/BaseObject.java index 22c7a6efc4e1..8691fff48040 100644 --- a/maven-model/src/main/java/org/apache/maven/model/BaseObject.java +++ b/maven-model/src/main/java/org/apache/maven/model/BaseObject.java @@ -35,7 +35,7 @@ public BaseObject(Object delegate, BaseObject parent) { } public BaseObject(Object delegate, ChildrenTracking parent) { - this.delegate = delegate; + this.delegate = requireNonNull(delegate, "delegate cannot be null"); this.childrenTracking = parent; } diff --git a/maven-repository-metadata/src/main/java/org/apache/maven/artifact/repository/metadata/BaseObject.java b/maven-repository-metadata/src/main/java/org/apache/maven/artifact/repository/metadata/BaseObject.java index c206298e2bc4..8c6f01f238f5 100644 --- a/maven-repository-metadata/src/main/java/org/apache/maven/artifact/repository/metadata/BaseObject.java +++ b/maven-repository-metadata/src/main/java/org/apache/maven/artifact/repository/metadata/BaseObject.java @@ -20,6 +20,8 @@ import java.io.Serializable; +import static java.util.Objects.requireNonNull; + public abstract class BaseObject implements Serializable, Cloneable { protected transient ChildrenTracking childrenTracking; @@ -28,12 +30,12 @@ public abstract class BaseObject implements Serializable, Cloneable { 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; } diff --git a/maven-settings/src/main/java/org/apache/maven/settings/BaseObject.java b/maven-settings/src/main/java/org/apache/maven/settings/BaseObject.java index 7b66110a8bef..b656ff7b42db 100644 --- a/maven-settings/src/main/java/org/apache/maven/settings/BaseObject.java +++ b/maven-settings/src/main/java/org/apache/maven/settings/BaseObject.java @@ -20,6 +20,8 @@ import java.io.Serializable; +import static java.util.Objects.requireNonNull; + public abstract class BaseObject implements Serializable, Cloneable { protected transient ChildrenTracking childrenTracking; @@ -28,12 +30,12 @@ public abstract class BaseObject implements Serializable, Cloneable { 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; } diff --git a/maven-toolchain-model/src/main/java/org/apache/maven/toolchain/model/BaseObject.java b/maven-toolchain-model/src/main/java/org/apache/maven/toolchain/model/BaseObject.java index 28bea64b8ea7..3a844a77c928 100644 --- a/maven-toolchain-model/src/main/java/org/apache/maven/toolchain/model/BaseObject.java +++ b/maven-toolchain-model/src/main/java/org/apache/maven/toolchain/model/BaseObject.java @@ -20,6 +20,8 @@ import java.io.Serializable; +import static java.util.Objects.requireNonNull; + public abstract class BaseObject implements Serializable, Cloneable { protected transient ChildrenTracking childrenTracking; @@ -28,12 +30,12 @@ public abstract class BaseObject implements Serializable, Cloneable { 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; } From 56cfdda0e0094e05957f1b616b7b407d0bbd9050 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Sat, 7 Sep 2024 16:03:32 +0200 Subject: [PATCH 21/63] Rename method # Conflicts: # maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java # Conflicts: # maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java --- .../apache/maven/internal/impl/model/DefaultModelBuilder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 831c0a99d3c5..6708b868c00e 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -654,7 +654,7 @@ public void mergeRepositories(List toAdd, boolean replace) { * @param model * @param path */ - public Model transform(Model model, Path path) { + Model transformRawToBuildPom(Model model, Path path) { Model.Builder builder = Model.newBuilder(model); handleParent(model, path, builder); handleReactorDependencies(model, path, builder); @@ -1329,7 +1329,7 @@ private Model doReadRawModel(DefaultModelBuilderSession build) throws ModelBuild && request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { Path pomFile = modelSource.getPath(); try { - rawModel = build.transform(rawModel, pomFile); + rawModel = build.transformRawToBuildPom(rawModel, pomFile); } catch (ModelTransformerException e) { build.add(Severity.FATAL, ModelProblem.Version.V40, null, e); } From e153026626900acf14824511b5c06212a8bf1053 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 20 Sep 2024 00:22:11 +0200 Subject: [PATCH 22/63] Clean up raw -> build transformation --- .../impl/model/DefaultModelBuilder.java | 47 ++++++++++++------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 6708b868c00e..c38fa2673316 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -648,45 +648,54 @@ public void mergeRepositories(List toAdd, boolean replace) { } } - /** - * ModelSourceTransformer for the build pom - * - * @param model - * @param path - */ - Model transformRawToBuildPom(Model model, Path path) { + // + // Transform raw model to build pom + // + Model transformRawToBuildPom(Model model) { Model.Builder builder = Model.newBuilder(model); - handleParent(model, path, builder); - handleReactorDependencies(model, path, builder); - handleCiFriendlyVersion(model, path, builder); + builder = handleParent(model, builder); + builder = handleReactorDependencies(model, builder); + builder = handleCiFriendlyVersion(model, builder); return builder.build(); } // // Infer parent information // - void handleParent(Model model, Path pomFile, Model.Builder builder) { + Model.Builder handleParent(Model model, Model.Builder builder) { Parent parent = model.getParent(); if (parent != null) { String version = parent.getVersion(); String modVersion = replaceCiFriendlyVersion(version); - builder.parent(parent.withVersion(modVersion)); + if (!Objects.equals(version, modVersion)) { + if (builder == null) { + builder = Model.newBuilder(model); + } + builder.parent(parent.withVersion(modVersion)); + } } + return builder; } // // CI friendly versions // - void handleCiFriendlyVersion(Model model, Path pomFile, Model.Builder builder) { + Model.Builder handleCiFriendlyVersion(Model model, Model.Builder builder) { String version = model.getVersion(); String modVersion = replaceCiFriendlyVersion(version); - builder.version(modVersion); + if (!Objects.equals(version, modVersion)) { + if (builder == null) { + builder = Model.newBuilder(model); + } + builder.version(modVersion); + } + return builder; } // // Infer inner reactor dependencies version // - void handleReactorDependencies(Model model, Path pomFile, Model.Builder builder) { + Model.Builder handleReactorDependencies(Model model, Model.Builder builder) { List newDeps = new ArrayList<>(); boolean modified = false; for (Dependency dep : model.getDependencies()) { @@ -721,8 +730,12 @@ void handleReactorDependencies(Model model, Path pomFile, Model.Builder builder) } } if (modified) { + if (builder == null) { + builder = Model.newBuilder(model); + } builder.dependencies(newDeps); } + return builder; } String replaceCiFriendlyVersion(String version) { @@ -1323,13 +1336,11 @@ Model readRawModel(DefaultModelBuilderSession build) throws ModelBuilderExceptio private Model doReadRawModel(DefaultModelBuilderSession build) throws ModelBuilderException { ModelBuilderRequest request = build.request; - ModelSource modelSource = request.getSource(); Model rawModel = readFileModel(build); if (!MODEL_VERSION_4_0_0.equals(rawModel.getModelVersion()) && request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { - Path pomFile = modelSource.getPath(); try { - rawModel = build.transformRawToBuildPom(rawModel, pomFile); + rawModel = build.transformRawToBuildPom(rawModel); } catch (ModelTransformerException e) { build.add(Severity.FATAL, ModelProblem.Version.V40, null, e); } From dbd2bb9b0a76fe63c3f2757aa81369a259a9581a Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 20 Sep 2024 07:14:30 +0200 Subject: [PATCH 23/63] Create proper session --- .../AbstractCoreMavenComponentTestCase.java | 79 +++++++++++-------- .../project/AbstractMavenProjectTestCase.java | 26 ++++-- .../AbstractCoreMavenComponentTestCase.java | 48 ++++++----- .../org/apache/maven/MavenTestHelper.java | 21 ++--- .../project/AbstractMavenProjectTestCase.java | 19 +++-- .../maven/project/PomConstructionTest.java | 6 +- .../PomConstructionWithSettingsTest.java | 6 +- 7 files changed, 125 insertions(+), 80 deletions(-) diff --git a/maven-compat/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java b/maven-compat/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java index 36c9110f9ec7..0201b2fd0a62 100644 --- a/maven-compat/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java +++ b/maven-compat/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java @@ -26,6 +26,7 @@ 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.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.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 @@ protected MavenSession createMavenSession(File pom, Properties executionProperti .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 projects = new ArrayList<>(); @@ -165,18 +153,45 @@ protected MavenSession createMavenSession(File pom, Properties executionProperti 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 @@ protected List getRemoteRepositories() throws InvalidReposit repository.setReleases(policy); repository.setSnapshots(policy); - return Arrays.asList(repositorySystem.buildArtifactRepository(repository)); + return Arrays.asList(mavenRepositorySystem.buildArtifactRepository(repository)); } protected List getPluginArtifactRepositories() throws InvalidRepositoryException { @@ -211,7 +226,7 @@ protected List getPluginArtifactRepositories() throws Invali 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 { diff --git a/maven-compat/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java b/maven-compat/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java index b57e953200b7..fffdbb85c655 100644 --- a/maven-compat/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java +++ b/maven-compat/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java @@ -26,25 +26,28 @@ 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; @@ -146,7 +155,7 @@ protected MavenProject getProject(File pom) throws Exception { 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 @@ protected void initRepoSession(ProjectBuildingRequest request) { 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); } } diff --git a/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java b/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java index 443e976129bb..bedc3c8ffda7 100644 --- a/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java +++ b/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java @@ -38,6 +38,7 @@ 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; @@ -119,16 +120,16 @@ protected MavenSession createMavenSession(File pom, Properties executionProperti 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 projects = new ArrayList<>(); if (pom != null) { @@ -151,34 +152,45 @@ protected MavenSession createMavenSession(File pom, Properties executionProperti 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() { diff --git a/maven-core/src/test/java/org/apache/maven/MavenTestHelper.java b/maven-core/src/test/java/org/apache/maven/MavenTestHelper.java index 3176a9473bbc..358ab86ebe6d 100644 --- a/maven-core/src/test/java/org/apache/maven/MavenTestHelper.java +++ b/maven-core/src/test/java/org/apache/maven/MavenTestHelper.java @@ -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; } diff --git a/maven-core/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java b/maven-core/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java index d20ec632803e..652479a879ab 100644 --- a/maven-core/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java +++ b/maven-core/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java @@ -26,6 +26,7 @@ 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.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 @@ protected ProjectBuildingRequest newBuildingRequest() throws Exception { 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)); diff --git a/maven-core/src/test/java/org/apache/maven/project/PomConstructionTest.java b/maven-core/src/test/java/org/apache/maven/project/PomConstructionTest.java index 61908e584e48..e5991ac34d81 100644 --- a/maven-core/src/test/java/org/apache/maven/project/PomConstructionTest.java +++ b/maven-core/src/test/java/org/apache/maven/project/PomConstructionTest.java @@ -38,6 +38,7 @@ 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 +74,9 @@ class PomConstructionTest { @Inject private MavenRepositorySystem repositorySystem; + @Inject + private PlexusContainer container; + private File testDirectory; @BeforeEach @@ -1888,7 +1892,7 @@ private PomTestWrapper buildPom( ? 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( diff --git a/maven-core/src/test/java/org/apache/maven/settings/PomConstructionWithSettingsTest.java b/maven-core/src/test/java/org/apache/maven/settings/PomConstructionWithSettingsTest.java index 8b04f176e95c..9aca25a9d36a 100644 --- a/maven-core/src/test/java/org/apache/maven/settings/PomConstructionWithSettingsTest.java +++ b/maven-core/src/test/java/org/apache/maven/settings/PomConstructionWithSettingsTest.java @@ -36,6 +36,7 @@ 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 @@ private PomTestWrapper buildPom(String pomPath) throws Exception { "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( From e041b99bcc687ef7a5ef408e9f294918f4b730e2 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 20 Sep 2024 08:07:23 +0200 Subject: [PATCH 24/63] Make ModelResolver a component of ModelBuilder --- .../api/services/ModelBuilderRequest.java | 19 ---- .../api/services/model}/ModelResolver.java | 3 +- .../model}/ModelResolverException.java | 4 +- .../impl/model/DefaultModelBuilder.java | 41 ++----- .../DefaultArtifactDescriptorReader.java | 5 +- .../impl/resolver/DefaultModelResolver.java | 4 +- .../resolver/DefaultModelResolverTest.java | 4 +- .../standalone/RepositorySystemSupplier.java | 4 +- .../impl/DefaultConsumerPomBuilder.java | 12 ++- .../maven/project/DefaultProjectBuilder.java | 100 +----------------- .../impl/ConsumerPomBuilderTest.java | 4 +- .../MavenRepositorySystemSupplier.java | 3 +- 12 files changed, 32 insertions(+), 171 deletions(-) rename {api/maven-api-core/src/main/java/org/apache/maven/api/services => maven-api-impl/src/main/java/org/apache/maven/api/services/model}/ModelResolver.java (97%) rename {api/maven-api-core/src/main/java/org/apache/maven/api/services => maven-api-impl/src/main/java/org/apache/maven/api/services/model}/ModelResolverException.java (97%) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java index 9a6616530f88..db2e87f05384 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java @@ -123,9 +123,6 @@ enum RepositoryMerging { @Nonnull Map getUserProperties(); - @Nonnull - ModelResolver getModelResolver(); - @Nonnull RepositoryMerging getRepositoryMerging(); @@ -183,7 +180,6 @@ class ModelBuilderRequestBuilder { List inactiveProfileIds; Map systemProperties; Map userProperties; - ModelResolver modelResolver; RepositoryMerging repositoryMerging; Object listener; ModelBuilderResult interimResult; @@ -202,7 +198,6 @@ class ModelBuilderRequestBuilder { this.inactiveProfileIds = request.getInactiveProfileIds(); this.systemProperties = request.getSystemProperties(); this.userProperties = request.getUserProperties(); - this.modelResolver = request.getModelResolver(); this.repositoryMerging = request.getRepositoryMerging(); this.listener = request.getListener(); this.interimResult = request.getInterimResult(); @@ -259,11 +254,6 @@ public ModelBuilderRequestBuilder userProperties(Map userPropert return this; } - public ModelBuilderRequestBuilder modelResolver(ModelResolver modelResolver) { - this.modelResolver = modelResolver; - return this; - } - public ModelBuilderRequestBuilder repositoryMerging(RepositoryMerging repositoryMerging) { this.repositoryMerging = repositoryMerging; return this; @@ -296,7 +286,6 @@ public ModelBuilderRequest build() { inactiveProfileIds, systemProperties, userProperties, - modelResolver, repositoryMerging, listener, interimResult, @@ -313,7 +302,6 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M private final List inactiveProfileIds; private final Map systemProperties; private final Map userProperties; - private final ModelResolver modelResolver; private final RepositoryMerging repositoryMerging; private final Object listener; private final ModelBuilderResult interimResult; @@ -331,7 +319,6 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M List inactiveProfileIds, Map systemProperties, Map userProperties, - ModelResolver modelResolver, RepositoryMerging repositoryMerging, Object listener, ModelBuilderResult interimResult, @@ -347,7 +334,6 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M this.systemProperties = systemProperties != null ? Map.copyOf(systemProperties) : session.getSystemProperties(); this.userProperties = userProperties != null ? Map.copyOf(userProperties) : session.getUserProperties(); - this.modelResolver = modelResolver; this.repositoryMerging = repositoryMerging; this.listener = listener; this.interimResult = interimResult; @@ -400,11 +386,6 @@ public Map getUserProperties() { return userProperties; } - @Override - public ModelResolver getModelResolver() { - return modelResolver; - } - @Override public RepositoryMerging getRepositoryMerging() { return repositoryMerging; diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelResolver.java b/maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelResolver.java similarity index 97% rename from api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelResolver.java rename to maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelResolver.java index 9bec73491766..b3a0e2332edc 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelResolver.java +++ b/maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelResolver.java @@ -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.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. diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelResolverException.java b/maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelResolverException.java similarity index 97% rename from api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelResolverException.java rename to maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelResolverException.java index 167e67070a9f..0c9f829210fb 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelResolverException.java +++ b/maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelResolverException.java @@ -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. diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index c38fa2673316..e684f26c581f 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -79,8 +79,6 @@ 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.services.ModelResolver; -import org.apache.maven.api.services.ModelResolverException; import org.apache.maven.api.services.ModelSource; import org.apache.maven.api.services.RepositoryFactory; import org.apache.maven.api.services.Source; @@ -98,6 +96,8 @@ 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.ModelResolverException; import org.apache.maven.api.services.model.ModelUrlNormalizer; import org.apache.maven.api.services.model.ModelValidator; import org.apache.maven.api.services.model.ModelVersionParser; @@ -111,7 +111,6 @@ import org.apache.maven.api.spi.ModelParserException; import org.apache.maven.api.spi.ModelTransformer; import org.apache.maven.api.spi.ModelTransformerException; -import org.apache.maven.internal.impl.resolver.DefaultModelResolver; import org.apache.maven.model.v4.MavenTransformer; import org.codehaus.plexus.interpolation.InterpolationException; import org.codehaus.plexus.interpolation.Interpolator; @@ -121,8 +120,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static java.util.Objects.requireNonNull; - /** */ @Named @@ -156,6 +153,7 @@ public class DefaultModelBuilder implements ModelBuilder { private final ModelVersionParser versionParser; private final List transformers; private final ModelCacheFactory modelCacheFactory; + private final ModelResolver modelResolver; @SuppressWarnings("checkstyle:ParameterNumber") @Inject @@ -178,7 +176,8 @@ public DefaultModelBuilder( ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator, ModelVersionParser versionParser, List transformers, - ModelCacheFactory modelCacheFactory) { + ModelCacheFactory modelCacheFactory, + ModelResolver modelResolver) { this.modelProcessor = modelProcessor; this.modelValidator = modelValidator; this.modelNormalizer = modelNormalizer; @@ -198,6 +197,7 @@ public DefaultModelBuilder( this.versionParser = versionParser; this.transformers = transformers; this.modelCacheFactory = modelCacheFactory; + this.modelResolver = modelResolver; } public ModelBuilderSession newSession() { @@ -206,7 +206,6 @@ public ModelBuilderSession newSession() { @Override public ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilderException { - request = fillRequestDefaults(request); if (request.getInterimResult() != null) { if (mainSession == null) { throw new IllegalStateException("ModelBuilderSession is not initialized"); @@ -751,14 +750,6 @@ String replaceCiFriendlyVersion(String version) { } } - private static ModelBuilderRequest fillRequestDefaults(ModelBuilderRequest request) { - ModelBuilderRequest.ModelBuilderRequestBuilder builder = ModelBuilderRequest.builder(request); - if (request.getModelResolver() == null) { - builder.modelResolver(new DefaultModelResolver()); - } - return builder.build(); - } - protected ModelBuilderResult build(DefaultModelBuilderSession build, Collection importIds) throws ModelBuilderException { // phase 1 @@ -1071,7 +1062,6 @@ public ModelBuilderResult build(final ModelBuilderRequest request, final ModelBu } public Model buildRawModel(ModelBuilderRequest request) throws ModelBuilderException { - request = fillRequestDefaults(request); DefaultModelBuilderSession build = new DefaultModelBuilderSession(request); Model model = readRawModel(build); if (hasModelErrors(build)) { @@ -1641,14 +1631,6 @@ private ModelData resolveAndReadParentExternally(DefaultModelBuilderSession buil String artifactId = parent.getArtifactId(); String version = parent.getVersion(); - ModelResolver modelResolver = getModelResolver(request); - requireNonNull( - modelResolver, - String.format( - "request.modelResolver cannot be null (parent POM %s and POM %s)", - ModelProblemUtils.toId(groupId, artifactId, version), - ModelProblemUtils.toSourceHint(childModel))); - ModelSource modelSource; try { AtomicReference modified = new AtomicReference<>(); @@ -1884,12 +1866,6 @@ private Model doLoadDependencyManagement( String version, Collection importIds) { final ModelBuilderRequest request = build.request; - final ModelResolver modelResolver = getModelResolver(request); - if (modelResolver == null) { - throw new NullPointerException(String.format( - "request.workspaceModelResolver and request.modelResolver cannot be null (parent POM %s and POM %s)", - ModelProblemUtils.toId(groupId, artifactId, version), ModelProblemUtils.toSourceHint(model))); - } Model importModel; // no workspace resolver or workspace resolver returned null (i.e. model not in workspace) @@ -1934,7 +1910,6 @@ private Model doLoadDependencyManagement( .systemProperties(request.getSystemProperties()) .userProperties(request.getUserProperties()) .source(importSource) - .modelResolver(modelResolver) .twoPhaseBuilding(false) .repositories(build.getRepositories()) .build(); @@ -2018,9 +1993,5 @@ private static ModelBuildingListener getModelBuildingListener(ModelBuilderReques return (ModelBuildingListener) request.getListener(); } - private static ModelResolver getModelResolver(ModelBuilderRequest request) { - return request.getModelResolver(); - } - record GAKey(String groupId, String artifactId) {} } diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java index 7115468c82aa..5852cfde2861 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java @@ -34,9 +34,8 @@ 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.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; @@ -193,7 +192,6 @@ private Model loadPom( .toList(); String gav = pomArtifact.getGroupId() + ":" + pomArtifact.getArtifactId() + ":" + pomArtifact.getVersion(); - ModelResolver modelResolver = new DefaultModelResolver(); ModelBuilderRequest modelRequest = ModelBuilderRequest.builder() .session(iSession) .requestType(ModelBuilderRequest.RequestType.DEPENDENCY) @@ -203,7 +201,6 @@ private Model loadPom( // properties in dependencies the user does not know. See MNG-7563 for details. .systemProperties(toProperties(session.getUserProperties(), session.getSystemProperties())) .userProperties(Map.of()) - .modelResolver(modelResolver) .repositoryMerging(ModelBuilderRequest.RepositoryMerging.REQUEST_DOMINANT) .repositories(repositories) .build(); diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelResolver.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelResolver.java index 4b66104f3dc4..9ba4e4e619da 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelResolver.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelResolver.java @@ -35,11 +35,11 @@ import org.apache.maven.api.di.Named; import org.apache.maven.api.di.Singleton; 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. diff --git a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/resolver/DefaultModelResolverTest.java b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/resolver/DefaultModelResolverTest.java index 51daf7079af0..187a8f4a5484 100644 --- a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/resolver/DefaultModelResolverTest.java +++ b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/resolver/DefaultModelResolverTest.java @@ -28,8 +28,8 @@ 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; diff --git a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/RepositorySystemSupplier.java b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/RepositorySystemSupplier.java index 94d83542f427..ad4d1f5f5dbf 100644 --- a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/RepositorySystemSupplier.java +++ b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/RepositorySystemSupplier.java @@ -50,6 +50,7 @@ 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; @@ -1058,7 +1059,8 @@ protected ModelBuilder createModelBuilder() { new ProfileActivationFilePathInterpolator(new DefaultPathTranslator(), new DefaultRootLocator()), new DefaultModelVersionParser(getVersionScheme()), List.of(), - new DefaultModelCacheFactory()); + new DefaultModelCacheFactory(), + new DefaultModelResolver()); } private RepositorySystem repositorySystem; diff --git a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java index ed61363140d4..a51230550614 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java @@ -27,7 +27,6 @@ import java.util.List; import java.util.stream.Collectors; -import org.apache.maven.api.SessionData; import org.apache.maven.api.model.Dependency; import org.apache.maven.api.model.DependencyManagement; import org.apache.maven.api.model.DistributionManagement; @@ -39,7 +38,6 @@ 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.SuperPomProvider; import org.apache.maven.api.services.model.DependencyManagementImporter; @@ -51,6 +49,7 @@ 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; @@ -97,6 +96,7 @@ class DefaultConsumerPomBuilder implements ConsumerPomBuilder { private final ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator; private final List transformers; private final ModelCacheFactory modelCacheFactory; + private final ModelResolver modelResolver; @Inject @SuppressWarnings("checkstyle:ParameterNumber") @@ -119,7 +119,8 @@ class DefaultConsumerPomBuilder implements ConsumerPomBuilder { RemoteRepositoryManager remoteRepositoryManager, ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator, List transformers, - ModelCacheFactory modelCacheFactory) { + ModelCacheFactory modelCacheFactory, + ModelResolver modelResolver) { this.profileInjector = profileInjector; this.inheritanceAssembler = inheritanceAssembler; this.dependencyManagementImporter = dependencyManagementImporter; @@ -139,6 +140,7 @@ class DefaultConsumerPomBuilder implements ConsumerPomBuilder { this.profileActivationFilePathInterpolator = profileActivationFilePathInterpolator; this.transformers = transformers; this.modelCacheFactory = modelCacheFactory; + this.modelResolver = modelResolver; } private final Logger logger = LoggerFactory.getLogger(getClass()); @@ -198,14 +200,14 @@ public List getActiveProfiles( profileActivationFilePathInterpolator, versionParser, transformers, - modelCacheFactory); + modelCacheFactory, + modelResolver); InternalSession iSession = InternalSession.from(session); ModelBuilderRequest.ModelBuilderRequestBuilder request = ModelBuilderRequest.builder(); request.requestType(ModelBuilderRequest.RequestType.BUILD_POM); request.session(iSession); request.source(ModelSource.fromPath(src)); request.locationTracking(false); - request.modelResolver(iSession.getData().get(SessionData.key(ModelResolver.class))); request.systemProperties(session.getSystemProperties()); request.userProperties(session.getUserProperties()); return modelBuilder.newSession().build(request.build()); diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index 5e59fb0b2e30..0a033d35e3c4 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -42,7 +42,6 @@ import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; @@ -60,7 +59,6 @@ import org.apache.maven.RepositoryUtils; import org.apache.maven.api.Constants; import org.apache.maven.api.Session; -import org.apache.maven.api.SessionData; import org.apache.maven.api.model.Build; import org.apache.maven.api.model.Dependency; import org.apache.maven.api.model.DependencyManagement; @@ -72,19 +70,18 @@ import org.apache.maven.api.model.Profile; import org.apache.maven.api.model.ReportPlugin; import org.apache.maven.api.services.BuilderProblem; -import org.apache.maven.api.services.MavenException; 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.ModelProblem; -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.model.ModelBuildingEvent; import org.apache.maven.api.services.model.ModelBuildingListener; import org.apache.maven.api.services.model.ModelProcessor; +import org.apache.maven.api.services.model.ModelResolver; +import org.apache.maven.api.services.model.ModelResolverException; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.InvalidArtifactRTException; import org.apache.maven.artifact.InvalidRepositoryException; @@ -103,12 +100,8 @@ import org.apache.maven.plugin.version.PluginVersionResolutionException; import org.apache.maven.repository.internal.ArtifactDescriptorUtils; import org.apache.maven.utils.Os; -import org.codehaus.plexus.interpolation.AbstractValueSource; -import org.codehaus.plexus.interpolation.InterpolationException; -import org.codehaus.plexus.interpolation.StringSearchInterpolator; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.RequestTrace; import org.eclipse.aether.impl.RemoteRepositoryManager; import org.eclipse.aether.repository.LocalRepositoryManager; import org.eclipse.aether.repository.RemoteRepository; @@ -382,12 +375,7 @@ public int hashCode() { class BuildSession implements AutoCloseable { private final ProjectBuildingRequest request; private final RepositorySystemSession session; - private final List repositories; - private final ReactorModelPool modelPool; - private final ConcurrentMap parentCache; private final ExecutorService executor; - private final ModelResolver modelResolver; - private final Map ciFriendlyVersions = new ConcurrentHashMap<>(); private final ModelBuilder.ModelBuilderSession modelBuilderSession; BuildSession(ProjectBuildingRequest request, boolean localProjects) { @@ -395,29 +383,7 @@ class BuildSession implements AutoCloseable { this.session = RepositoryUtils.overlay(request.getLocalRepository(), request.getRepositorySession(), repoSystem); InternalSession.from(session); - this.repositories = RepositoryUtils.toRepos(request.getRemoteRepositories()); this.executor = createExecutor(getParallelism(request)); - if (localProjects) { - this.modelPool = new ReactorModelPool(); - } else { - this.modelPool = null; - } - this.parentCache = new ConcurrentHashMap<>(); - this.modelResolver = new ModelResolverWrapper() { - @Override - protected org.apache.maven.model.resolution.ModelResolver getResolver( - List repositories) { - return new ProjectModelResolver( - session, - RequestTrace.newChild(null, request), - repoSystem, - repositoryManager, - repositories, - request.getRepositoryMerging(), - modelPool, - parentCache); - } - }; this.modelBuilderSession = modelBuilder.newSession(); } @@ -694,13 +660,6 @@ private InterimResult build( Model model = result.getActivatedFileModel(); - // In case the model is using CI friendly versions, at this point, it will contain uninterpolated version - // such as ${revision}${changelist}, so we need to take care of it now - Model modelWithVersion = getModelWithInterpolatedVersion(model, result.getProblems()::add); - if (model.getPomFile() != null) { - modelPool.put(model.getPomFile(), modelWithVersion); - } - InterimResult interimResult = new InterimResult(pomFile, modelBuildingRequest, result, project, isRoot); if (recursive) { @@ -778,59 +737,6 @@ private InterimResult build( return interimResult; } - private Model getModelWithInterpolatedVersion( - Model model, Consumer problems) { - String version = model.getVersion(); - if (version == null && model.getParent() != null) { - version = model.getParent().getVersion(); - } - if (version != null && version.contains("${")) { - try { - StringSearchInterpolator interpolator = new StringSearchInterpolator(); - interpolator.addValueSource(new AbstractValueSource(false) { - @Override - public String getValue(String key) { - String val = request.getUserProperties().getProperty(key); - if (val == null) { - val = model.getProperties().get(key); - if (val == null) { - val = request.getSystemProperties().getProperty(key); - if (val == null) { - val = ciFriendlyVersions.get(key); - } - } - } - if (val != null) { - String oldVal = ciFriendlyVersions.put(key, val); - if (oldVal != null && !val.equals(oldVal)) { - throw new MavenException("Non unique property value detected for key '" + key - + "' which is bound to '" + oldVal + "' and '" + val + "'"); - } - } - return val; - } - }); - version = interpolator.interpolate(version); - } catch (InterpolationException | MavenException e) { - ModelProblem problem = new org.apache.maven.internal.impl.model.DefaultModelProblem( - "Unable to interpolate ", - ModelProblem.Severity.ERROR, - ModelProblem.Version.BASE, - model, - -1, - -1, - null); - problems.accept(problem); - } - if (model.getVersion() != null) { - return model.withVersion(version); - } else { - return model.withParent(model.getParent().withVersion(version)); - } - } - return model; - } - private List build( Map projectIndex, List interimResults) { // The transformation may need to access dependencies raw models, @@ -1199,7 +1105,6 @@ private ModelBuilderRequest.ModelBuilderRequestBuilder getModelBuildingRequest() modelBuildingRequest.systemProperties(toMap(request.getSystemProperties())); modelBuildingRequest.userProperties(toMap(request.getUserProperties())); // bv4: modelBuildingRequest.setBuildStartTime(request.getBuildStartTime()); - modelBuildingRequest.modelResolver(modelResolver); modelBuildingRequest.repositoryMerging(ModelBuilderRequest.RepositoryMerging.valueOf( request.getRepositoryMerging().name())); modelBuildingRequest.repositories(request.getRemoteRepositories().stream() @@ -1216,7 +1121,6 @@ private ModelBuilderRequest.ModelBuilderRequestBuilder getModelBuildingRequest() } } */ - internalSession.getData().set(SessionData.key(ModelResolver.class), modelResolver); return modelBuildingRequest; } diff --git a/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java b/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java index 9e0e9a0346f1..8039f6a48eba 100644 --- a/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java +++ b/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java @@ -35,9 +35,9 @@ import org.apache.maven.api.model.Model; import org.apache.maven.api.model.Parent; import org.apache.maven.api.services.ModelBuilder; -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.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; diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemSupplier.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemSupplier.java index 12ae8c07260e..9b480f91519f 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemSupplier.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemSupplier.java @@ -1060,7 +1060,8 @@ protected ModelBuilder createModelBuilder() { new ProfileActivationFilePathInterpolator(new DefaultPathTranslator(), new DefaultRootLocator()), new DefaultModelVersionParser(getVersionScheme()), List.of(), - new DefaultModelCacheFactory()); + new DefaultModelCacheFactory(), + new org.apache.maven.internal.impl.resolver.DefaultModelResolver()); } private RepositorySystem repositorySystem; From 181186d282482da5aca5dfe3af2c651ce2bb10c9 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Mon, 23 Sep 2024 14:39:56 +0200 Subject: [PATCH 25/63] Move the recursive project load into the ModelBuilder --- .../api/services/ModelBuilderRequest.java | 18 +++ .../api/services/ModelBuilderResult.java | 3 + .../maven/api/services/model/RootLocator.java | 3 +- .../impl/model/DefaultModelBuilder.java | 127 +++++++++++++++--- .../impl/model/DefaultModelBuilderResult.java | 7 + .../impl/standalone/TestApiStandalone.java | 1 + .../maven/project/DefaultProjectBuilder.java | 78 ++--------- .../AbstractCoreMavenComponentTestCase.java | 1 + .../DefaultMavenProjectBuilderTest.java | 7 + .../maven/project/ProjectBuilderTest.java | 3 +- 10 files changed, 165 insertions(+), 83 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java index db2e87f05384..39f10363ea3c 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java @@ -91,6 +91,8 @@ enum RepositoryMerging { boolean isLocationTracking(); + boolean isRecursive(); + /** * Defines external profiles that may be activated for the given model. * Those are external profiles usually defined in {@link org.apache.maven.api.settings.Settings#getProfiles()}. @@ -174,6 +176,7 @@ class ModelBuilderRequestBuilder { RequestType requestType; boolean locationTracking; boolean twoPhaseBuilding; + boolean recursive; ModelSource source; Collection profiles; List activeProfileIds; @@ -192,6 +195,7 @@ class ModelBuilderRequestBuilder { this.requestType = request.getRequestType(); this.locationTracking = request.isLocationTracking(); this.twoPhaseBuilding = request.isTwoPhaseBuilding(); + this.recursive = request.isRecursive(); this.source = request.getSource(); this.profiles = request.getProfiles(); this.activeProfileIds = request.getActiveProfileIds(); @@ -224,6 +228,11 @@ public ModelBuilderRequestBuilder locationTracking(boolean locationTracking) { return this; } + public ModelBuilderRequestBuilder recursive(boolean recursive) { + this.recursive = recursive; + return this; + } + public ModelBuilderRequestBuilder source(ModelSource source) { this.source = source; return this; @@ -280,6 +289,7 @@ public ModelBuilderRequest build() { requestType, locationTracking, twoPhaseBuilding, + recursive, source, profiles, activeProfileIds, @@ -296,6 +306,7 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M private final RequestType requestType; private final boolean locationTracking; private final boolean twoPhaseBuilding; + private final boolean recursive; private final ModelSource source; private final Collection profiles; private final List activeProfileIds; @@ -313,6 +324,7 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M @Nonnull RequestType requestType, boolean locationTracking, boolean twoPhaseBuilding, + boolean recursive, @Nonnull ModelSource source, Collection profiles, List activeProfileIds, @@ -327,6 +339,7 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M this.requestType = nonNull(requestType, "requestType cannot be null"); this.locationTracking = locationTracking; this.twoPhaseBuilding = twoPhaseBuilding; + this.recursive = recursive; this.source = source; this.profiles = profiles != null ? List.copyOf(profiles) : List.of(); this.activeProfileIds = activeProfileIds != null ? List.copyOf(activeProfileIds) : List.of(); @@ -355,6 +368,11 @@ public boolean isLocationTracking() { return locationTracking; } + @Override + public boolean isRecursive() { + return recursive; + } + @Nonnull @Override public ModelSource getSource() { diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderResult.java index fcaf26b81dcb..f55b54614ae3 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderResult.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderResult.java @@ -118,6 +118,9 @@ public interface ModelBuilderResult { @Nonnull List getProblems(); + @Nonnull + List getChildren(); + /** * Creates a human-readable representation of these errors. */ diff --git a/maven-api-impl/src/main/java/org/apache/maven/api/services/model/RootLocator.java b/maven-api-impl/src/main/java/org/apache/maven/api/services/model/RootLocator.java index 505dbbe12a19..7f7d177a805a 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/api/services/model/RootLocator.java +++ b/maven-api-impl/src/main/java/org/apache/maven/api/services/model/RootLocator.java @@ -20,6 +20,7 @@ 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 @@ * 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\"" diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index e684f26c581f..6750f10f1628 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -106,6 +106,7 @@ 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.services.model.RootLocator; import org.apache.maven.api.services.xml.XmlReaderException; import org.apache.maven.api.services.xml.XmlReaderRequest; import org.apache.maven.api.spi.ModelParserException; @@ -301,6 +302,10 @@ private DefaultModelBuilderSession( } public DefaultModelBuilderSession derive(ModelSource source) { + return derive(source, result); + } + + public DefaultModelBuilderSession derive(ModelSource source, DefaultModelBuilderResult result) { return derive(ModelBuilderRequest.build(request, source), result); } @@ -405,10 +410,11 @@ private void doLoadFullReactor() { while (!toLoad.isEmpty()) { Path pom = toLoad.remove(0); try { - Model rawModel = readFileModel(derive(ModelSource.fromPath(pom))); - List subprojects = rawModel.getSubprojects(); + Model model = readFileModel(derive(ModelSource.fromPath(pom))); + model = activateFileModel(this, model); + List subprojects = model.getSubprojects(); if (subprojects.isEmpty()) { - subprojects = rawModel.getModules(); + subprojects = model.getModules(); } for (String subproject : subprojects) { Path subprojectFile = getModelProcessor() @@ -752,24 +758,112 @@ String replaceCiFriendlyVersion(String version) { protected ModelBuilderResult build(DefaultModelBuilderSession build, Collection importIds) throws ModelBuilderException { - // phase 1 - ModelBuilderRequest request = build.request; - DefaultModelBuilderResult result = build.result; + if (build.request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM + && build.request.isRecursive()) { + return buildRecursive(build, importIds); + } else { + return buildParentOrDependency(build, importIds); + } + } - // read and validate raw model - Model fileModel = readFileModel(build); - result.setFileModel(fileModel); + private ModelBuilderResult buildRecursive(DefaultModelBuilderSession build, Collection importIds) + throws ModelBuilderException { + Set buildParts = new HashSet<>(); + Path top = build.request.getSource().getPath(); + if (top == null) { + throw new IllegalStateException("Recursive build requested but source has no path"); + } + buildParts.add(top); - Model activatedFileModel = activateFileModel(build, fileModel); - result.setActivatedFileModel(activatedFileModel); + Path rootDirectory; + try { + rootDirectory = build.session.getRootDirectory(); + } catch (IllegalStateException e) { + rootDirectory = build.session.getService(RootLocator.class).findRoot(top); + } + List toLoad = new ArrayList<>(); + Path root = getModelProcessor().locateExistingPom(rootDirectory); + toLoad.add(root); + while (!toLoad.isEmpty()) { + Path pom = toLoad.remove(0); + DefaultModelBuilderResult r; + boolean isBuildPart = buildParts.contains(pom); + if (pom.equals(top)) { + r = build.result; + } else { + r = new DefaultModelBuilderResult(); + if (isBuildPart) { + build.result.getChildren().add(r); + } + } + try { + Model model = readFileModel(build.derive(ModelSource.fromPath(pom), r)); + r.setFileModel(model); + Model activated = activateFileModel(build, model); + r.setActivatedFileModel(activated); + List subprojects = activated.getSubprojects(); + if (subprojects.isEmpty()) { + subprojects = activated.getModules(); + } + for (String subproject : subprojects) { + Path subprojectFile = getModelProcessor() + .locateExistingPom(pom.getParent().resolve(subproject)); + if (subprojectFile != null) { + toLoad.add(subprojectFile); + if (isBuildPart) { + buildParts.add(subprojectFile); + } + } + } + } catch (ModelBuilderException e) { + // gathered with problem collector + build.add(Severity.ERROR, ModelProblem.Version.V40, "Failed to load project " + pom, e); + } + if (pom != root) { + build.result.getProblems().addAll(r.getProblems()); + r.getProblems().clear(); + } + } + if (hasModelErrors(build)) { + throw build.newModelBuilderException(); + } - if (!request.isTwoPhaseBuilding()) { - return build2(build, importIds); - } else if (hasModelErrors(build)) { + build2(build, importIds); + for (DefaultModelBuilderResult r : build.result.getChildren()) { + if (r.getFileModel() == null) { + continue; + } + var pbs = r.getProblems(); + r.setProblems(List.of()); + build2(build.derive(ModelSource.fromPath(r.getFileModel().getPomFile()), r), importIds); + build.result.getProblems().addAll(r.getProblems()); + pbs.addAll(r.getProblems()); + r.setProblems(pbs); + } + if (hasModelErrors(build)) { throw build.newModelBuilderException(); } - return result; + return build.result; + } + + private ModelBuilderResult buildParentOrDependency(DefaultModelBuilderSession build, Collection importIds) + throws ModelBuilderException { + // phase 1: read and validate raw model + Model fileModel = readFileModel(build); + build.result.setFileModel(fileModel); + + Model activatedFileModel = activateFileModel(build, fileModel); + build.result.setActivatedFileModel(activatedFileModel); + + // if (!build.request.isTwoPhaseBuilding()) { + // phase 2: build the effective model + return build2(build, importIds); + // } else if (hasModelErrors(build)) { + // throw build.newModelBuilderException(); + // } + + // return build.result; } private Model activateFileModel(DefaultModelBuilderSession build, Model inputModel) throws ModelBuilderException { @@ -1154,9 +1248,10 @@ private Model doReadFileModel(DefaultModelBuilderSession build) throws ModelBuil ModelSource modelSource = request.getSource(); Model model; build.setSource(modelSource.getLocation()); + logger.debug("Reading file model from " + modelSource.getLocation()); try { boolean strict = request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM; - + // TODO: we do cache, but what if strict does not have the same value? Path rootDirectory; try { rootDirectory = request.getSession().getRootDirectory(); diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilderResult.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilderResult.java index e10a7e864289..35becbd2a721 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilderResult.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilderResult.java @@ -52,6 +52,8 @@ class DefaultModelBuilderResult implements ModelBuilderResult { private List problems; + private final List children = new ArrayList<>(); + DefaultModelBuilderResult() { modelIds = new ArrayList<>(); rawModels = new HashMap<>(); @@ -185,6 +187,11 @@ public DefaultModelBuilderResult setProblems(List problems) { return this; } + @Override + public List getChildren() { + return children; + } + public String toString() { if (!modelIds.isEmpty()) { String modelId = modelIds.get(0); diff --git a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/TestApiStandalone.java b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/TestApiStandalone.java index 05710d116dc4..aa8a3db3e8ed 100644 --- a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/TestApiStandalone.java +++ b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/TestApiStandalone.java @@ -47,6 +47,7 @@ void testStandalone() { .session(session) .source(ModelSource.fromPath(Paths.get("pom.xml").toAbsolutePath())) .requestType(ModelBuilderRequest.RequestType.BUILD_POM) + .recursive(true) .build()); assertNotNull(result.getEffectiveModel()); diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index 0a033d35e3c4..75a695bee764 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -42,7 +42,6 @@ import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.LinkedBlockingQueue; @@ -99,7 +98,6 @@ import org.apache.maven.plugin.PluginResolutionException; import org.apache.maven.plugin.version.PluginVersionResolutionException; import org.apache.maven.repository.internal.ArtifactDescriptorUtils; -import org.apache.maven.utils.Os; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.impl.RemoteRepositoryManager; @@ -584,8 +582,7 @@ List doBuild(List pomFiles, boolean recursive) { try { // Phase 2: get effective models from the reactor - List results = build(projectIndex, interimResults); - return results; + return build(projectIndex, interimResults); } finally { Thread.currentThread().setContextClassLoader(oldContextClassLoader); } @@ -642,6 +639,7 @@ private InterimResult build( .twoPhaseBuilding(true) .locationTracking(true) .listener(listener) + .recursive(recursive) .build(); ModelBuilderResult result; @@ -658,11 +656,14 @@ private InterimResult build( // result.getProblems().addAll(e.getProblems()) ? } - Model model = result.getActivatedFileModel(); - InterimResult interimResult = new InterimResult(pomFile, modelBuildingRequest, result, project, isRoot); + interimResult.subprojects = result.getChildren().stream() + .map(r -> build(projectIndex, r.getFileModel().getPomFile().toFile(), aggregatorFiles, false, true)) + .toList(); + /* + Model model = result.getActivatedFileModel(); - if (recursive) { + if (recursive && model != null) { File basedir = pomFile.getParentFile(); List subprojects = model.getSubprojects(); if (subprojects.isEmpty()) { @@ -731,6 +732,7 @@ private InterimResult build( interimResult.subprojects = build(projectIndex, subprojectFiles, aggregatorFiles, false, recursive); } } + */ projectIndex.put(pomFile, project); @@ -739,62 +741,10 @@ private InterimResult build( private List build( Map projectIndex, List interimResults) { - // The transformation may need to access dependencies raw models, - // which may cause some re-entrance in the build() method and can - // actually cause deadlocks. In order to workaround the problem, - // we do a first pass by reading all rawModels in order. - /* - List results = new ArrayList<>(); - boolean failure = false; - for (InterimResult r : interimResults) { - DefaultProjectBuildingResult res; - try { - Model model = modelBuilder.buildRawModel(r.request); - res = new DefaultProjectBuildingResult( - model.getId(), - model.getPomFile() != null ? model.getPomFile().toFile() : null, - null); - } catch (ModelBuilderException e) { - failure = true; - res = new DefaultProjectBuildingResult( - e.getModelId(), - r.request.getSource().getPath() != null - ? r.request.getSource().getPath().toFile() - : null, - convert(e.getProblems())); - } - results.add(res); - } - if (failure) { - return results; - } - */ - - List>> callables = interimResults.stream() - .map(interimResult -> - (Callable>) () -> doBuild(projectIndex, interimResult)) + return interimResults.stream() + .map(ir -> doBuild(projectIndex, ir)) + .flatMap(List::stream) .collect(Collectors.toList()); - - try { - List>> futures = executor.invokeAll(callables); - return futures.stream() - .map(listFuture -> { - try { - return listFuture.get(); - } catch (InterruptedException e) { - uncheckedThrow(e); - return null; - } catch (ExecutionException e) { - uncheckedThrow(e.getCause()); - return null; - } - }) - .flatMap(List::stream) - .collect(Collectors.toList()); - } catch (InterruptedException e) { - uncheckedThrow(e); - return null; - } } private List doBuild(Map projectIndex, InterimResult interimResult) { @@ -803,9 +753,7 @@ private List doBuild(Map projectIndex } MavenProject project = interimResult.project; try { - ModelBuilderResult result = modelBuilderSession.build(ModelBuilderRequest.builder(interimResult.request) - .interimResult(interimResult.result) - .build()); + ModelBuilderResult result = interimResult.result; // 2nd pass of initialization: resolve and build parent if necessary List problems = convert(result.getProblems()); diff --git a/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java b/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java index bedc3c8ffda7..3560082c6c03 100644 --- a/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java +++ b/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java @@ -90,6 +90,7 @@ protected File getProject(String name) throws Exception { protected MavenExecutionRequest createMavenExecutionRequest(File pom) throws Exception { MavenExecutionRequest request = new DefaultMavenExecutionRequest() + .setRootDirectory(pom != null ? pom.toPath().getParent() : null) .setPom(pom) .setProjectPresent(true) .setShowErrors(true) diff --git a/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java b/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java index 98f8ba925403..cdef9df96d6f 100644 --- a/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java +++ b/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java @@ -29,6 +29,7 @@ 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; @@ -419,6 +420,12 @@ public void testBuildParentVersionRangeExternallyWithChildRevisionExpression() t 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 results = projectBuilder.build(List.of(pom), true, configuration); assertEquals(2, results.size()); diff --git a/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java b/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java index d1d4521c15ec..b398b17f6345 100644 --- a/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java +++ b/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java @@ -316,7 +316,8 @@ void testBuildProperties() throws Exception { ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest(); configuration.setRepositorySession(mavenSession.getRepositorySession()); configuration.setResolveDependencies(true); - List result = projectBuilder.build(Collections.singletonList(file), true, configuration); + List 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()); From 31dce4e764ae6424ab2770b22428f3a5d8b3422c Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Mon, 23 Sep 2024 19:29:55 +0200 Subject: [PATCH 26/63] fix --- .../maven/internal/impl/model/DefaultModelBuilder.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 6750f10f1628..a29185c566c6 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -768,12 +768,10 @@ protected ModelBuilderResult build(DefaultModelBuilderSession build, Collection< private ModelBuilderResult buildRecursive(DefaultModelBuilderSession build, Collection importIds) throws ModelBuilderException { - Set buildParts = new HashSet<>(); Path top = build.request.getSource().getPath(); if (top == null) { throw new IllegalStateException("Recursive build requested but source has no path"); } - buildParts.add(top); Path rootDirectory; try { @@ -784,6 +782,7 @@ private ModelBuilderResult buildRecursive(DefaultModelBuilderSession build, Coll List toLoad = new ArrayList<>(); Path root = getModelProcessor().locateExistingPom(rootDirectory); toLoad.add(root); + Set buildParts = new HashSet<>(); while (!toLoad.isEmpty()) { Path pom = toLoad.remove(0); DefaultModelBuilderResult r; @@ -810,7 +809,7 @@ private ModelBuilderResult buildRecursive(DefaultModelBuilderSession build, Coll .locateExistingPom(pom.getParent().resolve(subproject)); if (subprojectFile != null) { toLoad.add(subprojectFile); - if (isBuildPart) { + if (pom.equals(top)) { buildParts.add(subprojectFile); } } From 8a398da8c7e1453258e3d46ce48c750f317b06ad Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Mon, 23 Sep 2024 17:27:06 +0200 Subject: [PATCH 27/63] Cleanup # Conflicts: # maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java --- .../impl/model/DefaultModelBuilder.java | 1981 +++++++++-------- .../maven/project/TestProjectBuilder.java | 10 +- .../maven/project/DefaultProjectBuilder.java | 429 +--- 3 files changed, 1050 insertions(+), 1370 deletions(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index a29185c566c6..c6ed255f6457 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -47,6 +47,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.maven.api.Constants; import org.apache.maven.api.RemoteRepository; import org.apache.maven.api.Session; import org.apache.maven.api.SessionData; @@ -212,7 +213,7 @@ public ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilder throw new IllegalStateException("ModelBuilderSession is not initialized"); } DefaultModelBuilderResult result = asDefaultModelBuilderResult(request.getInterimResult()); - return DefaultModelBuilder.this.build2(mainSession.derive(request, result), new LinkedHashSet<>()); + return mainSession.derive(request, result).build2(new LinkedHashSet<>()); } else { DefaultModelBuilderSession session; if (mainSession == null) { @@ -221,7 +222,7 @@ public ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilder } else { session = mainSession.derive(request, new DefaultModelBuilderResult()); } - return DefaultModelBuilder.this.build(session, new LinkedHashSet<>()); + return session.build(new LinkedHashSet<>()); } } }; @@ -243,7 +244,7 @@ protected final class DefaultModelBuilderSession implements ModelProblemCollecto List externalRepositories; List repositories; - private Set severities = EnumSet.noneOf(ModelProblem.Severity.class); + private final Set severities = EnumSet.noneOf(ModelProblem.Severity.class); volatile boolean fullReactorLoaded; @@ -350,6 +351,19 @@ public String toString() { + cache + ']'; } + private int getParallelism() { + int parallelism = Runtime.getRuntime().availableProcessors() / 2 + 1; + try { + String str = request.getUserProperties().get(Constants.MAVEN_PROJECT_BUILDER_PARALLELISM); + if (str != null) { + parallelism = Integer.parseInt(str); + } + } catch (Exception e) { + // ignore + } + return Math.max(1, Math.min(parallelism, Runtime.getRuntime().availableProcessors())); + } + public Model getRawModel(Path from, String groupId, String artifactId) { ModelSource source = getSource(groupId, artifactId); if (source == null) { @@ -362,7 +376,7 @@ public Model getRawModel(Path from, String groupId, String artifactId) { return null; } try { - return readRawModel(derive(source)); + return derive(source).readRawModel(); } catch (ModelBuilderException e) { // gathered with problem collector } @@ -378,7 +392,7 @@ public Model getRawModel(Path from, Path path) { return null; } try { - return readRawModel(derive(ModelSource.fromPath(path))); + return derive(ModelSource.fromPath(path)).readRawModel(); } catch (ModelBuilderException e) { // gathered with problem collector } @@ -410,8 +424,8 @@ private void doLoadFullReactor() { while (!toLoad.isEmpty()) { Path pom = toLoad.remove(0); try { - Model model = readFileModel(derive(ModelSource.fromPath(pom))); - model = activateFileModel(this, model); + Model model = derive(ModelSource.fromPath(pom)).readFileModel(); + model = activateFileModel(model); List subprojects = model.getSubprojects(); if (subprojects.isEmpty()) { subprojects = model.getModules(); @@ -754,704 +768,1146 @@ String replaceCiFriendlyVersion(String version) { } return version; } - } - protected ModelBuilderResult build(DefaultModelBuilderSession build, Collection importIds) - throws ModelBuilderException { - if (build.request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM - && build.request.isRecursive()) { - return buildRecursive(build, importIds); - } else { - return buildParentOrDependency(build, importIds); + ModelBuilderResult build(Collection importIds) throws ModelBuilderException { + if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM && request.isRecursive()) { + return buildRecursive(importIds); + } else { + return buildParentOrDependency(importIds); + } } - } - private ModelBuilderResult buildRecursive(DefaultModelBuilderSession build, Collection importIds) - throws ModelBuilderException { - Path top = build.request.getSource().getPath(); - if (top == null) { - throw new IllegalStateException("Recursive build requested but source has no path"); - } - - Path rootDirectory; - try { - rootDirectory = build.session.getRootDirectory(); - } catch (IllegalStateException e) { - rootDirectory = build.session.getService(RootLocator.class).findRoot(top); - } - List toLoad = new ArrayList<>(); - Path root = getModelProcessor().locateExistingPom(rootDirectory); - toLoad.add(root); - Set buildParts = new HashSet<>(); - while (!toLoad.isEmpty()) { - Path pom = toLoad.remove(0); - DefaultModelBuilderResult r; - boolean isBuildPart = buildParts.contains(pom); - if (pom.equals(top)) { - r = build.result; - } else { - r = new DefaultModelBuilderResult(); - if (isBuildPart) { - build.result.getChildren().add(r); - } + private ModelBuilderResult buildRecursive(Collection importIds) throws ModelBuilderException { + Path top = request.getSource().getPath(); + if (top == null) { + throw new IllegalStateException("Recursive build requested but source has no path"); } + + Path rootDirectory; try { - Model model = readFileModel(build.derive(ModelSource.fromPath(pom), r)); - r.setFileModel(model); - Model activated = activateFileModel(build, model); - r.setActivatedFileModel(activated); - List subprojects = activated.getSubprojects(); - if (subprojects.isEmpty()) { - subprojects = activated.getModules(); + rootDirectory = session.getRootDirectory(); + } catch (IllegalStateException e) { + rootDirectory = session.getService(RootLocator.class).findRoot(top); + } + List toLoad = new ArrayList<>(); + Path root = getModelProcessor().locateExistingPom(rootDirectory); + toLoad.add(root); + Set buildParts = new HashSet<>(); + while (!toLoad.isEmpty()) { + Path pom = toLoad.remove(0); + DefaultModelBuilderResult r; + boolean isBuildPart = buildParts.contains(pom); + if (pom.equals(top)) { + r = result; + } else { + r = new DefaultModelBuilderResult(); + if (isBuildPart) { + result.getChildren().add(r); + } } - for (String subproject : subprojects) { - Path subprojectFile = getModelProcessor() - .locateExistingPom(pom.getParent().resolve(subproject)); - if (subprojectFile != null) { - toLoad.add(subprojectFile); - if (pom.equals(top)) { - buildParts.add(subprojectFile); + try { + Model model = derive(ModelSource.fromPath(pom), r).readFileModel(); + r.setFileModel(model); + Model activated = activateFileModel(model); + r.setActivatedFileModel(activated); + List subprojects = activated.getSubprojects(); + if (subprojects.isEmpty()) { + subprojects = activated.getModules(); + } + for (String subproject : subprojects) { + Path subprojectFile = getModelProcessor() + .locateExistingPom(pom.getParent().resolve(subproject)); + if (subprojectFile != null) { + toLoad.add(subprojectFile); + if (pom.equals(top)) { + buildParts.add(subprojectFile); + } } } + /* + TODO: adapt those checks + + if (subproject == null || subproject.isEmpty()) { + continue; + } + + subproject = subproject.replace('\\', File.separatorChar).replace('/', File.separatorChar); + + Path subprojectPath = modelProcessor.locateExistingPom(new File(basedir, subproject).toPath()); + File subprojectFile = subprojectPath != null ? subprojectPath.toFile() : null; + + if (subprojectFile == null) { + ModelProblem problem = new org.apache.maven.internal.impl.model.DefaultModelProblem( + "Child subproject " + subprojectFile + " of " + pomFile + " does not exist", + ModelProblem.Severity.ERROR, + ModelProblem.Version.BASE, + model, + -1, + -1, + null); + result.getProblems().add(problem); + continue; + } + + if (Os.IS_WINDOWS) { + // we don't canonicalize on unix to avoid interfering with symlinks + try { + subprojectFile = subprojectFile.getCanonicalFile(); + } catch (IOException e) { + subprojectFile = subprojectFile.getAbsoluteFile(); + } + } else { + subprojectFile = new File(subprojectFile.toURI().normalize()); + } + + if (aggregatorFiles.contains(subprojectFile)) { + StringBuilder buffer = new StringBuilder(256); + for (File aggregatorFile : aggregatorFiles) { + buffer.append(aggregatorFile).append(" -> "); + } + buffer.append(subprojectFile); + + ModelProblem problem = new org.apache.maven.internal.impl.model.DefaultModelProblem( + "Child subproject " + subprojectFile + " of " + pomFile + " forms aggregation cycle " + + buffer, + ModelProblem.Severity.ERROR, + ModelProblem.Version.BASE, + model, + -1, + -1, + null); + result.getProblems().add(problem); + + continue; + } + */ + } catch (ModelBuilderException e) { + // gathered with problem collector + add(Severity.ERROR, ModelProblem.Version.V40, "Failed to load project " + pom, e); + } + if (pom != root) { + result.getProblems().addAll(r.getProblems()); + r.getProblems().clear(); } - } catch (ModelBuilderException e) { - // gathered with problem collector - build.add(Severity.ERROR, ModelProblem.Version.V40, "Failed to load project " + pom, e); } - if (pom != root) { - build.result.getProblems().addAll(r.getProblems()); - r.getProblems().clear(); + if (hasErrors()) { + throw newModelBuilderException(); } - } - if (hasModelErrors(build)) { - throw build.newModelBuilderException(); - } - build2(build, importIds); - for (DefaultModelBuilderResult r : build.result.getChildren()) { - if (r.getFileModel() == null) { - continue; + build2(importIds); + for (DefaultModelBuilderResult r : result.getChildren()) { + if (r.getFileModel() == null) { + continue; + } + var pbs = r.getProblems(); + r.setProblems(List.of()); + derive(ModelSource.fromPath(r.getFileModel().getPomFile()), r).build2(importIds); + result.getProblems().addAll(r.getProblems()); + pbs.addAll(r.getProblems()); + r.setProblems(pbs); } - var pbs = r.getProblems(); - r.setProblems(List.of()); - build2(build.derive(ModelSource.fromPath(r.getFileModel().getPomFile()), r), importIds); - build.result.getProblems().addAll(r.getProblems()); - pbs.addAll(r.getProblems()); - r.setProblems(pbs); - } - if (hasModelErrors(build)) { - throw build.newModelBuilderException(); + if (hasErrors()) { + throw newModelBuilderException(); + } + + return result; } - return build.result; - } + private ModelBuilderResult buildParentOrDependency(Collection importIds) throws ModelBuilderException { + // phase 1: read and validate raw model + Model fileModel = readFileModel(); + result.setFileModel(fileModel); - private ModelBuilderResult buildParentOrDependency(DefaultModelBuilderSession build, Collection importIds) - throws ModelBuilderException { - // phase 1: read and validate raw model - Model fileModel = readFileModel(build); - build.result.setFileModel(fileModel); + Model activatedFileModel = activateFileModel(fileModel); + result.setActivatedFileModel(activatedFileModel); - Model activatedFileModel = activateFileModel(build, fileModel); - build.result.setActivatedFileModel(activatedFileModel); + // if (!build.request.isTwoPhaseBuilding()) { + // phase 2: build the effective model + return build2(importIds); + // } else if (hasModelErrors(build)) { + // throw build.newModelBuilderException(); + // } - // if (!build.request.isTwoPhaseBuilding()) { - // phase 2: build the effective model - return build2(build, importIds); - // } else if (hasModelErrors(build)) { - // throw build.newModelBuilderException(); - // } + // return build.result; + } - // return build.result; - } + private ModelBuilderResult build2(Collection importIds) throws ModelBuilderException { + // phase 2 + Model resultModel = readEffectiveModel(); + setSource(resultModel); + setRootModel(resultModel); - private Model activateFileModel(DefaultModelBuilderSession build, Model inputModel) throws ModelBuilderException { - build.setRootModel(inputModel); + // model path translation + resultModel = + modelPathTranslator.alignToBaseDirectory(resultModel, resultModel.getProjectDirectory(), request); - // profile activation - DefaultProfileActivationContext profileActivationContext = - getProfileActivationContext(build.request, inputModel); + // plugin management injection + resultModel = pluginManagementInjector.injectManagement(resultModel, request, this); - build.setSource("(external profiles)"); - List activeExternalProfiles = - profileSelector.getActiveProfiles(build.request.getProfiles(), profileActivationContext, build); + resultModel = fireEvent(resultModel, request, this, ModelBuildingListener::buildExtensionsAssembled); - build.result.setActiveExternalProfiles(activeExternalProfiles); + if (request.getRequestType() != ModelBuilderRequest.RequestType.DEPENDENCY) { + if (lifecycleBindingsInjector == null) { + throw new IllegalStateException("lifecycle bindings injector is missing"); + } - if (!activeExternalProfiles.isEmpty()) { - Properties profileProps = new Properties(); - for (Profile profile : activeExternalProfiles) { - profileProps.putAll(profile.getProperties()); + // lifecycle bindings injection + resultModel = lifecycleBindingsInjector.injectLifecycleBindings(resultModel, request, this); } - profileProps.putAll(profileActivationContext.getUserProperties()); - profileActivationContext.setUserProperties(profileProps); - } - profileActivationContext.setProjectProperties(inputModel.getProperties()); - build.setSource(inputModel); - List activePomProfiles = - profileSelector.getActiveProfiles(inputModel.getProfiles(), profileActivationContext, build); + // dependency management import + resultModel = importDependencyManagement(resultModel, importIds); - // model normalization - build.setSource(inputModel); - inputModel = modelNormalizer.mergeDuplicates(inputModel, build.request, build); + // dependency management injection + resultModel = dependencyManagementInjector.injectManagement(resultModel, request, this); - Map interpolatedActivations = getProfileActivations(inputModel); - inputModel = injectProfileActivations(inputModel, interpolatedActivations); + resultModel = modelNormalizer.injectDefaultValues(resultModel, request, this); - // profile injection - inputModel = profileInjector.injectProfiles(inputModel, activePomProfiles, build.request, build); - inputModel = profileInjector.injectProfiles(inputModel, activeExternalProfiles, build.request, build); + if (request.getRequestType() != ModelBuilderRequest.RequestType.DEPENDENCY) { + // plugins configuration + resultModel = pluginConfigurationExpander.expandPluginConfiguration(resultModel, request, this); + } - return inputModel; - } + for (var transformer : transformers) { + resultModel = transformer.transformEffectiveModel(resultModel); + } + + result.setEffectiveModel(resultModel); - @SuppressWarnings("checkstyle:methodlength") - private Model readEffectiveModel(final DefaultModelBuilderSession build) throws ModelBuilderException { + // effective model validation + modelValidator.validateEffectiveModel( + resultModel, + request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM + ? ModelValidator.VALIDATION_LEVEL_STRICT + : ModelValidator.VALIDATION_LEVEL_MINIMAL, + request, + this); - ModelBuilderRequest request = build.request; - DefaultModelBuilderResult result = build.result; + if (hasErrors()) { + throw newModelBuilderException(); + } - Model inputModel = readRawModel(build); - if (build.hasFatalErrors()) { - throw build.newModelBuilderException(); + return result; } - inputModel = activateFileModel(build, inputModel); + ModelData readParent(Model childModel, ModelSource childSource) throws ModelBuilderException { + ModelData parentData = null; - build.setRootModel(inputModel); + Parent parent = childModel.getParent(); + if (parent != null) { + parentData = readParentLocally(childModel, childSource); + if (parentData == null) { + parentData = resolveAndReadParentExternally(childModel); + } - ModelData resultData = new ModelData(request.getSource(), inputModel); - String superModelVersion = - inputModel.getModelVersion() != null ? inputModel.getModelVersion() : MODEL_VERSION_4_0_0; - if (!VALID_MODEL_VERSIONS.contains(superModelVersion)) { - // Maven 3.x is always using 4.0.0 version to load the supermodel, so - // do the same when loading a dependency. The model validator will also - // check that field later. - superModelVersion = MODEL_VERSION_4_0_0; - } - ModelData superData = new ModelData(null, getSuperModel(superModelVersion)); + Model parentModel = parentData.model(); + if (!"pom".equals(parentModel.getPackaging())) { + add( + Severity.ERROR, + ModelProblem.Version.BASE, + "Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint(parentModel) + + ", must be \"pom\" but is \"" + parentModel.getPackaging() + "\"", + parentModel.getLocation("packaging")); + } + } - // profile activation - DefaultProfileActivationContext profileActivationContext = getProfileActivationContext(request, inputModel); + return parentData; + } - List activeExternalProfiles = result.getActiveExternalProfiles(); + private ModelData readParentLocally(Model childModel, ModelSource childSource) throws ModelBuilderException { + ModelSource candidateSource = getParentPomFile(childModel, childSource); + if (candidateSource == null) { + return null; + } + final Model candidateModel = derive(candidateSource).readRawModel(); + + // + // TODO jvz Why isn't all this checking the job of the duty of the workspace resolver, we know that we + // have a model that is suitable, yet more checks are done here and the one for the version is problematic + // before because with parents as ranges it will never work in this scenario. + // + + String groupId = getGroupId(candidateModel); + String artifactId = candidateModel.getArtifactId(); + + Parent parent = childModel.getParent(); + if (groupId == null + || !groupId.equals(parent.getGroupId()) + || artifactId == null + || !artifactId.equals(parent.getArtifactId())) { + StringBuilder buffer = new StringBuilder(256); + buffer.append("'parent.relativePath'"); + if (childModel != getRootModel()) { + buffer.append(" of POM ").append(ModelProblemUtils.toSourceHint(childModel)); + } + buffer.append(" points at ").append(groupId).append(':').append(artifactId); + buffer.append(" instead of ").append(parent.getGroupId()).append(':'); + buffer.append(parent.getArtifactId()).append(", please verify your project structure"); - if (!activeExternalProfiles.isEmpty()) { - Properties profileProps = new Properties(); - for (Profile profile : activeExternalProfiles) { - profileProps.putAll(profile.getProperties()); + setSource(childModel); + add(Severity.WARNING, ModelProblem.Version.BASE, buffer.toString(), parent.getLocation("")); + return null; } - profileProps.putAll(profileActivationContext.getUserProperties()); - profileActivationContext.setUserProperties(profileProps); - } - Collection parentIds = new LinkedHashSet<>(); + String version = getVersion(candidateModel); + if (version != null && parent.getVersion() != null && !version.equals(parent.getVersion())) { + try { + VersionRange parentRange = versionParser.parseVersionRange(parent.getVersion()); + if (!parentRange.contains(versionParser.parseVersion(version))) { + // version skew drop back to resolution from the repository + return null; + } - List lineage = new ArrayList<>(); + // Validate versions aren't inherited when using parent ranges the same way as when read externally. + String rawChildModelVersion = childModel.getVersion(); - for (ModelData currentData = resultData; ; ) { - String modelId = currentData.id(); - result.addModelId(modelId); + if (rawChildModelVersion == null) { + // Message below is checked for in the MNG-2199 core IT. + add( + Severity.FATAL, + ModelProblem.Version.V31, + "Version must be a constant", + childModel.getLocation("")); - Model model = currentData.model(); - result.setRawModel(modelId, model); - build.setSource(model); + } else { + if (rawChildVersionReferencesParent(rawChildModelVersion)) { + // Message below is checked for in the MNG-2199 core IT. + add( + Severity.FATAL, + ModelProblem.Version.V31, + "Version must be a constant", + childModel.getLocation("version")); + } + } - // model normalization - model = modelNormalizer.mergeDuplicates(model, request, build); + // MNG-2199: What else to check here ? + } catch (VersionParserException e) { + // invalid version range, so drop back to resolution from the repository + return null; + } + } - // profile activation - profileActivationContext.setProjectProperties(model.getProperties()); + // + // Here we just need to know that a version is fine to use but this validation we can do in our workspace + // resolver. + // - List interpolatedProfiles = - interpolateActivations(model.getProfiles(), profileActivationContext, build); + /* + * if ( version == null || !version.equals( parent.getVersion() ) ) { return null; } + */ - // profile injection - List activePomProfiles = - profileSelector.getActiveProfiles(interpolatedProfiles, profileActivationContext, build); - result.setActivePomProfiles(modelId, activePomProfiles); - model = profileInjector.injectProfiles(model, activePomProfiles, request, build); - if (currentData == resultData) { - model = profileInjector.injectProfiles(model, activeExternalProfiles, request, build); - } + return new ModelData(candidateSource, candidateModel); + } - lineage.add(model); + ModelData resolveAndReadParentExternally(Model childModel) throws ModelBuilderException { + ModelBuilderRequest request = this.request; + setSource(childModel); - if (currentData == superData) { - break; - } + Parent parent = childModel.getParent(); - // add repositories specified by the current model so that we can resolve the parent - if (!model.getRepositories().isEmpty()) { - List oldRepos = - build.getRepositories().stream().map(Object::toString).toList(); - build.mergeRepositories(model.getRepositories(), false); - List newRepos = - build.getRepositories().stream().map(Object::toString).toList(); - if (!Objects.equals(oldRepos, newRepos)) { - logger.debug("Merging repositories from " + model.getId() + "\n" - + newRepos.stream().map(s -> " " + s).collect(Collectors.joining("\n"))); + String groupId = parent.getGroupId(); + String artifactId = parent.getArtifactId(); + String version = parent.getVersion(); + + ModelSource modelSource; + try { + AtomicReference modified = new AtomicReference<>(); + modelSource = modelResolver.resolveModel(request.getSession(), getRepositories(), parent, modified); + if (modified.get() != null) { + parent = modified.get(); + } + } catch (ModelResolverException e) { + // Message below is checked for in the MNG-2199 core IT. + StringBuilder buffer = new StringBuilder(256); + buffer.append("Non-resolvable parent POM"); + if (!containsCoordinates(e.getMessage(), groupId, artifactId, version)) { + buffer.append(' ').append(ModelProblemUtils.toId(groupId, artifactId, version)); + } + if (childModel != getRootModel()) { + buffer.append(" for ").append(ModelProblemUtils.toId(childModel)); } + buffer.append(": ").append(e.getMessage()); + if (childModel.getProjectDirectory() != null) { + if (parent.getRelativePath() == null + || parent.getRelativePath().isEmpty()) { + buffer.append(" and 'parent.relativePath' points at no local POM"); + } else { + buffer.append(" and 'parent.relativePath' points at wrong local POM"); + } + } + + add(Severity.FATAL, ModelProblem.Version.BASE, buffer.toString(), parent.getLocation(""), e); + throw newModelBuilderException(); } - // we pass a cloned model, so that resolving the parent version does not affect the returned model - ModelData parentData = readParent(build, model, currentData.source()); + ModelBuilderRequest lenientRequest = ModelBuilderRequest.builder(request) + .requestType(ModelBuilderRequest.RequestType.PARENT_POM) + .source(modelSource) + .build(); - if (parentData == null) { - currentData = superData; - } else if (!parentIds.add(parentData.id())) { - StringBuilder message = new StringBuilder("The parents form a cycle: "); - for (String parentId : parentIds) { - message.append(parentId).append(" -> "); - } - message.append(parentData.id()); + Model parentModel = new DefaultModelBuilderSession(lenientRequest, this.result).readParentModel(); - build.add(Severity.FATAL, ModelProblem.Version.BASE, message.toString()); + if (!parent.getVersion().equals(version)) { + String rawChildModelVersion = childModel.getVersion(); - throw build.newModelBuilderException(); - } else { - currentData = parentData; - } - } + if (rawChildModelVersion == null) { + // Message below is checked for in the MNG-2199 core IT. + add( + Severity.FATAL, + ModelProblem.Version.V31, + "Version must be a constant", + childModel.getLocation("")); + } else { + if (rawChildVersionReferencesParent(rawChildModelVersion)) { + // Message below is checked for in the MNG-2199 core IT. + add( + Severity.FATAL, + ModelProblem.Version.V31, + "Version must be a constant", + childModel.getLocation("version")); + } + } - Model tmpModel = lineage.get(0); + // MNG-2199: What else to check here ? + } - // inject interpolated activations - List interpolated = interpolateActivations(tmpModel.getProfiles(), profileActivationContext, build); - if (interpolated != tmpModel.getProfiles()) { - tmpModel = tmpModel.withProfiles(interpolated); + return new ModelData(modelSource, parentModel); } - // inject external profile into current model - tmpModel = profileInjector.injectProfiles(tmpModel, activeExternalProfiles, request, build); + Model activateFileModel(Model inputModel) throws ModelBuilderException { + setRootModel(inputModel); - lineage.set(0, tmpModel); + // profile activation + DefaultProfileActivationContext profileActivationContext = getProfileActivationContext(request, inputModel); - checkPluginVersions(lineage, request, build); + setSource("(external profiles)"); + List activeExternalProfiles = + profileSelector.getActiveProfiles(request.getProfiles(), profileActivationContext, this); - // inheritance assembly - Model resultModel = assembleInheritance(lineage, request, build); + result.setActiveExternalProfiles(activeExternalProfiles); - // consider caching inherited model + if (!activeExternalProfiles.isEmpty()) { + Properties profileProps = new Properties(); + for (Profile profile : activeExternalProfiles) { + profileProps.putAll(profile.getProperties()); + } + profileProps.putAll(profileActivationContext.getUserProperties()); + profileActivationContext.setUserProperties(profileProps); + } - build.setSource(resultModel); - build.setRootModel(resultModel); + profileActivationContext.setProjectProperties(inputModel.getProperties()); + setSource(inputModel); + List activePomProfiles = + profileSelector.getActiveProfiles(inputModel.getProfiles(), profileActivationContext, this); - // model interpolation - resultModel = interpolateModel(resultModel, request, build); + // model normalization + setSource(inputModel); + inputModel = modelNormalizer.mergeDuplicates(inputModel, request, this); - // url normalization - resultModel = modelUrlNormalizer.normalize(resultModel, request); + Map interpolatedActivations = getProfileActivations(inputModel); + inputModel = injectProfileActivations(inputModel, interpolatedActivations); - result.setEffectiveModel(resultModel); + // profile injection + inputModel = profileInjector.injectProfiles(inputModel, activePomProfiles, request, this); + inputModel = profileInjector.injectProfiles(inputModel, activeExternalProfiles, request, this); - // Now the fully interpolated model is available: reconfigure the resolver - if (!resultModel.getRepositories().isEmpty()) { - List oldRepos = - build.getRepositories().stream().map(Object::toString).toList(); - build.mergeRepositories(resultModel.getRepositories(), true); - List newRepos = - build.getRepositories().stream().map(Object::toString).toList(); - if (!Objects.equals(oldRepos, newRepos)) { - logger.debug("Replacing repositories from " + resultModel.getId() + "\n" - + newRepos.stream().map(s -> " " + s).collect(Collectors.joining("\n"))); - } + return inputModel; } - return resultModel; - } + @SuppressWarnings("checkstyle:methodlength") + private Model readEffectiveModel() throws ModelBuilderException { - private List interpolateActivations( - List profiles, DefaultProfileActivationContext context, ModelProblemCollector problems) { - if (profiles.stream() - .map(org.apache.maven.api.model.Profile::getActivation) - .noneMatch(Objects::nonNull)) { - return profiles; - } - final Interpolator xform = new RegexBasedInterpolator(); - xform.setCacheAnswers(true); - Stream.of(context.getUserProperties(), context.getSystemProperties()) - .map(MapBasedValueSource::new) - .forEach(xform::addValueSource); + ModelBuilderRequest request = this.request; + DefaultModelBuilderResult result = this.result; - class ProfileInterpolator extends MavenTransformer implements UnaryOperator { - ProfileInterpolator() { - super(s -> { - if (isNotEmpty(s)) { - try { - return xform.interpolate(s); - } catch (InterpolationException e) { - problems.add(Severity.ERROR, ModelProblem.Version.BASE, e.getMessage(), e); - } - } - return s; - }); + Model inputModel = readRawModel(); + if (hasFatalErrors()) { + throw newModelBuilderException(); } - @Override - public Profile apply(Profile p) { - return Profile.newBuilder(p) - .activation(transformActivation(p.getActivation())) - .build(); - } + inputModel = activateFileModel(inputModel); - @Override - protected ActivationFile.Builder transformActivationFile_Missing( - Supplier creator, - ActivationFile.Builder builder, - ActivationFile target) { - String path = target.getMissing(); - String xformed = transformPath(path, target, "missing"); - return xformed != path ? (builder != null ? builder : creator.get()).missing(xformed) : builder; - } + setRootModel(inputModel); - @Override - protected ActivationFile.Builder transformActivationFile_Exists( - Supplier creator, - ActivationFile.Builder builder, - ActivationFile target) { - final String path = target.getExists(); - final String xformed = transformPath(path, target, "exists"); - return xformed != path ? (builder != null ? builder : creator.get()).exists(xformed) : builder; + ModelData resultData = new ModelData(request.getSource(), inputModel); + String superModelVersion = + inputModel.getModelVersion() != null ? inputModel.getModelVersion() : MODEL_VERSION_4_0_0; + if (!VALID_MODEL_VERSIONS.contains(superModelVersion)) { + // Maven 3.x is always using 4.0.0 version to load the supermodel, so + // do the same when loading a dependency. The model validator will also + // check that field later. + superModelVersion = MODEL_VERSION_4_0_0; } + ModelData superData = new ModelData(null, getSuperModel(superModelVersion)); - private String transformPath(String path, ActivationFile target, String locationKey) { - if (isNotEmpty(path)) { - try { - return profileActivationFilePathInterpolator.interpolate(path, context); - } catch (InterpolationException e) { - addInterpolationProblem(problems, target, path, e, locationKey); - } + // profile activation + DefaultProfileActivationContext profileActivationContext = getProfileActivationContext(request, inputModel); + + List activeExternalProfiles = result.getActiveExternalProfiles(); + + if (!activeExternalProfiles.isEmpty()) { + Properties profileProps = new Properties(); + for (Profile profile : activeExternalProfiles) { + profileProps.putAll(profile.getProperties()); } - return path; + profileProps.putAll(profileActivationContext.getUserProperties()); + profileActivationContext.setUserProperties(profileProps); } - } - return profiles.stream().map(new ProfileInterpolator()).toList(); - } - private static void addInterpolationProblem( - ModelProblemCollector problems, - InputLocationTracker target, - String path, - InterpolationException e, - String locationKey) { - problems.add( - Severity.ERROR, - ModelProblem.Version.BASE, - "Failed to interpolate file location " + path + ": " + e.getMessage(), - target.getLocation(locationKey), - e); - } + Collection parentIds = new LinkedHashSet<>(); - private static boolean isNotEmpty(String string) { - return string != null && !string.isEmpty(); - } + List lineage = new ArrayList<>(); - public ModelBuilderResult build(final ModelBuilderRequest request, final ModelBuilderResult result) - throws ModelBuilderException { - return build( - new DefaultModelBuilderSession(request, (DefaultModelBuilderResult) result), new LinkedHashSet<>()); - } + for (ModelData currentData = resultData; ; ) { + String modelId = currentData.id(); + result.addModelId(modelId); - public Model buildRawModel(ModelBuilderRequest request) throws ModelBuilderException { - DefaultModelBuilderSession build = new DefaultModelBuilderSession(request); - Model model = readRawModel(build); - if (hasModelErrors(build)) { - throw build.newModelBuilderException(); - } - return model; - } + Model model = currentData.model(); + result.setRawModel(modelId, model); + setSource(model); - private ModelBuilderResult build2(DefaultModelBuilderSession build, Collection importIds) - throws ModelBuilderException { - ModelBuilderRequest request = build.request; - DefaultModelBuilderResult result = build.result; + // model normalization + model = modelNormalizer.mergeDuplicates(model, request, this); - // phase 2 - Model resultModel = readEffectiveModel(build); - build.setSource(resultModel); - build.setRootModel(resultModel); + // profile activation + profileActivationContext.setProjectProperties(model.getProperties()); - // model path translation - resultModel = modelPathTranslator.alignToBaseDirectory(resultModel, resultModel.getProjectDirectory(), request); + List interpolatedProfiles = + interpolateActivations(model.getProfiles(), profileActivationContext, this); - // plugin management injection - resultModel = pluginManagementInjector.injectManagement(resultModel, request, build); + // profile injection + List activePomProfiles = + profileSelector.getActiveProfiles(interpolatedProfiles, profileActivationContext, this); + result.setActivePomProfiles(modelId, activePomProfiles); + model = profileInjector.injectProfiles(model, activePomProfiles, request, this); + if (currentData == resultData) { + model = profileInjector.injectProfiles(model, activeExternalProfiles, request, this); + } - resultModel = fireEvent(resultModel, request, build, ModelBuildingListener::buildExtensionsAssembled); + lineage.add(model); - if (request.getRequestType() != ModelBuilderRequest.RequestType.DEPENDENCY) { - if (lifecycleBindingsInjector == null) { - throw new IllegalStateException("lifecycle bindings injector is missing"); - } + if (currentData == superData) { + break; + } - // lifecycle bindings injection - resultModel = lifecycleBindingsInjector.injectLifecycleBindings(resultModel, request, build); - } + // add repositories specified by the current model so that we can resolve the parent + if (!model.getRepositories().isEmpty()) { + List oldRepos = + getRepositories().stream().map(Object::toString).toList(); + mergeRepositories(model.getRepositories(), false); + List newRepos = + getRepositories().stream().map(Object::toString).toList(); + if (!Objects.equals(oldRepos, newRepos)) { + logger.debug("Merging repositories from " + model.getId() + "\n" + + newRepos.stream().map(s -> " " + s).collect(Collectors.joining("\n"))); + } + } - // dependency management import - resultModel = importDependencyManagement(build, resultModel, importIds); + // we pass a cloned model, so that resolving the parent version does not affect the returned model + ModelData parentData = readParent(model, currentData.source()); - // dependency management injection - resultModel = dependencyManagementInjector.injectManagement(resultModel, request, build); + if (parentData == null) { + currentData = superData; + } else if (!parentIds.add(parentData.id())) { + StringBuilder message = new StringBuilder("The parents form a cycle: "); + for (String parentId : parentIds) { + message.append(parentId).append(" -> "); + } + message.append(parentData.id()); - resultModel = modelNormalizer.injectDefaultValues(resultModel, request, build); + add(Severity.FATAL, ModelProblem.Version.BASE, message.toString()); - if (request.getRequestType() != ModelBuilderRequest.RequestType.DEPENDENCY) { - // plugins configuration - resultModel = pluginConfigurationExpander.expandPluginConfiguration(resultModel, request, build); - } + throw newModelBuilderException(); + } else { + currentData = parentData; + } + } - for (var transformer : transformers) { - resultModel = transformer.transformEffectiveModel(resultModel); - } + Model tmpModel = lineage.get(0); - result.setEffectiveModel(resultModel); + // inject interpolated activations + List interpolated = interpolateActivations(tmpModel.getProfiles(), profileActivationContext, this); + if (interpolated != tmpModel.getProfiles()) { + tmpModel = tmpModel.withProfiles(interpolated); + } - // effective model validation - modelValidator.validateEffectiveModel( - resultModel, - request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM - ? ModelValidator.VALIDATION_LEVEL_STRICT - : ModelValidator.VALIDATION_LEVEL_MINIMAL, - request, - build); + // inject external profile into current model + tmpModel = profileInjector.injectProfiles(tmpModel, activeExternalProfiles, request, this); - if (hasModelErrors(build)) { - throw build.newModelBuilderException(); - } + lineage.set(0, tmpModel); - return result; - } + checkPluginVersions(lineage, request, this); - private DefaultModelBuilderResult asDefaultModelBuilderResult(ModelBuilderResult phaseOneResult) { - if (phaseOneResult instanceof DefaultModelBuilderResult) { - return (DefaultModelBuilderResult) phaseOneResult; - } else { - return new DefaultModelBuilderResult(phaseOneResult); - } - } + // inheritance assembly + Model resultModel = assembleInheritance(lineage, request, this); - Model readFileModel(DefaultModelBuilderSession build) throws ModelBuilderException { - Model model = cache(build.cache, build.request.getSource(), FILE, () -> doReadFileModel(build)); - if (build.request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { - build.putSource(getGroupId(model), model.getArtifactId(), build.request.getSource()); - } - return model; - } + // consider caching inherited model - @SuppressWarnings("checkstyle:methodlength") - private Model doReadFileModel(DefaultModelBuilderSession build) throws ModelBuilderException { - ModelBuilderRequest request = build.request; - ModelSource modelSource = request.getSource(); - Model model; - build.setSource(modelSource.getLocation()); - logger.debug("Reading file model from " + modelSource.getLocation()); - try { - boolean strict = request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM; - // TODO: we do cache, but what if strict does not have the same value? - Path rootDirectory; + setSource(resultModel); + setRootModel(resultModel); + + // model interpolation + resultModel = interpolateModel(resultModel, request, this); + + // url normalization + resultModel = modelUrlNormalizer.normalize(resultModel, request); + + result.setEffectiveModel(resultModel); + + // Now the fully interpolated model is available: reconfigure the resolver + if (!resultModel.getRepositories().isEmpty()) { + List oldRepos = + getRepositories().stream().map(Object::toString).toList(); + mergeRepositories(resultModel.getRepositories(), true); + List newRepos = + getRepositories().stream().map(Object::toString).toList(); + if (!Objects.equals(oldRepos, newRepos)) { + logger.debug("Replacing repositories from " + resultModel.getId() + "\n" + + newRepos.stream().map(s -> " " + s).collect(Collectors.joining("\n"))); + } + } + + return resultModel; + } + + Model readFileModel() throws ModelBuilderException { + Model model = cache(request.getSource(), FILE, this::doReadFileModel); + if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { + putSource(getGroupId(model), model.getArtifactId(), request.getSource()); + } + return model; + } + + @SuppressWarnings("checkstyle:methodlength") + Model doReadFileModel() throws ModelBuilderException { + ModelBuilderRequest request = this.request; + ModelSource modelSource = request.getSource(); + Model model; + setSource(modelSource.getLocation()); + logger.debug("Reading file model from " + modelSource.getLocation()); try { - rootDirectory = request.getSession().getRootDirectory(); - } catch (IllegalStateException ignore) { - rootDirectory = modelSource.getPath(); - } - try (InputStream is = modelSource.openStream()) { - model = modelProcessor.read(XmlReaderRequest.builder() - .strict(strict) - .location(modelSource.getLocation()) - .path(modelSource.getPath()) - .rootDirectory(rootDirectory) - .inputStream(is) - .build()); - } catch (XmlReaderException e) { - if (!strict) { - throw e; + boolean strict = request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM; + // TODO: we do cache, but what if strict does not have the same value? + Path rootDirectory; + try { + rootDirectory = request.getSession().getRootDirectory(); + } catch (IllegalStateException ignore) { + rootDirectory = modelSource.getPath(); } try (InputStream is = modelSource.openStream()) { model = modelProcessor.read(XmlReaderRequest.builder() - .strict(false) + .strict(strict) .location(modelSource.getLocation()) .path(modelSource.getPath()) .rootDirectory(rootDirectory) .inputStream(is) .build()); - } catch (XmlReaderException ne) { - // still unreadable even in non-strict mode, rethrow original error - throw e; - } - - Severity severity = request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM - ? Severity.ERROR - : Severity.WARNING; - ((ModelProblemCollector) build) - .add( - severity, - ModelProblem.Version.V20, - "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage(), - e); - } + } catch (XmlReaderException e) { + if (!strict) { + throw e; + } + try (InputStream is = modelSource.openStream()) { + model = modelProcessor.read(XmlReaderRequest.builder() + .strict(false) + .location(modelSource.getLocation()) + .path(modelSource.getPath()) + .rootDirectory(rootDirectory) + .inputStream(is) + .build()); + } catch (XmlReaderException ne) { + // still unreadable even in non-strict mode, rethrow original error + throw e; + } - InputLocation loc = model.getLocation(""); - InputSource v4src = loc != null ? loc.getSource() : null; - if (v4src != null) { - try { - Field field = InputSource.class.getDeclaredField("modelId"); - field.setAccessible(true); - field.set(v4src, ModelProblemUtils.toId(model)); - } catch (Throwable t) { - // TODO: use a lazy source ? - throw new IllegalStateException("Unable to set modelId on InputSource", t); - } - } - } catch (XmlReaderException e) { - ((ModelProblemCollector) build) - .add( - Severity.FATAL, - ModelProblem.Version.BASE, - "Non-parseable POM " + modelSource.getLocation() + ": " + e.getMessage(), + Severity severity = request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM + ? Severity.ERROR + : Severity.WARNING; + add( + severity, + ModelProblem.Version.V20, + "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage(), e); - throw ((ModelProblemCollector) build).newModelBuilderException(); - } catch (IOException e) { - String msg = e.getMessage(); - if (msg == null || msg.isEmpty()) { - // NOTE: There's java.nio.charset.MalformedInputException and sun.io.MalformedInputException - if (e.getClass().getName().endsWith("MalformedInputException")) { - msg = "Some input bytes do not match the file encoding."; - } else { - msg = e.getClass().getSimpleName(); } - } - ((ModelProblemCollector) build) - .add( - Severity.FATAL, - ModelProblem.Version.BASE, - "Non-readable POM " + modelSource.getLocation() + ": " + msg, - e); - throw ((ModelProblemCollector) build).newModelBuilderException(); - } - - if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { - model = model.withPomFile(modelSource.getPath()); - Parent parent = model.getParent(); - if (parent != null) { - String groupId = parent.getGroupId(); - String artifactId = parent.getArtifactId(); - String version = parent.getVersion(); - String path = Optional.ofNullable(parent.getRelativePath()).orElse(".."); - if (version == null && !path.isEmpty()) { - Path pomFile = model.getPomFile(); - Path relativePath = Paths.get(path); - Path pomPath = pomFile.resolveSibling(relativePath).normalize(); - if (Files.isDirectory(pomPath)) { - pomPath = getModelProcessor().locateExistingPom(pomPath); + InputLocation loc = model.getLocation(""); + InputSource v4src = loc != null ? loc.getSource() : null; + if (v4src != null) { + try { + Field field = InputSource.class.getDeclaredField("modelId"); + field.setAccessible(true); + field.set(v4src, ModelProblemUtils.toId(model)); + } catch (Throwable t) { + // TODO: use a lazy source ? + throw new IllegalStateException("Unable to set modelId on InputSource", t); } - if (pomPath != null && Files.isRegularFile(pomPath)) { - Model parentModel = readFileModel(build.derive(ModelSource.fromPath(pomPath))); - if (parentModel != null) { - String parentGroupId = getGroupId(parentModel); - String parentArtifactId = parentModel.getArtifactId(); - String parentVersion = getVersion(parentModel); - if ((groupId == null || groupId.equals(parentGroupId)) - && (artifactId == null || artifactId.equals(parentArtifactId))) { - model = model.withParent(parent.with() - .groupId(parentGroupId) - .artifactId(parentArtifactId) - .version(parentVersion) - .build()); + } + } catch (XmlReaderException e) { + add( + Severity.FATAL, + ModelProblem.Version.BASE, + "Non-parseable POM " + modelSource.getLocation() + ": " + e.getMessage(), + e); + throw newModelBuilderException(); + } catch (IOException e) { + String msg = e.getMessage(); + if (msg == null || msg.isEmpty()) { + // NOTE: There's java.nio.charset.MalformedInputException and sun.io.MalformedInputException + if (e.getClass().getName().endsWith("MalformedInputException")) { + msg = "Some input bytes do not match the file encoding."; + } else { + msg = e.getClass().getSimpleName(); + } + } + add( + Severity.FATAL, + ModelProblem.Version.BASE, + "Non-readable POM " + modelSource.getLocation() + ": " + msg, + e); + throw newModelBuilderException(); + } + + if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { + model = model.withPomFile(modelSource.getPath()); + + Parent parent = model.getParent(); + if (parent != null) { + String groupId = parent.getGroupId(); + String artifactId = parent.getArtifactId(); + String version = parent.getVersion(); + String path = Optional.ofNullable(parent.getRelativePath()).orElse(".."); + if (version == null && !path.isEmpty()) { + Path pomFile = model.getPomFile(); + Path relativePath = Paths.get(path); + Path pomPath = pomFile.resolveSibling(relativePath).normalize(); + if (Files.isDirectory(pomPath)) { + pomPath = getModelProcessor().locateExistingPom(pomPath); + } + if (pomPath != null && Files.isRegularFile(pomPath)) { + Model parentModel = + derive(ModelSource.fromPath(pomPath)).readFileModel(); + if (parentModel != null) { + String parentGroupId = getGroupId(parentModel); + String parentArtifactId = parentModel.getArtifactId(); + String parentVersion = getVersion(parentModel); + if ((groupId == null || groupId.equals(parentGroupId)) + && (artifactId == null || artifactId.equals(parentArtifactId))) { + model = model.withParent(parent.with() + .groupId(parentGroupId) + .artifactId(parentArtifactId) + .version(parentVersion) + .build()); + } } } } } - } - // subprojects discovery - if (model.getSubprojects().isEmpty() - && model.getModules().isEmpty() - // only discover subprojects if POM > 4.0.0 - && !MODEL_VERSION_4_0_0.equals(model.getModelVersion()) - // and if packaging is POM (we check type, but the session is not yet available, - // we would require the project realm if we want to support extensions - && Type.POM.equals(model.getPackaging())) { - List subprojects = new ArrayList<>(); - try (Stream files = Files.list(model.getProjectDirectory())) { - for (Path f : files.toList()) { - if (Files.isDirectory(f)) { - Path subproject = modelProcessor.locateExistingPom(f); - if (subproject != null) { - subprojects.add(f.getFileName().toString()); + // subprojects discovery + if (model.getSubprojects().isEmpty() + && model.getModules().isEmpty() + // only discover subprojects if POM > 4.0.0 + && !MODEL_VERSION_4_0_0.equals(model.getModelVersion()) + // and if packaging is POM (we check type, but the session is not yet available, + // we would require the project realm if we want to support extensions + && Type.POM.equals(model.getPackaging())) { + List subprojects = new ArrayList<>(); + try (Stream files = Files.list(model.getProjectDirectory())) { + for (Path f : files.toList()) { + if (Files.isDirectory(f)) { + Path subproject = modelProcessor.locateExistingPom(f); + if (subproject != null) { + subprojects.add(f.getFileName().toString()); + } } } + if (!subprojects.isEmpty()) { + model = model.withSubprojects(subprojects); + } + } catch (IOException e) { + add(Severity.FATAL, ModelProblem.Version.V41, "Error discovering subprojects", e); } - if (!subprojects.isEmpty()) { - model = model.withSubprojects(subprojects); - } - } catch (IOException e) { - ((ModelProblemCollector) build) - .add(Severity.FATAL, ModelProblem.Version.V41, "Error discovering subprojects", e); } } + + for (var transformer : transformers) { + model = transformer.transformFileModel(model); + } + + setSource(model); + modelValidator.validateFileModel( + model, + request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM + ? ModelValidator.VALIDATION_LEVEL_STRICT + : ModelValidator.VALIDATION_LEVEL_MINIMAL, + request, + this); + if (hasFatalErrors()) { + throw newModelBuilderException(); + } + + return model; } - for (var transformer : transformers) { - model = transformer.transformFileModel(model); + Model readRawModel() throws ModelBuilderException { + return cache(request.getSource(), RAW, this::doReadRawModel); } - ((ModelProblemCollector) build).setSource(model); - modelValidator.validateFileModel( - model, - request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM - ? ModelValidator.VALIDATION_LEVEL_STRICT - : ModelValidator.VALIDATION_LEVEL_MINIMAL, - request, - build); - if (hasFatalErrors(build)) { - throw build.newModelBuilderException(); + private Model doReadRawModel() throws ModelBuilderException { + ModelBuilderRequest request = this.request; + Model rawModel = readFileModel(); + if (!MODEL_VERSION_4_0_0.equals(rawModel.getModelVersion()) + && request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { + try { + rawModel = transformRawToBuildPom(rawModel); + } catch (ModelTransformerException e) { + add(Severity.FATAL, ModelProblem.Version.V40, null, e); + } + } + + String namespace = rawModel.getNamespaceUri(); + if (rawModel.getModelVersion() == null && namespace != null && namespace.startsWith(NAMESPACE_PREFIX)) { + rawModel = rawModel.withModelVersion(namespace.substring(NAMESPACE_PREFIX.length())); + } + + for (var transformer : transformers) { + rawModel = transformer.transformRawModel(rawModel); + } + + modelValidator.validateRawModel( + rawModel, + request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM + ? ModelValidator.VALIDATION_LEVEL_STRICT + : ModelValidator.VALIDATION_LEVEL_MINIMAL, + request, + this); + + if (hasFatalErrors()) { + throw newModelBuilderException(); + } + + return rawModel; } - return model; - } + Model readParentModel() { + return cache(request.getSource(), PARENT, this::doReadParentModel); + } - Model readRawModel(DefaultModelBuilderSession build) throws ModelBuilderException { - return cache(build.cache, build.request.getSource(), RAW, () -> doReadRawModel(build)); - } + private Model doReadParentModel() { + Model raw = readRawModel(); + + ModelData parentData; + if (raw.getParent() != null) { + parentData = resolveAndReadParentExternally(raw); + } else { + String superModelVersion = raw.getModelVersion() != null ? raw.getModelVersion() : "4.0.0"; + if (!VALID_MODEL_VERSIONS.contains(superModelVersion)) { + // Maven 3.x is always using 4.0.0 version to load the supermodel, so + // do the same when loading a dependency. The model validator will also + // check that field later. + superModelVersion = MODEL_VERSION_4_0_0; + } + parentData = new ModelData(null, getSuperModel(superModelVersion)); + } + + Model parent = inheritanceAssembler.assembleModelInheritance(raw, parentData.model(), request, this); + return parent.withParent(null); + } + + private Model importDependencyManagement(Model model, Collection importIds) { + DependencyManagement depMgmt = model.getDependencyManagement(); + + if (depMgmt == null) { + return model; + } + + String importing = model.getGroupId() + ':' + model.getArtifactId() + ':' + model.getVersion(); + + importIds.add(importing); + + List importMgmts = null; + + List deps = new ArrayList<>(depMgmt.getDependencies()); + for (Iterator it = deps.iterator(); it.hasNext(); ) { + Dependency dependency = it.next(); + + if (!("pom".equals(dependency.getType()) && "import".equals(dependency.getScope())) + || "bom".equals(dependency.getType())) { + continue; + } + + it.remove(); + + DependencyManagement importMgmt = loadDependencyManagement(dependency, importIds); + + if (importMgmt != null) { + if (importMgmts == null) { + importMgmts = new ArrayList<>(); + } + + importMgmts.add(importMgmt); + } + } + + importIds.remove(importing); + + model = model.withDependencyManagement( + model.getDependencyManagement().withDependencies(deps)); + + return dependencyManagementImporter.importManagement(model, importMgmts, request, this); + } + + private DependencyManagement loadDependencyManagement(Dependency dependency, Collection importIds) { + String groupId = dependency.getGroupId(); + String artifactId = dependency.getArtifactId(); + String version = dependency.getVersion(); + + if (groupId == null || groupId.isEmpty()) { + add( + Severity.ERROR, + ModelProblem.Version.BASE, + "'dependencyManagement.dependencies.dependency.groupId' for " + dependency.getManagementKey() + + " is missing.", + dependency.getLocation("")); + return null; + } + if (artifactId == null || artifactId.isEmpty()) { + add( + Severity.ERROR, + ModelProblem.Version.BASE, + "'dependencyManagement.dependencies.dependency.artifactId' for " + dependency.getManagementKey() + + " is missing.", + dependency.getLocation("")); + return null; + } + if (version == null || version.isEmpty()) { + add( + Severity.ERROR, + ModelProblem.Version.BASE, + "'dependencyManagement.dependencies.dependency.version' for " + dependency.getManagementKey() + + " is missing.", + dependency.getLocation("")); + return null; + } + + String imported = groupId + ':' + artifactId + ':' + version; + + if (importIds.contains(imported)) { + StringBuilder message = + new StringBuilder("The dependencies of type=pom and with scope=import form a cycle: "); + for (String modelId : importIds) { + message.append(modelId).append(" -> "); + } + message.append(imported); + add(Severity.ERROR, ModelProblem.Version.BASE, message.toString()); + return null; + } + + Model importModel = cache( + groupId, + artifactId, + version, + IMPORT, + () -> doLoadDependencyManagement(dependency, groupId, artifactId, version, importIds)); + DependencyManagement importMgmt = importModel != null ? importModel.getDependencyManagement() : null; + if (importMgmt == null) { + importMgmt = DependencyManagement.newInstance(); + } + + // [MNG-5600] Dependency management import should support exclusions. + List exclusions = dependency.getExclusions(); + if (importMgmt != null && !exclusions.isEmpty()) { + // Dependency excluded from import. + List dependencies = importMgmt.getDependencies().stream() + .filter(candidate -> exclusions.stream().noneMatch(exclusion -> match(exclusion, candidate))) + .map(candidate -> addExclusions(candidate, exclusions)) + .collect(Collectors.toList()); + importMgmt = importMgmt.withDependencies(dependencies); + } + + return importMgmt; + } + + @SuppressWarnings("checkstyle:parameternumber") + private Model doLoadDependencyManagement( + Dependency dependency, + String groupId, + String artifactId, + String version, + Collection importIds) { + Model importModel; + // no workspace resolver or workspace resolver returned null (i.e. model not in workspace) + final ModelSource importSource; + try { + importSource = modelResolver.resolveModel( + request.getSession(), getRepositories(), dependency, new AtomicReference<>()); + } catch (ModelBuilderException e) { + StringBuilder buffer = new StringBuilder(256); + buffer.append("Non-resolvable import POM"); + if (!containsCoordinates(e.getMessage(), groupId, artifactId, version)) { + buffer.append(' ').append(ModelProblemUtils.toId(groupId, artifactId, version)); + } + buffer.append(": ").append(e.getMessage()); + + add(Severity.ERROR, ModelProblem.Version.BASE, buffer.toString(), dependency.getLocation(""), e); + return null; + } + + Path rootDirectory; + try { + rootDirectory = request.getSession().getRootDirectory(); + } catch (IllegalStateException e) { + rootDirectory = null; + } + if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM && rootDirectory != null) { + Path sourcePath = importSource.getPath(); + if (sourcePath != null && sourcePath.startsWith(rootDirectory)) { + add( + Severity.WARNING, + ModelProblem.Version.BASE, + "BOM imports from within reactor should be avoided", + dependency.getLocation("")); + } + } - private Model doReadRawModel(DefaultModelBuilderSession build) throws ModelBuilderException { - ModelBuilderRequest request = build.request; - Model rawModel = readFileModel(build); - if (!MODEL_VERSION_4_0_0.equals(rawModel.getModelVersion()) - && request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { + final ModelBuilderResult importResult; try { - rawModel = build.transformRawToBuildPom(rawModel); - } catch (ModelTransformerException e) { - build.add(Severity.FATAL, ModelProblem.Version.V40, null, e); + ModelBuilderRequest importRequest = ModelBuilderRequest.builder() + .session(request.getSession()) + .requestType(ModelBuilderRequest.RequestType.DEPENDENCY) + .systemProperties(request.getSystemProperties()) + .userProperties(request.getUserProperties()) + .source(importSource) + .twoPhaseBuilding(false) + .repositories(getRepositories()) + .build(); + importResult = new DefaultModelBuilderSession(importRequest).build(importIds); + } catch (ModelBuilderException e) { + e.getResult().getProblems().forEach(this::add); + return null; } + + importResult.getProblems().forEach(this::add); + + importModel = importResult.getEffectiveModel(); + + return importModel; } - String namespace = rawModel.getNamespaceUri(); - if (rawModel.getModelVersion() == null && namespace != null && namespace.startsWith(NAMESPACE_PREFIX)) { - rawModel = rawModel.withModelVersion(namespace.substring(NAMESPACE_PREFIX.length())); + private T cache(String groupId, String artifactId, String version, String tag, Callable supplier) { + return cache.computeIfAbsent(groupId, artifactId, version, tag, asSupplier(supplier)); } - for (var transformer : transformers) { - rawModel = transformer.transformRawModel(rawModel); + private T cache(Source source, String tag, Callable supplier) { + return cache.computeIfAbsent(source, tag, asSupplier(supplier)); + } + } + + private List interpolateActivations( + List profiles, DefaultProfileActivationContext context, ModelProblemCollector problems) { + if (profiles.stream() + .map(org.apache.maven.api.model.Profile::getActivation) + .noneMatch(Objects::nonNull)) { + return profiles; + } + final Interpolator xform = new RegexBasedInterpolator(); + xform.setCacheAnswers(true); + Stream.of(context.getUserProperties(), context.getSystemProperties()) + .map(MapBasedValueSource::new) + .forEach(xform::addValueSource); + + class ProfileInterpolator extends MavenTransformer implements UnaryOperator { + ProfileInterpolator() { + super(s -> { + if (isNotEmpty(s)) { + try { + return xform.interpolate(s); + } catch (InterpolationException e) { + problems.add(Severity.ERROR, ModelProblem.Version.BASE, e.getMessage(), e); + } + } + return s; + }); + } + + @Override + public Profile apply(Profile p) { + return Profile.newBuilder(p) + .activation(transformActivation(p.getActivation())) + .build(); + } + + @Override + protected ActivationFile.Builder transformActivationFile_Missing( + Supplier creator, + ActivationFile.Builder builder, + ActivationFile target) { + String path = target.getMissing(); + String xformed = transformPath(path, target, "missing"); + return xformed != path ? (builder != null ? builder : creator.get()).missing(xformed) : builder; + } + + @Override + protected ActivationFile.Builder transformActivationFile_Exists( + Supplier creator, + ActivationFile.Builder builder, + ActivationFile target) { + final String path = target.getExists(); + final String xformed = transformPath(path, target, "exists"); + return xformed != path ? (builder != null ? builder : creator.get()).exists(xformed) : builder; + } + + private String transformPath(String path, ActivationFile target, String locationKey) { + if (isNotEmpty(path)) { + try { + return profileActivationFilePathInterpolator.interpolate(path, context); + } catch (InterpolationException e) { + addInterpolationProblem(problems, target, path, e, locationKey); + } + } + return path; + } } + return profiles.stream().map(new ProfileInterpolator()).toList(); + } + + private static void addInterpolationProblem( + ModelProblemCollector problems, + InputLocationTracker target, + String path, + InterpolationException e, + String locationKey) { + problems.add( + Severity.ERROR, + ModelProblem.Version.BASE, + "Failed to interpolate file location " + path + ": " + e.getMessage(), + target.getLocation(locationKey), + e); + } - modelValidator.validateRawModel( - rawModel, - request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM - ? ModelValidator.VALIDATION_LEVEL_STRICT - : ModelValidator.VALIDATION_LEVEL_MINIMAL, - request, - build); + private static boolean isNotEmpty(String string) { + return string != null && !string.isEmpty(); + } - if (hasFatalErrors(build)) { + public ModelBuilderResult build(final ModelBuilderRequest request, final ModelBuilderResult result) + throws ModelBuilderException { + return new DefaultModelBuilderSession(request, (DefaultModelBuilderResult) result).build(new LinkedHashSet<>()); + } + + public Model buildRawModel(ModelBuilderRequest request) throws ModelBuilderException { + DefaultModelBuilderSession build = new DefaultModelBuilderSession(request); + Model model = build.readRawModel(); + if (((ModelProblemCollector) build).hasErrors()) { throw build.newModelBuilderException(); } + return model; + } - return rawModel; + private DefaultModelBuilderResult asDefaultModelBuilderResult(ModelBuilderResult phaseOneResult) { + if (phaseOneResult instanceof DefaultModelBuilderResult) { + return (DefaultModelBuilderResult) phaseOneResult; + } else { + return new DefaultModelBuilderResult(phaseOneResult); + } } static String getGroupId(Model model) { @@ -1587,117 +2043,6 @@ private Model interpolateModel(Model model, ModelBuilderRequest request, ModelPr return interpolatedModel; } - private ModelData readParent(DefaultModelBuilderSession build, Model childModel, ModelSource childSource) - throws ModelBuilderException { - ModelData parentData = null; - - Parent parent = childModel.getParent(); - if (parent != null) { - parentData = readParentLocally(build, childModel, childSource); - if (parentData == null) { - parentData = resolveAndReadParentExternally(build, childModel); - } - - Model parentModel = parentData.model(); - if (!"pom".equals(parentModel.getPackaging())) { - build.add( - Severity.ERROR, - ModelProblem.Version.BASE, - "Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint(parentModel) - + ", must be \"pom\" but is \"" + parentModel.getPackaging() + "\"", - parentModel.getLocation("packaging")); - } - } - - return parentData; - } - - private ModelData readParentLocally(DefaultModelBuilderSession build, Model childModel, ModelSource childSource) - throws ModelBuilderException { - ModelSource candidateSource = getParentPomFile(childModel, childSource); - if (candidateSource == null) { - return null; - } - final Model candidateModel = readRawModel(build.derive(candidateSource)); - - // - // TODO jvz Why isn't all this checking the job of the duty of the workspace resolver, we know that we - // have a model that is suitable, yet more checks are done here and the one for the version is problematic - // before because with parents as ranges it will never work in this scenario. - // - - String groupId = getGroupId(candidateModel); - String artifactId = candidateModel.getArtifactId(); - - Parent parent = childModel.getParent(); - if (groupId == null - || !groupId.equals(parent.getGroupId()) - || artifactId == null - || !artifactId.equals(parent.getArtifactId())) { - StringBuilder buffer = new StringBuilder(256); - buffer.append("'parent.relativePath'"); - if (childModel != build.getRootModel()) { - buffer.append(" of POM ").append(ModelProblemUtils.toSourceHint(childModel)); - } - buffer.append(" points at ").append(groupId).append(':').append(artifactId); - buffer.append(" instead of ").append(parent.getGroupId()).append(':'); - buffer.append(parent.getArtifactId()).append(", please verify your project structure"); - - build.setSource(childModel); - build.add(Severity.WARNING, ModelProblem.Version.BASE, buffer.toString(), parent.getLocation("")); - return null; - } - - String version = getVersion(candidateModel); - if (version != null && parent.getVersion() != null && !version.equals(parent.getVersion())) { - try { - VersionRange parentRange = versionParser.parseVersionRange(parent.getVersion()); - if (!parentRange.contains(versionParser.parseVersion(version))) { - // version skew drop back to resolution from the repository - return null; - } - - // Validate versions aren't inherited when using parent ranges the same way as when read externally. - String rawChildModelVersion = childModel.getVersion(); - - if (rawChildModelVersion == null) { - // Message below is checked for in the MNG-2199 core IT. - build.add( - Severity.FATAL, - ModelProblem.Version.V31, - "Version must be a constant", - childModel.getLocation("")); - - } else { - if (rawChildVersionReferencesParent(rawChildModelVersion)) { - // Message below is checked for in the MNG-2199 core IT. - build.add( - Severity.FATAL, - ModelProblem.Version.V31, - "Version must be a constant", - childModel.getLocation("version")); - } - } - - // MNG-2199: What else to check here ? - } catch (VersionParserException e) { - // invalid version range, so drop back to resolution from the repository - return null; - } - } - - // - // Here we just need to know that a version is fine to use but this validation we can do in our workspace - // resolver. - // - - /* - * if ( version == null || !version.equals( parent.getVersion() ) ) { return null; } - */ - - return new ModelData(candidateSource, candidateModel); - } - private boolean rawChildVersionReferencesParent(String rawChildModelVersion) { return rawChildModelVersion.equals("${pom.version}") || rawChildModelVersion.equals("${project.version}") @@ -1714,227 +2059,10 @@ private ModelSource getParentPomFile(Model childModel, ModelSource source) { } } - private ModelData resolveAndReadParentExternally(DefaultModelBuilderSession build, Model childModel) - throws ModelBuilderException { - ModelBuilderRequest request = build.request; - build.setSource(childModel); - - Parent parent = childModel.getParent(); - - String groupId = parent.getGroupId(); - String artifactId = parent.getArtifactId(); - String version = parent.getVersion(); - - ModelSource modelSource; - try { - AtomicReference modified = new AtomicReference<>(); - modelSource = modelResolver.resolveModel(request.getSession(), build.getRepositories(), parent, modified); - if (modified.get() != null) { - parent = modified.get(); - } - } catch (ModelResolverException e) { - // Message below is checked for in the MNG-2199 core IT. - StringBuilder buffer = new StringBuilder(256); - buffer.append("Non-resolvable parent POM"); - if (!containsCoordinates(e.getMessage(), groupId, artifactId, version)) { - buffer.append(' ').append(ModelProblemUtils.toId(groupId, artifactId, version)); - } - if (childModel != ((ModelProblemCollector) build).getRootModel()) { - buffer.append(" for ").append(ModelProblemUtils.toId(childModel)); - } - buffer.append(": ").append(e.getMessage()); - if (childModel.getProjectDirectory() != null) { - if (parent.getRelativePath() == null || parent.getRelativePath().isEmpty()) { - buffer.append(" and 'parent.relativePath' points at no local POM"); - } else { - buffer.append(" and 'parent.relativePath' points at wrong local POM"); - } - } - - ((ModelProblemCollector) build) - .add(Severity.FATAL, ModelProblem.Version.BASE, buffer.toString(), parent.getLocation(""), e); - throw ((ModelProblemCollector) build).newModelBuilderException(); - } - - ModelBuilderRequest lenientRequest = ModelBuilderRequest.builder(request) - .requestType(ModelBuilderRequest.RequestType.PARENT_POM) - .source(modelSource) - .build(); - - Model parentModel = readParentModel(new DefaultModelBuilderSession(lenientRequest, build.result)); - - if (!parent.getVersion().equals(version)) { - String rawChildModelVersion = childModel.getVersion(); - - if (rawChildModelVersion == null) { - // Message below is checked for in the MNG-2199 core IT. - build.add( - Severity.FATAL, - ModelProblem.Version.V31, - "Version must be a constant", - childModel.getLocation("")); - } else { - if (rawChildVersionReferencesParent(rawChildModelVersion)) { - // Message below is checked for in the MNG-2199 core IT. - build.add( - Severity.FATAL, - ModelProblem.Version.V31, - "Version must be a constant", - childModel.getLocation("version")); - } - } - - // MNG-2199: What else to check here ? - } - - return new ModelData(modelSource, parentModel); - } - - Model readParentModel(DefaultModelBuilderSession build) { - return cache(build.cache, build.request.getSource(), PARENT, () -> doReadParentModel(build)); - } - - private Model doReadParentModel(DefaultModelBuilderSession build) { - Model raw = readRawModel(build); - - ModelData parentData; - if (raw.getParent() != null) { - parentData = resolveAndReadParentExternally(build, raw); - } else { - String superModelVersion = raw.getModelVersion() != null ? raw.getModelVersion() : "4.0.0"; - if (!VALID_MODEL_VERSIONS.contains(superModelVersion)) { - // Maven 3.x is always using 4.0.0 version to load the supermodel, so - // do the same when loading a dependency. The model validator will also - // check that field later. - superModelVersion = MODEL_VERSION_4_0_0; - } - parentData = new ModelData(null, getSuperModel(superModelVersion)); - } - - Model parent = inheritanceAssembler.assembleModelInheritance(raw, parentData.model(), build.request, build); - return parent.withParent(null); - } - private Model getSuperModel(String modelVersion) { return superPomProvider.getSuperPom(modelVersion); } - private Model importDependencyManagement( - DefaultModelBuilderSession build, Model model, Collection importIds) { - DependencyManagement depMgmt = model.getDependencyManagement(); - - if (depMgmt == null) { - return model; - } - - String importing = model.getGroupId() + ':' + model.getArtifactId() + ':' + model.getVersion(); - - importIds.add(importing); - - List importMgmts = null; - - List deps = new ArrayList<>(depMgmt.getDependencies()); - for (Iterator it = deps.iterator(); it.hasNext(); ) { - Dependency dependency = it.next(); - - if (!("pom".equals(dependency.getType()) && "import".equals(dependency.getScope())) - || "bom".equals(dependency.getType())) { - continue; - } - - it.remove(); - - DependencyManagement importMgmt = loadDependencyManagement(build, model, dependency, importIds); - - if (importMgmt != null) { - if (importMgmts == null) { - importMgmts = new ArrayList<>(); - } - - importMgmts.add(importMgmt); - } - } - - importIds.remove(importing); - - model = model.withDependencyManagement(model.getDependencyManagement().withDependencies(deps)); - - return dependencyManagementImporter.importManagement(model, importMgmts, build.request, build); - } - - private DependencyManagement loadDependencyManagement( - DefaultModelBuilderSession build, Model model, Dependency dependency, Collection importIds) { - String groupId = dependency.getGroupId(); - String artifactId = dependency.getArtifactId(); - String version = dependency.getVersion(); - - if (groupId == null || groupId.isEmpty()) { - build.add( - Severity.ERROR, - ModelProblem.Version.BASE, - "'dependencyManagement.dependencies.dependency.groupId' for " + dependency.getManagementKey() - + " is missing.", - dependency.getLocation("")); - return null; - } - if (artifactId == null || artifactId.isEmpty()) { - build.add( - Severity.ERROR, - ModelProblem.Version.BASE, - "'dependencyManagement.dependencies.dependency.artifactId' for " + dependency.getManagementKey() - + " is missing.", - dependency.getLocation("")); - return null; - } - if (version == null || version.isEmpty()) { - build.add( - Severity.ERROR, - ModelProblem.Version.BASE, - "'dependencyManagement.dependencies.dependency.version' for " + dependency.getManagementKey() - + " is missing.", - dependency.getLocation("")); - return null; - } - - String imported = groupId + ':' + artifactId + ':' + version; - - if (importIds.contains(imported)) { - StringBuilder message = - new StringBuilder("The dependencies of type=pom and with scope=import form a cycle: "); - for (String modelId : importIds) { - message.append(modelId).append(" -> "); - } - message.append(imported); - build.add(Severity.ERROR, ModelProblem.Version.BASE, message.toString()); - return null; - } - - Model importModel = cache( - build.cache, - groupId, - artifactId, - version, - IMPORT, - () -> doLoadDependencyManagement(build, model, dependency, groupId, artifactId, version, importIds)); - DependencyManagement importMgmt = importModel != null ? importModel.getDependencyManagement() : null; - if (importMgmt == null) { - importMgmt = DependencyManagement.newInstance(); - } - - // [MNG-5600] Dependency management import should support exclusions. - List exclusions = dependency.getExclusions(); - if (importMgmt != null && !exclusions.isEmpty()) { - // Dependency excluded from import. - List dependencies = importMgmt.getDependencies().stream() - .filter(candidate -> exclusions.stream().noneMatch(exclusion -> match(exclusion, candidate))) - .map(candidate -> addExclusions(candidate, exclusions)) - .collect(Collectors.toList()); - importMgmt = importMgmt.withDependencies(dependencies); - } - - return importMgmt; - } - private static org.apache.maven.api.model.Dependency addExclusions( org.apache.maven.api.model.Dependency candidate, List exclusions) { return candidate.withExclusions(Stream.concat(candidate.getExclusions().stream(), exclusions.stream()) @@ -1950,85 +2078,6 @@ private boolean match(String match, String text) { return match.equals("*") || match.equals(text); } - @SuppressWarnings("checkstyle:parameternumber") - private Model doLoadDependencyManagement( - DefaultModelBuilderSession build, - Model model, - Dependency dependency, - String groupId, - String artifactId, - String version, - Collection importIds) { - final ModelBuilderRequest request = build.request; - - Model importModel; - // no workspace resolver or workspace resolver returned null (i.e. model not in workspace) - final ModelSource importSource; - try { - importSource = modelResolver.resolveModel( - request.getSession(), build.getRepositories(), dependency, new AtomicReference<>()); - } catch (ModelBuilderException e) { - StringBuilder buffer = new StringBuilder(256); - buffer.append("Non-resolvable import POM"); - if (!containsCoordinates(e.getMessage(), groupId, artifactId, version)) { - buffer.append(' ').append(ModelProblemUtils.toId(groupId, artifactId, version)); - } - buffer.append(": ").append(e.getMessage()); - - build.add(Severity.ERROR, ModelProblem.Version.BASE, buffer.toString(), dependency.getLocation(""), e); - return null; - } - - Path rootDirectory; - try { - rootDirectory = request.getSession().getRootDirectory(); - } catch (IllegalStateException e) { - rootDirectory = null; - } - if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM && rootDirectory != null) { - Path sourcePath = importSource.getPath(); - if (sourcePath != null && sourcePath.startsWith(rootDirectory)) { - build.add( - Severity.WARNING, - ModelProblem.Version.BASE, - "BOM imports from within reactor should be avoided", - dependency.getLocation("")); - } - } - - final ModelBuilderResult importResult; - try { - ModelBuilderRequest importRequest = ModelBuilderRequest.builder() - .session(request.getSession()) - .requestType(ModelBuilderRequest.RequestType.DEPENDENCY) - .systemProperties(request.getSystemProperties()) - .userProperties(request.getUserProperties()) - .source(importSource) - .twoPhaseBuilding(false) - .repositories(build.getRepositories()) - .build(); - importResult = build(new DefaultModelBuilderSession(importRequest), importIds); - } catch (ModelBuilderException e) { - e.getResult().getProblems().forEach(build::add); - return null; - } - - importResult.getProblems().forEach(build::add); - - importModel = importResult.getEffectiveModel(); - - return importModel; - } - - private static T cache( - ModelCache cache, String groupId, String artifactId, String version, String tag, Callable supplier) { - return cache.computeIfAbsent(groupId, artifactId, version, tag, asSupplier(supplier)); - } - - private static T cache(ModelCache cache, Source source, String tag, Callable supplier) { - return cache.computeIfAbsent(source, tag, asSupplier(supplier)); - } - private static Supplier asSupplier(Callable supplier) { return () -> { try { @@ -2071,14 +2120,6 @@ private boolean containsCoordinates(String message, String groupId, String artif && (version == null || message.contains(version)); } - protected boolean hasModelErrors(ModelProblemCollector problems) { - return problems.hasErrors(); - } - - protected boolean hasFatalErrors(ModelProblemCollector problems) { - return problems.hasFatalErrors(); - } - ModelProcessor getModelProcessor() { return modelProcessor; } diff --git a/maven-compat/src/test/java/org/apache/maven/project/TestProjectBuilder.java b/maven-compat/src/test/java/org/apache/maven/project/TestProjectBuilder.java index cfda6e1caccf..826b1277f651 100644 --- a/maven-compat/src/test/java/org/apache/maven/project/TestProjectBuilder.java +++ b/maven-compat/src/test/java/org/apache/maven/project/TestProjectBuilder.java @@ -47,15 +47,7 @@ public TestProjectBuilder( RemoteRepositoryManager repositoryManager, ProjectDependenciesResolver dependencyResolver, RootLocator rootLocator) { - super( - modelBuilder, - modelProcessor, - projectBuildingHelper, - repositorySystem, - repoSystem, - repositoryManager, - dependencyResolver, - rootLocator); + super(modelBuilder, projectBuildingHelper, repositorySystem, repoSystem, dependencyResolver, rootLocator); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index 75a695bee764..d25ecda01f5f 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -29,8 +29,6 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -40,31 +38,19 @@ import java.util.Objects; import java.util.Properties; import java.util.Set; -import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Consumer; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.maven.ProjectCycleException; import org.apache.maven.RepositoryUtils; -import org.apache.maven.api.Constants; -import org.apache.maven.api.Session; import org.apache.maven.api.model.Build; import org.apache.maven.api.model.Dependency; import org.apache.maven.api.model.DependencyManagement; import org.apache.maven.api.model.DeploymentRepository; import org.apache.maven.api.model.Extension; import org.apache.maven.api.model.Model; -import org.apache.maven.api.model.Parent; import org.apache.maven.api.model.Plugin; import org.apache.maven.api.model.Profile; import org.apache.maven.api.model.ReportPlugin; @@ -78,9 +64,6 @@ import org.apache.maven.api.services.Source; import org.apache.maven.api.services.model.ModelBuildingEvent; import org.apache.maven.api.services.model.ModelBuildingListener; -import org.apache.maven.api.services.model.ModelProcessor; -import org.apache.maven.api.services.model.ModelResolver; -import org.apache.maven.api.services.model.ModelResolverException; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.InvalidArtifactRTException; import org.apache.maven.artifact.InvalidRepositoryException; @@ -92,7 +75,6 @@ import org.apache.maven.model.building.ModelBuildingRequest; import org.apache.maven.model.building.ModelSource2; import org.apache.maven.model.building.ModelSource3; -import org.apache.maven.model.resolution.UnresolvableModelException; import org.apache.maven.model.root.RootLocator; import org.apache.maven.plugin.PluginManagerException; import org.apache.maven.plugin.PluginResolutionException; @@ -100,9 +82,7 @@ import org.apache.maven.repository.internal.ArtifactDescriptorUtils; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.impl.RemoteRepositoryManager; import org.eclipse.aether.repository.LocalRepositoryManager; -import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.repository.WorkspaceRepository; import org.eclipse.aether.resolution.ArtifactRequest; import org.eclipse.aether.resolution.ArtifactResult; @@ -116,15 +96,11 @@ @Singleton public class DefaultProjectBuilder implements ProjectBuilder { - public static final int DEFAULT_BUILDER_PARALLELISM = Runtime.getRuntime().availableProcessors() / 2 + 1; - private final Logger logger = LoggerFactory.getLogger(getClass()); private final ModelBuilder modelBuilder; - private final ModelProcessor modelProcessor; private final ProjectBuildingHelper projectBuildingHelper; private final MavenRepositorySystem repositorySystem; private final org.eclipse.aether.RepositorySystem repoSystem; - private final RemoteRepositoryManager repositoryManager; private final ProjectDependenciesResolver dependencyResolver; private final RootLocator rootLocator; @@ -132,19 +108,15 @@ public class DefaultProjectBuilder implements ProjectBuilder { @Inject public DefaultProjectBuilder( ModelBuilder modelBuilder, - ModelProcessor modelProcessor, ProjectBuildingHelper projectBuildingHelper, MavenRepositorySystem repositorySystem, RepositorySystem repoSystem, - RemoteRepositoryManager repositoryManager, ProjectDependenciesResolver dependencyResolver, RootLocator rootLocator) { this.modelBuilder = modelBuilder; - this.modelProcessor = modelProcessor; this.projectBuildingHelper = projectBuildingHelper; this.repositorySystem = repositorySystem; this.repoSystem = repoSystem; - this.repositoryManager = repositoryManager; this.dependencyResolver = dependencyResolver; this.rootLocator = rootLocator; } @@ -154,7 +126,7 @@ public DefaultProjectBuilder( @Override public ProjectBuildingResult build(File pomFile, ProjectBuildingRequest request) throws ProjectBuildingException { - try (BuildSession bs = new BuildSession(request, false)) { + try (BuildSession bs = new BuildSession(request)) { Path path = pomFile.toPath(); return bs.build(path, ModelSource.fromPath(path)); } @@ -180,7 +152,7 @@ static ModelSource toSource(org.apache.maven.model.building.ModelSource modelSou @Override public ProjectBuildingResult build(ModelSource modelSource, ProjectBuildingRequest request) throws ProjectBuildingException { - try (BuildSession bs = new BuildSession(request, false)) { + try (BuildSession bs = new BuildSession(request)) { return bs.build(null, modelSource); } } @@ -194,7 +166,7 @@ public ProjectBuildingResult build(Artifact artifact, ProjectBuildingRequest req @Override public ProjectBuildingResult build(Artifact artifact, boolean allowStubModel, ProjectBuildingRequest request) throws ProjectBuildingException { - try (BuildSession bs = new BuildSession(request, false)) { + try (BuildSession bs = new BuildSession(request)) { return bs.build(artifact, allowStubModel); } } @@ -202,48 +174,11 @@ public ProjectBuildingResult build(Artifact artifact, boolean allowStubModel, Pr @Override public List build(List pomFiles, boolean recursive, ProjectBuildingRequest request) throws ProjectBuildingException { - try (BuildSession bs = new BuildSession(request, true)) { + try (BuildSession bs = new BuildSession(request)) { return bs.build(pomFiles, recursive); } } - static class InterimResult { - - File pomFile; - - ModelBuilderRequest request; - - ModelBuilderResult result; - - MavenProject project; - - boolean root; - - List subprojects = Collections.emptyList(); - - ProjectBuildingResult projectBuildingResult; - - InterimResult( - File pomFile, - ModelBuilderRequest request, - ModelBuilderResult result, - MavenProject project, - boolean root) { - this.pomFile = pomFile; - this.request = request; - this.result = result; - this.project = project; - this.root = root; - } - - InterimResult(ModelBuilderRequest request, ProjectBuildingResult projectBuildingResult) { - this.request = request; - this.projectBuildingResult = projectBuildingResult; - this.pomFile = projectBuildingResult.getPomFile(); - this.project = projectBuildingResult.getProject(); - } - } - private static class StubModelSource implements ModelSource { private final String xml; private final Artifact artifact; @@ -373,68 +308,19 @@ public int hashCode() { class BuildSession implements AutoCloseable { private final ProjectBuildingRequest request; private final RepositorySystemSession session; - private final ExecutorService executor; private final ModelBuilder.ModelBuilderSession modelBuilderSession; + private final Map projectIndex = new ConcurrentHashMap<>(256); - BuildSession(ProjectBuildingRequest request, boolean localProjects) { + BuildSession(ProjectBuildingRequest request) { this.request = request; this.session = RepositoryUtils.overlay(request.getLocalRepository(), request.getRepositorySession(), repoSystem); InternalSession.from(session); - this.executor = createExecutor(getParallelism(request)); this.modelBuilderSession = modelBuilder.newSession(); } - ExecutorService createExecutor(int parallelism) { - // - // We need an executor that will not block. - // We can't use work stealing, as we are building a graph - // and this could lead to cycles where a thread waits for - // a task to finish, then execute another one which waits - // for the initial task... - // In order to work around that problem, we override the - // invokeAll method, so that whenever the method is called, - // the pool core size will be incremented before submitting - // all the tasks, then the thread will block waiting for all - // those subtasks to finish. - // This ensures the number of running workers is no more than - // the defined parallism, while making sure the pool will not - // be exhausted - // - return new ThreadPoolExecutor( - parallelism, Integer.MAX_VALUE, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()) { - final AtomicInteger parked = new AtomicInteger(); - - @Override - public List> invokeAll(Collection> tasks) - throws InterruptedException { - setCorePoolSize(parallelism + parked.incrementAndGet()); - try { - return super.invokeAll(tasks); - } finally { - setCorePoolSize(parallelism + parked.decrementAndGet()); - } - } - }; - } - @Override - public void close() { - this.executor.shutdownNow(); - } - - private int getParallelism(ProjectBuildingRequest request) { - int parallelism = DEFAULT_BUILDER_PARALLELISM; - try { - String str = request.getUserProperties().getProperty(Constants.MAVEN_PROJECT_BUILDER_PARALLELISM); - if (str != null) { - parallelism = Integer.parseInt(str); - } - } catch (Exception e) { - // ignore - } - return Math.max(1, Math.min(parallelism, Runtime.getRuntime().availableProcessors())); - } + public void close() {} ProjectBuildingResult build(Path pomFile, ModelSource modelSource) throws ProjectBuildingException { ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader(); @@ -484,14 +370,13 @@ ProjectBuildingResult build(Path pomFile, ModelSource modelSource) throws Projec modelProblems = result.getProblems(); - initProject(project, Collections.emptyMap(), result); - } else if (request.isResolveDependencies()) { - projectBuildingHelper.selectProjectRealm(project); + initProject(project, result); } DependencyResolutionResult resolutionResult = null; if (request.isResolveDependencies()) { + projectBuildingHelper.selectProjectRealm(project); resolutionResult = resolveDependencies(project); } @@ -573,58 +458,19 @@ List build(List pomFiles, boolean recursive) throws } List doBuild(List pomFiles, boolean recursive) { - Map projectIndex = new ConcurrentHashMap<>(256); - - // phase 1: get file Models from the reactor. - List interimResults = build(projectIndex, pomFiles, new LinkedHashSet<>(), true, recursive); - ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader(); - try { - // Phase 2: get effective models from the reactor - return build(projectIndex, interimResults); + return pomFiles.stream() + .map(pomFile -> build(pomFile, true, recursive)) + .flatMap(List::stream) + .collect(Collectors.toList()); } finally { Thread.currentThread().setContextClassLoader(oldContextClassLoader); } } @SuppressWarnings("checkstyle:parameternumber") - private List build( - Map projectIndex, - List pomFiles, - Set aggregatorFiles, - boolean root, - boolean recursive) { - List> tasks = pomFiles.stream() - .map(pomFile -> ((Callable) - () -> build(projectIndex, pomFile, concat(aggregatorFiles, pomFile), root, recursive))) - .collect(Collectors.toList()); - try { - List> futures = executor.invokeAll(tasks); - List list = new ArrayList<>(); - for (Future future : futures) { - InterimResult interimResult = future.get(); - list.add(interimResult); - } - return list; - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private Set concat(Set set, T elem) { - Set newSet = new HashSet<>(set); - newSet.add(elem); - return newSet; - } - - @SuppressWarnings("checkstyle:parameternumber") - private InterimResult build( - Map projectIndex, - File pomFile, - Set aggregatorFiles, - boolean isRoot, - boolean recursive) { + private List build(File pomFile, boolean topLevel, boolean recursive) { MavenProject project = new MavenProject(); project.setFile(pomFile); @@ -648,117 +494,19 @@ private InterimResult build( } catch (ModelBuilderException e) { result = e.getResult(); if (result == null || result.getFileModel() == null) { - return new InterimResult( - modelBuildingRequest, - new DefaultProjectBuildingResult(e.getModelId(), pomFile, convert(e.getProblems()))); + return List.of(new DefaultProjectBuildingResult(e.getModelId(), pomFile, convert(e.getProblems()))); } // validation error, continue project building and delay failing to help IDEs // result.getProblems().addAll(e.getProblems()) ? } - InterimResult interimResult = new InterimResult(pomFile, modelBuildingRequest, result, project, isRoot); - interimResult.subprojects = result.getChildren().stream() - .map(r -> build(projectIndex, r.getFileModel().getPomFile().toFile(), aggregatorFiles, false, true)) - .toList(); - /* - Model model = result.getActivatedFileModel(); - - if (recursive && model != null) { - File basedir = pomFile.getParentFile(); - List subprojects = model.getSubprojects(); - if (subprojects.isEmpty()) { - subprojects = model.getModules(); - } - List subprojectFiles = new ArrayList<>(); - for (String subproject : subprojects) { - if (subproject == null || subproject.isEmpty()) { - continue; - } - - subproject = subproject.replace('\\', File.separatorChar).replace('/', File.separatorChar); - - Path subprojectPath = modelProcessor.locateExistingPom(new File(basedir, subproject).toPath()); - File subprojectFile = subprojectPath != null ? subprojectPath.toFile() : null; - - if (subprojectFile == null) { - ModelProblem problem = new org.apache.maven.internal.impl.model.DefaultModelProblem( - "Child subproject " + subprojectFile + " of " + pomFile + " does not exist", - ModelProblem.Severity.ERROR, - ModelProblem.Version.BASE, - model, - -1, - -1, - null); - result.getProblems().add(problem); - continue; - } - - if (Os.IS_WINDOWS) { - // we don't canonicalize on unix to avoid interfering with symlinks - try { - subprojectFile = subprojectFile.getCanonicalFile(); - } catch (IOException e) { - subprojectFile = subprojectFile.getAbsoluteFile(); - } - } else { - subprojectFile = new File(subprojectFile.toURI().normalize()); - } - - if (aggregatorFiles.contains(subprojectFile)) { - StringBuilder buffer = new StringBuilder(256); - for (File aggregatorFile : aggregatorFiles) { - buffer.append(aggregatorFile).append(" -> "); - } - buffer.append(subprojectFile); - - ModelProblem problem = new org.apache.maven.internal.impl.model.DefaultModelProblem( - "Child subproject " + subprojectFile + " of " + pomFile + " forms aggregation cycle " - + buffer, - ModelProblem.Severity.ERROR, - ModelProblem.Version.BASE, - model, - -1, - -1, - null); - result.getProblems().add(problem); - - continue; - } - - subprojectFiles.add(subprojectFile); - } - - if (!subprojectFiles.isEmpty()) { - interimResult.subprojects = build(projectIndex, subprojectFiles, aggregatorFiles, false, recursive); - } - } - */ - projectIndex.put(pomFile, project); - return interimResult; - } - - private List build( - Map projectIndex, List interimResults) { - return interimResults.stream() - .map(ir -> doBuild(projectIndex, ir)) - .flatMap(List::stream) - .collect(Collectors.toList()); - } - - private List doBuild(Map projectIndex, InterimResult interimResult) { - if (interimResult.projectBuildingResult != null) { - return Collections.singletonList(interimResult.projectBuildingResult); - } - MavenProject project = interimResult.project; try { - ModelBuilderResult result = interimResult.result; - // 2nd pass of initialization: resolve and build parent if necessary List problems = convert(result.getProblems()); try { - initProject(project, projectIndex, result); + initProject(project, result); } catch (InvalidArtifactRTException iarte) { problems.add(new DefaultModelProblem( null, @@ -770,9 +518,12 @@ private List doBuild(Map projectIndex iarte)); } - List results = build(projectIndex, interimResult.subprojects); + List results = result.getChildren().stream() + .map(r -> build(r.getFileModel().getPomFile().toFile(), false, true)) + .flatMap(List::stream) + .collect(Collectors.toList()); - project.setExecutionRoot(interimResult.root); + project.setExecutionRoot(topLevel); project.setCollectedProjects( results.stream().map(ProjectBuildingResult::getProject).collect(Collectors.toList())); DependencyResolutionResult resolutionResult = null; @@ -784,15 +535,14 @@ private List doBuild(Map projectIndex return results; } catch (ModelBuilderException e) { - DefaultProjectBuildingResult result; - if (project == null || interimResult.result.getEffectiveModel() == null) { - result = new DefaultProjectBuildingResult( - e.getModelId(), interimResult.pomFile, convert(e.getProblems())); + DefaultProjectBuildingResult eresult; + if (result.getEffectiveModel() == null) { + eresult = new DefaultProjectBuildingResult(e.getModelId(), pomFile, convert(e.getProblems())); } else { - project.setModel(new org.apache.maven.model.Model(interimResult.result.getEffectiveModel())); - result = new DefaultProjectBuildingResult(project, convert(e.getProblems()), null); + project.setModel(new org.apache.maven.model.Model(result.getEffectiveModel())); + eresult = new DefaultProjectBuildingResult(project, convert(e.getProblems()), null); } - return Collections.singletonList(result); + return Collections.singletonList(eresult); } } @@ -816,11 +566,11 @@ private List convert(List projects, ModelBuilderResult result) { + private void initProject(MavenProject project, ModelBuilderResult result) { project.setModel(new org.apache.maven.model.Model(result.getEffectiveModel())); project.setOriginalModel(new org.apache.maven.model.Model(result.getFileModel())); - initParent(project, projects, result); + initParent(project, result); Artifact projectArtifact = repositorySystem.createArtifact( project.getGroupId(), project.getArtifactId(), project.getVersion(), null, project.getPackaging()); @@ -973,7 +723,7 @@ private void initProject(MavenProject project, Map projects, } } - private void initParent(MavenProject project, Map projects, ModelBuilderResult result) { + private void initParent(MavenProject project, ModelBuilderResult result) { Model parentModel = result.getModelIds().size() > 1 && !result.getModelIds().get(1).isEmpty() ? result.getRawModel(result.getModelIds().get(1)).orElse(null) @@ -990,7 +740,7 @@ private void initParent(MavenProject project, Map projects, String parentModelId = result.getModelIds().get(1); Path parentPomFile = result.getRawModel(parentModelId).map(Model::getPomFile).orElse(null); - MavenProject parent = parentPomFile != null ? projects.get(parentPomFile.toFile()) : null; + MavenProject parent = parentPomFile != null ? projectIndex.get(parentPomFile.toFile()) : null; if (parent == null) { // // At this point the DefaultModelBuildingListener has fired and it populates the @@ -1052,24 +802,11 @@ private ModelBuilderRequest.ModelBuilderRequestBuilder getModelBuildingRequest() modelBuildingRequest.inactiveProfileIds(request.getInactiveProfileIds()); modelBuildingRequest.systemProperties(toMap(request.getSystemProperties())); modelBuildingRequest.userProperties(toMap(request.getUserProperties())); - // bv4: modelBuildingRequest.setBuildStartTime(request.getBuildStartTime()); modelBuildingRequest.repositoryMerging(ModelBuilderRequest.RepositoryMerging.valueOf( request.getRepositoryMerging().name())); modelBuildingRequest.repositories(request.getRemoteRepositories().stream() .map(r -> internalSession.getRemoteRepository(RepositoryUtils.toRepo(r))) .toList()); - /* TODO: bv4 - InternalMavenSession session = - (InternalMavenSession) this.session.getData().get(InternalMavenSession.class); - if (session != null) { - try { - modelBuildingRequest.setRootDirectory(session.getRootDirectory()); - } catch (IllegalStateException e) { - // can happen if root directory cannot be found, just ignore - } - } - */ - return modelBuildingRequest; } @@ -1114,19 +851,13 @@ private List getProfileIds(List profiles) { } private static ModelSource createStubModelSource(Artifact artifact) { - StringBuilder buffer = new StringBuilder(1024); - - buffer.append(""); - buffer.append(""); - buffer.append("4.0.0"); - buffer.append("").append(artifact.getGroupId()).append(""); - buffer.append("").append(artifact.getArtifactId()).append(""); - buffer.append("").append(artifact.getBaseVersion()).append(""); - buffer.append("").append(artifact.getType()).append(""); - buffer.append(""); - - String xml = buffer.toString(); - + String xml = "" + "" + + "4.0.0" + + "" + + artifact.getGroupId() + "" + "" + + artifact.getArtifactId() + "" + "" + + artifact.getBaseVersion() + "" + "" + + artifact.getType() + "" + ""; return new StubModelSource(xml, artifact); } @@ -1160,17 +891,11 @@ private static Map toMap(Properties properties) { if (properties != null && !properties.isEmpty()) { return properties.entrySet().stream() .collect(Collectors.toMap(e -> String.valueOf(e.getKey()), e -> String.valueOf(e.getValue()))); - } else { return null; } } - @SuppressWarnings("unchecked") - static void uncheckedThrow(Throwable t) throws T { - throw (T) t; // rely on vacuous cast - } - static class LazyMap extends AbstractMap { private final Supplier> supplier; private volatile Map delegate; @@ -1192,84 +917,6 @@ public Set> entrySet() { } } - protected abstract class ModelResolverWrapper implements ModelResolver { - - protected abstract org.apache.maven.model.resolution.ModelResolver getResolver( - List repositories); - - @Override - public ModelSource resolveModel( - Session session, - List repositories, - String groupId, - String artifactId, - String version, - Consumer resolved) - throws ModelResolverException { - try { - InternalSession internalSession = InternalSession.from(session); - org.apache.maven.model.resolution.ModelResolver resolver = getResolver(internalSession.toRepositories( - repositories != null ? repositories : internalSession.getRemoteRepositories())); - org.apache.maven.model.Parent p = new org.apache.maven.model.Parent(Parent.newBuilder() - .groupId(groupId) - .artifactId(artifactId) - .version(version) - .build()); - org.apache.maven.model.building.ModelSource modelSource = resolver.resolveModel(p); - if (!p.getVersion().equals(version)) { - resolved.accept(p.getVersion()); - } - return toSource(modelSource); - } catch (UnresolvableModelException e) { - throw new ModelResolverException(e.getMessage(), e.getGroupId(), e.getArtifactId(), e.getVersion(), e); - } - } - - @Override - public ModelSource resolveModel( - Session session, - List repositories, - Parent parent, - AtomicReference modified) - throws ModelResolverException { - try { - org.apache.maven.model.Parent p = new org.apache.maven.model.Parent(parent); - InternalSession internalSession = InternalSession.from(session); - org.apache.maven.model.resolution.ModelResolver resolver = getResolver(internalSession.toRepositories( - repositories != null ? repositories : internalSession.getRemoteRepositories())); - ModelSource source = toSource(resolver.resolveModel(p)); - if (p.getDelegate() != parent) { - modified.set(p.getDelegate()); - } - return source; - } catch (UnresolvableModelException e) { - throw new ModelResolverException(e.getMessage(), e.getGroupId(), e.getArtifactId(), e.getVersion(), e); - } - } - - @Override - public ModelSource resolveModel( - Session session, - List repositories, - Dependency dependency, - AtomicReference modified) - throws ModelResolverException { - try { - org.apache.maven.model.Dependency d = new org.apache.maven.model.Dependency(dependency); - InternalSession internalSession = InternalSession.from(session); - org.apache.maven.model.resolution.ModelResolver resolver = getResolver(internalSession.toRepositories( - repositories != null ? repositories : internalSession.getRemoteRepositories())); - ModelSource source = toSource(resolver.resolveModel(d)); - if (d.getDelegate() != dependency) { - modified.set(d.getDelegate()); - } - return source; - } catch (UnresolvableModelException e) { - throw new ModelResolverException(e.getMessage(), e.getGroupId(), e.getArtifactId(), e.getVersion(), e); - } - } - } - /** * Processes events from the model builder while building the effective model for a {@link MavenProject} instance. * From ac18d888b06870d20e30de33c7bee985c13c6896 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 24 Sep 2024 06:26:38 +0200 Subject: [PATCH 28/63] Support non explicit root directories --- .../impl/model/DefaultModelBuilder.java | 60 ++++++++++++------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index c6ed255f6457..a3d488a69d5d 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -789,8 +789,33 @@ private ModelBuilderResult buildRecursive(Collection importIds) throws M } catch (IllegalStateException e) { rootDirectory = session.getService(RootLocator.class).findRoot(top); } - List toLoad = new ArrayList<>(); + loadFromRoot(rootDirectory, top); + if (hasErrors()) { + throw newModelBuilderException(); + } + + build2(importIds); + for (DefaultModelBuilderResult r : result.getChildren()) { + if (r.getFileModel() == null) { + continue; + } + var pbs = r.getProblems(); + r.setProblems(List.of()); + derive(ModelSource.fromPath(r.getFileModel().getPomFile()), r).build2(importIds); + result.getProblems().addAll(r.getProblems()); + pbs.addAll(r.getProblems()); + r.setProblems(pbs); + } + if (hasErrors()) { + throw newModelBuilderException(); + } + + return result; + } + + private void loadFromRoot(Path rootDirectory, Path top) { Path root = getModelProcessor().locateExistingPom(rootDirectory); + List toLoad = new ArrayList<>(); toLoad.add(root); Set buildParts = new HashSet<>(); while (!toLoad.isEmpty()) { @@ -885,32 +910,23 @@ private ModelBuilderResult buildRecursive(Collection importIds) throws M // gathered with problem collector add(Severity.ERROR, ModelProblem.Version.V40, "Failed to load project " + pom, e); } - if (pom != root) { + if (r != result) { result.getProblems().addAll(r.getProblems()); r.getProblems().clear(); } } - if (hasErrors()) { - throw newModelBuilderException(); - } - - build2(importIds); - for (DefaultModelBuilderResult r : result.getChildren()) { - if (r.getFileModel() == null) { - continue; - } - var pbs = r.getProblems(); - r.setProblems(List.of()); - derive(ModelSource.fromPath(r.getFileModel().getPomFile()), r).build2(importIds); - result.getProblems().addAll(r.getProblems()); - pbs.addAll(r.getProblems()); - r.setProblems(pbs); - } - if (hasErrors()) { - throw newModelBuilderException(); + if (result.getFileModel() == null && !Objects.equals(top.getParent(), rootDirectory)) { + logger.warn( + "The top project ({}) cannot be found in the reactor from root project ({}). " + + "Make sure the root directory is correct (a missing '.mvn' directory in the root " + + "project is the most common cause) and the project is correctly included " + + "in the reactor (missing activated profiles, command line options, etc.). For this " + + "build, the top project will be used as the root project.", + top, + rootDirectory); + cache.clear(); + loadFromRoot(top.getParent(), top); } - - return result; } private ModelBuilderResult buildParentOrDependency(Collection importIds) throws ModelBuilderException { From 1b22e5f07fee4916dd6f3c5334b9c5c73ea4e6e6 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 24 Sep 2024 08:15:46 +0200 Subject: [PATCH 29/63] Fix --- .../java/org/apache/maven/project/DefaultProjectBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index d25ecda01f5f..f849aa2eaada 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -493,7 +493,7 @@ private List build(File pomFile, boolean topLevel, boolea result = modelBuilderSession.build(modelBuildingRequest); } catch (ModelBuilderException e) { result = e.getResult(); - if (result == null || result.getFileModel() == null) { + if (result == null || result.getEffectiveModel() == null) { return List.of(new DefaultProjectBuildingResult(e.getModelId(), pomFile, convert(e.getProblems()))); } // validation error, continue project building and delay failing to help IDEs From dbe400bf46aba138d305a93d60f916fce3588a3f Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 24 Sep 2024 09:03:16 +0200 Subject: [PATCH 30/63] Better fix --- .../internal/impl/model/DefaultModelBuilder.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index a3d488a69d5d..2f6d7b0fd95e 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -789,7 +789,8 @@ private ModelBuilderResult buildRecursive(Collection importIds) throws M } catch (IllegalStateException e) { rootDirectory = session.getService(RootLocator.class).findRoot(top); } - loadFromRoot(rootDirectory, top); + Path root = getModelProcessor().locateExistingPom(rootDirectory); + loadFromRoot(root, top); if (hasErrors()) { throw newModelBuilderException(); } @@ -813,8 +814,7 @@ private ModelBuilderResult buildRecursive(Collection importIds) throws M return result; } - private void loadFromRoot(Path rootDirectory, Path top) { - Path root = getModelProcessor().locateExistingPom(rootDirectory); + private void loadFromRoot(Path root, Path top) { List toLoad = new ArrayList<>(); toLoad.add(root); Set buildParts = new HashSet<>(); @@ -915,7 +915,7 @@ private void loadFromRoot(Path rootDirectory, Path top) { r.getProblems().clear(); } } - if (result.getFileModel() == null && !Objects.equals(top.getParent(), rootDirectory)) { + if (result.getFileModel() == null && !Objects.equals(top, root)) { logger.warn( "The top project ({}) cannot be found in the reactor from root project ({}). " + "Make sure the root directory is correct (a missing '.mvn' directory in the root " @@ -923,9 +923,9 @@ private void loadFromRoot(Path rootDirectory, Path top) { + "in the reactor (missing activated profiles, command line options, etc.). For this " + "build, the top project will be used as the root project.", top, - rootDirectory); + root); cache.clear(); - loadFromRoot(top.getParent(), top); + loadFromRoot(top, top); } } From 22f0a9fbfe72f5e8245729afaf9ef7aefbffbde6 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 24 Sep 2024 11:34:37 +0200 Subject: [PATCH 31/63] Fixes --- .../impl/model/DefaultModelBuilder.java | 130 +++++++++--------- 1 file changed, 64 insertions(+), 66 deletions(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 2f6d7b0fd95e..0e120e832182 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -18,6 +18,7 @@ */ package org.apache.maven.internal.impl.model; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; @@ -814,12 +815,17 @@ private ModelBuilderResult buildRecursive(Collection importIds) throws M return result; } + record PomToLoad(Path pom, Set parents) {} + + @SuppressWarnings("checkstyle:MethodLength") private void loadFromRoot(Path root, Path top) { - List toLoad = new ArrayList<>(); - toLoad.add(root); + List toLoad = new ArrayList<>(); + toLoad.add(new PomToLoad(root, Set.of())); Set buildParts = new HashSet<>(); while (!toLoad.isEmpty()) { - Path pom = toLoad.remove(0); + PomToLoad pomToLoad = toLoad.remove(0); + Path pom = pomToLoad.pom; + Set parents = pomToLoad.parents; DefaultModelBuilderResult r; boolean isBuildPart = buildParts.contains(pom); if (pom.equals(top)) { @@ -831,6 +837,7 @@ private void loadFromRoot(Path root, Path top) { } } try { + Path pomDirectory = Files.isDirectory(pom) ? pom : pom.getParent(); Model model = derive(ModelSource.fromPath(pom), r).readFileModel(); r.setFileModel(model); Model activated = activateFileModel(model); @@ -840,72 +847,56 @@ private void loadFromRoot(Path root, Path top) { subprojects = activated.getModules(); } for (String subproject : subprojects) { - Path subprojectFile = getModelProcessor() - .locateExistingPom(pom.getParent().resolve(subproject)); - if (subprojectFile != null) { - toLoad.add(subprojectFile); - if (pom.equals(top)) { - buildParts.add(subprojectFile); + if (subproject == null || subproject.isEmpty()) { + continue; + } + + subproject = + subproject.replace('\\', File.separatorChar).replace('/', File.separatorChar); + + Path subprojectFile = modelProcessor.locateExistingPom(pomDirectory.resolve(subproject)); + + if (subprojectFile == null) { + ModelProblem problem = new org.apache.maven.internal.impl.model.DefaultModelProblem( + "Child subproject " + subprojectFile + " of " + pomDirectory + " does not exist", + ModelProblem.Severity.ERROR, + ModelProblem.Version.BASE, + model, + -1, + -1, + null); + r.getProblems().add(problem); + add(problem); + continue; + } + + subprojectFile = subprojectFile.toAbsolutePath().normalize(); + + if (parents.contains(subprojectFile)) { + StringBuilder buffer = new StringBuilder(256); + for (Path aggregatorFile : parents) { + buffer.append(aggregatorFile).append(" -> "); } + buffer.append(subprojectFile); + + ModelProblem problem = new org.apache.maven.internal.impl.model.DefaultModelProblem( + "Child subproject " + subprojectFile + " of " + pom + " forms aggregation cycle " + + buffer, + ModelProblem.Severity.ERROR, + ModelProblem.Version.BASE, + model, + -1, + -1, + null); + r.getProblems().add(problem); + continue; + } + + toLoad.add(new PomToLoad(subprojectFile, concat(parents, pom))); + if (pom.equals(top)) { + buildParts.add(subprojectFile); } } - /* - TODO: adapt those checks - - if (subproject == null || subproject.isEmpty()) { - continue; - } - - subproject = subproject.replace('\\', File.separatorChar).replace('/', File.separatorChar); - - Path subprojectPath = modelProcessor.locateExistingPom(new File(basedir, subproject).toPath()); - File subprojectFile = subprojectPath != null ? subprojectPath.toFile() : null; - - if (subprojectFile == null) { - ModelProblem problem = new org.apache.maven.internal.impl.model.DefaultModelProblem( - "Child subproject " + subprojectFile + " of " + pomFile + " does not exist", - ModelProblem.Severity.ERROR, - ModelProblem.Version.BASE, - model, - -1, - -1, - null); - result.getProblems().add(problem); - continue; - } - - if (Os.IS_WINDOWS) { - // we don't canonicalize on unix to avoid interfering with symlinks - try { - subprojectFile = subprojectFile.getCanonicalFile(); - } catch (IOException e) { - subprojectFile = subprojectFile.getAbsoluteFile(); - } - } else { - subprojectFile = new File(subprojectFile.toURI().normalize()); - } - - if (aggregatorFiles.contains(subprojectFile)) { - StringBuilder buffer = new StringBuilder(256); - for (File aggregatorFile : aggregatorFiles) { - buffer.append(aggregatorFile).append(" -> "); - } - buffer.append(subprojectFile); - - ModelProblem problem = new org.apache.maven.internal.impl.model.DefaultModelProblem( - "Child subproject " + subprojectFile + " of " + pomFile + " forms aggregation cycle " - + buffer, - ModelProblem.Severity.ERROR, - ModelProblem.Version.BASE, - model, - -1, - -1, - null); - result.getProblems().add(problem); - - continue; - } - */ } catch (ModelBuilderException e) { // gathered with problem collector add(Severity.ERROR, ModelProblem.Version.V40, "Failed to load project " + pom, e); @@ -925,10 +916,17 @@ private void loadFromRoot(Path root, Path top) { top, root); cache.clear(); + mappedSources.clear(); loadFromRoot(top, top); } } + static Set concat(Set a, T b) { + Set result = new HashSet<>(a); + result.add(b); + return Set.copyOf(result); + } + private ModelBuilderResult buildParentOrDependency(Collection importIds) throws ModelBuilderException { // phase 1: read and validate raw model Model fileModel = readFileModel(); From b253adb2a89f8048b2ea0fa96762a6f2e15c156b Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 24 Sep 2024 14:15:59 +0200 Subject: [PATCH 32/63] Improve model resolution --- .../impl/model/DefaultModelBuilder.java | 35 ++++++-- .../impl/resolver/DefaultModelResolver.java | 84 +++++++++++++++++-- .../resolver/DefaultModelResolverTest.java | 8 +- 3 files changed, 107 insertions(+), 20 deletions(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 0e120e832182..f15135963952 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -1125,10 +1125,13 @@ ModelData resolveAndReadParentExternally(Model childModel) throws ModelBuilderEx ModelSource modelSource; try { - AtomicReference modified = new AtomicReference<>(); - modelSource = modelResolver.resolveModel(request.getSession(), getRepositories(), parent, modified); - if (modified.get() != null) { - parent = modified.get(); + modelSource = resolveReactorModel(groupId, artifactId, version); + if (modelSource == null) { + AtomicReference modified = new AtomicReference<>(); + modelSource = modelResolver.resolveModel(request.getSession(), getRepositories(), parent, modified); + if (modified.get() != null) { + parent = modified.get(); + } } } catch (ModelResolverException e) { // Message below is checked for in the MNG-2199 core IT. @@ -1749,11 +1752,13 @@ private Model doLoadDependencyManagement( String version, Collection importIds) { Model importModel; - // no workspace resolver or workspace resolver returned null (i.e. model not in workspace) - final ModelSource importSource; + ModelSource importSource; try { - importSource = modelResolver.resolveModel( - request.getSession(), getRepositories(), dependency, new AtomicReference<>()); + importSource = resolveReactorModel(groupId, artifactId, version); + if (importSource == null) { + importSource = modelResolver.resolveModel( + request.getSession(), getRepositories(), dependency, new AtomicReference<>()); + } } catch (ModelBuilderException e) { StringBuilder buffer = new StringBuilder(256); buffer.append("Non-resolvable import POM"); @@ -1807,6 +1812,20 @@ private Model doLoadDependencyManagement( return importModel; } + ModelSource resolveReactorModel(String groupId, String artifactId, String version) { + Set sources = mappedSources.get(new GAKey(groupId, artifactId)); + if (sources != null) { + for (ModelSource source : sources) { + Model model = derive(source).readRawModel(); + if (Objects.equals(model.getVersion(), version)) { + return source; + } + } + // TODO: log a warning ? + } + return null; + } + private T cache(String groupId, String artifactId, String version, String tag, Callable supplier) { return cache.computeIfAbsent(groupId, artifactId, version, tag, asSupplier(supplier)); } diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelResolver.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelResolver.java index 9ba4e4e619da..1eaf9f2c8f18 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelResolver.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelResolver.java @@ -24,6 +24,7 @@ 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,8 +33,13 @@ 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.ModelSource; import org.apache.maven.api.services.Source; @@ -50,13 +56,64 @@ @Singleton public class DefaultModelResolver implements ModelResolver { + @Nonnull @Override + public ModelSource resolveModel( + @Nonnull Session session, + @Nullable List repositories, + @Nonnull Parent parent, + @Nonnull AtomicReference 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 repositories, + @Nonnull Dependency dependency, + @Nonnull AtomicReference 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 repositories, + @Nonnull String groupId, + @Nonnull String artifactId, + @Nonnull String version, + @Nonnull Consumer resolvedVersion) + throws ModelResolverException { + return resolveModel(session, repositories, groupId, artifactId, version, null, null, resolvedVersion); + } + + @SuppressWarnings("checkstyle:ParameterNumber") public ModelSource resolveModel( Session session, List repositories, String groupId, String artifactId, String version, + String type, + InputLocation location, Consumer resolvedVersion) throws ModelResolverException { try { @@ -65,7 +122,9 @@ public ModelSource resolveModel( && 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 ModelSource resolveModel( List 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 ModelSource resolveModel( 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 ModelSource resolveModel( } } - private static class ResolverModelSource implements ModelSource { + protected Path getPath( + Session session, + List 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; diff --git a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/resolver/DefaultModelResolverTest.java b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/resolver/DefaultModelResolverTest.java index 187a8f4a5484..42f3686382d9 100644 --- a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/resolver/DefaultModelResolverTest.java +++ b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/resolver/DefaultModelResolverTest.java @@ -87,7 +87,7 @@ void testResolveParentThrowsModelResolverExceptionWhenNoMatchingVersionFound() t 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 @@ void testResolveParentThrowsModelResolverExceptionWhenUsingRangesWithoutUpperBou 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 @@ void testResolveDependencyThrowsModelResolverExceptionWhenNoMatchingVersionFound 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 @@ void testResolveDependencyThrowsModelResolverExceptionWhenUsingRangesWithoutUppe 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 From 151645b1094e080b4fb27f81c01544453df56696 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 24 Sep 2024 16:27:06 +0200 Subject: [PATCH 33/63] wip --- .../impl/model/DefaultModelBuilder.java | 68 +++---------------- .../impl/model/DefaultRootLocator.java | 12 ++++ .../impl/DefaultConsumerPomBuilder.java | 9 ++- .../maven/project/DefaultProjectBuilder.java | 4 +- .../maven/project/PomConstructionTest.java | 12 ++++ 5 files changed, 46 insertions(+), 59 deletions(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index f15135963952..fc2d43e652d2 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -247,8 +247,6 @@ protected final class DefaultModelBuilderSession implements ModelProblemCollecto private final Set severities = EnumSet.noneOf(ModelProblem.Severity.class); - volatile boolean fullReactorLoaded; - DefaultModelBuilderSession(ModelBuilderRequest request) { this(request, new DefaultModelBuilderResult()); } @@ -335,7 +333,7 @@ public ModelBuilderRequest request() { return request; } - public DefaultModelBuilderResult result() { + public ModelBuilderResult result() { return result; } @@ -367,11 +365,6 @@ private int getParallelism() { public Model getRawModel(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())) { return null; @@ -400,51 +393,6 @@ public Model getRawModel(Path from, Path path) { return null; } - private void loadFullReactor() { - if (!fullReactorLoaded) { - synchronized (this) { - if (!fullReactorLoaded) { - doLoadFullReactor(); - fullReactorLoaded = true; - } - } - } - } - - private void doLoadFullReactor() { - Path rootDirectory; - try { - rootDirectory = session().getRootDirectory(); - } catch (IllegalStateException e) { - // if no root directory, bail out - return; - } - List toLoad = new ArrayList<>(); - Path root = getModelProcessor().locateExistingPom(rootDirectory); - toLoad.add(root); - while (!toLoad.isEmpty()) { - Path pom = toLoad.remove(0); - try { - Model model = derive(ModelSource.fromPath(pom)).readFileModel(); - model = activateFileModel(model); - List subprojects = model.getSubprojects(); - if (subprojects.isEmpty()) { - subprojects = model.getModules(); - } - for (String subproject : subprojects) { - Path subprojectFile = getModelProcessor() - .locateExistingPom(pom.getParent().resolve(subproject)); - if (subprojectFile != null) { - toLoad.add(subprojectFile); - } - } - } catch (ModelBuilderException e) { - // gathered with problem collector - add(Severity.ERROR, ModelProblem.Version.V40, "Failed to load project " + pom, e); - } - } - } - private boolean addEdge(Path from, Path p) { try { dag.addEdge(from.toString(), p.toString()); @@ -771,18 +719,19 @@ String replaceCiFriendlyVersion(String version) { } ModelBuilderResult build(Collection importIds) throws ModelBuilderException { - if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM && request.isRecursive()) { - return buildRecursive(importIds); + if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { + return buildBuildPom(importIds); } else { return buildParentOrDependency(importIds); } } - private ModelBuilderResult buildRecursive(Collection importIds) throws ModelBuilderException { + private ModelBuilderResult buildBuildPom(Collection importIds) throws ModelBuilderException { Path top = request.getSource().getPath(); if (top == null) { throw new IllegalStateException("Recursive build requested but source has no path"); } + top = top.toAbsolutePath().normalize(); Path rootDirectory; try { @@ -791,6 +740,11 @@ private ModelBuilderResult buildRecursive(Collection importIds) throws M rootDirectory = session.getService(RootLocator.class).findRoot(top); } Path root = getModelProcessor().locateExistingPom(rootDirectory); + if (root != null) { + root = root.toAbsolutePath().normalize(); + } else { + root = top; + } loadFromRoot(root, top); if (hasErrors()) { throw newModelBuilderException(); @@ -893,7 +847,7 @@ private void loadFromRoot(Path root, Path top) { } toLoad.add(new PomToLoad(subprojectFile, concat(parents, pom))); - if (pom.equals(top)) { + if (pom.equals(top) && request.isRecursive()) { buildParts.add(subprojectFile); } } diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultRootLocator.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultRootLocator.java index e50db13f24ca..a5a36490189a 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultRootLocator.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultRootLocator.java @@ -27,12 +27,24 @@ 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; diff --git a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java index a51230550614..3153df80284c 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.stream.Collectors; +import org.apache.maven.api.SessionData; import org.apache.maven.api.model.Dependency; import org.apache.maven.api.model.DependencyManagement; import org.apache.maven.api.model.DistributionManagement; @@ -34,6 +35,7 @@ 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; @@ -210,7 +212,12 @@ public List getActiveProfiles( request.locationTracking(false); request.systemProperties(session.getSystemProperties()); request.userProperties(session.getUserProperties()); - return modelBuilder.newSession().build(request.build()); + 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) { diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index f849aa2eaada..baaf7716384a 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -45,6 +45,7 @@ import org.apache.maven.ProjectCycleException; import org.apache.maven.RepositoryUtils; +import org.apache.maven.api.SessionData; import org.apache.maven.api.model.Build; import org.apache.maven.api.model.Dependency; import org.apache.maven.api.model.DependencyManagement; @@ -315,8 +316,9 @@ class BuildSession implements AutoCloseable { this.request = request; this.session = RepositoryUtils.overlay(request.getLocalRepository(), request.getRepositorySession(), repoSystem); - InternalSession.from(session); + InternalSession iSession = InternalSession.from(session); this.modelBuilderSession = modelBuilder.newSession(); + iSession.getData().set(SessionData.key(ModelBuilder.ModelBuilderSession.class), modelBuilderSession); } @Override diff --git a/maven-core/src/test/java/org/apache/maven/project/PomConstructionTest.java b/maven-core/src/test/java/org/apache/maven/project/PomConstructionTest.java index e5991ac34d81..be6770eefaab 100644 --- a/maven-core/src/test/java/org/apache/maven/project/PomConstructionTest.java +++ b/maven-core/src/test/java/org/apache/maven/project/PomConstructionTest.java @@ -21,6 +21,8 @@ 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 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; @@ -1899,6 +1903,14 @@ private PomTestWrapper buildPom( 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()); } From 6fdbfff0503d0d7bbe145f77a4f19f0edd995f2d Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 24 Sep 2024 17:29:02 +0200 Subject: [PATCH 34/63] Fix --- .../impl/model/DefaultModelBuilder.java | 20 ++++------- .../impl/ConsumerPomBuilderTest.java | 6 ++-- .../DefaultMavenProjectBuilderTest.java | 5 +++ .../maven/project/PomConstructionTest.java | 6 ++-- .../maven/project/ProjectBuilderTest.java | 1 + .../complete-model/w-parent/sub/sub/pom.xml | 11 ++++++ .../complete-model/wo-parent/sub/pom.xml | 11 ++++++ .../plugin-exec-inheritance/pom.xml | 4 +-- .../pom-inheritance/{sub => child-1}/pom.xml | 0 .../pom-inheritance/child-2/pom.xml | 36 +++++++++++++++++++ .../maven-inherit-plugin/pom.xml | 12 +++++++ .../maven-pax-plugin/pom.xml | 12 +++++++ .../profile-module-inheritance/sub/pom.xml | 2 +- .../profile-module/module-1/pom.xml | 9 +++++ .../profile-module/module-2/pom.xml | 9 +++++ .../profile-module/module-3/pom.xml | 9 +++++ .../profile-module/module-4/pom.xml | 9 +++++ .../profile-module/module-5/pom.xml | 9 +++++ .../reporting-plugin-config/pom.xml | 2 +- .../unc-path/pom.xml | 2 +- .../test/resources/consumer/trivial/pom.xml | 2 +- 21 files changed, 153 insertions(+), 24 deletions(-) create mode 100644 maven-core/src/test/resources-project-builder/complete-model/w-parent/sub/sub/pom.xml create mode 100644 maven-core/src/test/resources-project-builder/complete-model/wo-parent/sub/pom.xml rename maven-core/src/test/resources-project-builder/pom-inheritance/{sub => child-1}/pom.xml (100%) create mode 100644 maven-core/src/test/resources-project-builder/pom-inheritance/child-2/pom.xml create mode 100644 maven-core/src/test/resources-project-builder/profile-module-inheritance/maven-inherit-plugin/pom.xml create mode 100644 maven-core/src/test/resources-project-builder/profile-module-inheritance/maven-pax-plugin/pom.xml create mode 100644 maven-core/src/test/resources-project-builder/profile-module/module-1/pom.xml create mode 100644 maven-core/src/test/resources-project-builder/profile-module/module-2/pom.xml create mode 100644 maven-core/src/test/resources-project-builder/profile-module/module-3/pom.xml create mode 100644 maven-core/src/test/resources-project-builder/profile-module/module-4/pom.xml create mode 100644 maven-core/src/test/resources-project-builder/profile-module/module-5/pom.xml diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index fc2d43e652d2..285c0c123060 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -28,7 +28,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -245,8 +244,6 @@ protected final class DefaultModelBuilderSession implements ModelProblemCollecto List externalRepositories; List repositories; - private final Set severities = EnumSet.noneOf(ModelProblem.Severity.class); - DefaultModelBuilderSession(ModelBuilderRequest request) { this(request, new DefaultModelBuilderResult()); } @@ -298,7 +295,6 @@ private DefaultModelBuilderSession( this.externalRepositories = externalRepositories; this.repositories = repositories; } - this.result.getProblems().forEach(p -> severities.add(p.getSeverity())); } public DefaultModelBuilderSession derive(ModelSource source) { @@ -447,11 +443,13 @@ public void putSource(String groupId, String artifactId, ModelSource source) { } public boolean hasFatalErrors() { - return severities.contains(ModelProblem.Severity.FATAL); + return result.getProblems().stream().anyMatch(p -> p.getSeverity() == ModelProblem.Severity.FATAL); } public boolean hasErrors() { - return severities.contains(ModelProblem.Severity.ERROR) || severities.contains(ModelProblem.Severity.FATAL); + return result.getProblems().stream() + .anyMatch(p -> p.getSeverity() == ModelProblem.Severity.FATAL + || p.getSeverity() == ModelProblem.Severity.ERROR); } @Override @@ -499,16 +497,10 @@ public String getRootModelId() { @Override public void add(ModelProblem problem) { result.getProblems().add(problem); - - severities.add(problem.getSeverity()); } public void addAll(Collection problems) { this.result.getProblems().addAll(problems); - - for (ModelProblem problem : problems) { - severities.add(problem.getSeverity()); - } } @Override @@ -758,7 +750,7 @@ private ModelBuilderResult buildBuildPom(Collection importIds) throws Mo var pbs = r.getProblems(); r.setProblems(List.of()); derive(ModelSource.fromPath(r.getFileModel().getPomFile()), r).build2(importIds); - result.getProblems().addAll(r.getProblems()); + r.getProblems().forEach(this::add); pbs.addAll(r.getProblems()); r.setProblems(pbs); } @@ -812,7 +804,7 @@ private void loadFromRoot(Path root, Path top) { if (subprojectFile == null) { ModelProblem problem = new org.apache.maven.internal.impl.model.DefaultModelProblem( - "Child subproject " + subprojectFile + " of " + pomDirectory + " does not exist", + "Child subproject " + subproject + " of " + pomDirectory + " does not exist", ModelProblem.Severity.ERROR, ModelProblem.Version.BASE, model, diff --git a/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java b/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java index 8039f6a48eba..0cf6c5c92ca0 100644 --- a/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java +++ b/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java @@ -92,9 +92,12 @@ void testTrivialConsumer() throws Exception { 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); } + InternalMavenSession.from(InternalSession.from(session)) + .getMavenSession() + .getRequest() + .setRootDirectory(Paths.get("src/test/resources/consumer/trivial")); Model model = builder.build(session, project, file); assertNotNull(model); @@ -114,7 +117,6 @@ void testSimpleConsumer() throws Exception { 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.setOriginalModel(model); } InternalMavenSession.from(InternalSession.from(session)) diff --git a/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java b/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java index cdef9df96d6f..1a963559db60 100644 --- a/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java +++ b/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java @@ -324,6 +324,11 @@ void rereadPom_mng7063() throws Exception { 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); diff --git a/maven-core/src/test/java/org/apache/maven/project/PomConstructionTest.java b/maven-core/src/test/java/org/apache/maven/project/PomConstructionTest.java index be6770eefaab..c1d6a8ad3ecd 100644 --- a/maven-core/src/test/java/org/apache/maven/project/PomConstructionTest.java +++ b/maven-core/src/test/java/org/apache/maven/project/PomConstructionTest.java @@ -1234,7 +1234,7 @@ void testPropertiesNoDuplication() throws Exception { @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")); } @@ -1906,7 +1906,9 @@ private PomTestWrapper buildPom( 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"))) { + while (root != null + && !Files.isDirectory(root.resolve(".mvn")) + && Files.isRegularFile(root.resolve("../pom.xml"))) { root = root.getParent(); } mSession.getMavenSession().getRequest().setRootDirectory(root); diff --git a/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java b/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java index b398b17f6345..508fe0cf278f 100644 --- a/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java +++ b/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java @@ -171,6 +171,7 @@ void testReadModifiedPoms(@TempDir Path tempDir) throws Exception { 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 = diff --git a/maven-core/src/test/resources-project-builder/complete-model/w-parent/sub/sub/pom.xml b/maven-core/src/test/resources-project-builder/complete-model/w-parent/sub/sub/pom.xml new file mode 100644 index 000000000000..bbee8d734860 --- /dev/null +++ b/maven-core/src/test/resources-project-builder/complete-model/w-parent/sub/sub/pom.xml @@ -0,0 +1,11 @@ + + 4.0.0 + + + org.apache.maven.its.mng + test + 0.2 + + + sub + diff --git a/maven-core/src/test/resources-project-builder/complete-model/wo-parent/sub/pom.xml b/maven-core/src/test/resources-project-builder/complete-model/wo-parent/sub/pom.xml new file mode 100644 index 000000000000..bbee8d734860 --- /dev/null +++ b/maven-core/src/test/resources-project-builder/complete-model/wo-parent/sub/pom.xml @@ -0,0 +1,11 @@ + + 4.0.0 + + + org.apache.maven.its.mng + test + 0.2 + + + sub + diff --git a/maven-core/src/test/resources-project-builder/plugin-exec-inheritance/pom.xml b/maven-core/src/test/resources-project-builder/plugin-exec-inheritance/pom.xml index cbed746d1e6a..5e76b70f1d85 100644 --- a/maven-core/src/test/resources-project-builder/plugin-exec-inheritance/pom.xml +++ b/maven-core/src/test/resources-project-builder/plugin-exec-inheritance/pom.xml @@ -33,8 +33,8 @@ under the License. - child-1 - child-2 + w-merge + wo-merge diff --git a/maven-core/src/test/resources-project-builder/pom-inheritance/sub/pom.xml b/maven-core/src/test/resources-project-builder/pom-inheritance/child-1/pom.xml similarity index 100% rename from maven-core/src/test/resources-project-builder/pom-inheritance/sub/pom.xml rename to maven-core/src/test/resources-project-builder/pom-inheritance/child-1/pom.xml diff --git a/maven-core/src/test/resources-project-builder/pom-inheritance/child-2/pom.xml b/maven-core/src/test/resources-project-builder/pom-inheritance/child-2/pom.xml new file mode 100644 index 000000000000..c175dc2a4ad1 --- /dev/null +++ b/maven-core/src/test/resources-project-builder/pom-inheritance/child-2/pom.xml @@ -0,0 +1,36 @@ + + + + + + 4.0.0 + + + + + org.apache.maven.its.mng3843 + parent-1 + 0.1 + + + child-2 + diff --git a/maven-core/src/test/resources-project-builder/profile-module-inheritance/maven-inherit-plugin/pom.xml b/maven-core/src/test/resources-project-builder/profile-module-inheritance/maven-inherit-plugin/pom.xml new file mode 100644 index 000000000000..60f057cce38e --- /dev/null +++ b/maven-core/src/test/resources-project-builder/profile-module-inheritance/maven-inherit-plugin/pom.xml @@ -0,0 +1,12 @@ + + + org.ops4j.pax + construct + 1.0 + + + 4.0.0 + org.ops4j + maven-inherit-plugin + 1.1 + diff --git a/maven-core/src/test/resources-project-builder/profile-module-inheritance/maven-pax-plugin/pom.xml b/maven-core/src/test/resources-project-builder/profile-module-inheritance/maven-pax-plugin/pom.xml new file mode 100644 index 000000000000..422f76d023df --- /dev/null +++ b/maven-core/src/test/resources-project-builder/profile-module-inheritance/maven-pax-plugin/pom.xml @@ -0,0 +1,12 @@ + + + org.ops4j.pax + construct + 1.0 + + + 4.0.0 + org.ops4j + maven-pax-plugin + 1.1 + diff --git a/maven-core/src/test/resources-project-builder/profile-module-inheritance/sub/pom.xml b/maven-core/src/test/resources-project-builder/profile-module-inheritance/sub/pom.xml index 60f057cce38e..d64644d4c9a8 100644 --- a/maven-core/src/test/resources-project-builder/profile-module-inheritance/sub/pom.xml +++ b/maven-core/src/test/resources-project-builder/profile-module-inheritance/sub/pom.xml @@ -7,6 +7,6 @@ 4.0.0 org.ops4j - maven-inherit-plugin + sub 1.1 diff --git a/maven-core/src/test/resources-project-builder/profile-module/module-1/pom.xml b/maven-core/src/test/resources-project-builder/profile-module/module-1/pom.xml new file mode 100644 index 000000000000..3d475ef2acaa --- /dev/null +++ b/maven-core/src/test/resources-project-builder/profile-module/module-1/pom.xml @@ -0,0 +1,9 @@ + + 4.0.0 + + gid + aid + 1.0 + + module-1 + diff --git a/maven-core/src/test/resources-project-builder/profile-module/module-2/pom.xml b/maven-core/src/test/resources-project-builder/profile-module/module-2/pom.xml new file mode 100644 index 000000000000..08706a5a050f --- /dev/null +++ b/maven-core/src/test/resources-project-builder/profile-module/module-2/pom.xml @@ -0,0 +1,9 @@ + + 4.0.0 + + gid + aid + 1.0 + + module-2 + diff --git a/maven-core/src/test/resources-project-builder/profile-module/module-3/pom.xml b/maven-core/src/test/resources-project-builder/profile-module/module-3/pom.xml new file mode 100644 index 000000000000..5fb40a8a4961 --- /dev/null +++ b/maven-core/src/test/resources-project-builder/profile-module/module-3/pom.xml @@ -0,0 +1,9 @@ + + 4.0.0 + + gid + aid + 1.0 + + module-3 + diff --git a/maven-core/src/test/resources-project-builder/profile-module/module-4/pom.xml b/maven-core/src/test/resources-project-builder/profile-module/module-4/pom.xml new file mode 100644 index 000000000000..aae87db1d4cd --- /dev/null +++ b/maven-core/src/test/resources-project-builder/profile-module/module-4/pom.xml @@ -0,0 +1,9 @@ + + 4.0.0 + + gid + aid + 1.0 + + module-4 + diff --git a/maven-core/src/test/resources-project-builder/profile-module/module-5/pom.xml b/maven-core/src/test/resources-project-builder/profile-module/module-5/pom.xml new file mode 100644 index 000000000000..517e1505bcf9 --- /dev/null +++ b/maven-core/src/test/resources-project-builder/profile-module/module-5/pom.xml @@ -0,0 +1,9 @@ + + 4.0.0 + + gid + aid + 1.0 + + module-5 + diff --git a/maven-core/src/test/resources-project-builder/reporting-plugin-config/pom.xml b/maven-core/src/test/resources-project-builder/reporting-plugin-config/pom.xml index 4a5063805a00..25b7eef5899a 100644 --- a/maven-core/src/test/resources-project-builder/reporting-plugin-config/pom.xml +++ b/maven-core/src/test/resources-project-builder/reporting-plugin-config/pom.xml @@ -29,7 +29,7 @@ Test inheritance of reporting plugin configuration - child + sub diff --git a/maven-core/src/test/resources-project-builder/unc-path/pom.xml b/maven-core/src/test/resources-project-builder/unc-path/pom.xml index c1e63ba556b1..c1ce59926eb8 100644 --- a/maven-core/src/test/resources-project-builder/unc-path/pom.xml +++ b/maven-core/src/test/resources-project-builder/unc-path/pom.xml @@ -29,7 +29,7 @@ Test inheritance of UNC paths - child + sub diff --git a/maven-core/src/test/resources/consumer/trivial/pom.xml b/maven-core/src/test/resources/consumer/trivial/pom.xml index 69512db6c7a7..c739cc33b9d2 100644 --- a/maven-core/src/test/resources/consumer/trivial/pom.xml +++ b/maven-core/src/test/resources/consumer/trivial/pom.xml @@ -5,7 +5,7 @@ pom - child.xml + child From d967e1b23df8b51fa358cbe3399dfba9cb9bd4fe Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 24 Sep 2024 18:25:36 +0200 Subject: [PATCH 35/63] Remove remaining references to the two phase building --- .../api/services/ModelBuilderRequest.java | 18 ------------------ .../impl/model/DefaultModelBuilder.java | 7 ------- .../DefaultArtifactDescriptorReader.java | 1 - .../maven/project/DefaultProjectBuilder.java | 1 - 4 files changed, 27 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java index 39f10363ea3c..ce3fe158528d 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java @@ -87,8 +87,6 @@ enum RepositoryMerging { @Nonnull RequestType getRequestType(); - boolean isTwoPhaseBuilding(); - boolean isLocationTracking(); boolean isRecursive(); @@ -175,7 +173,6 @@ class ModelBuilderRequestBuilder { Session session; RequestType requestType; boolean locationTracking; - boolean twoPhaseBuilding; boolean recursive; ModelSource source; Collection profiles; @@ -194,7 +191,6 @@ class ModelBuilderRequestBuilder { this.session = request.getSession(); this.requestType = request.getRequestType(); this.locationTracking = request.isLocationTracking(); - this.twoPhaseBuilding = request.isTwoPhaseBuilding(); this.recursive = request.isRecursive(); this.source = request.getSource(); this.profiles = request.getProfiles(); @@ -218,11 +214,6 @@ public ModelBuilderRequestBuilder requestType(RequestType requestType) { return this; } - public ModelBuilderRequestBuilder twoPhaseBuilding(boolean twoPhaseBuilding) { - this.twoPhaseBuilding = twoPhaseBuilding; - return this; - } - public ModelBuilderRequestBuilder locationTracking(boolean locationTracking) { this.locationTracking = locationTracking; return this; @@ -288,7 +279,6 @@ public ModelBuilderRequest build() { session, requestType, locationTracking, - twoPhaseBuilding, recursive, source, profiles, @@ -305,7 +295,6 @@ public ModelBuilderRequest build() { private static class DefaultModelBuilderRequest extends BaseRequest implements ModelBuilderRequest { private final RequestType requestType; private final boolean locationTracking; - private final boolean twoPhaseBuilding; private final boolean recursive; private final ModelSource source; private final Collection profiles; @@ -323,7 +312,6 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M @Nonnull Session session, @Nonnull RequestType requestType, boolean locationTracking, - boolean twoPhaseBuilding, boolean recursive, @Nonnull ModelSource source, Collection profiles, @@ -338,7 +326,6 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M super(session); this.requestType = nonNull(requestType, "requestType cannot be null"); this.locationTracking = locationTracking; - this.twoPhaseBuilding = twoPhaseBuilding; this.recursive = recursive; this.source = source; this.profiles = profiles != null ? List.copyOf(profiles) : List.of(); @@ -358,11 +345,6 @@ public RequestType getRequestType() { return requestType; } - @Override - public boolean isTwoPhaseBuilding() { - return twoPhaseBuilding; - } - @Override public boolean isLocationTracking() { return locationTracking; diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 285c0c123060..5a45aad225b2 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -881,14 +881,8 @@ private ModelBuilderResult buildParentOrDependency(Collection importIds) Model activatedFileModel = activateFileModel(fileModel); result.setActivatedFileModel(activatedFileModel); - // if (!build.request.isTwoPhaseBuilding()) { // phase 2: build the effective model return build2(importIds); - // } else if (hasModelErrors(build)) { - // throw build.newModelBuilderException(); - // } - - // return build.result; } private ModelBuilderResult build2(Collection importIds) throws ModelBuilderException { @@ -1742,7 +1736,6 @@ private Model doLoadDependencyManagement( .systemProperties(request.getSystemProperties()) .userProperties(request.getUserProperties()) .source(importSource) - .twoPhaseBuilding(false) .repositories(getRepositories()) .build(); importResult = new DefaultModelBuilderSession(importRequest).build(importIds); diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java index 5852cfde2861..82bae431cfae 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java @@ -195,7 +195,6 @@ private Model loadPom( ModelBuilderRequest modelRequest = ModelBuilderRequest.builder() .session(iSession) .requestType(ModelBuilderRequest.RequestType.DEPENDENCY) - .twoPhaseBuilding(false) .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. diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index baaf7716384a..12271e48e0ce 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -484,7 +484,6 @@ private List build(File pomFile, boolean topLevel, boolea ModelBuilderRequest modelBuildingRequest = getModelBuildingRequest() .source(ModelSource.fromPath(pomFile.toPath())) .requestType(ModelBuilderRequest.RequestType.BUILD_POM) - .twoPhaseBuilding(true) .locationTracking(true) .listener(listener) .recursive(recursive) From 61004e0af5c34daf6bf905e06e64bb6895050a91 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 24 Sep 2024 20:06:13 +0200 Subject: [PATCH 36/63] Get rid of ModelBuildingListener --- .../api/services/ModelBuilderRequest.java | 38 ---- .../services/model/ModelBuildingEvent.java | 55 ----- .../services/model/ModelBuildingListener.java | 33 --- .../impl/model/DefaultModelBuilder.java | 49 +---- .../impl/model/DefaultModelBuildingEvent.java | 33 --- .../maven/project/DefaultProjectBuilder.java | 206 ++++++++---------- 6 files changed, 100 insertions(+), 314 deletions(-) delete mode 100644 maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelBuildingEvent.java delete mode 100644 maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelBuildingListener.java delete mode 100644 maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuildingEvent.java diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java index ce3fe158528d..070a47c20539 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java @@ -126,12 +126,6 @@ enum RepositoryMerging { @Nonnull RepositoryMerging getRepositoryMerging(); - @Nullable - Object getListener(); - - @Nullable - ModelBuilderResult getInterimResult(); - @Nullable List getRepositories(); @@ -181,8 +175,6 @@ class ModelBuilderRequestBuilder { Map systemProperties; Map userProperties; RepositoryMerging repositoryMerging; - Object listener; - ModelBuilderResult interimResult; List repositories; ModelBuilderRequestBuilder() {} @@ -199,8 +191,6 @@ class ModelBuilderRequestBuilder { this.systemProperties = request.getSystemProperties(); this.userProperties = request.getUserProperties(); this.repositoryMerging = request.getRepositoryMerging(); - this.listener = request.getListener(); - this.interimResult = request.getInterimResult(); this.repositories = request.getRepositories(); } @@ -259,16 +249,6 @@ public ModelBuilderRequestBuilder repositoryMerging(RepositoryMerging repository return this; } - public ModelBuilderRequestBuilder listener(Object listener) { - this.listener = listener; - return this; - } - - public ModelBuilderRequestBuilder interimResult(ModelBuilderResult interimResult) { - this.interimResult = interimResult; - return this; - } - public ModelBuilderRequestBuilder repositories(List repositories) { this.repositories = repositories; return this; @@ -287,8 +267,6 @@ public ModelBuilderRequest build() { systemProperties, userProperties, repositoryMerging, - listener, - interimResult, repositories); } @@ -303,8 +281,6 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M private final Map systemProperties; private final Map userProperties; private final RepositoryMerging repositoryMerging; - private final Object listener; - private final ModelBuilderResult interimResult; private final List repositories; @SuppressWarnings("checkstyle:ParameterNumber") @@ -320,8 +296,6 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M Map systemProperties, Map userProperties, RepositoryMerging repositoryMerging, - Object listener, - ModelBuilderResult interimResult, List repositories) { super(session); this.requestType = nonNull(requestType, "requestType cannot be null"); @@ -335,8 +309,6 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M systemProperties != null ? Map.copyOf(systemProperties) : session.getSystemProperties(); this.userProperties = userProperties != null ? Map.copyOf(userProperties) : session.getUserProperties(); this.repositoryMerging = repositoryMerging; - this.listener = listener; - this.interimResult = interimResult; this.repositories = repositories != null ? List.copyOf(repositories) : null; } @@ -391,16 +363,6 @@ public RepositoryMerging getRepositoryMerging() { return repositoryMerging; } - @Override - public Object getListener() { - return listener; - } - - @Override - public ModelBuilderResult getInterimResult() { - return interimResult; - } - @Override public List getRepositories() { return repositories; diff --git a/maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelBuildingEvent.java b/maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelBuildingEvent.java deleted file mode 100644 index f2d8bf861984..000000000000 --- a/maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelBuildingEvent.java +++ /dev/null @@ -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 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(); -} diff --git a/maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelBuildingListener.java b/maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelBuildingListener.java deleted file mode 100644 index a0c2bfb4a768..000000000000 --- a/maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelBuildingListener.java +++ /dev/null @@ -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) {} -} diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 5a45aad225b2..daaab4cb9f81 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -41,7 +41,6 @@ import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.BiConsumer; import java.util.function.Supplier; import java.util.function.UnaryOperator; import java.util.stream.Collectors; @@ -89,8 +88,6 @@ import org.apache.maven.api.services.model.DependencyManagementInjector; import org.apache.maven.api.services.model.InheritanceAssembler; import org.apache.maven.api.services.model.LifecycleBindingsInjector; -import org.apache.maven.api.services.model.ModelBuildingEvent; -import org.apache.maven.api.services.model.ModelBuildingListener; import org.apache.maven.api.services.model.ModelCache; import org.apache.maven.api.services.model.ModelCacheFactory; import org.apache.maven.api.services.model.ModelInterpolator; @@ -208,22 +205,14 @@ public ModelBuilderSession newSession() { @Override public ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilderException { - if (request.getInterimResult() != null) { - if (mainSession == null) { - throw new IllegalStateException("ModelBuilderSession is not initialized"); - } - DefaultModelBuilderResult result = asDefaultModelBuilderResult(request.getInterimResult()); - return mainSession.derive(request, result).build2(new LinkedHashSet<>()); + DefaultModelBuilderSession session; + if (mainSession == null) { + mainSession = new DefaultModelBuilderSession(request); + session = mainSession; } else { - DefaultModelBuilderSession session; - if (mainSession == null) { - mainSession = new DefaultModelBuilderSession(request); - session = mainSession; - } else { - session = mainSession.derive(request, new DefaultModelBuilderResult()); - } - return session.build(new LinkedHashSet<>()); + session = mainSession.derive(request, new DefaultModelBuilderResult()); } + return session.build(new LinkedHashSet<>()); } }; } @@ -898,8 +887,6 @@ private ModelBuilderResult build2(Collection importIds) throws ModelBuil // plugin management injection resultModel = pluginManagementInjector.injectManagement(resultModel, request, this); - resultModel = fireEvent(resultModel, request, this, ModelBuildingListener::buildExtensionsAssembled); - if (request.getRequestType() != ModelBuilderRequest.RequestType.DEPENDENCY) { if (lifecycleBindingsInjector == null) { throw new IllegalStateException("lifecycle bindings injector is missing"); @@ -2065,26 +2052,6 @@ static void uncheckedThrow(Throwable t) throws T { throw (T) t; // rely on vacuous cast } - private Model fireEvent( - Model model, - ModelBuilderRequest request, - ModelProblemCollector problems, - BiConsumer catapult) { - ModelBuildingListener listener = getModelBuildingListener(request); - - if (listener != null) { - AtomicReference m = new AtomicReference<>(model); - - ModelBuildingEvent event = new DefaultModelBuildingEvent(model, m::set, request, problems); - - catapult.accept(listener, event); - - return m.get(); - } - - return model; - } - private boolean containsCoordinates(String message, String groupId, String artifactId, String version) { return message != null && (groupId == null || message.contains(groupId)) @@ -2096,9 +2063,5 @@ ModelProcessor getModelProcessor() { return modelProcessor; } - private static ModelBuildingListener getModelBuildingListener(ModelBuilderRequest request) { - return (ModelBuildingListener) request.getListener(); - } - record GAKey(String groupId, String artifactId) {} } diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuildingEvent.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuildingEvent.java deleted file mode 100644 index db76a0686675..000000000000 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuildingEvent.java +++ /dev/null @@ -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 update, ModelBuilderRequest request, ModelProblemCollector problems) - implements ModelBuildingEvent {} diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index 12271e48e0ce..969d800c4294 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -63,15 +63,13 @@ import org.apache.maven.api.services.ModelProblem; import org.apache.maven.api.services.ModelSource; import org.apache.maven.api.services.Source; -import org.apache.maven.api.services.model.ModelBuildingEvent; -import org.apache.maven.api.services.model.ModelBuildingListener; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.InvalidArtifactRTException; import org.apache.maven.artifact.InvalidRepositoryException; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.bridge.MavenRepositorySystem; import org.apache.maven.internal.impl.InternalSession; -import org.apache.maven.model.building.DefaultModelProblem; +import org.apache.maven.internal.impl.model.DefaultModelProblem; import org.apache.maven.model.building.FileModelSource; import org.apache.maven.model.building.ModelBuildingRequest; import org.apache.maven.model.building.ModelSource2; @@ -337,9 +335,6 @@ ProjectBuildingResult build(Path pomFile, ModelSource modelSource) throws Projec project = new MavenProject(); project.setFile(pomFile != null ? pomFile.toFile() : null); - ModelBuildingListener listener = - new DefaultModelBuildingListener(project, projectBuildingHelper, this.request); - ModelBuilderRequest.ModelBuilderRequestBuilder builder = getModelBuildingRequest(); ModelBuilderRequest request = builder.source(modelSource) .requestType( @@ -350,7 +345,6 @@ ProjectBuildingResult build(Path pomFile, ModelSource modelSource) throws Projec ? ModelBuilderRequest.RequestType.BUILD_POM : ModelBuilderRequest.RequestType.DEPENDENCY) .locationTracking(true) - .listener(listener) .build(); if (pomFile != null) { @@ -360,6 +354,15 @@ ProjectBuildingResult build(Path pomFile, ModelSource modelSource) throws Projec ModelBuilderResult result; try { result = modelBuilderSession.build(request); + + buildExtensionsAssembled( + result.getEffectiveModel(), + result.getProblems(), + request, + project, + projectBuildingHelper, + this.request); + } catch (ModelBuilderException e) { result = e.getResult(); if (result == null || result.getEffectiveModel() == null) { @@ -479,19 +482,25 @@ private List build(File pomFile, boolean topLevel, boolea project.setRootDirectory( rootLocator.findRoot(pomFile.getParentFile().toPath())); - ModelBuildingListener listener = new DefaultModelBuildingListener(project, projectBuildingHelper, request); - ModelBuilderRequest modelBuildingRequest = getModelBuildingRequest() .source(ModelSource.fromPath(pomFile.toPath())) .requestType(ModelBuilderRequest.RequestType.BUILD_POM) .locationTracking(true) - .listener(listener) .recursive(recursive) .build(); ModelBuilderResult result; try { result = modelBuilderSession.build(modelBuildingRequest); + + buildExtensionsAssembled( + result.getEffectiveModel(), + result.getProblems(), + modelBuildingRequest, + project, + projectBuildingHelper, + request); + } catch (ModelBuilderException e) { result = e.getResult(); if (result == null || result.getEffectiveModel() == null) { @@ -509,7 +518,7 @@ private List build(File pomFile, boolean topLevel, boolea try { initProject(project, result); } catch (InvalidArtifactRTException iarte) { - problems.add(new DefaultModelProblem( + problems.add(new org.apache.maven.model.building.DefaultModelProblem( null, org.apache.maven.model.building.ModelProblem.Severity.ERROR, null, @@ -552,17 +561,18 @@ private List convert(List (org.apache.maven.model.building.ModelProblem) new DefaultModelProblem( - p.getMessage(), - org.apache.maven.model.building.ModelProblem.Severity.valueOf( - p.getSeverity().name()), - org.apache.maven.model.building.ModelProblem.Version.valueOf( - p.getVersion().name()), - p.getSource(), - p.getLineNumber(), - p.getColumnNumber(), - p.getModelId(), - p.getException())) + .map(p -> (org.apache.maven.model.building.ModelProblem) + new org.apache.maven.model.building.DefaultModelProblem( + p.getMessage(), + org.apache.maven.model.building.ModelProblem.Severity.valueOf( + p.getSeverity().name()), + org.apache.maven.model.building.ModelProblem.Version.valueOf( + p.getVersion().name()), + p.getSource(), + p.getLineNumber(), + p.getColumnNumber(), + p.getModelId(), + p.getException())) .toList(); } @@ -918,97 +928,69 @@ public Set> entrySet() { } } - /** - * Processes events from the model builder while building the effective model for a {@link MavenProject} instance. - * - */ - public static class DefaultModelBuildingListener implements ModelBuildingListener { - - private final MavenProject project; - - private final ProjectBuildingHelper projectBuildingHelper; - - private final ProjectBuildingRequest projectBuildingRequest; - - private List remoteRepositories; - - private List 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) { - org.apache.maven.model.Model model = new org.apache.maven.model.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().getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { - 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 + public void buildExtensionsAssembled( + Model model, + List problems, + ModelBuilderRequest request, + MavenProject project, + ProjectBuildingHelper projectBuildingHelper, + ProjectBuildingRequest projectBuildingRequest) { + org.apache.maven.model.Model model3 = new org.apache.maven.model.Model(model); + List remoteRepositories = projectBuildingRequest.getRemoteRepositories(); + List pluginRepositories = projectBuildingRequest.getPluginArtifactRepositories(); + try { + pluginRepositories = projectBuildingHelper.createArtifactRepositories( + model3.getPluginRepositories(), pluginRepositories, projectBuildingRequest); + } catch (Exception e) { + add( + problems, + BuilderProblem.Severity.ERROR, + ModelProblem.Version.BASE, + "Invalid plugin repository: " + e.getMessage(), + e); + } + project.setPluginArtifactRepositories(pluginRepositories); + + if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { 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); + ProjectRealmCache.CacheRecord record = + projectBuildingHelper.createProjectRealm(project, model3, projectBuildingRequest); + + project.setClassRealm(record.getRealm()); + project.setExtensionDependencyFilter(record.getExtensionArtifactFilter()); + } catch (PluginResolutionException | PluginManagerException | PluginVersionResolutionException e) { + add( + problems, + 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( + model3.getRepositories(), remoteRepositories, projectBuildingRequest); + } catch (Exception e) { + add( + problems, + 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()); - } - } + void add( + List problems, + BuilderProblem.Severity severity, + ModelProblem.Version version, + String message, + Exception e) { + problems.add(new DefaultModelProblem(null, severity, version, null, -1, -1, message, e)); } } From 88ab3102b04bdf587d027f8185bf7d2171fc1e48 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 24 Sep 2024 20:11:15 +0200 Subject: [PATCH 37/63] Small fixes --- .../maven/internal/impl/model/DefaultModelBuilder.java | 4 ---- .../apache/maven/internal/impl/InternalMavenSession.java | 6 +++++- .../transformation/impl/DefaultConsumerPomBuilder.java | 5 ----- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index daaab4cb9f81..3d241965fb63 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -1033,10 +1033,6 @@ private ModelData readParentLocally(Model childModel, ModelSource childSource) t // resolver. // - /* - * if ( version == null || !version.equals( parent.getVersion() ) ) { return null; } - */ - return new ModelData(candidateSource, candidateModel); } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/InternalMavenSession.java b/maven-core/src/main/java/org/apache/maven/internal/impl/InternalMavenSession.java index 4df67943e8ea..e165dfd8e6c5 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/InternalMavenSession.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/InternalMavenSession.java @@ -34,10 +34,14 @@ static InternalMavenSession from(Session session) { 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 getProjects(List projects); /** - * May return null if the input projcet is null or is not part of the reactor. + * 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); diff --git a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java index 3153df80284c..7dfe11a5dddb 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java @@ -68,7 +68,6 @@ import org.apache.maven.model.v4.MavenModelVersion; import org.apache.maven.project.MavenProject; import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.impl.RemoteRepositoryManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -93,8 +92,6 @@ class DefaultConsumerPomBuilder implements ConsumerPomBuilder { private final PluginManagementInjector pluginManagementInjector; private final SuperPomProvider superPomProvider; private final ModelVersionParser versionParser; - // To break circular dependency private final Provider repositorySystem; - private final RemoteRepositoryManager remoteRepositoryManager; private final ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator; private final List transformers; private final ModelCacheFactory modelCacheFactory; @@ -118,7 +115,6 @@ class DefaultConsumerPomBuilder implements ConsumerPomBuilder { PluginManagementInjector pluginManagementInjector, SuperPomProvider superPomProvider, ModelVersionParser versionParser, - RemoteRepositoryManager remoteRepositoryManager, ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator, List transformers, ModelCacheFactory modelCacheFactory, @@ -138,7 +134,6 @@ class DefaultConsumerPomBuilder implements ConsumerPomBuilder { this.pluginManagementInjector = pluginManagementInjector; this.superPomProvider = superPomProvider; this.versionParser = versionParser; - this.remoteRepositoryManager = remoteRepositoryManager; this.profileActivationFilePathInterpolator = profileActivationFilePathInterpolator; this.transformers = transformers; this.modelCacheFactory = modelCacheFactory; From fa1c107bf64856167ab5cc0273b98b4a1db4483b Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 24 Sep 2024 21:26:55 +0200 Subject: [PATCH 38/63] Make ModelBuilder threaded --- .../impl/model/DefaultModelBuilder.java | 232 ++++++++++-------- 1 file changed, 134 insertions(+), 98 deletions(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 3d241965fb63..bac3e63ddd1b 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -40,6 +40,9 @@ import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; import java.util.function.UnaryOperator; @@ -335,6 +338,10 @@ public String toString() { + cache + ']'; } + ExecutorService createExecutor() { + return Executors.newFixedThreadPool(getParallelism()); + } + private int getParallelism() { int parallelism = Runtime.getRuntime().availableProcessors() / 2 + 1; try { @@ -731,17 +738,25 @@ private ModelBuilderResult buildBuildPom(Collection importIds) throws Mo throw newModelBuilderException(); } - build2(importIds); - for (DefaultModelBuilderResult r : result.getChildren()) { - if (r.getFileModel() == null) { - continue; + ExecutorService executor = createExecutor(); + try { + executor.submit(() -> build2(importIds)); + for (DefaultModelBuilderResult r : result.getChildren()) { + if (r.getFileModel() == null) { + continue; + } + executor.submit(() -> { + var pbs = r.getProblems(); + r.setProblems(List.of()); + derive(ModelSource.fromPath(r.getFileModel().getPomFile()), r) + .build2(importIds); + r.getProblems().forEach(this::add); + pbs.addAll(r.getProblems()); + r.setProblems(pbs); + }); } - var pbs = r.getProblems(); - r.setProblems(List.of()); - derive(ModelSource.fromPath(r.getFileModel().getPomFile()), r).build2(importIds); - r.getProblems().forEach(this::add); - pbs.addAll(r.getProblems()); - r.setProblems(pbs); + } finally { + close(executor); } if (hasErrors()) { throw newModelBuilderException(); @@ -750,96 +765,13 @@ private ModelBuilderResult buildBuildPom(Collection importIds) throws Mo return result; } - record PomToLoad(Path pom, Set parents) {} - @SuppressWarnings("checkstyle:MethodLength") private void loadFromRoot(Path root, Path top) { - List toLoad = new ArrayList<>(); - toLoad.add(new PomToLoad(root, Set.of())); - Set buildParts = new HashSet<>(); - while (!toLoad.isEmpty()) { - PomToLoad pomToLoad = toLoad.remove(0); - Path pom = pomToLoad.pom; - Set parents = pomToLoad.parents; - DefaultModelBuilderResult r; - boolean isBuildPart = buildParts.contains(pom); - if (pom.equals(top)) { - r = result; - } else { - r = new DefaultModelBuilderResult(); - if (isBuildPart) { - result.getChildren().add(r); - } - } - try { - Path pomDirectory = Files.isDirectory(pom) ? pom : pom.getParent(); - Model model = derive(ModelSource.fromPath(pom), r).readFileModel(); - r.setFileModel(model); - Model activated = activateFileModel(model); - r.setActivatedFileModel(activated); - List subprojects = activated.getSubprojects(); - if (subprojects.isEmpty()) { - subprojects = activated.getModules(); - } - for (String subproject : subprojects) { - if (subproject == null || subproject.isEmpty()) { - continue; - } - - subproject = - subproject.replace('\\', File.separatorChar).replace('/', File.separatorChar); - - Path subprojectFile = modelProcessor.locateExistingPom(pomDirectory.resolve(subproject)); - - if (subprojectFile == null) { - ModelProblem problem = new org.apache.maven.internal.impl.model.DefaultModelProblem( - "Child subproject " + subproject + " of " + pomDirectory + " does not exist", - ModelProblem.Severity.ERROR, - ModelProblem.Version.BASE, - model, - -1, - -1, - null); - r.getProblems().add(problem); - add(problem); - continue; - } - - subprojectFile = subprojectFile.toAbsolutePath().normalize(); - - if (parents.contains(subprojectFile)) { - StringBuilder buffer = new StringBuilder(256); - for (Path aggregatorFile : parents) { - buffer.append(aggregatorFile).append(" -> "); - } - buffer.append(subprojectFile); - - ModelProblem problem = new org.apache.maven.internal.impl.model.DefaultModelProblem( - "Child subproject " + subprojectFile + " of " + pom + " forms aggregation cycle " - + buffer, - ModelProblem.Severity.ERROR, - ModelProblem.Version.BASE, - model, - -1, - -1, - null); - r.getProblems().add(problem); - continue; - } - - toLoad.add(new PomToLoad(subprojectFile, concat(parents, pom))); - if (pom.equals(top) && request.isRecursive()) { - buildParts.add(subprojectFile); - } - } - } catch (ModelBuilderException e) { - // gathered with problem collector - add(Severity.ERROR, ModelProblem.Version.V40, "Failed to load project " + pom, e); - } - if (r != result) { - result.getProblems().addAll(r.getProblems()); - r.getProblems().clear(); - } + ExecutorService executor = createExecutor(); + try { + loadFilePom(executor, top, root, Set.of(), new HashSet<>()); + } finally { + close(executor); } if (result.getFileModel() == null && !Objects.equals(top, root)) { logger.warn( @@ -856,6 +788,110 @@ private void loadFromRoot(Path root, Path top) { } } + private void close(ExecutorService executor) { + boolean terminated = executor.isTerminated(); + if (!terminated) { + executor.shutdown(); + boolean interrupted = false; + while (!terminated) { + try { + terminated = executor.awaitTermination(1L, TimeUnit.DAYS); + } catch (InterruptedException e) { + if (!interrupted) { + executor.shutdownNow(); + interrupted = true; + } + } + } + if (interrupted) { + Thread.currentThread().interrupt(); + } + } + } + + private void loadFilePom( + ExecutorService executor, Path top, Path pom, Set parents, Set buildParts) { + DefaultModelBuilderResult r; + boolean isBuildPart = buildParts.contains(pom); + if (pom.equals(top)) { + r = result; + } else { + r = new DefaultModelBuilderResult(); + if (isBuildPart) { + result.getChildren().add(r); + } + } + try { + Path pomDirectory = Files.isDirectory(pom) ? pom : pom.getParent(); + Model model = derive(ModelSource.fromPath(pom), r).readFileModel(); + r.setFileModel(model); + Model activated = activateFileModel(model); + r.setActivatedFileModel(activated); + List subprojects = activated.getSubprojects(); + if (subprojects.isEmpty()) { + subprojects = activated.getModules(); + } + for (String subproject : subprojects) { + if (subproject == null || subproject.isEmpty()) { + continue; + } + + subproject = subproject.replace('\\', File.separatorChar).replace('/', File.separatorChar); + + Path rawSubprojectFile = modelProcessor.locateExistingPom(pomDirectory.resolve(subproject)); + + if (rawSubprojectFile == null) { + ModelProblem problem = new DefaultModelProblem( + "Child subproject " + subproject + " of " + pomDirectory + " does not exist", + Severity.ERROR, + ModelProblem.Version.BASE, + model, + -1, + -1, + null); + r.getProblems().add(problem); + add(problem); + continue; + } + + Path subprojectFile = rawSubprojectFile.toAbsolutePath().normalize(); + + if (parents.contains(subprojectFile)) { + StringBuilder buffer = new StringBuilder(256); + for (Path aggregatorFile : parents) { + buffer.append(aggregatorFile).append(" -> "); + } + buffer.append(subprojectFile); + + ModelProblem problem = new DefaultModelProblem( + "Child subproject " + subprojectFile + " of " + pom + " forms aggregation cycle " + + buffer, + Severity.ERROR, + ModelProblem.Version.BASE, + model, + -1, + -1, + null); + r.getProblems().add(problem); + continue; + } + + executor.submit(() -> loadFilePom(executor, top, subprojectFile, concat(parents, pom), buildParts)); + + if (pom.equals(top) && request.isRecursive()) { + buildParts.add(subprojectFile); + } + } + } catch (ModelBuilderException e) { + // gathered with problem collector + add(Severity.ERROR, ModelProblem.Version.V40, "Failed to load project " + pom, e); + } + if (r != result) { + result.getProblems().addAll(r.getProblems()); + r.getProblems().clear(); + } + } + static Set concat(Set a, T b) { Set result = new HashSet<>(a); result.add(b); From 9ecb6c12e06c3720a9170bdf8e0bf1b80c3551f2 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 25 Sep 2024 13:54:27 +0200 Subject: [PATCH 39/63] Fixes --- .../api/services/ModelBuilderRequest.java | 23 ++- .../api/services/ModelBuilderResult.java | 3 + .../maven/api/services/ModelTransformer.java | 43 +++++ .../impl/model/DefaultModelBuilder.java | 181 ++++++++++-------- .../impl/model/DefaultModelBuilderResult.java | 10 + .../standalone/RepositorySystemSupplier.java | 1 - .../maven/project/TestProjectBuilder.java | 20 +- .../impl/DefaultConsumerPomBuilder.java | 2 +- .../maven/project/DefaultProjectBuilder.java | 175 ++++++----------- .../maven/project/ProjectBuilderTest.java | 2 +- .../project-builder/MNG-6723/.mvn/.gitkeep | 0 .../complete-model/w-parent/pom.xml | 3 + .../MavenRepositorySystemSupplier.java | 1 - 13 files changed, 252 insertions(+), 212 deletions(-) create mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformer.java create mode 100644 maven-core/src/test/projects/project-builder/MNG-6723/.mvn/.gitkeep diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java index 070a47c20539..ccd39248b137 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java @@ -129,6 +129,9 @@ enum RepositoryMerging { @Nullable List getRepositories(); + @Nullable + ModelTransformer getLifecycleBindingsInjector(); + @Nonnull static ModelBuilderRequest build(@Nonnull ModelBuilderRequest request, @Nonnull ModelSource source) { return builder(nonNull(request, "request cannot be null")) @@ -176,6 +179,7 @@ class ModelBuilderRequestBuilder { Map userProperties; RepositoryMerging repositoryMerging; List repositories; + ModelTransformer lifecycleBindingsInjector; ModelBuilderRequestBuilder() {} @@ -192,6 +196,7 @@ class ModelBuilderRequestBuilder { this.userProperties = request.getUserProperties(); this.repositoryMerging = request.getRepositoryMerging(); this.repositories = request.getRepositories(); + this.lifecycleBindingsInjector = request.getLifecycleBindingsInjector(); } public ModelBuilderRequestBuilder session(Session session) { @@ -254,6 +259,11 @@ public ModelBuilderRequestBuilder repositories(List repositori return this; } + public ModelBuilderRequestBuilder lifecycleBindingsInjector(ModelTransformer lifecycleBindingsInjector) { + this.lifecycleBindingsInjector = lifecycleBindingsInjector; + return this; + } + public ModelBuilderRequest build() { return new DefaultModelBuilderRequest( session, @@ -267,7 +277,8 @@ public ModelBuilderRequest build() { systemProperties, userProperties, repositoryMerging, - repositories); + repositories, + lifecycleBindingsInjector); } private static class DefaultModelBuilderRequest extends BaseRequest implements ModelBuilderRequest { @@ -282,6 +293,7 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M private final Map userProperties; private final RepositoryMerging repositoryMerging; private final List repositories; + private final ModelTransformer lifecycleBindingsInjector; @SuppressWarnings("checkstyle:ParameterNumber") DefaultModelBuilderRequest( @@ -296,7 +308,8 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M Map systemProperties, Map userProperties, RepositoryMerging repositoryMerging, - List repositories) { + List repositories, + ModelTransformer lifecycleBindingsInjector) { super(session); this.requestType = nonNull(requestType, "requestType cannot be null"); this.locationTracking = locationTracking; @@ -310,6 +323,7 @@ private static class DefaultModelBuilderRequest extends BaseRequest implements M this.userProperties = userProperties != null ? Map.copyOf(userProperties) : session.getUserProperties(); this.repositoryMerging = repositoryMerging; this.repositories = repositories != null ? List.copyOf(repositories) : null; + this.lifecycleBindingsInjector = lifecycleBindingsInjector; } @Override @@ -367,6 +381,11 @@ public RepositoryMerging getRepositoryMerging() { public List getRepositories() { return repositories; } + + @Override + public ModelTransformer getLifecycleBindingsInjector() { + return lifecycleBindingsInjector; + } } } } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderResult.java index f55b54614ae3..722161a82c3c 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderResult.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderResult.java @@ -121,6 +121,9 @@ public interface ModelBuilderResult { @Nonnull List getChildren(); + @Nonnull + ModelSource getSource(); + /** * Creates a human-readable representation of these errors. */ diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformer.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformer.java new file mode 100644 index 000000000000..5d2503ec31bc --- /dev/null +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelTransformer.java @@ -0,0 +1,43 @@ +/* + * 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; +import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.model.Model; + +/** + * A model transformer. + * + * @since 4.0.0 + */ +@Experimental +public interface ModelTransformer { + + /** + * 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 Model model, @Nonnull ModelBuilderRequest request, @Nonnull ModelProblemCollector problems); +} diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index bac3e63ddd1b..16a5554ae63a 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -40,9 +40,10 @@ import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.Phaser; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; import java.util.function.UnaryOperator; @@ -55,7 +56,6 @@ import org.apache.maven.api.SessionData; import org.apache.maven.api.Type; import org.apache.maven.api.VersionRange; -import org.apache.maven.api.annotations.Nullable; import org.apache.maven.api.di.Inject; import org.apache.maven.api.di.Named; import org.apache.maven.api.di.Singleton; @@ -90,7 +90,6 @@ import org.apache.maven.api.services.model.DependencyManagementImporter; import org.apache.maven.api.services.model.DependencyManagementInjector; import org.apache.maven.api.services.model.InheritanceAssembler; -import org.apache.maven.api.services.model.LifecycleBindingsInjector; import org.apache.maven.api.services.model.ModelCache; import org.apache.maven.api.services.model.ModelCacheFactory; import org.apache.maven.api.services.model.ModelInterpolator; @@ -149,7 +148,6 @@ public class DefaultModelBuilder implements ModelBuilder { private final PluginManagementInjector pluginManagementInjector; private final DependencyManagementInjector dependencyManagementInjector; private final DependencyManagementImporter dependencyManagementImporter; - private final LifecycleBindingsInjector lifecycleBindingsInjector; private final PluginConfigurationExpander pluginConfigurationExpander; private final ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator; private final ModelVersionParser versionParser; @@ -173,7 +171,6 @@ public DefaultModelBuilder( PluginManagementInjector pluginManagementInjector, DependencyManagementInjector dependencyManagementInjector, DependencyManagementImporter dependencyManagementImporter, - @Nullable LifecycleBindingsInjector lifecycleBindingsInjector, PluginConfigurationExpander pluginConfigurationExpander, ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator, ModelVersionParser versionParser, @@ -193,7 +190,6 @@ public DefaultModelBuilder( this.pluginManagementInjector = pluginManagementInjector; this.dependencyManagementInjector = dependencyManagementInjector; this.dependencyManagementImporter = dependencyManagementImporter; - this.lifecycleBindingsInjector = lifecycleBindingsInjector; this.pluginConfigurationExpander = pluginConfigurationExpander; this.profileActivationFilePathInterpolator = profileActivationFilePathInterpolator; this.versionParser = versionParser; @@ -215,7 +211,11 @@ public ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilder } else { session = mainSession.derive(request, new DefaultModelBuilderResult()); } - return session.build(new LinkedHashSet<>()); + if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { + return session.buildBuildPom(); + } else { + return session.buildParentOrDependency(new LinkedHashSet<>()); + } } }; } @@ -338,8 +338,49 @@ public String toString() { + cache + ']'; } - ExecutorService createExecutor() { - return Executors.newFixedThreadPool(getParallelism()); + static class TaskTreeExecutor implements Executor, AutoCloseable { + private final ExecutorService executor; + private final Phaser phaser; + + TaskTreeExecutor(int nThreads) { + this.executor = Executors.newFixedThreadPool(nThreads); + this.phaser = new Phaser(); + } + + public void execute(Runnable task) { + phaser.register(); + executor.submit(new WrappedTask(task)); + } + + public void close() { + // Otherwise, register and then wait + phaser.register(); + phaser.arriveAndAwaitAdvance(); + phaser.arriveAndDeregister(); + // Close executor + executor.shutdownNow(); + } + + private class WrappedTask implements Runnable { + private final Runnable task; + + WrappedTask(Runnable task) { + this.task = task; + } + + @Override + public void run() { + try { + task.run(); + } finally { + phaser.arrive(); + } + } + } + } + + TaskTreeExecutor createExecutor() { + return new TaskTreeExecutor(getParallelism()); } private int getParallelism() { @@ -706,15 +747,7 @@ String replaceCiFriendlyVersion(String version) { return version; } - ModelBuilderResult build(Collection importIds) throws ModelBuilderException { - if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { - return buildBuildPom(importIds); - } else { - return buildParentOrDependency(importIds); - } - } - - private ModelBuilderResult buildBuildPom(Collection importIds) throws ModelBuilderException { + private ModelBuilderResult buildBuildPom() throws ModelBuilderException { Path top = request.getSource().getPath(); if (top == null) { throw new IllegalStateException("Recursive build requested but source has no path"); @@ -738,26 +771,29 @@ private ModelBuilderResult buildBuildPom(Collection importIds) throws Mo throw newModelBuilderException(); } - ExecutorService executor = createExecutor(); - try { - executor.submit(() -> build2(importIds)); - for (DefaultModelBuilderResult r : result.getChildren()) { - if (r.getFileModel() == null) { - continue; + var allResults = results(result).toList(); + try (TaskTreeExecutor executor = createExecutor()) { + allResults.forEach(r -> executor.execute(() -> { + try { + derive(r.getSource(), r).build2(new LinkedHashSet<>()); + } catch (ModelBuilderException e) { + // gathered with problem collector + } catch (Exception t) { + r.getProblems() + .add(new DefaultModelProblem( + t.getMessage(), + Severity.FATAL, + ModelProblem.Version.BASE, + null, + -1, + -1, + null, + t)); } - executor.submit(() -> { - var pbs = r.getProblems(); - r.setProblems(List.of()); - derive(ModelSource.fromPath(r.getFileModel().getPomFile()), r) - .build2(importIds); - r.getProblems().forEach(this::add); - pbs.addAll(r.getProblems()); - r.setProblems(pbs); - }); - } - } finally { - close(executor); + })); } + allResults.stream().filter(r -> r != result).forEach(r -> r.getProblems() + .forEach(this::add)); if (hasErrors()) { throw newModelBuilderException(); } @@ -765,13 +801,14 @@ private ModelBuilderResult buildBuildPom(Collection importIds) throws Mo return result; } + Stream results(DefaultModelBuilderResult r) { + return Stream.concat(Stream.of(r), r.getChildren().stream().flatMap(this::results)); + } + @SuppressWarnings("checkstyle:MethodLength") private void loadFromRoot(Path root, Path top) { - ExecutorService executor = createExecutor(); - try { - loadFilePom(executor, top, root, Set.of(), new HashSet<>()); - } finally { - close(executor); + try (TaskTreeExecutor executor = createExecutor()) { + loadFilePom(executor, top, root, Set.of(), null); } if (result.getFileModel() == null && !Objects.equals(top, root)) { logger.warn( @@ -788,43 +825,23 @@ private void loadFromRoot(Path root, Path top) { } } - private void close(ExecutorService executor) { - boolean terminated = executor.isTerminated(); - if (!terminated) { - executor.shutdown(); - boolean interrupted = false; - while (!terminated) { - try { - terminated = executor.awaitTermination(1L, TimeUnit.DAYS); - } catch (InterruptedException e) { - if (!interrupted) { - executor.shutdownNow(); - interrupted = true; - } - } - } - if (interrupted) { - Thread.currentThread().interrupt(); - } - } - } - private void loadFilePom( - ExecutorService executor, Path top, Path pom, Set parents, Set buildParts) { + Executor executor, Path top, Path pom, Set parents, DefaultModelBuilderResult parent) { DefaultModelBuilderResult r; - boolean isBuildPart = buildParts.contains(pom); if (pom.equals(top)) { r = result; } else { r = new DefaultModelBuilderResult(); - if (isBuildPart) { - result.getChildren().add(r); + if (parent != null) { + parent.getChildren().add(r); } } try { Path pomDirectory = Files.isDirectory(pom) ? pom : pom.getParent(); - Model model = derive(ModelSource.fromPath(pom), r).readFileModel(); + ModelSource src = ModelSource.fromPath(pom); + Model model = derive(src, r).readFileModel(); r.setFileModel(model); + r.setSource(src); Model activated = activateFileModel(model); r.setActivatedFileModel(activated); List subprojects = activated.getSubprojects(); @@ -876,11 +893,12 @@ private void loadFilePom( continue; } - executor.submit(() -> loadFilePom(executor, top, subprojectFile, concat(parents, pom), buildParts)); - - if (pom.equals(top) && request.isRecursive()) { - buildParts.add(subprojectFile); - } + executor.execute(() -> loadFilePom( + executor, + top, + subprojectFile, + concat(parents, pom), + (parent != null || Objects.equals(pom, top)) && request.isRecursive() ? r : null)); } } catch (ModelBuilderException e) { // gathered with problem collector @@ -902,6 +920,7 @@ private ModelBuilderResult buildParentOrDependency(Collection importIds) // phase 1: read and validate raw model Model fileModel = readFileModel(); result.setFileModel(fileModel); + result.setSource(request.getSource()); Model activatedFileModel = activateFileModel(fileModel); result.setActivatedFileModel(activatedFileModel); @@ -923,13 +942,13 @@ private ModelBuilderResult build2(Collection importIds) throws ModelBuil // plugin management injection resultModel = pluginManagementInjector.injectManagement(resultModel, request, this); + // lifecycle bindings injection if (request.getRequestType() != ModelBuilderRequest.RequestType.DEPENDENCY) { - if (lifecycleBindingsInjector == null) { - throw new IllegalStateException("lifecycle bindings injector is missing"); + org.apache.maven.api.services.ModelTransformer lifecycleBindingsInjector = + request.getLifecycleBindingsInjector(); + if (lifecycleBindingsInjector != null) { + resultModel = lifecycleBindingsInjector.transform(resultModel, request, this); } - - // lifecycle bindings injection - resultModel = lifecycleBindingsInjector.injectLifecycleBindings(resultModel, request, this); } // dependency management import @@ -1358,6 +1377,7 @@ Model readFileModel() throws ModelBuilderException { Model doReadFileModel() throws ModelBuilderException { ModelBuilderRequest request = this.request; ModelSource modelSource = request.getSource(); + result.setSource(modelSource); Model model; setSource(modelSource.getLocation()); logger.debug("Reading file model from " + modelSource.getLocation()); @@ -1757,7 +1777,7 @@ private Model doLoadDependencyManagement( .source(importSource) .repositories(getRepositories()) .build(); - importResult = new DefaultModelBuilderSession(importRequest).build(importIds); + importResult = new DefaultModelBuilderSession(importRequest).buildParentOrDependency(importIds); } catch (ModelBuilderException e) { e.getResult().getProblems().forEach(this::add); return null; @@ -1879,11 +1899,6 @@ private static boolean isNotEmpty(String string) { return string != null && !string.isEmpty(); } - public ModelBuilderResult build(final ModelBuilderRequest request, final ModelBuilderResult result) - throws ModelBuilderException { - return new DefaultModelBuilderSession(request, (DefaultModelBuilderResult) result).build(new LinkedHashSet<>()); - } - public Model buildRawModel(ModelBuilderRequest request) throws ModelBuilderException { DefaultModelBuilderSession build = new DefaultModelBuilderSession(request); Model model = build.readRawModel(); diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilderResult.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilderResult.java index 35becbd2a721..4dfdd0aa4036 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilderResult.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilderResult.java @@ -31,12 +31,14 @@ 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; @@ -76,6 +78,14 @@ class DefaultModelBuilderResult implements ModelBuilderResult { } } + public ModelSource getSource() { + return source; + } + + public void setSource(ModelSource source) { + this.source = source; + } + @Override public Model getFileModel() { return fileModel; diff --git a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/RepositorySystemSupplier.java b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/RepositorySystemSupplier.java index ad4d1f5f5dbf..09eb857e8597 100644 --- a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/RepositorySystemSupplier.java +++ b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/RepositorySystemSupplier.java @@ -1054,7 +1054,6 @@ protected ModelBuilder createModelBuilder() { new DefaultPluginManagementInjector(), new DefaultDependencyManagementInjector(), new DefaultDependencyManagementImporter(), - (m, r, b) -> m, new DefaultPluginConfigurationExpander(), new ProfileActivationFilePathInterpolator(new DefaultPathTranslator(), new DefaultRootLocator()), new DefaultModelVersionParser(getVersionScheme()), diff --git a/maven-compat/src/test/java/org/apache/maven/project/TestProjectBuilder.java b/maven-compat/src/test/java/org/apache/maven/project/TestProjectBuilder.java index 826b1277f651..0fc0ba33cc09 100644 --- a/maven-compat/src/test/java/org/apache/maven/project/TestProjectBuilder.java +++ b/maven-compat/src/test/java/org/apache/maven/project/TestProjectBuilder.java @@ -26,12 +26,10 @@ 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,14 +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) { - super(modelBuilder, projectBuildingHelper, repositorySystem, repoSystem, dependencyResolver, rootLocator); + RootLocator rootLocator, + LifecycleBindingsInjector lifecycleBindingsInjector) { + super( + modelBuilder, + projectBuildingHelper, + repositorySystem, + repoSystem, + dependencyResolver, + rootLocator, + lifecycleBindingsInjector); } @Override @@ -55,7 +59,7 @@ public ProjectBuildingResult build(File pomFile, ProjectBuildingRequest configur throws ProjectBuildingException { ProjectBuildingResult result = super.build(pomFile, configuration); - result.getProject().setRemoteArtifactRepositories(Collections.emptyList()); + result.getProject().setRemoteArtifactRepositories(Collections.emptyList()); return result; } diff --git a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java index 7dfe11a5dddb..2ad05360cf3f 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java @@ -192,7 +192,6 @@ public List getActiveProfiles( pluginManagementInjector, dependencyManagementInjector, dependencyManagementImporter, - lifecycleBindingsInjector, pluginConfigurationExpander, profileActivationFilePathInterpolator, versionParser, @@ -207,6 +206,7 @@ public List getActiveProfiles( request.locationTracking(false); request.systemProperties(session.getSystemProperties()); request.userProperties(session.getUserProperties()); + request.lifecycleBindingsInjector(lifecycleBindingsInjector::injectLifecycleBindings); ModelBuilder.ModelBuilderSession mbSession = iSession.getData().get(SessionData.key(ModelBuilder.ModelBuilderSession.class)); if (mbSession == null) { diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index 969d800c4294..0b95863ab4c9 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -29,6 +29,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.AbstractMap; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -55,21 +56,23 @@ import org.apache.maven.api.model.Plugin; import org.apache.maven.api.model.Profile; import org.apache.maven.api.model.ReportPlugin; -import org.apache.maven.api.services.BuilderProblem; +import org.apache.maven.api.services.BuilderProblem.Severity; 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.ModelProblem; +import org.apache.maven.api.services.ModelProblem.Version; +import org.apache.maven.api.services.ModelProblemCollector; import org.apache.maven.api.services.ModelSource; +import org.apache.maven.api.services.ModelTransformer; import org.apache.maven.api.services.Source; +import org.apache.maven.api.services.model.LifecycleBindingsInjector; import org.apache.maven.artifact.Artifact; -import org.apache.maven.artifact.InvalidArtifactRTException; import org.apache.maven.artifact.InvalidRepositoryException; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.bridge.MavenRepositorySystem; import org.apache.maven.internal.impl.InternalSession; -import org.apache.maven.internal.impl.model.DefaultModelProblem; import org.apache.maven.model.building.FileModelSource; import org.apache.maven.model.building.ModelBuildingRequest; import org.apache.maven.model.building.ModelSource2; @@ -102,6 +105,7 @@ public class DefaultProjectBuilder implements ProjectBuilder { private final org.eclipse.aether.RepositorySystem repoSystem; private final ProjectDependenciesResolver dependencyResolver; private final RootLocator rootLocator; + private final LifecycleBindingsInjector lifecycleBindingsInjector; @SuppressWarnings("checkstyle:ParameterNumber") @Inject @@ -111,13 +115,15 @@ public DefaultProjectBuilder( MavenRepositorySystem repositorySystem, RepositorySystem repoSystem, ProjectDependenciesResolver dependencyResolver, - RootLocator rootLocator) { + RootLocator rootLocator, + LifecycleBindingsInjector lifecycleBindingsInjector) { this.modelBuilder = modelBuilder; this.projectBuildingHelper = projectBuildingHelper; this.repositorySystem = repositorySystem; this.repoSystem = repoSystem; this.dependencyResolver = dependencyResolver; this.rootLocator = rootLocator; + this.lifecycleBindingsInjector = lifecycleBindingsInjector; } // ---------------------------------------------------------------------- // MavenProjectBuilder Implementation @@ -308,7 +314,7 @@ class BuildSession implements AutoCloseable { private final ProjectBuildingRequest request; private final RepositorySystemSession session; private final ModelBuilder.ModelBuilderSession modelBuilderSession; - private final Map projectIndex = new ConcurrentHashMap<>(256); + private final Map projectIndex = new ConcurrentHashMap<>(256); BuildSession(ProjectBuildingRequest request) { this.request = request; @@ -336,15 +342,17 @@ ProjectBuildingResult build(Path pomFile, ModelSource modelSource) throws Projec project.setFile(pomFile != null ? pomFile.toFile() : null); ModelBuilderRequest.ModelBuilderRequestBuilder builder = getModelBuildingRequest(); + ModelBuilderRequest.RequestType type = pomFile != null + && this.request.isProcessPlugins() + && this.request.getValidationLevel() == ModelBuildingRequest.VALIDATION_LEVEL_STRICT + ? ModelBuilderRequest.RequestType.BUILD_POM + : ModelBuilderRequest.RequestType.PARENT_POM; + MavenProject theProject = project; ModelBuilderRequest request = builder.source(modelSource) - .requestType( - pomFile != null - && this.request.isProcessPlugins() - && this.request.getValidationLevel() - == ModelBuildingRequest.VALIDATION_LEVEL_STRICT - ? ModelBuilderRequest.RequestType.BUILD_POM - : ModelBuilderRequest.RequestType.DEPENDENCY) + .requestType(type) .locationTracking(true) + .lifecycleBindingsInjector( + (m, r, p) -> injectLifecycleBindings(m, r, p, theProject, this.request)) .build(); if (pomFile != null) { @@ -354,15 +362,6 @@ ProjectBuildingResult build(Path pomFile, ModelSource modelSource) throws Projec ModelBuilderResult result; try { result = modelBuilderSession.build(request); - - buildExtensionsAssembled( - result.getEffectiveModel(), - result.getProblems(), - request, - project, - projectBuildingHelper, - this.request); - } catch (ModelBuilderException e) { result = e.getResult(); if (result == null || result.getEffectiveModel() == null) { @@ -466,7 +465,7 @@ List doBuild(List pomFiles, boolean recursive) { ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader(); try { return pomFiles.stream() - .map(pomFile -> build(pomFile, true, recursive)) + .map(pomFile -> build(pomFile, recursive)) .flatMap(List::stream) .collect(Collectors.toList()); } finally { @@ -475,85 +474,54 @@ List doBuild(List pomFiles, boolean recursive) { } @SuppressWarnings("checkstyle:parameternumber") - private List build(File pomFile, boolean topLevel, boolean recursive) { - MavenProject project = new MavenProject(); - project.setFile(pomFile); - - project.setRootDirectory( - rootLocator.findRoot(pomFile.getParentFile().toPath())); - - ModelBuilderRequest modelBuildingRequest = getModelBuildingRequest() - .source(ModelSource.fromPath(pomFile.toPath())) - .requestType(ModelBuilderRequest.RequestType.BUILD_POM) - .locationTracking(true) - .recursive(recursive) - .build(); - + private List build(File pomFile, boolean recursive) { ModelBuilderResult result; try { + ModelTransformer injector = (m, r, p) -> { + MavenProject project = projectIndex.computeIfAbsent(m.getId(), f -> new MavenProject()); + return injectLifecycleBindings(m, r, p, project, request); + }; + ModelBuilderRequest modelBuildingRequest = getModelBuildingRequest() + .source(ModelSource.fromPath(pomFile.toPath())) + .requestType(ModelBuilderRequest.RequestType.BUILD_POM) + .locationTracking(true) + .recursive(recursive) + .lifecycleBindingsInjector(injector) + .build(); result = modelBuilderSession.build(modelBuildingRequest); - - buildExtensionsAssembled( - result.getEffectiveModel(), - result.getProblems(), - modelBuildingRequest, - project, - projectBuildingHelper, - request); - } catch (ModelBuilderException e) { result = e.getResult(); if (result == null || result.getEffectiveModel() == null) { return List.of(new DefaultProjectBuildingResult(e.getModelId(), pomFile, convert(e.getProblems()))); } - // validation error, continue project building and delay failing to help IDEs - // result.getProblems().addAll(e.getProblems()) ? } - projectIndex.put(pomFile, project); + List results = new ArrayList<>(); + Path rootDirectory = rootLocator.findRoot(pomFile.getParentFile().toPath()); + List allModels = results(result).toList(); + for (ModelBuilderResult r : allModels) { + File pom = r.getSource().getPath().toFile(); + MavenProject project = projectIndex.get(r.getEffectiveModel().getId()); + project.setRootDirectory(rootDirectory); + project.setFile(pom); + project.setExecutionRoot(pom.equals(pomFile)); + initProject(project, r); + project.setCollectedProjects(r.getChildren().stream() + .map(cr -> projectIndex.get(cr.getEffectiveModel().getId())) + .collect(Collectors.toList())); - try { - // 2nd pass of initialization: resolve and build parent if necessary - List problems = convert(result.getProblems()); - try { - initProject(project, result); - } catch (InvalidArtifactRTException iarte) { - problems.add(new org.apache.maven.model.building.DefaultModelProblem( - null, - org.apache.maven.model.building.ModelProblem.Severity.ERROR, - null, - new org.apache.maven.model.Model(result.getEffectiveModel()), - -1, - -1, - iarte)); - } - - List results = result.getChildren().stream() - .map(r -> build(r.getFileModel().getPomFile().toFile(), false, true)) - .flatMap(List::stream) - .collect(Collectors.toList()); - - project.setExecutionRoot(topLevel); - project.setCollectedProjects( - results.stream().map(ProjectBuildingResult::getProject).collect(Collectors.toList())); DependencyResolutionResult resolutionResult = null; if (request.isResolveDependencies()) { resolutionResult = resolveDependencies(project); } - - results.add(new DefaultProjectBuildingResult(project, problems, resolutionResult)); - - return results; - } catch (ModelBuilderException e) { - DefaultProjectBuildingResult eresult; - if (result.getEffectiveModel() == null) { - eresult = new DefaultProjectBuildingResult(e.getModelId(), pomFile, convert(e.getProblems())); - } else { - project.setModel(new org.apache.maven.model.Model(result.getEffectiveModel())); - eresult = new DefaultProjectBuildingResult(project, convert(e.getProblems()), null); - } - return Collections.singletonList(eresult); + results.add(new DefaultProjectBuildingResult(project, convert(result.getProblems()), resolutionResult)); } + return results; + } + + private Stream results(ModelBuilderResult result) { + return Stream.concat( + Stream.of(result), result.getChildren().stream().flatMap(this::results)); } private List convert(List problems) { @@ -928,12 +896,11 @@ public Set> entrySet() { } } - public void buildExtensionsAssembled( + private Model injectLifecycleBindings( Model model, - List problems, ModelBuilderRequest request, + ModelProblemCollector problems, MavenProject project, - ProjectBuildingHelper projectBuildingHelper, ProjectBuildingRequest projectBuildingRequest) { org.apache.maven.model.Model model3 = new org.apache.maven.model.Model(model); List remoteRepositories = projectBuildingRequest.getRemoteRepositories(); @@ -942,12 +909,7 @@ public void buildExtensionsAssembled( pluginRepositories = projectBuildingHelper.createArtifactRepositories( model3.getPluginRepositories(), pluginRepositories, projectBuildingRequest); } catch (Exception e) { - add( - problems, - BuilderProblem.Severity.ERROR, - ModelProblem.Version.BASE, - "Invalid plugin repository: " + e.getMessage(), - e); + problems.add(Severity.ERROR, Version.BASE, "Invalid plugin repository: " + e.getMessage(), e); } project.setPluginArtifactRepositories(pluginRepositories); @@ -959,14 +921,9 @@ public void buildExtensionsAssembled( project.setClassRealm(record.getRealm()); project.setExtensionDependencyFilter(record.getExtensionArtifactFilter()); } catch (PluginResolutionException | PluginManagerException | PluginVersionResolutionException e) { - add( - problems, - BuilderProblem.Severity.ERROR, - ModelProblem.Version.BASE, - "Unresolvable build extension: " + e.getMessage(), - e); - } + problems.add(Severity.ERROR, Version.BASE, "Unresolvable build extension: " + e.getMessage(), e); + } projectBuildingHelper.selectProjectRealm(project); } @@ -975,22 +932,10 @@ public void buildExtensionsAssembled( remoteRepositories = projectBuildingHelper.createArtifactRepositories( model3.getRepositories(), remoteRepositories, projectBuildingRequest); } catch (Exception e) { - add( - problems, - BuilderProblem.Severity.ERROR, - ModelProblem.Version.BASE, - "Invalid artifact repository: " + e.getMessage(), - e); + problems.add(Severity.ERROR, Version.BASE, "Invalid artifact repository: " + e.getMessage(), e); } project.setRemoteArtifactRepositories(remoteRepositories); - } - void add( - List problems, - BuilderProblem.Severity severity, - ModelProblem.Version version, - String message, - Exception e) { - problems.add(new DefaultModelProblem(null, severity, version, null, -1, -1, message, e)); + return lifecycleBindingsInjector.injectLifecycleBindings(model, request, problems); } } diff --git a/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java b/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java index 508fe0cf278f..ef4eede2846c 100644 --- a/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java +++ b/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java @@ -221,7 +221,7 @@ void testReadErroneousMavenProjectContainsReference() throws Exception { // 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(); diff --git a/maven-core/src/test/projects/project-builder/MNG-6723/.mvn/.gitkeep b/maven-core/src/test/projects/project-builder/MNG-6723/.mvn/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/maven-core/src/test/resources-project-builder/complete-model/w-parent/pom.xml b/maven-core/src/test/resources-project-builder/complete-model/w-parent/pom.xml index ae49ae2fb057..439c77eaf735 100644 --- a/maven-core/src/test/resources-project-builder/complete-model/w-parent/pom.xml +++ b/maven-core/src/test/resources-project-builder/complete-model/w-parent/pom.xml @@ -28,4 +28,7 @@ under the License. pom + + sub + diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemSupplier.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemSupplier.java index 9b480f91519f..754bbc236872 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemSupplier.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemSupplier.java @@ -1055,7 +1055,6 @@ protected ModelBuilder createModelBuilder() { new DefaultPluginManagementInjector(), new DefaultDependencyManagementInjector(), new DefaultDependencyManagementImporter(), - (m, r, b) -> m, new DefaultPluginConfigurationExpander(), new ProfileActivationFilePathInterpolator(new DefaultPathTranslator(), new DefaultRootLocator()), new DefaultModelVersionParser(getVersionScheme()), From 0ab67292ab84ac9b3d6bd8596ebff72d46dd1ce3 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 25 Sep 2024 16:04:04 +0200 Subject: [PATCH 40/63] Fix dots on javadoc --- .../main/java/org/apache/maven/api/Artifact.java | 13 +++++++------ .../org/apache/maven/api/ArtifactCoordinates.java | 6 +++--- .../main/java/org/apache/maven/api/Dependency.java | 5 +++-- .../apache/maven/api/DependencyCoordinates.java | 7 ++++--- .../main/java/org/apache/maven/api/PathType.java | 2 +- .../main/java/org/apache/maven/api/plugin/Log.java | 8 ++++---- .../api/services/DependencyResolverResult.java | 2 +- .../internal/impl/AetherDependencyWrapper.java | 14 +++++++------- .../maven/internal/impl/PathModularization.java | 7 ++++--- 9 files changed, 34 insertions(+), 30 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Artifact.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Artifact.java index 0967ba92b2a8..7303e8e61c58 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Artifact.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Artifact.java @@ -39,7 +39,7 @@ @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 @@ default String key() { } /** - * {@return the group identifier of the artifact}. + * {@return the group identifier of the artifact} * * @see ArtifactCoordinates#getGroupId() */ @@ -66,7 +66,7 @@ default String key() { String getGroupId(); /** - * {@return the identifier of the artifact}. + * {@return the identifier of the artifact} * * @see ArtifactCoordinates#getArtifactId() */ @@ -74,7 +74,8 @@ default String key() { 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 @@ default String key() { 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 @@ default String key() { 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) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/ArtifactCoordinates.java b/api/maven-api-core/src/main/java/org/apache/maven/api/ArtifactCoordinates.java index de9796796413..dab32ee48c35 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/ArtifactCoordinates.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/ArtifactCoordinates.java @@ -33,13 +33,13 @@ @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 diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java index 5436a3e14391..50fbb6035327 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java @@ -36,7 +36,8 @@ @Immutable public interface Dependency extends Artifact { /** - * {@return the type of the dependency}. A dependency can be a JAR file, + * {@return the type of the dependency} + * A dependency can be a JAR file, * a modular-JAR if it is intended to be placed on the module-path, * a JAR containing test classes, etc. * @@ -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() diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyCoordinates.java b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyCoordinates.java index 13999eaedf73..a7330bcbb7e8 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyCoordinates.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyCoordinates.java @@ -39,7 +39,8 @@ @Immutable public interface DependencyCoordinates extends ArtifactCoordinates { /** - * {@return the type of the dependency}. A dependency can be a JAR file, + * {@return the type of the dependency} + * A dependency can be a JAR file, * a modular-JAR if it is intended to be placed on the module-path, * a JAR containing test classes, etc. */ @@ -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 getExclusions(); diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java b/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java index 4672f6b49f32..368d14443cba 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java @@ -123,7 +123,7 @@ public String[] option(Iterable paths) { 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 diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/Log.java b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/Log.java index 16a55a805527..f2968295e456 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/Log.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/Log.java @@ -37,7 +37,7 @@ @Provider public interface Log { /** - * {@return true if the debug error level is enabled}. + * {@return true if the debug error level is enabled} */ boolean isDebugEnabled(); @@ -70,7 +70,7 @@ public interface Log { void debug(Supplier content, Throwable error); /** - * {@return true if the info error level is enabled}. + * {@return true if the info error level is enabled} */ boolean isInfoEnabled(); @@ -103,7 +103,7 @@ public interface Log { void info(Supplier content, Throwable error); /** - * {@return true if the warn error level is enabled}. + * {@return true if the warn error level is enabled} */ boolean isWarnEnabled(); @@ -136,7 +136,7 @@ public interface Log { void warn(Supplier content, Throwable error); /** - * {@return true if the error error level is enabled}. + * {@return true if the error error level is enabled} */ boolean isErrorEnabled(); diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverResult.java index c8f125eb7e6f..e2ab1c2a9e4e 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverResult.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverResult.java @@ -97,7 +97,7 @@ public interface DependencyResolverResult { Map> 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 diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/AetherDependencyWrapper.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/AetherDependencyWrapper.java index e6d130de42f9..39bf82517431 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/AetherDependencyWrapper.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/AetherDependencyWrapper.java @@ -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 @@ public String getGroupId() { } /** - * {@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 @@ public String getArtifactId() { } /** - * {@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 @@ public String getExtension() { } /** - * {@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 @@ public Type getType() { } /** - * {@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 @@ public String getClassifier() { } /** - * {@return the scope (compile, test, …) of this dependency}. + * {@return the scope (compile, test, …) of this dependency} */ @Nonnull public DependencyScope getScope() { @@ -117,7 +117,7 @@ public DependencyScope getScope() { } /** - * {@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 diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/PathModularization.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/PathModularization.java index d8e9e941ddcf..1b3cf9b0071b 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/PathModularization.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/PathModularization.java @@ -222,7 +222,8 @@ private 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 @@ public void addIfFilenameBasedAutomodules(Collection automodulesDetected } /** - * {@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 From 3d6ab6fedb8676b497b001edb4911907705b315f Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 25 Sep 2024 18:06:46 +0200 Subject: [PATCH 41/63] wip --- .../api/services/ModelBuilderException.java | 11 +- .../api/services/ModelBuilderResult.java | 44 ++-- .../impl/model/DefaultModelBuilder.java | 223 ++++++------------ .../impl/model/DefaultModelBuilderResult.java | 100 +++----- .../model/DefaultModelProblemCollector.java | 22 +- .../maven/internal/impl/model/ModelData.java | 1 + .../maven/project/DefaultProjectBuilder.java | 60 ++--- 7 files changed, 171 insertions(+), 290 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderException.java index 0448904665c2..13d5176609ed 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderException.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderException.java @@ -60,10 +60,17 @@ public ModelBuilderResult getResult() { * @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); } /** diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderResult.java index 722161a82c3c..478155016c20 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderResult.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderResult.java @@ -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 @@ public interface ModelBuilderResult { /** - * Gets the sequence of model identifiers that denote the lineage of models from which the effective model was - * constructed. Model identifiers have the form {@code ::}. The first identifier from - * the list denotes the model on which the model builder was originally invoked. The last identifier will always be - * an empty string that by definition denotes 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 getModelIds(); + ModelSource getSource(); /** * Gets the file model. @@ -70,36 +66,28 @@ public interface ModelBuilderResult { Model getRawModel(); /** - * Gets the assembled model with inheritance, interpolation and profile injection. + * Gets the effective model of the parent POM. * - * @return The assembled model, never {@code null}. + * @return the effective model of the parent POM, never {@code null} */ @Nonnull - Model getEffectiveModel(); + Model getParentModel(); /** - * 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()}. As a special case, an empty string - * can be used as the identifier for the super POM. + * Gets the assembled model with inheritance, interpolation and profile injection. * - * @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 assembled model, never {@code null}. */ @Nonnull - Optional getRawModel(@Nonnull String modelId); + Model getEffectiveModel(); /** - * 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()}. As a special case, an empty string can be used as the - * identifier for the super POM. + * Gets the profiles that were active during model building. * - * @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. + * @return The active profiles of the model or an empty list if the model has no active profiles. */ @Nonnull - List getActivePomProfiles(@Nonnull String modelId); + List getActivePomProfiles(); /** * Gets the external profiles that were active during model building. External profiles are those that were @@ -118,12 +106,14 @@ public interface ModelBuilderResult { @Nonnull List getProblems(); + /** + * Gets the children of this result. + * + * @return the children of this result, can be empty but never {@code null} + */ @Nonnull List getChildren(); - @Nonnull - ModelSource getSource(); - /** * Creates a human-readable representation of these errors. */ diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 16a5554ae63a..813fdbc6ede1 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -597,17 +597,17 @@ public void add( } 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; - } +// ModelBuilderResult result = this.result; +// if (result.getEffectiveModel() == null && result.getParentModel() == null) { +// DefaultModelBuilderResult tmp = new DefaultModelBuilderResult(); +// tmp.setParentModel(result.getParentModel()); +// tmp.setEffectiveModel(result.getEffectiveModel()); +// tmp.setProblems(getProblems()); +// tmp.setActiveExternalProfiles(result.getActiveExternalProfiles()); +// String id = getRootModelId(); +// tmp.setRawModel(id, getRootModel()); +// result = tmp; +// } return new ModelBuilderException(result); } @@ -648,8 +648,12 @@ public void mergeRepositories(List toAdd, boolean replace) { // // Transform raw model to build pom // - Model transformRawToBuildPom(Model model) { + Model transformFileToRaw(Model model) { Model.Builder builder = Model.newBuilder(model); + String namespace = model.getNamespaceUri(); + if (model.getModelVersion() == null && namespace != null && namespace.startsWith(NAMESPACE_PREFIX)) { + builder.modelVersion(namespace.substring(NAMESPACE_PREFIX.length())); + } builder = handleParent(model, builder); builder = handleReactorDependencies(model, builder); builder = handleCiFriendlyVersion(model, builder); @@ -773,24 +777,18 @@ private ModelBuilderResult buildBuildPom() throws ModelBuilderException { var allResults = results(result).toList(); try (TaskTreeExecutor executor = createExecutor()) { - allResults.forEach(r -> executor.execute(() -> { - try { - derive(r.getSource(), r).build2(new LinkedHashSet<>()); - } catch (ModelBuilderException e) { - // gathered with problem collector - } catch (Exception t) { - r.getProblems() - .add(new DefaultModelProblem( - t.getMessage(), - Severity.FATAL, - ModelProblem.Version.BASE, - null, - -1, - -1, - null, - t)); - } - })); + for (DefaultModelBuilderResult r : allResults) { + executor.execute(() -> { + DefaultModelBuilderSession mbs = derive(r.getSource(), r); + try { + mbs.build2(new LinkedHashSet<>()); + } catch (ModelBuilderException e) { + // gathered with problem collector + } catch (Exception t) { + mbs.add(Severity.FATAL, ModelProblem.Version.BASE, t.getMessage(), t); + } + }); + } } allResults.stream().filter(r -> r != result).forEach(r -> r.getProblems() .forEach(this::add)); @@ -986,17 +984,16 @@ private ModelBuilderResult build2(Collection importIds) throws ModelBuil return result; } - ModelData readParent(Model childModel, ModelSource childSource) throws ModelBuilderException { - ModelData parentData = null; + Model readParent(Model childModel, ModelSource childSource) throws ModelBuilderException { + Model parentModel = null; Parent parent = childModel.getParent(); if (parent != null) { - parentData = readParentLocally(childModel, childSource); - if (parentData == null) { - parentData = resolveAndReadParentExternally(childModel); + parentModel = readParentLocally(childModel, childSource); + if (parentModel == null) { + parentModel = resolveAndReadParentExternally(childModel); } - Model parentModel = parentData.model(); if (!"pom".equals(parentModel.getPackaging())) { add( Severity.ERROR, @@ -1007,15 +1004,16 @@ ModelData readParent(Model childModel, ModelSource childSource) throws ModelBuil } } - return parentData; + return parentModel; } - private ModelData readParentLocally(Model childModel, ModelSource childSource) throws ModelBuilderException { + private Model readParentLocally(Model childModel, ModelSource childSource) throws ModelBuilderException { ModelSource candidateSource = getParentPomFile(childModel, childSource); if (candidateSource == null) { return null; } - final Model candidateModel = derive(candidateSource).readRawModel(); + + Model candidateModel = derive(candidateSource).readParentModel(); // // TODO jvz Why isn't all this checking the job of the duty of the workspace resolver, we know that we @@ -1088,10 +1086,10 @@ private ModelData readParentLocally(Model childModel, ModelSource childSource) t // resolver. // - return new ModelData(candidateSource, candidateModel); + return candidateModel; } - ModelData resolveAndReadParentExternally(Model childModel) throws ModelBuilderException { + Model resolveAndReadParentExternally(Model childModel) throws ModelBuilderException { ModelBuilderRequest request = this.request; setSource(childModel); @@ -1166,7 +1164,7 @@ ModelData resolveAndReadParentExternally(Model childModel) throws ModelBuilderEx // MNG-2199: What else to check here ? } - return new ModelData(modelSource, parentModel); + return parentModel; } Model activateFileModel(Model inputModel) throws ModelBuilderException { @@ -1219,22 +1217,12 @@ private Model readEffectiveModel() throws ModelBuilderException { if (hasFatalErrors()) { throw newModelBuilderException(); } + result.setRawModel(inputModel); inputModel = activateFileModel(inputModel); setRootModel(inputModel); - ModelData resultData = new ModelData(request.getSource(), inputModel); - String superModelVersion = - inputModel.getModelVersion() != null ? inputModel.getModelVersion() : MODEL_VERSION_4_0_0; - if (!VALID_MODEL_VERSIONS.contains(superModelVersion)) { - // Maven 3.x is always using 4.0.0 version to load the supermodel, so - // do the same when loading a dependency. The model validator will also - // check that field later. - superModelVersion = MODEL_VERSION_4_0_0; - } - ModelData superData = new ModelData(null, getSuperModel(superModelVersion)); - // profile activation DefaultProfileActivationContext profileActivationContext = getProfileActivationContext(request, inputModel); @@ -1249,99 +1237,40 @@ private Model readEffectiveModel() throws ModelBuilderException { profileActivationContext.setUserProperties(profileProps); } - Collection parentIds = new LinkedHashSet<>(); - - List lineage = new ArrayList<>(); - - for (ModelData currentData = resultData; ; ) { - String modelId = currentData.id(); - result.addModelId(modelId); - - Model model = currentData.model(); - result.setRawModel(modelId, model); - setSource(model); - - // model normalization - model = modelNormalizer.mergeDuplicates(model, request, this); - - // profile activation - profileActivationContext.setProjectProperties(model.getProperties()); - - List interpolatedProfiles = - interpolateActivations(model.getProfiles(), profileActivationContext, this); - - // profile injection - List activePomProfiles = - profileSelector.getActiveProfiles(interpolatedProfiles, profileActivationContext, this); - result.setActivePomProfiles(modelId, activePomProfiles); - model = profileInjector.injectProfiles(model, activePomProfiles, request, this); - if (currentData == resultData) { - model = profileInjector.injectProfiles(model, activeExternalProfiles, request, this); - } - - lineage.add(model); - - if (currentData == superData) { - break; - } - - // add repositories specified by the current model so that we can resolve the parent - if (!model.getRepositories().isEmpty()) { - List oldRepos = - getRepositories().stream().map(Object::toString).toList(); - mergeRepositories(model.getRepositories(), false); - List newRepos = - getRepositories().stream().map(Object::toString).toList(); - if (!Objects.equals(oldRepos, newRepos)) { - logger.debug("Merging repositories from " + model.getId() + "\n" - + newRepos.stream().map(s -> " " + s).collect(Collectors.joining("\n"))); - } - } - - // we pass a cloned model, so that resolving the parent version does not affect the returned model - ModelData parentData = readParent(model, currentData.source()); - - if (parentData == null) { - currentData = superData; - } else if (!parentIds.add(parentData.id())) { - StringBuilder message = new StringBuilder("The parents form a cycle: "); - for (String parentId : parentIds) { - message.append(parentId).append(" -> "); - } - message.append(parentData.id()); - - add(Severity.FATAL, ModelProblem.Version.BASE, message.toString()); - - throw newModelBuilderException(); - } else { - currentData = parentData; + Model parentModel = readParent(inputModel, request.getSource()); + if (parentModel == null) { + String superModelVersion = + inputModel.getModelVersion() != null ? inputModel.getModelVersion() : MODEL_VERSION_4_0_0; + if (!VALID_MODEL_VERSIONS.contains(superModelVersion)) { + // Maven 3.x is always using 4.0.0 version to load the supermodel, so + // do the same when loading a dependency. The model validator will also + // check that field later. + superModelVersion = MODEL_VERSION_4_0_0; } + parentModel = getSuperModel(superModelVersion); + } else { + result.setParentModel(parentModel); } - Model tmpModel = lineage.get(0); - - // inject interpolated activations - List interpolated = interpolateActivations(tmpModel.getProfiles(), profileActivationContext, this); - if (interpolated != tmpModel.getProfiles()) { - tmpModel = tmpModel.withProfiles(interpolated); - } - - // inject external profile into current model - tmpModel = profileInjector.injectProfiles(tmpModel, activeExternalProfiles, request, this); - - lineage.set(0, tmpModel); + Model model = inheritanceAssembler.assembleModelInheritance(inputModel, parentModel, request, this); - checkPluginVersions(lineage, request, this); + // model normalization + model = modelNormalizer.mergeDuplicates(model, request, this); - // inheritance assembly - Model resultModel = assembleInheritance(lineage, request, this); + // profile activation + profileActivationContext.setProjectProperties(model.getProperties()); - // consider caching inherited model + List interpolatedProfiles = + interpolateActivations(model.getProfiles(), profileActivationContext, this); - setSource(resultModel); - setRootModel(resultModel); + // profile injection + List activePomProfiles = + profileSelector.getActiveProfiles(interpolatedProfiles, profileActivationContext, this); + result.setActivePomProfiles(activePomProfiles); + model = profileInjector.injectProfiles(model, activePomProfiles, request, this); - // model interpolation + // model interpolation + Model resultModel = model; resultModel = interpolateModel(resultModel, request, this); // url normalization @@ -1551,20 +1480,16 @@ Model readRawModel() throws ModelBuilderException { private Model doReadRawModel() throws ModelBuilderException { ModelBuilderRequest request = this.request; Model rawModel = readFileModel(); + if (!MODEL_VERSION_4_0_0.equals(rawModel.getModelVersion()) && request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { try { - rawModel = transformRawToBuildPom(rawModel); + rawModel = transformFileToRaw(rawModel); } catch (ModelTransformerException e) { - add(Severity.FATAL, ModelProblem.Version.V40, null, e); + add(Severity.FATAL, ModelProblem.Version.V41, null, e); } } - String namespace = rawModel.getNamespaceUri(); - if (rawModel.getModelVersion() == null && namespace != null && namespace.startsWith(NAMESPACE_PREFIX)) { - rawModel = rawModel.withModelVersion(namespace.substring(NAMESPACE_PREFIX.length())); - } - for (var transformer : transformers) { rawModel = transformer.transformRawModel(rawModel); } @@ -1591,7 +1516,7 @@ Model readParentModel() { private Model doReadParentModel() { Model raw = readRawModel(); - ModelData parentData; + Model parentData; if (raw.getParent() != null) { parentData = resolveAndReadParentExternally(raw); } else { @@ -1602,10 +1527,10 @@ private Model doReadParentModel() { // check that field later. superModelVersion = MODEL_VERSION_4_0_0; } - parentData = new ModelData(null, getSuperModel(superModelVersion)); + parentData = getSuperModel(superModelVersion); } - Model parent = inheritanceAssembler.assembleModelInheritance(raw, parentData.model(), request, this); + Model parent = inheritanceAssembler.assembleModelInheritance(raw, parentData, request, this); return parent.withParent(null); } @@ -1924,7 +1849,7 @@ static String getGroupId(Model model) { return groupId; } - private String getVersion(Model model) { + static String getVersion(Model model) { String version = model.getVersion(); if (version == null && model.getParent() != null) { version = model.getParent().getVersion(); diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilderResult.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilderResult.java index 4dfdd0aa4036..6cf00ad70202 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilderResult.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilderResult.java @@ -19,11 +19,7 @@ package org.apache.maven.internal.impl.model; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -41,25 +37,17 @@ class DefaultModelBuilderResult implements ModelBuilderResult { private ModelSource source; private Model fileModel; private Model activatedFileModel; - + private Model rawModel; + private Model parentModel; private Model effectiveModel; - - private List modelIds; - - private Map rawModels; - - private Map> activePomProfiles; - + private List activePomProfiles; private List activeExternalProfiles; - private List problems; private final List children = new ArrayList<>(); DefaultModelBuilderResult() { - modelIds = new ArrayList<>(); - rawModels = new HashMap<>(); - activePomProfiles = new HashMap<>(); + activePomProfiles = new ArrayList<>(); activeExternalProfiles = new ArrayList<>(); problems = new ArrayList<>(); } @@ -67,15 +55,12 @@ class DefaultModelBuilderResult implements ModelBuilderResult { DefaultModelBuilderResult(ModelBuilderResult result) { this(); this.activeExternalProfiles.addAll(result.getActiveExternalProfiles()); + this.activePomProfiles.addAll(result.getActivePomProfiles()); this.effectiveModel = result.getEffectiveModel(); + this.parentModel = result.getParentModel(); this.fileModel = result.getFileModel(); + this.rawModel = result.getRawModel(); this.problems.addAll(result.getProblems()); - - 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() { @@ -100,68 +85,48 @@ public Model getActivatedFileModel() { return activatedFileModel; } - public DefaultModelBuilderResult setActivatedFileModel(Model activatedFileModel) { + public void setActivatedFileModel(Model activatedFileModel) { this.activatedFileModel = activatedFileModel; - return this; } @Override - public Model getEffectiveModel() { - return effectiveModel; + public Model getRawModel() { + return rawModel; } - public DefaultModelBuilderResult setEffectiveModel(Model model) { - this.effectiveModel = model; - return this; + public void setRawModel(Model rawModel) { + this.rawModel = rawModel; } @Override - public List getModelIds() { - return modelIds; + public Model getParentModel() { + return parentModel; } - 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)); + public void setParentModel(Model parentModel) { + this.parentModel = parentModel; } @Override - public Optional getRawModel(String modelId) { - return Optional.ofNullable(rawModels.get(modelId)); + public Model getEffectiveModel() { + return effectiveModel; } - 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); - + public DefaultModelBuilderResult setEffectiveModel(Model model) { + this.effectiveModel = model; return this; } @Override - public List getActivePomProfiles(String modelId) { - List profiles = activePomProfiles.get(modelId); - return profiles != null ? profiles : List.of(); + public List getActivePomProfiles() { + return activePomProfiles; } - public DefaultModelBuilderResult setActivePomProfiles(String modelId, List activeProfiles) { - // Intentionally notNull because Super POM may not contain a modelId - Objects.requireNonNull(modelId, "modelId cannot be null"); - + public DefaultModelBuilderResult setActivePomProfiles(List activeProfiles) { if (activeProfiles != null) { - this.activePomProfiles.put(modelId, new ArrayList<>(activeProfiles)); + this.activePomProfiles = new ArrayList<>(activeProfiles); } else { - this.activePomProfiles.remove(modelId); + this.activePomProfiles.clear(); } return this; @@ -203,8 +168,17 @@ public List getChildren() { } 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( @@ -234,6 +208,6 @@ public String toString() { } return sb.toString(); } - return null; + return modelId; } } diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelProblemCollector.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelProblemCollector.java index 23f26f3c2395..8d12032051e3 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelProblemCollector.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelProblemCollector.java @@ -182,17 +182,17 @@ public void add( } 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; - } + // 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); } } diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/ModelData.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/ModelData.java index ffa8c10a93ec..ef0bf75f3465 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/ModelData.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/ModelData.java @@ -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() : ""; } diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index 0b95863ab4c9..cbba96df7b0e 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -563,16 +563,16 @@ private void initProject(MavenProject project, ModelBuilderResult result) { project.addTestCompileSourceRoot(build.getTestSourceDirectory()); } - project.setActiveProfiles(Stream.concat( - result.getActivePomProfiles(result.getModelIds().get(0)).stream(), - result.getActiveExternalProfiles().stream()) - .map(org.apache.maven.model.Profile::new) - .toList()); + project.setActiveProfiles( + Stream.concat(result.getActivePomProfiles().stream(), result.getActiveExternalProfiles().stream()) + .map(org.apache.maven.model.Profile::new) + .toList()); - project.setInjectedProfileIds("external", getProfileIds(result.getActiveExternalProfiles())); - for (String modelId : result.getModelIds()) { - project.setInjectedProfileIds(modelId, getProfileIds(result.getActivePomProfiles(modelId))); - } + // project.setInjectedProfileIds("external", getProfileIds(result.getActiveExternalProfiles())); + // for (String modelId : result.getModelIds()) { + // project.setInjectedProfileIds(modelId, + // getProfileIds(result.getActivePomProfiles(modelId))); + // } // // All the parts that were taken out of MavenProject for Maven 4.0.0 @@ -703,23 +703,16 @@ private void initProject(MavenProject project, ModelBuilderResult result) { } private void initParent(MavenProject project, ModelBuilderResult result) { - Model parentModel = result.getModelIds().size() > 1 - && !result.getModelIds().get(1).isEmpty() - ? result.getRawModel(result.getModelIds().get(1)).orElse(null) - : null; + Model parentModel = result.getParentModel(); if (parentModel != null) { - final String parentGroupId = inheritedGroupId(result, 1); - final String parentVersion = inheritedVersion(result, 1); + final String parentGroupId = getGroupId(parentModel); + final String parentVersion = getVersion(parentModel); project.setParentArtifact(repositorySystem.createProjectArtifact( parentGroupId, parentModel.getArtifactId(), parentVersion)); - // org.apache.maven.its.mng4834:parent:0.1 - String parentModelId = result.getModelIds().get(1); - Path parentPomFile = - result.getRawModel(parentModelId).map(Model::getPomFile).orElse(null); - MavenProject parent = parentPomFile != null ? projectIndex.get(parentPomFile.toFile()) : null; + MavenProject parent = projectIndex.get(parentModel.getId()); if (parent == null) { // // At this point the DefaultModelBuildingListener has fired and it populates the @@ -727,6 +720,7 @@ private void initParent(MavenProject project, ModelBuilderResult result) { // defined repositories. // request.setRemoteRepositories(project.getRemoteArtifactRepositories()); + Path parentPomFile = parentModel.getPomFile(); if (parentPomFile != null) { project.setParentFile(parentPomFile.toFile()); try { @@ -840,29 +834,19 @@ private static ModelSource createStubModelSource(Artifact artifact) { return new StubModelSource(xml, artifact); } - private static String inheritedGroupId(final ModelBuilderResult result, final int modelIndex) { - String groupId = null; - final String modelId = result.getModelIds().get(modelIndex); - - if (!modelId.isEmpty()) { - final Model model = result.getRawModel(modelId).orElseThrow(); - groupId = model.getGroupId() != null ? model.getGroupId() : inheritedGroupId(result, modelIndex + 1); + static String getGroupId(Model model) { + String groupId = model.getGroupId(); + if (groupId == null && model.getParent() != null) { + groupId = model.getParent().getGroupId(); } - return groupId; } - private static String inheritedVersion(final ModelBuilderResult result, final int modelIndex) { - String version = null; - final String modelId = result.getModelIds().get(modelIndex); - - if (!modelId.isEmpty()) { - version = result.getRawModel(modelId).map(Model::getVersion).orElse(null); - if (version == null) { - version = inheritedVersion(result, modelIndex + 1); - } + static String getVersion(Model model) { + String version = model.getVersion(); + if (version == null && model.getParent() != null) { + version = model.getParent().getVersion(); } - return version; } From 8e784fcb0182e0d4a646ed0635a1981ca96235c3 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 25 Sep 2024 23:20:34 +0200 Subject: [PATCH 42/63] tmp --- .../java/org/apache/maven/api/Constants.java | 2 +- .../impl/model/DefaultModelBuilder.java | 79 +++++++++++++------ .../maven/project/DefaultProjectBuilder.java | 3 +- src/site/markdown/configuration.md | 12 +-- 4 files changed, 66 insertions(+), 30 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Constants.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Constants.java index 3006de198ab8..00997bd44556 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Constants.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Constants.java @@ -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. diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 813fdbc6ede1..e3e001d50791 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -386,7 +386,7 @@ TaskTreeExecutor createExecutor() { private int getParallelism() { int parallelism = Runtime.getRuntime().availableProcessors() / 2 + 1; try { - String str = request.getUserProperties().get(Constants.MAVEN_PROJECT_BUILDER_PARALLELISM); + String str = request.getUserProperties().get(Constants.MAVEN_MODEL_BUILDER_PARALLELISM); if (str != null) { parallelism = Integer.parseInt(str); } @@ -597,17 +597,17 @@ public void add( } public ModelBuilderException newModelBuilderException() { -// ModelBuilderResult result = this.result; -// if (result.getEffectiveModel() == null && result.getParentModel() == null) { -// DefaultModelBuilderResult tmp = new DefaultModelBuilderResult(); -// tmp.setParentModel(result.getParentModel()); -// tmp.setEffectiveModel(result.getEffectiveModel()); -// tmp.setProblems(getProblems()); -// tmp.setActiveExternalProfiles(result.getActiveExternalProfiles()); -// String id = getRootModelId(); -// tmp.setRawModel(id, getRootModel()); -// result = tmp; -// } + // ModelBuilderResult result = this.result; + // if (result.getEffectiveModel() == null && result.getParentModel() == null) { + // DefaultModelBuilderResult tmp = new DefaultModelBuilderResult(); + // tmp.setParentModel(result.getParentModel()); + // tmp.setEffectiveModel(result.getEffectiveModel()); + // tmp.setProblems(getProblems()); + // tmp.setActiveExternalProfiles(result.getActiveExternalProfiles()); + // String id = getRootModelId(); + // tmp.setRawModel(id, getRootModel()); + // result = tmp; + // } return new ModelBuilderException(result); } @@ -1138,7 +1138,9 @@ Model resolveAndReadParentExternally(Model childModel) throws ModelBuilderExcept .source(modelSource) .build(); - Model parentModel = new DefaultModelBuilderSession(lenientRequest, this.result).readParentModel(); + DefaultModelBuilderResult r = new DefaultModelBuilderResult(); + Model parentModel = new DefaultModelBuilderSession(lenientRequest, r).readParentModel(); + this.result.getProblems().addAll(r.getProblems()); if (!parent.getVersion().equals(version)) { String rawChildModelVersion = childModel.getVersion(); @@ -1209,10 +1211,6 @@ Model activateFileModel(Model inputModel) throws ModelBuilderException { @SuppressWarnings("checkstyle:methodlength") private Model readEffectiveModel() throws ModelBuilderException { - - ModelBuilderRequest request = this.request; - DefaultModelBuilderResult result = this.result; - Model inputModel = readRawModel(); if (hasFatalErrors()) { throw newModelBuilderException(); @@ -1252,7 +1250,16 @@ private Model readEffectiveModel() throws ModelBuilderException { result.setParentModel(parentModel); } - Model model = inheritanceAssembler.assembleModelInheritance(inputModel, parentModel, request, this); + List parentInterpolatedProfiles = + interpolateActivations(parentModel.getProfiles(), profileActivationContext, this); + // profile injection + List parentActivePomProfiles = + profileSelector.getActiveProfiles(parentInterpolatedProfiles, profileActivationContext, this); + Model injectedParentModel = profileInjector + .injectProfiles(parentModel, parentActivePomProfiles, request, this) + .withProfiles(List.of()); + + Model model = inheritanceAssembler.assembleModelInheritance(inputModel, injectedParentModel, request, this); // model normalization model = modelNormalizer.mergeDuplicates(model, request, this); @@ -1269,7 +1276,7 @@ private Model readEffectiveModel() throws ModelBuilderException { result.setActivePomProfiles(activePomProfiles); model = profileInjector.injectProfiles(model, activePomProfiles, request, this); - // model interpolation + // model interpolation Model resultModel = model; resultModel = interpolateModel(resultModel, request, this); @@ -1304,7 +1311,6 @@ Model readFileModel() throws ModelBuilderException { @SuppressWarnings("checkstyle:methodlength") Model doReadFileModel() throws ModelBuilderException { - ModelBuilderRequest request = this.request; ModelSource modelSource = request.getSource(); result.setSource(modelSource); Model model; @@ -1518,7 +1524,7 @@ private Model doReadParentModel() { Model parentData; if (raw.getParent() != null) { - parentData = resolveAndReadParentExternally(raw); + parentData = readParent(raw, request.getSource()); } else { String superModelVersion = raw.getModelVersion() != null ? raw.getModelVersion() : "4.0.0"; if (!VALID_MODEL_VERSIONS.contains(superModelVersion)) { @@ -1530,7 +1536,36 @@ private Model doReadParentModel() { parentData = getSuperModel(superModelVersion); } - Model parent = inheritanceAssembler.assembleModelInheritance(raw, parentData, request, this); + Model parent = new DefaultInheritanceAssembler.InheritanceModelMerger() { + @Override + protected void mergeModel_Modules( + Model.Builder builder, + Model target, + Model source, + boolean sourceDominant, + Map context) {} + + @Override + protected void mergeModel_Subprojects( + Model.Builder builder, + Model target, + Model source, + boolean sourceDominant, + Map context) {} + + @Override + protected void mergeModel_Profiles( + Model.Builder builder, + Model target, + Model source, + boolean sourceDominant, + Map context) { + builder.profiles(Stream.concat(source.getProfiles().stream(), target.getProfiles().stream()) + .map(p -> p.withModules(null).withSubprojects(null)) + .toList()); + } + }.merge(raw, parentData, false, Map.of()); + return parent.withParent(null); } diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index cbba96df7b0e..26d3fa5476f6 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -506,7 +506,8 @@ private List build(File pomFile, boolean recursive) { project.setFile(pom); project.setExecutionRoot(pom.equals(pomFile)); initProject(project, r); - project.setCollectedProjects(r.getChildren().stream() + project.setCollectedProjects(results(r) + .filter(cr -> cr != r) .map(cr -> projectIndex.get(cr.getEffectiveModel().getId())) .collect(Collectors.toList())); diff --git a/src/site/markdown/configuration.md b/src/site/markdown/configuration.md index 4aae75769282..03f197d9004a 100644 --- a/src/site/markdown/configuration.md +++ b/src/site/markdown/configuration.md @@ -33,12 +33,12 @@ under the License. | 6. | `maven.installation.extensions` | `String` | Maven installation extensions. | `${maven.installation.conf}/extensions.xml` | 4.0.0 | User properties | | 7. | `maven.installation.settings` | `String` | Maven installation settings. | `${maven.installation.conf}/settings.xml` | 4.0.0 | User properties | | 8. | `maven.installation.toolchains` | `String` | Maven installation toolchains. | `${maven.installation.conf}/toolchains.xml` | 4.0.0 | User properties | -| 9. | `maven.plugin.validation` | `String` | Plugin validation level. | `inline` | 3.9.2 | User properties | -| 10. | `maven.plugin.validation.excludes` | `String` | Plugin validation exclusions. | - | 3.9.6 | User properties | -| 11. | `maven.project.conf` | `String` | Maven project configuration directory. | `${session.rootDirectory}/.mvn` | 4.0.0 | User properties | -| 12. | `maven.project.extensions` | `String` | Maven project extensions. | `${maven.project.conf}/extensions.xml` | 4.0.0 | User properties | -| 13. | `maven.project.settings` | `String` | Maven project settings. | `${maven.project.conf}/settings.xml` | 4.0.0 | User properties | -| 14. | `maven.projectBuilder.parallelism` | `Integer` | ProjectBuilder parallelism. | `cores/2 + 1` | 4.0.0 | User properties | +| 9. | `maven.modelBuilder.parallelism` | `Integer` | ProjectBuilder parallelism. | `cores/2 + 1` | 4.0.0 | User properties | +| 10. | `maven.plugin.validation` | `String` | Plugin validation level. | `inline` | 3.9.2 | User properties | +| 11. | `maven.plugin.validation.excludes` | `String` | Plugin validation exclusions. | - | 3.9.6 | User properties | +| 12. | `maven.project.conf` | `String` | Maven project configuration directory. | `${session.rootDirectory}/.mvn` | 4.0.0 | User properties | +| 13. | `maven.project.extensions` | `String` | Maven project extensions. | `${maven.project.conf}/extensions.xml` | 4.0.0 | User properties | +| 14. | `maven.project.settings` | `String` | Maven project settings. | `${maven.project.conf}/settings.xml` | 4.0.0 | User properties | | 15. | `maven.relocations.entries` | `String` | User controlled relocations. This property is a comma separated list of entries with the syntax GAV>GAV. The first GAV can contain \* for any elem (so \*:\*:\* would mean ALL, something you don't want). The second GAV is either fully specified, or also can contain \*, then it behaves as "ordinary relocation": the coordinate is preserved from relocated artifact. Finally, if right hand GAV is absent (line looks like GAV>), the left hand matching GAV is banned fully (from resolving).
Note: the > means project level, while >> means global (whole session level, so even plugins will get relocated artifacts) relocation.
For example,

maven.relocations.entries = org.foo:\*:\*>, \\
org.here:\*:\*>org.there:\*:\*, \\
javax.inject:javax.inject:1>>jakarta.inject:jakarta.inject:1.0.5
means: 3 entries, ban org.foo group (exactly, so org.foo.bar is allowed), relocate org.here to org.there and finally globally relocate (see >> above) javax.inject:javax.inject:1 to jakarta.inject:jakarta.inject:1.0.5. | - | 4.0.0 | User properties | | 16. | `maven.repo.central` | `String` | Maven central repository URL. The property will have the value of the MAVEN_REPO_CENTRAL environment variable if it is defined. | `https://repo.maven.apache.org/maven2` | 4.0.0 | User properties | | 17. | `maven.repo.local` | `String` | Maven local repository. | `${maven.user.conf}/repository` | 3.0.0 | User properties | From eb13d7144d0f0b07cdac86f441d24b68b54d65a9 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 26 Sep 2024 11:10:56 +0200 Subject: [PATCH 43/63] Fix --- .../model/DefaultInheritanceAssembler.java | 29 +++++---- .../impl/model/DefaultModelBuilder.java | 60 ++++++++++--------- 2 files changed, 48 insertions(+), 41 deletions(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultInheritanceAssembler.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultInheritanceAssembler.java index 43d75e184bee..5c4040aa4e53 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultInheritanceAssembler.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultInheritanceAssembler.java @@ -24,6 +24,7 @@ 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.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 @@ protected String extrapolateChildUrl(String parentUrl, boolean appendPath, Map context) {} - - @Override - protected void mergeModel_Subprojects( - Model.Builder builder, - Model target, - Model source, - boolean sourceDominant, - Map context) {} - - @Override - protected void mergeModel_Profiles( - Model.Builder builder, - Model target, - Model source, - boolean sourceDominant, - Map context) { - builder.profiles(Stream.concat(source.getProfiles().stream(), target.getProfiles().stream()) - .map(p -> p.withModules(null).withSubprojects(null)) - .toList()); - } - }.merge(raw, parentData, false, Map.of()); + Model parent = new DefaultInheritanceAssembler(new DefaultInheritanceAssembler.InheritanceModelMerger() { + @Override + protected void mergeModel_Modules( + Model.Builder builder, + Model target, + Model source, + boolean sourceDominant, + Map context) {} + + @Override + protected void mergeModel_Subprojects( + Model.Builder builder, + Model target, + Model source, + boolean sourceDominant, + Map context) {} + + @Override + protected void mergeModel_Profiles( + Model.Builder builder, + Model target, + Model source, + boolean sourceDominant, + Map context) { + builder.profiles(Stream.concat(source.getProfiles().stream(), target.getProfiles().stream()) + .map(p -> p.withModules(null).withSubprojects(null)) + .toList()); + } + }) + .assembleModelInheritance(raw, parentData, request, this); return parent.withParent(null); } From 71143740655c83616cbf7576ba8fdcce6c338f52 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 26 Sep 2024 11:57:57 +0200 Subject: [PATCH 44/63] Fix threading issues with the executor --- .../impl/model/DefaultModelBuilder.java | 52 ++----------------- .../internal/impl/util}/PhasingExecutor.java | 18 +++++-- .../impl/util}/PhasingExecutorTest.java | 10 ++-- .../concurrent/BuildPlanExecutor.java | 4 +- 4 files changed, 27 insertions(+), 57 deletions(-) rename {maven-core/src/main/java/org/apache/maven/lifecycle/internal/concurrent => maven-api-impl/src/main/java/org/apache/maven/internal/impl/util}/PhasingExecutor.java (69%) rename {maven-core/src/test/java/org/apache/maven/lifecycle/internal/concurrent => maven-api-impl/src/test/java/org/apache/maven/internal/impl/util}/PhasingExecutorTest.java (84%) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index c95eb6a86e77..2378ad90cbe1 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -41,9 +41,7 @@ import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.Phaser; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; import java.util.function.UnaryOperator; @@ -112,6 +110,7 @@ import org.apache.maven.api.spi.ModelParserException; import org.apache.maven.api.spi.ModelTransformer; import org.apache.maven.api.spi.ModelTransformerException; +import org.apache.maven.internal.impl.util.PhasingExecutor; import org.apache.maven.model.v4.MavenTransformer; import org.codehaus.plexus.interpolation.InterpolationException; import org.codehaus.plexus.interpolation.Interpolator; @@ -338,49 +337,8 @@ public String toString() { + cache + ']'; } - static class TaskTreeExecutor implements Executor, AutoCloseable { - private final ExecutorService executor; - private final Phaser phaser; - - TaskTreeExecutor(int nThreads) { - this.executor = Executors.newFixedThreadPool(nThreads); - this.phaser = new Phaser(); - } - - public void execute(Runnable task) { - phaser.register(); - executor.submit(new WrappedTask(task)); - } - - public void close() { - // Otherwise, register and then wait - phaser.register(); - phaser.arriveAndAwaitAdvance(); - phaser.arriveAndDeregister(); - // Close executor - executor.shutdownNow(); - } - - private class WrappedTask implements Runnable { - private final Runnable task; - - WrappedTask(Runnable task) { - this.task = task; - } - - @Override - public void run() { - try { - task.run(); - } finally { - phaser.arrive(); - } - } - } - } - - TaskTreeExecutor createExecutor() { - return new TaskTreeExecutor(getParallelism()); + PhasingExecutor createExecutor() { + return new PhasingExecutor(Executors.newFixedThreadPool(getParallelism())); } private int getParallelism() { @@ -776,7 +734,7 @@ private ModelBuilderResult buildBuildPom() throws ModelBuilderException { } var allResults = results(result).toList(); - try (TaskTreeExecutor executor = createExecutor()) { + try (PhasingExecutor executor = createExecutor()) { for (DefaultModelBuilderResult r : allResults) { executor.execute(() -> { DefaultModelBuilderSession mbs = derive(r.getSource(), r); @@ -805,7 +763,7 @@ Stream results(DefaultModelBuilderResult r) { @SuppressWarnings("checkstyle:MethodLength") private void loadFromRoot(Path root, Path top) { - try (TaskTreeExecutor executor = createExecutor()) { + try (PhasingExecutor executor = createExecutor()) { loadFilePom(executor, top, root, Set.of(), null); } if (result.getFileModel() == null && !Objects.equals(top, root)) { diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/concurrent/PhasingExecutor.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/util/PhasingExecutor.java similarity index 69% rename from maven-core/src/main/java/org/apache/maven/lifecycle/internal/concurrent/PhasingExecutor.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/util/PhasingExecutor.java index c27f5ce5b3f5..85d4ed597695 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/concurrent/PhasingExecutor.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/util/PhasingExecutor.java @@ -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 void execute(Runnable command) { }); } - public void await() { - phaser.arriveAndAwaitAdvance(); + public AutoCloseable phase() { + phaser.register(); + return () -> phaser.awaitAdvance(phaser.arriveAndDeregister()); } @Override public void close() { + phaser.arriveAndAwaitAdvance(); executor.shutdownNow(); } } diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/concurrent/PhasingExecutorTest.java b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/util/PhasingExecutorTest.java similarity index 84% rename from maven-core/src/test/java/org/apache/maven/lifecycle/internal/concurrent/PhasingExecutorTest.java rename to maven-api-impl/src/test/java/org/apache/maven/internal/impl/util/PhasingExecutorTest.java index 5c038cd072e2..623c24a3f45e 100644 --- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/concurrent/PhasingExecutorTest.java +++ b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/util/PhasingExecutorTest.java @@ -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) { diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/concurrent/BuildPlanExecutor.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/concurrent/BuildPlanExecutor.java index 6f77b927815b..d40e2e5ac47e 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/concurrent/BuildPlanExecutor.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/concurrent/BuildPlanExecutor.java @@ -53,6 +53,7 @@ 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 @@ following plugin(s) that have goals not built with Maven 4 to support concurrent } void execute() { - try { + try (var phase = executor.phase()) { plan(); executePlan(); - executor.await(); } catch (Exception e) { session.getResult().addException(e); } From a2a68fdf0523401c9df07e319f9ddde106fc2fb9 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 26 Sep 2024 12:27:43 +0200 Subject: [PATCH 45/63] Fix javadoc --- .../java/org/apache/maven/api/services/ModelProblem.java | 5 ++++- .../maven/internal/impl/model/DefaultModelProblem.java | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelProblem.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelProblem.java index eda871cb9cec..f0741828813e 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelProblem.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelProblem.java @@ -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 @@ enum Version { * 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(); } diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelProblem.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelProblem.java index f30bffddf22a..0787b0eec118 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelProblem.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelProblem.java @@ -107,7 +107,7 @@ public DefaultModelProblem( this.columnNumber = columnNumber; this.modelId = (modelId != null) ? modelId : ""; this.exception = exception; - this.version = version; + this.version = version != null ? version : Version.BASE; } @Override From 0c62b2d8764d9387e39eebcad26507b6cd90ea15 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 26 Sep 2024 12:37:34 +0200 Subject: [PATCH 46/63] Fix javadoc --- .../java/org/apache/maven/model/building/ModelProblem.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblem.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblem.java index 9c0cc109c5a1..a68704c2a3b5 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblem.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblem.java @@ -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 @@ enum Version { * 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(); From e8f217db91ec7ebe62b17f4aef17c10c59bce164 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 26 Sep 2024 13:29:08 +0200 Subject: [PATCH 47/63] Restore injected profiles ids --- .../org/apache/maven/project/DefaultProjectBuilder.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index 26d3fa5476f6..7d0ebf2bbc20 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -569,11 +569,9 @@ private void initProject(MavenProject project, ModelBuilderResult result) { .map(org.apache.maven.model.Profile::new) .toList()); - // project.setInjectedProfileIds("external", getProfileIds(result.getActiveExternalProfiles())); - // for (String modelId : result.getModelIds()) { - // project.setInjectedProfileIds(modelId, - // getProfileIds(result.getActivePomProfiles(modelId))); - // } + project.setInjectedProfileIds("external", getProfileIds(result.getActiveExternalProfiles())); + project.setInjectedProfileIds( + result.getEffectiveModel().getId(), getProfileIds(result.getActivePomProfiles())); // // All the parts that were taken out of MavenProject for Maven 4.0.0 From 03e48aa868f14929ff1c7b66aa38df62d3ee35cf Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 27 Sep 2024 07:08:50 +0200 Subject: [PATCH 48/63] Move modelVersion inferrence down to file model --- .../impl/model/DefaultModelBuilder.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 2378ad90cbe1..2781a1d9f2f3 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -109,7 +109,6 @@ import org.apache.maven.api.services.xml.XmlReaderRequest; import org.apache.maven.api.spi.ModelParserException; import org.apache.maven.api.spi.ModelTransformer; -import org.apache.maven.api.spi.ModelTransformerException; import org.apache.maven.internal.impl.util.PhasingExecutor; import org.apache.maven.model.v4.MavenTransformer; import org.codehaus.plexus.interpolation.InterpolationException; @@ -608,10 +607,6 @@ public void mergeRepositories(List toAdd, boolean replace) { // Model transformFileToRaw(Model model) { Model.Builder builder = Model.newBuilder(model); - String namespace = model.getNamespaceUri(); - if (model.getModelVersion() == null && namespace != null && namespace.startsWith(NAMESPACE_PREFIX)) { - builder.modelVersion(namespace.substring(NAMESPACE_PREFIX.length())); - } builder = handleParent(model, builder); builder = handleReactorDependencies(model, builder); builder = handleCiFriendlyVersion(model, builder); @@ -1356,6 +1351,14 @@ Model doReadFileModel() throws ModelBuilderException { throw newModelBuilderException(); } + if (model.getModelVersion() == null + && request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { + String namespace = model.getNamespaceUri(); + if (namespace != null && namespace.startsWith(NAMESPACE_PREFIX)) { + model = model.withModelVersion(namespace.substring(NAMESPACE_PREFIX.length())); + } + } + if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { model = model.withPomFile(modelSource.getPath()); @@ -1448,11 +1451,7 @@ private Model doReadRawModel() throws ModelBuilderException { if (!MODEL_VERSION_4_0_0.equals(rawModel.getModelVersion()) && request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { - try { - rawModel = transformFileToRaw(rawModel); - } catch (ModelTransformerException e) { - add(Severity.FATAL, ModelProblem.Version.V41, null, e); - } + rawModel = transformFileToRaw(rawModel); } for (var transformer : transformers) { From f5b2f3d4d179ab928ecbba7bb2d01f9f6d69cf51 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 27 Sep 2024 08:16:38 +0200 Subject: [PATCH 49/63] Fix UT which rely on file -> raw transformation for build poms --- .../src/test/resources/projects/tree/consumer/pom.xml | 2 +- .../src/test/resources/projects/tree/dep/pom.xml | 2 +- maven-core/src/test/resources/projects/tree/pom.xml | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/maven-core/src/test/resources/projects/tree/consumer/pom.xml b/maven-core/src/test/resources/projects/tree/consumer/pom.xml index c52711230737..71597091b672 100644 --- a/maven-core/src/test/resources/projects/tree/consumer/pom.xml +++ b/maven-core/src/test/resources/projects/tree/consumer/pom.xml @@ -1,4 +1,4 @@ - + org.apache.maven.ut diff --git a/maven-core/src/test/resources/projects/tree/dep/pom.xml b/maven-core/src/test/resources/projects/tree/dep/pom.xml index 09ccb88d1d6b..93a3f45ef601 100644 --- a/maven-core/src/test/resources/projects/tree/dep/pom.xml +++ b/maven-core/src/test/resources/projects/tree/dep/pom.xml @@ -1,4 +1,4 @@ - + org.apache.maven.ut diff --git a/maven-core/src/test/resources/projects/tree/pom.xml b/maven-core/src/test/resources/projects/tree/pom.xml index 8534ac440ea3..98996f3a09d0 100644 --- a/maven-core/src/test/resources/projects/tree/pom.xml +++ b/maven-core/src/test/resources/projects/tree/pom.xml @@ -1,10 +1,10 @@ - + org.apache.maven.ut parent 1.0-SNAPSHOT pom - - dep - consumer - + + dep + consumer + From 7443273aca6e23c293733f05a3f0e43a3e5393cb Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 27 Sep 2024 09:34:48 +0200 Subject: [PATCH 50/63] Restore repositories support --- .../internal/impl/model/DefaultModelBuilder.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 2781a1d9f2f3..8b50ed81087f 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -1188,6 +1188,19 @@ private Model readEffectiveModel() throws ModelBuilderException { profileActivationContext.setUserProperties(profileProps); } + // add repositories specified by the current model so that we can resolve the parent + if (!inputModel.getRepositories().isEmpty()) { + List oldRepos = + getRepositories().stream().map(Object::toString).toList(); + mergeRepositories(inputModel.getRepositories(), false); + List newRepos = + getRepositories().stream().map(Object::toString).toList(); + if (!Objects.equals(oldRepos, newRepos)) { + logger.debug("Merging repositories from " + inputModel.getId() + "\n" + + newRepos.stream().map(s -> " " + s).collect(Collectors.joining("\n"))); + } + } + Model parentModel = readParent(inputModel, request.getSource()); if (parentModel == null) { String superModelVersion = From dee4667123e78b1af23cf09ef7cf4146e3c9b196 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 27 Sep 2024 11:23:34 +0200 Subject: [PATCH 51/63] Refactor a bit --- .../api/services/ModelBuilderResult.java | 8 - .../impl/model/DefaultModelBuilder.java | 184 ++++++++---------- .../impl/model/DefaultModelBuilderResult.java | 89 ++++----- 3 files changed, 117 insertions(+), 164 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderResult.java index 478155016c20..bf98e933911b 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderResult.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderResult.java @@ -49,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. * diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 8b50ed81087f..329cec2aff86 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -64,7 +64,6 @@ import org.apache.maven.api.model.DependencyManagement; import org.apache.maven.api.model.Exclusion; import org.apache.maven.api.model.InputLocation; -import org.apache.maven.api.model.InputLocationTracker; import org.apache.maven.api.model.InputSource; import org.apache.maven.api.model.Model; import org.apache.maven.api.model.Parent; @@ -200,8 +199,16 @@ public ModelBuilderSession newSession() { return new ModelBuilderSession() { DefaultModelBuilderSession mainSession; + /** + * Builds a model based on the provided ModelBuilderRequest. + * + * @param request The request containing the parameters for building the model. + * @return The result of the model building process. + * @throws ModelBuilderException If an error occurs during model building. + */ @Override public ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilderException { + // Create or derive a session based on the request DefaultModelBuilderSession session; if (mainSession == null) { mainSession = new DefaultModelBuilderSession(request); @@ -209,11 +216,15 @@ public ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilder } else { session = mainSession.derive(request, new DefaultModelBuilderResult()); } + // Build the request if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { - return session.buildBuildPom(); + // build the build poms + session.buildBuildPom(); } else { - return session.buildParentOrDependency(new LinkedHashSet<>()); + // simply build the effective model + session.buildEffectiveModel(new LinkedHashSet<>()); } + return session.result(); } }; } @@ -287,15 +298,15 @@ private DefaultModelBuilderSession( } } - public DefaultModelBuilderSession derive(ModelSource source) { - return derive(source, result); + DefaultModelBuilderSession derive(ModelSource source) { + return derive(source, new DefaultModelBuilderResult(result)); } - public DefaultModelBuilderSession derive(ModelSource source, DefaultModelBuilderResult result) { + DefaultModelBuilderSession derive(ModelSource source, DefaultModelBuilderResult result) { return derive(ModelBuilderRequest.build(request, source), result); } - public DefaultModelBuilderSession derive(ModelBuilderRequest request, DefaultModelBuilderResult result) { + DefaultModelBuilderSession derive(ModelBuilderRequest request, DefaultModelBuilderResult result) { if (session != request.getSession()) { throw new IllegalArgumentException("Session mismatch"); } @@ -388,15 +399,12 @@ private boolean addEdge(Path from, Path p) { dag.addEdge(from.toString(), p.toString()); return true; } catch (Graph.CycleDetectedException e) { - add(new DefaultModelProblem( - "Cycle detected between models at " + from + " and " + p, + add( Severity.FATAL, + ModelProblem.Version.BASE, + "Cycle detected between models at " + from + " and " + p, null, - null, - 0, - 0, - null, - e)); + e); return false; } } @@ -484,17 +492,9 @@ public Model getRootModel() { return rootModel; } - public String getRootModelId() { - return ModelProblemUtils.toId(rootModel); - } - @Override public void add(ModelProblem problem) { - result.getProblems().add(problem); - } - - public void addAll(Collection problems) { - this.result.getProblems().addAll(problems); + result.addProblem(problem); } @Override @@ -704,37 +704,47 @@ String replaceCiFriendlyVersion(String version) { return version; } - private ModelBuilderResult buildBuildPom() throws ModelBuilderException { + private void buildBuildPom() throws ModelBuilderException { + // Retrieve and normalize the source path, ensuring it's non-null and in absolute form Path top = request.getSource().getPath(); if (top == null) { throw new IllegalStateException("Recursive build requested but source has no path"); } top = top.toAbsolutePath().normalize(); + // Obtain the root directory, resolving it if necessary Path rootDirectory; try { rootDirectory = session.getRootDirectory(); } catch (IllegalStateException e) { rootDirectory = session.getService(RootLocator.class).findRoot(top); } + + // Locate and normalize the root POM if it exists, fallback to top otherwise Path root = getModelProcessor().locateExistingPom(rootDirectory); if (root != null) { root = root.toAbsolutePath().normalize(); } else { root = top; } + + // Load all models starting from the root loadFromRoot(root, top); + + // Check for errors after loading models if (hasErrors()) { throw newModelBuilderException(); } + // For the top model and all its children, build the effective model. + // This is done through the phased executor var allResults = results(result).toList(); try (PhasingExecutor executor = createExecutor()) { for (DefaultModelBuilderResult r : allResults) { executor.execute(() -> { DefaultModelBuilderSession mbs = derive(r.getSource(), r); try { - mbs.build2(new LinkedHashSet<>()); + mbs.buildEffectiveModel(new LinkedHashSet<>()); } catch (ModelBuilderException e) { // gathered with problem collector } catch (Exception t) { @@ -743,15 +753,21 @@ private ModelBuilderResult buildBuildPom() throws ModelBuilderException { }); } } - allResults.stream().filter(r -> r != result).forEach(r -> r.getProblems() - .forEach(this::add)); + + // Check for errors again after execution if (hasErrors()) { throw newModelBuilderException(); } - - return result; } + /** + * Generates a stream of DefaultModelBuilderResult objects, starting with the provided + * result and recursively including all its child results. + * + * @param r The initial DefaultModelBuilderResult object from which to generate the stream. + * @return A Stream of DefaultModelBuilderResult objects, starting with the provided result + * and including all its child results. + */ Stream results(DefaultModelBuilderResult r) { return Stream.concat(Stream.of(r), r.getChildren().stream().flatMap(this::results)); } @@ -782,7 +798,7 @@ private void loadFilePom( if (pom.equals(top)) { r = result; } else { - r = new DefaultModelBuilderResult(); + r = new DefaultModelBuilderResult(parent); if (parent != null) { parent.getChildren().add(r); } @@ -791,10 +807,8 @@ private void loadFilePom( Path pomDirectory = Files.isDirectory(pom) ? pom : pom.getParent(); ModelSource src = ModelSource.fromPath(pom); Model model = derive(src, r).readFileModel(); - r.setFileModel(model); - r.setSource(src); + putSource(getGroupId(model), model.getArtifactId(), src); Model activated = activateFileModel(model); - r.setActivatedFileModel(activated); List subprojects = activated.getSubprojects(); if (subprojects.isEmpty()) { subprojects = activated.getModules(); @@ -817,8 +831,7 @@ private void loadFilePom( -1, -1, null); - r.getProblems().add(problem); - add(problem); + r.addProblem(problem); continue; } @@ -840,7 +853,7 @@ private void loadFilePom( -1, -1, null); - r.getProblems().add(problem); + r.addProblem(problem); continue; } @@ -856,8 +869,7 @@ private void loadFilePom( add(Severity.ERROR, ModelProblem.Version.V40, "Failed to load project " + pom, e); } if (r != result) { - result.getProblems().addAll(r.getProblems()); - r.getProblems().clear(); + r.getProblems().forEach(result::addProblem); } } @@ -867,21 +879,7 @@ static Set concat(Set a, T b) { return Set.copyOf(result); } - private ModelBuilderResult buildParentOrDependency(Collection importIds) throws ModelBuilderException { - // phase 1: read and validate raw model - Model fileModel = readFileModel(); - result.setFileModel(fileModel); - result.setSource(request.getSource()); - - Model activatedFileModel = activateFileModel(fileModel); - result.setActivatedFileModel(activatedFileModel); - - // phase 2: build the effective model - return build2(importIds); - } - - private ModelBuilderResult build2(Collection importIds) throws ModelBuilderException { - // phase 2 + void buildEffectiveModel(Collection importIds) throws ModelBuilderException { Model resultModel = readEffectiveModel(); setSource(resultModel); setRootModel(resultModel); @@ -933,8 +931,6 @@ private ModelBuilderResult build2(Collection importIds) throws ModelBuil if (hasErrors()) { throw newModelBuilderException(); } - - return result; } Model readParent(Model childModel, ModelSource childSource) throws ModelBuilderException { @@ -1052,6 +1048,19 @@ Model resolveAndReadParentExternally(Model childModel) throws ModelBuilderExcept String artifactId = parent.getArtifactId(); String version = parent.getVersion(); + // add repositories specified by the current model so that we can resolve the parent + if (!childModel.getRepositories().isEmpty()) { + List oldRepos = + getRepositories().stream().map(Object::toString).toList(); + mergeRepositories(childModel.getRepositories(), false); + List newRepos = + getRepositories().stream().map(Object::toString).toList(); + if (!Objects.equals(oldRepos, newRepos)) { + logger.debug("Merging repositories from " + childModel.getId() + "\n" + + newRepos.stream().map(s -> " " + s).collect(Collectors.joining("\n"))); + } + } + ModelSource modelSource; try { modelSource = resolveReactorModel(groupId, artifactId, version); @@ -1091,9 +1100,8 @@ Model resolveAndReadParentExternally(Model childModel) throws ModelBuilderExcept .source(modelSource) .build(); - DefaultModelBuilderResult r = new DefaultModelBuilderResult(); + DefaultModelBuilderResult r = new DefaultModelBuilderResult(this.result); Model parentModel = new DefaultModelBuilderSession(lenientRequest, r).readParentModel(); - this.result.getProblems().addAll(r.getProblems()); if (!parent.getVersion().equals(version)) { String rawChildModelVersion = childModel.getVersion(); @@ -1168,7 +1176,6 @@ private Model readEffectiveModel() throws ModelBuilderException { if (hasFatalErrors()) { throw newModelBuilderException(); } - result.setRawModel(inputModel); inputModel = activateFileModel(inputModel); @@ -1188,19 +1195,6 @@ private Model readEffectiveModel() throws ModelBuilderException { profileActivationContext.setUserProperties(profileProps); } - // add repositories specified by the current model so that we can resolve the parent - if (!inputModel.getRepositories().isEmpty()) { - List oldRepos = - getRepositories().stream().map(Object::toString).toList(); - mergeRepositories(inputModel.getRepositories(), false); - List newRepos = - getRepositories().stream().map(Object::toString).toList(); - if (!Objects.equals(oldRepos, newRepos)) { - logger.debug("Merging repositories from " + inputModel.getId() + "\n" - + newRepos.stream().map(s -> " " + s).collect(Collectors.joining("\n"))); - } - } - Model parentModel = readParent(inputModel, request.getSource()); if (parentModel == null) { String superModelVersion = @@ -1269,17 +1263,15 @@ private Model readEffectiveModel() throws ModelBuilderException { } Model readFileModel() throws ModelBuilderException { + result.setSource(request.getSource()); Model model = cache(request.getSource(), FILE, this::doReadFileModel); - if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { - putSource(getGroupId(model), model.getArtifactId(), request.getSource()); - } + result.setFileModel(model); return model; } @SuppressWarnings("checkstyle:methodlength") Model doReadFileModel() throws ModelBuilderException { ModelSource modelSource = request.getSource(); - result.setSource(modelSource); Model model; setSource(modelSource.getLocation()); logger.debug("Reading file model from " + modelSource.getLocation()); @@ -1364,8 +1356,7 @@ Model doReadFileModel() throws ModelBuilderException { throw newModelBuilderException(); } - if (model.getModelVersion() == null - && request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) { + if (model.getModelVersion() == null) { String namespace = model.getNamespaceUri(); if (namespace != null && namespace.startsWith(NAMESPACE_PREFIX)) { model = model.withModelVersion(namespace.substring(NAMESPACE_PREFIX.length())); @@ -1455,7 +1446,10 @@ Model doReadFileModel() throws ModelBuilderException { } Model readRawModel() throws ModelBuilderException { - return cache(request.getSource(), RAW, this::doReadRawModel); + readFileModel(); + Model model = cache(request.getSource(), RAW, this::doReadRawModel); + result.setRawModel(model); + return model; } private Model doReadRawModel() throws ModelBuilderException { @@ -1709,7 +1703,10 @@ private Model doLoadDependencyManagement( .source(importSource) .repositories(getRepositories()) .build(); - importResult = new DefaultModelBuilderSession(importRequest).buildParentOrDependency(importIds); + DefaultModelBuilderSession modelBuilderSession = new DefaultModelBuilderSession(importRequest); + // build the effective model + modelBuilderSession.buildEffectiveModel(importIds); + importResult = modelBuilderSession.result(); } catch (ModelBuilderException e) { e.getResult().getProblems().forEach(this::add); return null; @@ -1804,7 +1801,12 @@ private String transformPath(String path, ActivationFile target, String location try { return profileActivationFilePathInterpolator.interpolate(path, context); } catch (InterpolationException e) { - addInterpolationProblem(problems, target, path, e, locationKey); + problems.add( + Severity.ERROR, + ModelProblem.Version.BASE, + "Failed to interpolate file location " + path + ": " + e.getMessage(), + target.getLocation(locationKey), + e); } } return path; @@ -1813,20 +1815,6 @@ private String transformPath(String path, ActivationFile target, String location return profiles.stream().map(new ProfileInterpolator()).toList(); } - private static void addInterpolationProblem( - ModelProblemCollector problems, - InputLocationTracker target, - String path, - InterpolationException e, - String locationKey) { - problems.add( - Severity.ERROR, - ModelProblem.Version.BASE, - "Failed to interpolate file location " + path + ": " + e.getMessage(), - target.getLocation(locationKey), - e); - } - private static boolean isNotEmpty(String string) { return string != null && !string.isEmpty(); } @@ -1840,14 +1828,6 @@ public Model buildRawModel(ModelBuilderRequest request) throws ModelBuilderExcep return model; } - private DefaultModelBuilderResult asDefaultModelBuilderResult(ModelBuilderResult phaseOneResult) { - if (phaseOneResult instanceof DefaultModelBuilderResult) { - return (DefaultModelBuilderResult) phaseOneResult; - } else { - return new DefaultModelBuilderResult(phaseOneResult); - } - } - static String getGroupId(Model model) { String groupId = model.getGroupId(); if (groupId == null && model.getParent() != null) { diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilderResult.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilderResult.java index 6cf00ad70202..372f11e53b23 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilderResult.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilderResult.java @@ -19,6 +19,7 @@ package org.apache.maven.internal.impl.model; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -31,36 +32,26 @@ /** * 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 activePomProfiles; private List activeExternalProfiles; - private List problems; + private final List problems = new ArrayList<>(); + private final DefaultModelBuilderResult problemHolder; private final List children = new ArrayList<>(); DefaultModelBuilderResult() { - activePomProfiles = new ArrayList<>(); - activeExternalProfiles = new ArrayList<>(); - problems = new ArrayList<>(); + this(null); } - DefaultModelBuilderResult(ModelBuilderResult result) { - this(); - this.activeExternalProfiles.addAll(result.getActiveExternalProfiles()); - this.activePomProfiles.addAll(result.getActivePomProfiles()); - this.effectiveModel = result.getEffectiveModel(); - this.parentModel = result.getParentModel(); - this.fileModel = result.getFileModel(); - this.rawModel = result.getRawModel(); - this.problems.addAll(result.getProblems()); + DefaultModelBuilderResult(DefaultModelBuilderResult problemHolder) { + this.problemHolder = problemHolder; } public ModelSource getSource() { @@ -76,17 +67,8 @@ public Model getFileModel() { return fileModel; } - public DefaultModelBuilderResult setFileModel(Model fileModel) { + public void setFileModel(Model fileModel) { this.fileModel = fileModel; - return this; - } - - public Model getActivatedFileModel() { - return activatedFileModel; - } - - public void setActivatedFileModel(Model activatedFileModel) { - this.activatedFileModel = activatedFileModel; } @Override @@ -112,9 +94,8 @@ public Model getEffectiveModel() { return effectiveModel; } - public DefaultModelBuilderResult setEffectiveModel(Model model) { + public void setEffectiveModel(Model model) { this.effectiveModel = model; - return this; } @Override @@ -122,14 +103,8 @@ public List getActivePomProfiles() { return activePomProfiles; } - public DefaultModelBuilderResult setActivePomProfiles(List activeProfiles) { - if (activeProfiles != null) { - this.activePomProfiles = new ArrayList<>(activeProfiles); - } else { - this.activePomProfiles.clear(); - } - - return this; + public void setActivePomProfiles(List activeProfiles) { + this.activePomProfiles = activeProfiles; } @Override @@ -137,29 +112,31 @@ public List getActiveExternalProfiles() { return activeExternalProfiles; } - public DefaultModelBuilderResult setActiveExternalProfiles(List activeProfiles) { - if (activeProfiles != null) { - this.activeExternalProfiles = new ArrayList<>(activeProfiles); - } else { - this.activeExternalProfiles.clear(); - } - - return this; + public void setActiveExternalProfiles(List activeProfiles) { + this.activeExternalProfiles = activeProfiles; } + /** + * 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 getProblems() { - return problems; - } - - public DefaultModelBuilderResult setProblems(List problems) { - if (problems != null) { - this.problems = new ArrayList<>(problems); - } else { - this.problems.clear(); + 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); } - - return this; } @Override @@ -194,7 +171,11 @@ public String toString() { 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() : "", From 483818bc761de5349d2104577ebaeeea48b57ec9 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 27 Sep 2024 12:03:38 +0200 Subject: [PATCH 52/63] Do not wrap non build exceptions --- .../internal/impl/model/DefaultModelBuilder.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 329cec2aff86..830073ada43c 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -40,6 +40,7 @@ import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicReference; @@ -73,6 +74,7 @@ import org.apache.maven.api.model.Repository; import org.apache.maven.api.services.BuilderProblem; import org.apache.maven.api.services.BuilderProblem.Severity; +import org.apache.maven.api.services.MavenException; import org.apache.maven.api.services.ModelBuilder; import org.apache.maven.api.services.ModelBuilderException; import org.apache.maven.api.services.ModelBuilderRequest; @@ -739,6 +741,7 @@ private void buildBuildPom() throws ModelBuilderException { // For the top model and all its children, build the effective model. // This is done through the phased executor var allResults = results(result).toList(); + List exceptions = new CopyOnWriteArrayList<>(); try (PhasingExecutor executor = createExecutor()) { for (DefaultModelBuilderResult r : allResults) { executor.execute(() -> { @@ -747,15 +750,21 @@ private void buildBuildPom() throws ModelBuilderException { mbs.buildEffectiveModel(new LinkedHashSet<>()); } catch (ModelBuilderException e) { // gathered with problem collector - } catch (Exception t) { - mbs.add(Severity.FATAL, ModelProblem.Version.BASE, t.getMessage(), t); + } catch (RuntimeException t) { + exceptions.add(t); } }); } } // Check for errors again after execution - if (hasErrors()) { + if (exceptions.size() == 1) { + throw exceptions.get(0); + } else if (exceptions.size() > 1) { + MavenException fatalException = new MavenException("Multiple fatal exceptions occurred"); + exceptions.forEach(fatalException::addSuppressed); + throw fatalException; + } else if (hasErrors()) { throw newModelBuilderException(); } } From 0731a21f1f4845c5fe39373f717a57bddbe6adb9 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 27 Sep 2024 13:50:05 +0200 Subject: [PATCH 53/63] Fix order --- .../java/org/apache/maven/project/DefaultProjectBuilder.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index 7d0ebf2bbc20..1764d967f321 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -521,8 +521,7 @@ private List build(File pomFile, boolean recursive) { } private Stream results(ModelBuilderResult result) { - return Stream.concat( - Stream.of(result), result.getChildren().stream().flatMap(this::results)); + return Stream.concat(result.getChildren().stream().flatMap(this::results), Stream.of(result)); } private List convert(List problems) { From 5ecb637ccfff908b261e4b002d78c08e9f06d73b Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 27 Sep 2024 14:29:03 +0200 Subject: [PATCH 54/63] Fix lost plugin version resolution --- .../java/org/apache/maven/project/DefaultProjectBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index 1764d967f321..8c6b03769a61 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -918,6 +918,6 @@ private Model injectLifecycleBindings( } project.setRemoteArtifactRepositories(remoteRepositories); - return lifecycleBindingsInjector.injectLifecycleBindings(model, request, problems); + return lifecycleBindingsInjector.injectLifecycleBindings(model3.getDelegate(), request, problems); } } From 89861091364dbdf754f121187c9b92486ab0674b Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 27 Sep 2024 14:44:40 +0200 Subject: [PATCH 55/63] Fix project root directory --- .../java/org/apache/maven/project/DefaultProjectBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index 8c6b03769a61..09ab3fe9eb54 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -497,11 +497,11 @@ private List build(File pomFile, boolean recursive) { } List results = new ArrayList<>(); - Path rootDirectory = rootLocator.findRoot(pomFile.getParentFile().toPath()); List allModels = results(result).toList(); for (ModelBuilderResult r : allModels) { File pom = r.getSource().getPath().toFile(); MavenProject project = projectIndex.get(r.getEffectiveModel().getId()); + Path rootDirectory = rootLocator.findRoot(pom.getParentFile().toPath()); project.setRootDirectory(rootDirectory); project.setFile(pom); project.setExecutionRoot(pom.equals(pomFile)); From 12d2977d1dcee53946cedac8bedee7b2f0ccd606 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 27 Sep 2024 15:45:17 +0200 Subject: [PATCH 56/63] Cleanup --- .../impl/model/DefaultModelBuilder.java | 167 ++++-------------- .../impl/model/DefaultModelValidator.java | 12 +- 2 files changed, 48 insertions(+), 131 deletions(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 830073ada43c..7dfc28488ce7 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -60,7 +60,6 @@ import org.apache.maven.api.di.Singleton; import org.apache.maven.api.model.Activation; import org.apache.maven.api.model.ActivationFile; -import org.apache.maven.api.model.Build; import org.apache.maven.api.model.Dependency; import org.apache.maven.api.model.DependencyManagement; import org.apache.maven.api.model.Exclusion; @@ -68,8 +67,6 @@ import org.apache.maven.api.model.InputSource; import org.apache.maven.api.model.Model; import org.apache.maven.api.model.Parent; -import org.apache.maven.api.model.Plugin; -import org.apache.maven.api.model.PluginManagement; import org.apache.maven.api.model.Profile; import org.apache.maven.api.model.Repository; import org.apache.maven.api.services.BuilderProblem; @@ -231,7 +228,7 @@ public ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilder }; } - protected final class DefaultModelBuilderSession implements ModelProblemCollector { + protected class DefaultModelBuilderSession implements ModelProblemCollector { final Session session; final ModelBuilderRequest request; final DefaultModelBuilderResult result; @@ -252,21 +249,25 @@ protected final class DefaultModelBuilderSession implements ModelProblemCollecto } DefaultModelBuilderSession(ModelBuilderRequest request, DefaultModelBuilderResult result) { - this(request.getSession(), request, result); - } - - DefaultModelBuilderSession(Session session, ModelBuilderRequest request, DefaultModelBuilderResult result) { this( - session, + request.getSession(), request, result, - session.getData() - .computeIfAbsent(SessionData.key(ModelCache.class), modelCacheFactory::newInstance)); + request.getSession() + .getData() + .computeIfAbsent(SessionData.key(ModelCache.class), modelCacheFactory::newInstance), + new Graph(), + new ConcurrentHashMap<>(64), + List.of(), + repos(request), + repos(request)); } - DefaultModelBuilderSession( - Session session, ModelBuilderRequest request, DefaultModelBuilderResult result, ModelCache cache) { - this(session, request, result, cache, new Graph(), new ConcurrentHashMap<>(64), null, null, null); + static List repos(ModelBuilderRequest request) { + return List.copyOf( + request.getRepositories() != null + ? request.getRepositories() + : request.getSession().getRemoteRepositories()); } @SuppressWarnings("checkstyle:ParameterNumber") @@ -286,18 +287,9 @@ private DefaultModelBuilderSession( this.cache = cache; this.dag = dag; this.mappedSources = mappedSources; - if (pomRepositories == null) { - this.pomRepositories = List.of(); - this.externalRepositories = List.copyOf( - request.getRepositories() != null - ? request.getRepositories() - : session.getRemoteRepositories()); - this.repositories = this.externalRepositories; - } else { - this.pomRepositories = pomRepositories; - this.externalRepositories = externalRepositories; - this.repositories = repositories; - } + this.pomRepositories = pomRepositories; + this.externalRepositories = externalRepositories; + this.repositories = repositories; } DefaultModelBuilderSession derive(ModelSource source) { @@ -412,37 +404,26 @@ private boolean addEdge(Path from, Path p) { } public ModelSource getSource(String groupId, String artifactId) { - Set sources; - if (groupId != null) { - sources = mappedSources.get(new GAKey(groupId, artifactId)); - if (sources == null) { - return null; - } - } else if (artifactId != null) { - sources = mappedSources.get(new GAKey(null, artifactId)); - if (sources == null) { - return null; - } - } else { - return null; + Set sources = mappedSources.get(new GAKey(groupId, artifactId)); + if (sources != 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); } - 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); + return null; } public void putSource(String groupId, String artifactId, ModelSource source) { mappedSources .computeIfAbsent(new GAKey(groupId, artifactId), k -> new HashSet<>()) .add(source); + // Also register the source under the null groupId if (groupId != null) { - mappedSources - .computeIfAbsent(new GAKey(null, artifactId), k -> new HashSet<>()) - .add(source); + putSource(null, artifactId, source); } } @@ -556,27 +537,9 @@ public void add( } public ModelBuilderException newModelBuilderException() { - // ModelBuilderResult result = this.result; - // if (result.getEffectiveModel() == null && result.getParentModel() == null) { - // DefaultModelBuilderResult tmp = new DefaultModelBuilderResult(); - // tmp.setParentModel(result.getParentModel()); - // tmp.setEffectiveModel(result.getEffectiveModel()); - // tmp.setProblems(getProblems()); - // tmp.setActiveExternalProfiles(result.getActiveExternalProfiles()); - // String id = getRootModelId(); - // tmp.setRawModel(id, getRootModel()); - // result = tmp; - // } return new ModelBuilderException(result); } - public List getRepositories() { - return repositories; - } - - /** - * TODO: this is not thread safe and the session is mutated - */ public void mergeRepositories(List toAdd, boolean replace) { List repos = toAdd.stream().map(session::createRemoteRepository).toList(); @@ -1060,10 +1023,10 @@ Model resolveAndReadParentExternally(Model childModel) throws ModelBuilderExcept // add repositories specified by the current model so that we can resolve the parent if (!childModel.getRepositories().isEmpty()) { List oldRepos = - getRepositories().stream().map(Object::toString).toList(); + repositories.stream().map(Object::toString).toList(); mergeRepositories(childModel.getRepositories(), false); List newRepos = - getRepositories().stream().map(Object::toString).toList(); + repositories.stream().map(Object::toString).toList(); if (!Objects.equals(oldRepos, newRepos)) { logger.debug("Merging repositories from " + childModel.getId() + "\n" + newRepos.stream().map(s -> " " + s).collect(Collectors.joining("\n"))); @@ -1075,7 +1038,7 @@ Model resolveAndReadParentExternally(Model childModel) throws ModelBuilderExcept modelSource = resolveReactorModel(groupId, artifactId, version); if (modelSource == null) { AtomicReference modified = new AtomicReference<>(); - modelSource = modelResolver.resolveModel(request.getSession(), getRepositories(), parent, modified); + modelSource = modelResolver.resolveModel(request.getSession(), repositories, parent, modified); if (modified.get() != null) { parent = modified.get(); } @@ -1110,7 +1073,7 @@ Model resolveAndReadParentExternally(Model childModel) throws ModelBuilderExcept .build(); DefaultModelBuilderResult r = new DefaultModelBuilderResult(this.result); - Model parentModel = new DefaultModelBuilderSession(lenientRequest, r).readParentModel(); + Model parentModel = derive(lenientRequest, r).readParentModel(); if (!parent.getVersion().equals(version)) { String rawChildModelVersion = childModel.getVersion(); @@ -1253,15 +1216,13 @@ private Model readEffectiveModel() throws ModelBuilderException { // url normalization resultModel = modelUrlNormalizer.normalize(resultModel, request); - result.setEffectiveModel(resultModel); - // Now the fully interpolated model is available: reconfigure the resolver if (!resultModel.getRepositories().isEmpty()) { List oldRepos = - getRepositories().stream().map(Object::toString).toList(); + repositories.stream().map(Object::toString).toList(); mergeRepositories(resultModel.getRepositories(), true); List newRepos = - getRepositories().stream().map(Object::toString).toList(); + repositories.stream().map(Object::toString).toList(); if (!Objects.equals(oldRepos, newRepos)) { logger.debug("Replacing repositories from " + resultModel.getId() + "\n" + newRepos.stream().map(s -> " " + s).collect(Collectors.joining("\n"))); @@ -1671,7 +1632,7 @@ private Model doLoadDependencyManagement( importSource = resolveReactorModel(groupId, artifactId, version); if (importSource == null) { importSource = modelResolver.resolveModel( - request.getSession(), getRepositories(), dependency, new AtomicReference<>()); + request.getSession(), repositories, dependency, new AtomicReference<>()); } } catch (ModelBuilderException e) { StringBuilder buffer = new StringBuilder(256); @@ -1710,7 +1671,7 @@ private Model doLoadDependencyManagement( .systemProperties(request.getSystemProperties()) .userProperties(request.getUserProperties()) .source(importSource) - .repositories(getRepositories()) + .repositories(repositories) .build(); DefaultModelBuilderSession modelBuilderSession = new DefaultModelBuilderSession(importRequest); // build the effective model @@ -1870,58 +1831,6 @@ private DefaultProfileActivationContext getProfileActivationContext(ModelBuilder return context; } - private void checkPluginVersions(List lineage, ModelBuilderRequest request, ModelProblemCollector problems) { - if (request.getRequestType() != ModelBuilderRequest.RequestType.BUILD_POM) { - return; - } - - Map plugins = new HashMap<>(); - Map versions = new HashMap<>(); - Map managedVersions = new HashMap<>(); - - for (int i = lineage.size() - 1; i >= 0; i--) { - Model model = lineage.get(i); - Build build = model.getBuild(); - if (build != null) { - for (Plugin plugin : build.getPlugins()) { - String key = plugin.getKey(); - if (versions.get(key) == null) { - versions.put(key, plugin.getVersion()); - plugins.put(key, plugin); - } - } - PluginManagement mgmt = build.getPluginManagement(); - if (mgmt != null) { - for (Plugin plugin : mgmt.getPlugins()) { - String key = plugin.getKey(); - managedVersions.computeIfAbsent(key, k -> plugin.getVersion()); - } - } - } - } - - for (String key : versions.keySet()) { - if (versions.get(key) == null && managedVersions.get(key) == null) { - InputLocation location = plugins.get(key).getLocation(""); - problems.add( - Severity.WARNING, - ModelProblem.Version.V20, - "'build.plugins.plugin.version' for " + key + " is missing.", - location); - } - } - } - - private Model assembleInheritance( - List lineage, ModelBuilderRequest request, ModelProblemCollector problems) { - Model parent = lineage.get(lineage.size() - 1); - for (int i = lineage.size() - 2; i >= 0; i--) { - Model child = lineage.get(i); - parent = inheritanceAssembler.assembleModelInheritance(child, parent, request, problems); - } - return parent; - } - private Map getProfileActivations(Model model) { return model.getProfiles().stream() .filter(p -> p.getActivation() != null) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelValidator.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelValidator.java index db4ec5a64280..65545d1b8eef 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelValidator.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelValidator.java @@ -66,6 +66,7 @@ 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; @@ -2040,8 +2041,15 @@ private boolean validate20PluginVersion( 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(validationLevel, ModelValidator.VALIDATION_LEVEL_MAVEN_3_0); From 6d78b75a0a865205baef616e74a5f9fe324919e2 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 27 Sep 2024 16:43:25 +0200 Subject: [PATCH 57/63] Cleanup --- .../impl/model/DefaultModelBuilder.java | 181 +++++++----------- 1 file changed, 74 insertions(+), 107 deletions(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 7dfc28488ce7..816356bd627d 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -38,7 +38,6 @@ import java.util.Optional; import java.util.Properties; import java.util.Set; -import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; @@ -118,6 +117,10 @@ import org.slf4j.LoggerFactory; /** + * The model builder is responsible for building the {@link Model} from the POM file. + * There are two ways to main use cases: the first one is to build the model from a POM file + * on the file system in order to actually build the project. The second one is to build the + * model for a dependency or an external parent. */ @Named @Singleton @@ -223,7 +226,7 @@ public ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilder // simply build the effective model session.buildEffectiveModel(new LinkedHashSet<>()); } - return session.result(); + return session.result; } }; } @@ -245,14 +248,10 @@ protected class DefaultModelBuilderSession implements ModelProblemCollector { List repositories; DefaultModelBuilderSession(ModelBuilderRequest request) { - this(request, new DefaultModelBuilderResult()); - } - - DefaultModelBuilderSession(ModelBuilderRequest request, DefaultModelBuilderResult result) { this( request.getSession(), request, - result, + new DefaultModelBuilderResult(), request.getSession() .getData() .computeIfAbsent(SessionData.key(ModelCache.class), modelCacheFactory::newInstance), @@ -300,6 +299,13 @@ DefaultModelBuilderSession derive(ModelSource source, DefaultModelBuilderResult return derive(ModelBuilderRequest.build(request, source), result); } + /** + * Creates a new session, sharing cached datas and propagating errors. + */ + DefaultModelBuilderSession derive(ModelBuilderRequest request) { + return derive(request, new DefaultModelBuilderResult(result)); + } + DefaultModelBuilderSession derive(ModelBuilderRequest request, DefaultModelBuilderResult result) { if (session != request.getSession()) { throw new IllegalArgumentException("Session mismatch"); @@ -316,22 +322,6 @@ DefaultModelBuilderSession derive(ModelBuilderRequest request, DefaultModelBuild repositories); } - public Session session() { - return session; - } - - public ModelBuilderRequest request() { - return request; - } - - public ModelBuilderResult result() { - return result; - } - - public ModelCache cache() { - return cache; - } - @Override public String toString() { return "ModelBuilderSession[" + "session=" @@ -361,7 +351,7 @@ private int getParallelism() { public Model getRawModel(Path from, String groupId, String artifactId) { ModelSource source = getSource(groupId, artifactId); if (source != null) { - if (!addEdge(from, source.getPath())) { + if (addEdge(from, source.getPath())) { return null; } try { @@ -377,7 +367,7 @@ public Model getRawModel(Path from, Path path) { if (!Files.isRegularFile(path)) { throw new IllegalArgumentException("Not a regular file: " + path); } - if (!addEdge(from, path)) { + if (addEdge(from, path)) { return null; } try { @@ -388,10 +378,13 @@ public Model getRawModel(Path from, Path path) { return null; } + /** + * Returns false if the edge was added, true if it caused a cycle. + */ private boolean addEdge(Path from, Path p) { try { dag.addEdge(from.toString(), p.toString()); - return true; + return false; } catch (Graph.CycleDetectedException e) { add( Severity.FATAL, @@ -399,7 +392,7 @@ private boolean addEdge(Path from, Path p) { "Cycle detected between models at " + from + " and " + p, null, e); - return false; + return true; } } @@ -686,7 +679,7 @@ private void buildBuildPom() throws ModelBuilderException { } // Locate and normalize the root POM if it exists, fallback to top otherwise - Path root = getModelProcessor().locateExistingPom(rootDirectory); + Path root = modelProcessor.locateExistingPom(rootDirectory); if (root != null) { root = root.toAbsolutePath().normalize(); } else { @@ -779,13 +772,11 @@ private void loadFilePom( Path pomDirectory = Files.isDirectory(pom) ? pom : pom.getParent(); ModelSource src = ModelSource.fromPath(pom); Model model = derive(src, r).readFileModel(); + // keep all loaded file models in memory, those will be needed + // during the raw to build transformation putSource(getGroupId(model), model.getArtifactId(), src); Model activated = activateFileModel(model); - List subprojects = activated.getSubprojects(); - if (subprojects.isEmpty()) { - subprojects = activated.getModules(); - } - for (String subproject : subprojects) { + for (String subproject : getSubprojects(activated)) { if (subproject == null || subproject.isEmpty()) { continue; } @@ -905,12 +896,12 @@ void buildEffectiveModel(Collection importIds) throws ModelBuilderExcept } } - Model readParent(Model childModel, ModelSource childSource) throws ModelBuilderException { - Model parentModel = null; + Model readParent(Model childModel) throws ModelBuilderException { + Model parentModel; Parent parent = childModel.getParent(); if (parent != null) { - parentModel = readParentLocally(childModel, childSource); + parentModel = readParentLocally(childModel); if (parentModel == null) { parentModel = resolveAndReadParentExternally(childModel); } @@ -923,18 +914,28 @@ Model readParent(Model childModel, ModelSource childSource) throws ModelBuilderE + ", must be \"pom\" but is \"" + parentModel.getPackaging() + "\"", parentModel.getLocation("packaging")); } + result.setParentModel(parentModel); + } else { + String superModelVersion = childModel.getModelVersion(); + if (superModelVersion == null || !VALID_MODEL_VERSIONS.contains(superModelVersion)) { + // Maven 3.x is always using 4.0.0 version to load the supermodel, so + // do the same when loading a dependency. The model validator will also + // check that field later. + superModelVersion = MODEL_VERSION_4_0_0; + } + parentModel = getSuperModel(superModelVersion); } return parentModel; } - private Model readParentLocally(Model childModel, ModelSource childSource) throws ModelBuilderException { - ModelSource candidateSource = getParentPomFile(childModel, childSource); + private Model readParentLocally(Model childModel) throws ModelBuilderException { + ModelSource candidateSource = getParentPomFile(childModel, request.getSource()); if (candidateSource == null) { return null; } - Model candidateModel = derive(candidateSource).readParentModel(); + Model candidateModel = derive(candidateSource).readAsParentModel(); // // TODO jvz Why isn't all this checking the job of the duty of the workspace resolver, we know that we @@ -1022,14 +1023,15 @@ Model resolveAndReadParentExternally(Model childModel) throws ModelBuilderExcept // add repositories specified by the current model so that we can resolve the parent if (!childModel.getRepositories().isEmpty()) { - List oldRepos = - repositories.stream().map(Object::toString).toList(); + var previousRepositories = repositories; mergeRepositories(childModel.getRepositories(), false); - List newRepos = - repositories.stream().map(Object::toString).toList(); - if (!Objects.equals(oldRepos, newRepos)) { - logger.debug("Merging repositories from " + childModel.getId() + "\n" - + newRepos.stream().map(s -> " " + s).collect(Collectors.joining("\n"))); + if (!Objects.equals(previousRepositories, repositories)) { + if (logger.isDebugEnabled()) { + logger.debug("Merging repositories from " + childModel.getId() + "\n" + + repositories.stream() + .map(Object::toString) + .collect(Collectors.joining("\n", " ", ""))); + } } } @@ -1072,8 +1074,7 @@ Model resolveAndReadParentExternally(Model childModel) throws ModelBuilderExcept .source(modelSource) .build(); - DefaultModelBuilderResult r = new DefaultModelBuilderResult(this.result); - Model parentModel = derive(lenientRequest, r).readParentModel(); + Model parentModel = derive(lenientRequest).readAsParentModel(); if (!parent.getVersion().equals(version)) { String rawChildModelVersion = childModel.getVersion(); @@ -1167,20 +1168,7 @@ private Model readEffectiveModel() throws ModelBuilderException { profileActivationContext.setUserProperties(profileProps); } - Model parentModel = readParent(inputModel, request.getSource()); - if (parentModel == null) { - String superModelVersion = - inputModel.getModelVersion() != null ? inputModel.getModelVersion() : MODEL_VERSION_4_0_0; - if (!VALID_MODEL_VERSIONS.contains(superModelVersion)) { - // Maven 3.x is always using 4.0.0 version to load the supermodel, so - // do the same when loading a dependency. The model validator will also - // check that field later. - superModelVersion = MODEL_VERSION_4_0_0; - } - parentModel = getSuperModel(superModelVersion); - } else { - result.setParentModel(parentModel); - } + Model parentModel = readParent(inputModel); List parentInterpolatedProfiles = interpolateActivations(parentModel.getProfiles(), profileActivationContext, this); @@ -1347,7 +1335,7 @@ Model doReadFileModel() throws ModelBuilderException { Path relativePath = Paths.get(path); Path pomPath = pomFile.resolveSibling(relativePath).normalize(); if (Files.isDirectory(pomPath)) { - pomPath = getModelProcessor().locateExistingPom(pomPath); + pomPath = modelProcessor.locateExistingPom(pomPath); } if (pomPath != null && Files.isRegularFile(pomPath)) { Model parentModel = @@ -1370,8 +1358,7 @@ Model doReadFileModel() throws ModelBuilderException { } // subprojects discovery - if (model.getSubprojects().isEmpty() - && model.getModules().isEmpty() + if (getSubprojects(model).isEmpty() // only discover subprojects if POM > 4.0.0 && !MODEL_VERSION_4_0_0.equals(model.getModelVersion()) // and if packaging is POM (we check type, but the session is not yet available, @@ -1450,27 +1437,16 @@ private Model doReadRawModel() throws ModelBuilderException { return rawModel; } - Model readParentModel() { - return cache(request.getSource(), PARENT, this::doReadParentModel); + /** + * Reads the request source's parent. + */ + Model readAsParentModel() { + return cache(request.getSource(), PARENT, this::doReadAsParentModel); } - private Model doReadParentModel() { + private Model doReadAsParentModel() throws ModelBuilderException { Model raw = readRawModel(); - - Model parentData; - if (raw.getParent() != null) { - parentData = readParent(raw, request.getSource()); - } else { - String superModelVersion = raw.getModelVersion() != null ? raw.getModelVersion() : "4.0.0"; - if (!VALID_MODEL_VERSIONS.contains(superModelVersion)) { - // Maven 3.x is always using 4.0.0 version to load the supermodel, so - // do the same when loading a dependency. The model validator will also - // check that field later. - superModelVersion = MODEL_VERSION_4_0_0; - } - parentData = getSuperModel(superModelVersion); - } - + Model parentData = readParent(raw); Model parent = new DefaultInheritanceAssembler(new DefaultInheritanceAssembler.InheritanceModelMerger() { @Override protected void mergeModel_Modules( @@ -1488,6 +1464,7 @@ protected void mergeModel_Subprojects( boolean sourceDominant, Map context) {} + @SuppressWarnings("deprecation") @Override protected void mergeModel_Profiles( Model.Builder builder, @@ -1676,7 +1653,7 @@ private Model doLoadDependencyManagement( DefaultModelBuilderSession modelBuilderSession = new DefaultModelBuilderSession(importRequest); // build the effective model modelBuilderSession.buildEffectiveModel(importIds); - importResult = modelBuilderSession.result(); + importResult = modelBuilderSession.result; } catch (ModelBuilderException e) { e.getResult().getProblems().forEach(this::add); return null; @@ -1703,15 +1680,24 @@ ModelSource resolveReactorModel(String groupId, String artifactId, String versio return null; } - private T cache(String groupId, String artifactId, String version, String tag, Callable supplier) { - return cache.computeIfAbsent(groupId, artifactId, version, tag, asSupplier(supplier)); + private T cache(String groupId, String artifactId, String version, String tag, Supplier supplier) { + return cache.computeIfAbsent(groupId, artifactId, version, tag, supplier); } - private T cache(Source source, String tag, Callable supplier) { - return cache.computeIfAbsent(source, tag, asSupplier(supplier)); + private T cache(Source source, String tag, Supplier supplier) { + return cache.computeIfAbsent(source, tag, supplier); } } + @SuppressWarnings("deprecation") + private static List getSubprojects(Model activated) { + List subprojects = activated.getSubprojects(); + if (subprojects.isEmpty()) { + subprojects = activated.getModules(); + } + return subprojects; + } + private List interpolateActivations( List profiles, DefaultProfileActivationContext context, ModelProblemCollector problems) { if (profiles.stream() @@ -1914,21 +1900,6 @@ private boolean match(String match, String text) { return match.equals("*") || match.equals(text); } - private static Supplier asSupplier(Callable supplier) { - return () -> { - try { - return supplier.call(); - } catch (Exception e) { - uncheckedThrow(e); - return null; - } - }; - } - - static void uncheckedThrow(Throwable t) throws T { - throw (T) t; // rely on vacuous cast - } - private boolean containsCoordinates(String message, String groupId, String artifactId, String version) { return message != null && (groupId == null || message.contains(groupId)) @@ -1936,9 +1907,5 @@ private boolean containsCoordinates(String message, String groupId, String artif && (version == null || message.contains(version)); } - ModelProcessor getModelProcessor() { - return modelProcessor; - } - record GAKey(String groupId, String artifactId) {} } From be716a40276e63cdee823ff1b2897a85764e430a Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 27 Sep 2024 17:41:34 +0200 Subject: [PATCH 58/63] Minor fixes --- .../maven/internal/impl/model/DefaultModelBuilder.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 816356bd627d..9d7afb13ea27 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -289,6 +289,7 @@ private DefaultModelBuilderSession( this.pomRepositories = pomRepositories; this.externalRepositories = externalRepositories; this.repositories = repositories; + this.result.setSource(this.request.getSource()); } DefaultModelBuilderSession derive(ModelSource source) { @@ -1221,8 +1222,8 @@ private Model readEffectiveModel() throws ModelBuilderException { } Model readFileModel() throws ModelBuilderException { - result.setSource(request.getSource()); Model model = cache(request.getSource(), FILE, this::doReadFileModel); + // set the file model in the result outside the cache result.setFileModel(model); return model; } @@ -1267,11 +1268,8 @@ Model doReadFileModel() throws ModelBuilderException { throw e; } - Severity severity = request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM - ? Severity.ERROR - : Severity.WARNING; add( - severity, + Severity.ERROR, ModelProblem.Version.V20, "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage(), e); @@ -1403,8 +1401,10 @@ Model doReadFileModel() throws ModelBuilderException { } Model readRawModel() throws ModelBuilderException { + // ensure file model is available readFileModel(); Model model = cache(request.getSource(), RAW, this::doReadRawModel); + // set the raw model in the result outside the cache result.setRawModel(model); return model; } From fad0f36e52fba4ec73cf00bcc9c6cf629009ec03 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 27 Sep 2024 20:27:34 +0200 Subject: [PATCH 59/63] Remove unused class --- .../model/DefaultModelProblemCollector.java | 198 ------------------ 1 file changed, 198 deletions(-) delete mode 100644 maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelProblemCollector.java diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelProblemCollector.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelProblemCollector.java deleted file mode 100644 index 8d12032051e3..000000000000 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelProblemCollector.java +++ /dev/null @@ -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 problems; - - private String source; - - private Model sourceModel; - - private Model rootModel; - - private Set 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 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; - } - } - - public 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 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); - } -} From e3943fedc0ba3f195f19368ac8808995dd21ad83 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 27 Sep 2024 18:18:45 +0200 Subject: [PATCH 60/63] Keep the result order deterministic --- .../impl/model/DefaultModelBuilder.java | 27 +++++++------------ 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 9d7afb13ea27..887d716d9961 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -741,7 +741,8 @@ Stream results(DefaultModelBuilderResult r) { @SuppressWarnings("checkstyle:MethodLength") private void loadFromRoot(Path root, Path top) { try (PhasingExecutor executor = createExecutor()) { - loadFilePom(executor, top, root, Set.of(), null); + DefaultModelBuilderResult r = Objects.equals(top, root) ? result : new DefaultModelBuilderResult(); + loadFilePom(executor, top, root, Set.of(), r); } if (result.getFileModel() == null && !Objects.equals(top, root)) { logger.warn( @@ -759,16 +760,7 @@ private void loadFromRoot(Path root, Path top) { } private void loadFilePom( - Executor executor, Path top, Path pom, Set parents, DefaultModelBuilderResult parent) { - DefaultModelBuilderResult r; - if (pom.equals(top)) { - r = result; - } else { - r = new DefaultModelBuilderResult(parent); - if (parent != null) { - parent.getChildren().add(r); - } - } + Executor executor, Path top, Path pom, Set parents, DefaultModelBuilderResult r) { try { Path pomDirectory = Files.isDirectory(pom) ? pom : pom.getParent(); ModelSource src = ModelSource.fromPath(pom); @@ -821,12 +813,13 @@ private void loadFilePom( continue; } - executor.execute(() -> loadFilePom( - executor, - top, - subprojectFile, - concat(parents, pom), - (parent != null || Objects.equals(pom, top)) && request.isRecursive() ? r : null)); + DefaultModelBuilderResult cr = + Objects.equals(top, subprojectFile) ? result : new DefaultModelBuilderResult(r); + if (request.isRecursive()) { + r.getChildren().add(cr); + } + + executor.execute(() -> loadFilePom(executor, top, subprojectFile, concat(parents, pom), cr)); } } catch (ModelBuilderException e) { // gathered with problem collector From 5315e27538de275e7e3b5d8ddd15af8d37f89800 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 27 Sep 2024 22:17:20 +0200 Subject: [PATCH 61/63] Default to 1 thread for model builder --- .../apache/maven/internal/impl/model/DefaultModelBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 887d716d9961..71ff9794cd4b 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -337,7 +337,7 @@ PhasingExecutor createExecutor() { } private int getParallelism() { - int parallelism = Runtime.getRuntime().availableProcessors() / 2 + 1; + int parallelism = 1; // Runtime.getRuntime().availableProcessors() / 2 + 1; try { String str = request.getUserProperties().get(Constants.MAVEN_MODEL_BUILDER_PARALLELISM); if (str != null) { From cf27eefe21eefc7c30816d9c059f251ff89ccbab Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 27 Sep 2024 22:36:55 +0200 Subject: [PATCH 62/63] Restore multi threaded builder --- .../apache/maven/internal/impl/model/DefaultModelBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index 71ff9794cd4b..887d716d9961 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -337,7 +337,7 @@ PhasingExecutor createExecutor() { } private int getParallelism() { - int parallelism = 1; // Runtime.getRuntime().availableProcessors() / 2 + 1; + int parallelism = Runtime.getRuntime().availableProcessors() / 2 + 1; try { String str = request.getUserProperties().get(Constants.MAVEN_MODEL_BUILDER_PARALLELISM); if (str != null) { From 86ef9058d3798ce065c7d9fc934ae46950886c11 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 27 Sep 2024 23:14:59 +0200 Subject: [PATCH 63/63] Fix possible ConcurrentException --- .../maven/internal/impl/model/DefaultModelBuilderResult.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilderResult.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilderResult.java index 372f11e53b23..f834577a596c 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilderResult.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilderResult.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -41,7 +42,7 @@ class DefaultModelBuilderResult implements ModelBuilderResult { private Model effectiveModel; private List activePomProfiles; private List activeExternalProfiles; - private final List problems = new ArrayList<>(); + private final List problems = new CopyOnWriteArrayList<>(); private final DefaultModelBuilderResult problemHolder; private final List children = new ArrayList<>();