Skip to content

Commit fee69f2

Browse files
authored
[MNG-8294] Consistency checks when loading parent (#1784)
1 parent 4452363 commit fee69f2

File tree

8 files changed

+295
-263
lines changed

8 files changed

+295
-263
lines changed

api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ enum RequestType {
5252
* The request is for building a model from a POM file in a project on the filesystem.
5353
*/
5454
BUILD_POM,
55+
/**
56+
* The request is for building the consumer POM.
57+
*/
58+
CONSUMER_POM,
5559
/**
5660
* The request is for building a model from a parent POM file from a downloaded artifact.
5761
*/

api/maven-api-model/src/main/mdo/maven.mdo

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1744,20 +1744,16 @@
17441744
<name>relativePath</name>
17451745
<version>4.0.0+</version>
17461746
<description>
1747-
The relative path of the parent {@code pom.xml} file within the checkout.
1748-
If not specified, it defaults to {@code ../pom.xml}.
1747+
The relative path of the parent subproject POM file or directory within the checkout.
1748+
If not specified, it defaults to {@code ..}, i.e. the parent directory.
17491749
Maven looks for the parent POM first in this location on
1750-
the filesystem, then the local repository, and lastly in the remote repo.
1751-
{@code relativePath} allows you to select a different location,
1752-
for example when your structure is flat, or deeper without an intermediate parent POM.
1753-
However, the group ID, artifact ID and version are still required,
1754-
and must match the file in the location given, or it will revert to the repository for the POM.
1755-
This feature is only for enhancing the development in a local checkout of that project.
1756-
Set the value to an empty string in case you want to disable the feature and always resolve
1757-
the parent POM from the repositories.
1750+
the filesystem if explicitly provided, then in the reactor if groupId and artifactId are provided,
1751+
then in the default parent directory, then the local repository, and lastly in the remote repo.
1752+
However, if the both relative path and the group ID / artifact ID are provided,
1753+
they must match the file in the location given.
1754+
Specify either the {@code relativePath} or the {@code groupId}/{@code artifactId}, not both.
17581755
</description>
17591756
<type>String</type>
1760-
<defaultValue>..</defaultValue>
17611757
</field>
17621758
</fields>
17631759
<codeSegments>

maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java

Lines changed: 132 additions & 72 deletions
Large diffs are not rendered by default.

maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelValidator.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,24 @@ public void validateFileModel(
326326
"is either LATEST or RELEASE (both of them are being deprecated)",
327327
parent);
328328
}
329+
330+
if (parent.getRelativePath() != null
331+
&& !parent.getRelativePath().isEmpty()
332+
&& (parent.getGroupId() != null && !parent.getGroupId().isEmpty()
333+
|| parent.getArtifactId() != null
334+
&& !parent.getArtifactId().isEmpty())
335+
&& validationLevel >= ModelValidator.VALIDATION_LEVEL_MAVEN_4_0
336+
&& VALID_MODEL_VERSIONS.contains(m.getModelVersion())
337+
&& !Objects.equals(m.getModelVersion(), ModelBuilder.MODEL_VERSION_4_0_0)) {
338+
addViolation(
339+
problems,
340+
Severity.WARNING,
341+
Version.BASE,
342+
"parent.relativePath",
343+
null,
344+
"only specify relativePath or groupId/artifactId in modelVersion 4.1.0",
345+
parent);
346+
}
329347
}
330348

331349
if (validationLevel == ModelValidator.VALIDATION_LEVEL_MINIMAL) {

maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java

Lines changed: 69 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,14 @@
2121
import javax.inject.Inject;
2222
import javax.inject.Named;
2323

24+
import java.io.File;
25+
import java.io.IOException;
26+
import java.io.InputStream;
27+
import java.nio.file.Files;
2428
import java.nio.file.Path;
2529
import java.util.ArrayList;
26-
import java.util.Collection;
2730
import java.util.List;
31+
import java.util.Objects;
2832
import java.util.stream.Collectors;
2933

3034
import org.apache.maven.api.SessionData;
@@ -35,117 +39,32 @@
3539
import org.apache.maven.api.model.ModelBase;
3640
import org.apache.maven.api.model.Profile;
3741
import org.apache.maven.api.model.Repository;
38-
import org.apache.maven.api.services.Interpolator;
3942
import org.apache.maven.api.services.ModelBuilder;
4043
import org.apache.maven.api.services.ModelBuilderException;
4144
import org.apache.maven.api.services.ModelBuilderRequest;
4245
import org.apache.maven.api.services.ModelBuilderResult;
43-
import org.apache.maven.api.services.ModelProblemCollector;
4446
import org.apache.maven.api.services.ModelSource;
45-
import org.apache.maven.api.services.SuperPomProvider;
46-
import org.apache.maven.api.services.model.DependencyManagementImporter;
47-
import org.apache.maven.api.services.model.DependencyManagementInjector;
48-
import org.apache.maven.api.services.model.InheritanceAssembler;
47+
import org.apache.maven.api.services.Source;
4948
import org.apache.maven.api.services.model.LifecycleBindingsInjector;
50-
import org.apache.maven.api.services.model.ModelCacheFactory;
51-
import org.apache.maven.api.services.model.ModelInterpolator;
52-
import org.apache.maven.api.services.model.ModelNormalizer;
53-
import org.apache.maven.api.services.model.ModelPathTranslator;
54-
import org.apache.maven.api.services.model.ModelProcessor;
55-
import org.apache.maven.api.services.model.ModelResolver;
56-
import org.apache.maven.api.services.model.ModelUrlNormalizer;
57-
import org.apache.maven.api.services.model.ModelValidator;
58-
import org.apache.maven.api.services.model.ModelVersionParser;
59-
import org.apache.maven.api.services.model.PluginConfigurationExpander;
60-
import org.apache.maven.api.services.model.PluginManagementInjector;
61-
import org.apache.maven.api.services.model.ProfileActivationContext;
62-
import org.apache.maven.api.services.model.ProfileInjector;
63-
import org.apache.maven.api.services.model.ProfileSelector;
64-
import org.apache.maven.api.spi.ModelTransformer;
6549
import org.apache.maven.internal.impl.InternalSession;
66-
import org.apache.maven.internal.impl.model.DefaultModelBuilder;
67-
import org.apache.maven.internal.impl.model.DefaultProfileSelector;
68-
import org.apache.maven.internal.impl.model.ProfileActivationFilePathInterpolator;
6950
import org.apache.maven.model.v4.MavenModelVersion;
7051
import org.apache.maven.project.MavenProject;
7152
import org.eclipse.aether.RepositorySystemSession;
72-
import org.slf4j.Logger;
73-
import org.slf4j.LoggerFactory;
7453

7554
@Named
7655
class DefaultConsumerPomBuilder implements ConsumerPomBuilder {
7756
private static final String BOM_PACKAGING = "bom";
7857

7958
public static final String POM_PACKAGING = "pom";
8059

81-
private final ProfileInjector profileInjector;
82-
private final InheritanceAssembler inheritanceAssembler;
83-
private final DependencyManagementImporter dependencyManagementImporter;
84-
private final DependencyManagementInjector dependencyManagementInjector;
8560
private final LifecycleBindingsInjector lifecycleBindingsInjector;
86-
private final ModelInterpolator modelInterpolator;
87-
private final ModelNormalizer modelNormalizer;
88-
private final ModelPathTranslator modelPathTranslator;
89-
private final ModelProcessor modelProcessor;
90-
private final ModelUrlNormalizer modelUrlNormalizer;
91-
private final ModelValidator modelValidator;
92-
private final PluginConfigurationExpander pluginConfigurationExpander;
93-
private final PluginManagementInjector pluginManagementInjector;
94-
private final SuperPomProvider superPomProvider;
95-
private final ModelVersionParser versionParser;
96-
private final ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator;
97-
private final List<ModelTransformer> transformers;
98-
private final ModelCacheFactory modelCacheFactory;
99-
private final ModelResolver modelResolver;
100-
private final Interpolator interpolator;
10161

10262
@Inject
10363
@SuppressWarnings("checkstyle:ParameterNumber")
104-
DefaultConsumerPomBuilder(
105-
ProfileInjector profileInjector,
106-
InheritanceAssembler inheritanceAssembler,
107-
DependencyManagementImporter dependencyManagementImporter,
108-
DependencyManagementInjector dependencyManagementInjector,
109-
LifecycleBindingsInjector lifecycleBindingsInjector,
110-
ModelInterpolator modelInterpolator,
111-
ModelNormalizer modelNormalizer,
112-
ModelPathTranslator modelPathTranslator,
113-
ModelProcessor modelProcessor,
114-
ModelUrlNormalizer modelUrlNormalizer,
115-
ModelValidator modelValidator,
116-
PluginConfigurationExpander pluginConfigurationExpander,
117-
PluginManagementInjector pluginManagementInjector,
118-
SuperPomProvider superPomProvider,
119-
ModelVersionParser versionParser,
120-
ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator,
121-
List<ModelTransformer> transformers,
122-
ModelCacheFactory modelCacheFactory,
123-
ModelResolver modelResolver,
124-
Interpolator interpolator) {
125-
this.profileInjector = profileInjector;
126-
this.inheritanceAssembler = inheritanceAssembler;
127-
this.dependencyManagementImporter = dependencyManagementImporter;
128-
this.dependencyManagementInjector = dependencyManagementInjector;
64+
DefaultConsumerPomBuilder(LifecycleBindingsInjector lifecycleBindingsInjector) {
12965
this.lifecycleBindingsInjector = lifecycleBindingsInjector;
130-
this.modelInterpolator = modelInterpolator;
131-
this.modelNormalizer = modelNormalizer;
132-
this.modelPathTranslator = modelPathTranslator;
133-
this.modelProcessor = modelProcessor;
134-
this.modelUrlNormalizer = modelUrlNormalizer;
135-
this.modelValidator = modelValidator;
136-
this.pluginConfigurationExpander = pluginConfigurationExpander;
137-
this.pluginManagementInjector = pluginManagementInjector;
138-
this.superPomProvider = superPomProvider;
139-
this.versionParser = versionParser;
140-
this.profileActivationFilePathInterpolator = profileActivationFilePathInterpolator;
141-
this.transformers = transformers;
142-
this.modelCacheFactory = modelCacheFactory;
143-
this.modelResolver = modelResolver;
144-
this.interpolator = interpolator;
14566
}
14667

147-
private final Logger logger = LoggerFactory.getLogger(getClass());
148-
14968
@Override
15069
public Model build(RepositorySystemSession session, MavenProject project, Path src) throws ModelBuilderException {
15170
Model model = project.getModel().getDelegate();
@@ -174,49 +93,18 @@ protected Model buildNonPom(RepositorySystemSession session, MavenProject projec
17493

17594
private ModelBuilderResult buildModel(RepositorySystemSession session, MavenProject project, Path src)
17695
throws ModelBuilderException {
177-
ProfileSelector customSelector = new DefaultProfileSelector() {
178-
@Override
179-
public List<Profile> getActiveProfiles(
180-
Collection<Profile> profiles, ProfileActivationContext context, ModelProblemCollector problems) {
181-
return new ArrayList<>();
182-
}
183-
};
184-
// TODO: the custom selector should be used as a flag on the request
185-
DefaultModelBuilder modelBuilder = new DefaultModelBuilder(
186-
modelProcessor,
187-
modelValidator,
188-
modelNormalizer,
189-
modelInterpolator,
190-
modelPathTranslator,
191-
modelUrlNormalizer,
192-
superPomProvider,
193-
inheritanceAssembler,
194-
customSelector,
195-
profileInjector,
196-
pluginManagementInjector,
197-
dependencyManagementInjector,
198-
dependencyManagementImporter,
199-
pluginConfigurationExpander,
200-
profileActivationFilePathInterpolator,
201-
versionParser,
202-
transformers,
203-
modelCacheFactory,
204-
modelResolver,
205-
interpolator);
20696
InternalSession iSession = InternalSession.from(session);
20797
ModelBuilderRequest.ModelBuilderRequestBuilder request = ModelBuilderRequest.builder();
208-
request.requestType(ModelBuilderRequest.RequestType.BUILD_POM);
98+
request.requestType(ModelBuilderRequest.RequestType.CONSUMER_POM);
20999
request.session(iSession);
210-
request.source(ModelSource.fromPath(src));
100+
// in order to resolve parents, we need to fake being at the correct location
101+
request.source(new PomConsumerModelSource(project.getModel().getPomPath(), src));
211102
request.locationTracking(false);
212103
request.systemProperties(session.getSystemProperties());
213104
request.userProperties(session.getUserProperties());
214105
request.lifecycleBindingsInjector(lifecycleBindingsInjector::injectLifecycleBindings);
215106
ModelBuilder.ModelBuilderSession mbSession =
216107
iSession.getData().get(SessionData.key(ModelBuilder.ModelBuilderSession.class));
217-
if (mbSession == null) {
218-
mbSession = modelBuilder.newSession();
219-
}
220108
return mbSession.build(request.build());
221109
}
222110

@@ -320,4 +208,63 @@ private static List<Repository> pruneRepositories(List<Repository> repositories)
320208
.filter(r -> !org.apache.maven.api.Repository.CENTRAL_ID.equals(r.getId()))
321209
.collect(Collectors.toList());
322210
}
211+
212+
static class PomConsumerModelSource implements ModelSource {
213+
final Path path;
214+
final Path src;
215+
216+
PomConsumerModelSource(Path path, Path src) {
217+
this.path = path;
218+
this.src = src;
219+
}
220+
221+
@Override
222+
public Path getPath() {
223+
return path;
224+
}
225+
226+
@Override
227+
public InputStream openStream() throws IOException {
228+
return Files.newInputStream(src);
229+
}
230+
231+
@Override
232+
public String getLocation() {
233+
return src.toString();
234+
}
235+
236+
@Override
237+
public Source resolve(String relative) {
238+
return ModelSource.fromPath(path.resolve(relative));
239+
}
240+
241+
@Override
242+
public ModelSource resolve(ModelLocator locator, String relative) {
243+
String norm = relative.replace('\\', File.separatorChar).replace('/', File.separatorChar);
244+
Path path = getPath().getParent().resolve(norm);
245+
Path relatedPom = locator.locateExistingPom(path);
246+
if (relatedPom != null) {
247+
return ModelSource.fromPath(relatedPom);
248+
}
249+
return null;
250+
}
251+
252+
@Override
253+
public boolean equals(Object o) {
254+
return this == o
255+
|| o.getClass() == getClass()
256+
&& Objects.equals(path, ((PomConsumerModelSource) o).path)
257+
&& Objects.equals(src, ((PomConsumerModelSource) o).src);
258+
}
259+
260+
@Override
261+
public int hashCode() {
262+
return Objects.hash(path, src);
263+
}
264+
265+
@Override
266+
public String toString() {
267+
return "PomConsumerModelSource[" + "path=" + path + ']';
268+
}
269+
}
323270
}

maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
import org.apache.maven.bridge.MavenRepositorySystem;
7575
import org.apache.maven.internal.impl.InternalSession;
7676
import org.apache.maven.internal.impl.resolver.ArtifactDescriptorUtils;
77+
import org.apache.maven.model.building.DefaultModelProblem;
7778
import org.apache.maven.model.building.FileModelSource;
7879
import org.apache.maven.model.building.ModelBuildingRequest;
7980
import org.apache.maven.model.building.ModelSource2;
@@ -499,6 +500,11 @@ private List<ProjectBuildingResult> build(File pomFile, boolean recursive) {
499500
List<ProjectBuildingResult> results = new ArrayList<>();
500501
List<ModelBuilderResult> allModels = results(result).toList();
501502
for (ModelBuilderResult r : allModels) {
503+
List<ModelProblem> problems = new ArrayList<>(r.getProblems());
504+
results(r)
505+
.filter(c -> c != r)
506+
.flatMap(c -> c.getProblems().stream())
507+
.forEach(problems::remove);
502508
if (r.getEffectiveModel() != null) {
503509
File pom = r.getSource().getPath().toFile();
504510
MavenProject project =
@@ -510,18 +516,17 @@ private List<ProjectBuildingResult> build(File pomFile, boolean recursive) {
510516
project.setExecutionRoot(pom.equals(pomFile));
511517
initProject(project, r);
512518
project.setCollectedProjects(results(r)
513-
.filter(cr -> cr != r)
519+
.filter(cr -> cr != r && cr.getEffectiveModel() != null)
514520
.map(cr -> projectIndex.get(cr.getEffectiveModel().getId()))
515521
.collect(Collectors.toList()));
516522

517523
DependencyResolutionResult resolutionResult = null;
518524
if (request.isResolveDependencies()) {
519525
resolutionResult = resolveDependencies(project);
520526
}
521-
results.add(
522-
new DefaultProjectBuildingResult(project, convert(result.getProblems()), resolutionResult));
527+
results.add(new DefaultProjectBuildingResult(project, convert(problems), resolutionResult));
523528
} else {
524-
results.add(new DefaultProjectBuildingResult(null, convert(result.getProblems()), null));
529+
results.add(new DefaultProjectBuildingResult(null, convert(problems), null));
525530
}
526531
}
527532
return results;
@@ -535,20 +540,21 @@ private List<org.apache.maven.model.building.ModelProblem> convert(List<ModelPro
535540
if (problems == null) {
536541
return null;
537542
}
538-
return problems.stream()
539-
.map(p -> (org.apache.maven.model.building.ModelProblem)
540-
new org.apache.maven.model.building.DefaultModelProblem(
541-
p.getMessage(),
542-
org.apache.maven.model.building.ModelProblem.Severity.valueOf(
543-
p.getSeverity().name()),
544-
org.apache.maven.model.building.ModelProblem.Version.valueOf(
545-
p.getVersion().name()),
546-
p.getSource(),
547-
p.getLineNumber(),
548-
p.getColumnNumber(),
549-
p.getModelId(),
550-
p.getException()))
551-
.toList();
543+
return problems.stream().map(p -> convert(p)).toList();
544+
}
545+
546+
private static org.apache.maven.model.building.ModelProblem convert(ModelProblem p) {
547+
return new DefaultModelProblem(
548+
p.getMessage(),
549+
org.apache.maven.model.building.ModelProblem.Severity.valueOf(
550+
p.getSeverity().name()),
551+
org.apache.maven.model.building.ModelProblem.Version.valueOf(
552+
p.getVersion().name()),
553+
p.getSource(),
554+
p.getLineNumber(),
555+
p.getColumnNumber(),
556+
p.getModelId(),
557+
p.getException());
552558
}
553559

554560
@SuppressWarnings({"checkstyle:methodlength", "deprecation"})

0 commit comments

Comments
 (0)