Skip to content

Commit b370e5e

Browse files
gnodetdesruisseaux
andauthored
[MNG-8210] Replace Maven "module" term by "subproject" (#1651)
Co-authored-by: Martin Desruisseaux <[email protected]>
1 parent e11b475 commit b370e5e

File tree

25 files changed

+231
-74
lines changed

25 files changed

+231
-74
lines changed

api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/Mojo.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@
7676
boolean projectRequired() default true;
7777

7878
/**
79-
* if the Mojo uses the Maven project and its child modules.
80-
* @return uses the Maven project and its child modules
79+
* if the Mojo uses the Maven project and its subprojects.
80+
* @return uses the Maven project and its subprojects
8181
*/
8282
boolean aggregator() default false;
8383

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@
2525

2626
public interface ModelBuilder extends Service {
2727

28-
List<String> VALID_MODEL_VERSIONS = List.of("4.0.0", "4.1.0");
28+
String MODEL_VERSION_4_0_0 = "4.0.0";
29+
30+
String MODEL_VERSION_4_1_0 = "4.1.0";
31+
32+
List<String> VALID_MODEL_VERSIONS = List.of(MODEL_VERSION_4_0_0, MODEL_VERSION_4_1_0);
2933

3034
ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilderException;
3135

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ enum Version {
3535
V20,
3636
V30,
3737
V31,
38-
V40
38+
V40,
39+
V41
3940
}
4041

4142
/**

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
/**
2929
* A Source specific to load POMs. The {@link #resolve(ModelLocator, String)} method
30-
* will be used to find POMs for children modules.
30+
* will be used to find POMs for subprojects.
3131
*
3232
* @since 4.0.0
3333
*/

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

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@
313313
<!-- SCM -->
314314
<!-- ====================================================================== -->
315315

316-
<field xdoc.separator="blank" xml.insertParentFieldsUpTo="modules">
316+
<field xdoc.separator="blank" xml.insertParentFieldsUpTo="subprojects">
317317
<name>scm</name>
318318
<version>4.0.0+</version>
319319
<description>Specification for the SCM used by the project, such as CVS, Subversion, etc.</description>
@@ -527,11 +527,25 @@
527527
<fields>
528528
<field xdoc.separator="blank">
529529
<name>modules</name>
530-
<version>4.0.0+</version>
531-
<description>The modules (sometimes called subprojects) to build as a part of this
532-
project. Each module listed is a relative path to the directory containing the module.
533-
To be consistent with the way default urls are calculated from parent, it is recommended
534-
to have module names match artifact ids.</description>
530+
<version>4.0.0/4.1.0</version>
531+
<description>
532+
@deprecated Use {@link #subprojects} instead.
533+
</description>
534+
<association>
535+
<type>String</type>
536+
<multiplicity>*</multiplicity>
537+
</association>
538+
<annotations>
539+
<annotation>@Deprecated</annotation>
540+
</annotations>
541+
</field>
542+
<field xdoc.separator="blank">
543+
<name>subprojects</name>
544+
<version>4.1.0</version>
545+
<description>The subprojects (formerly called modules) to build as a part of this
546+
project. Each subproject listed is a relative path to the directory containing the subproject.
547+
To be consistent with the way default URLs are calculated from parent, it is recommended
548+
to have subproject names match artifact ids.</description>
535549
<association>
536550
<type>String</type>
537551
<multiplicity>*</multiplicity>
@@ -755,8 +769,8 @@
755769
<name>defaultGoal</name>
756770
<version>3.0.0+</version>
757771
<description>The default goal (or phase in Maven 2) to execute when none is specified for
758-
the project. Note that in case of a multi-module build, only the default goal of the top-level
759-
project is relevant, i.e. the default goals of child modules are ignored. Since Maven 3,
772+
the project. Note that in case of a build with subprojects, only the default goal of the top-level
773+
project is relevant, i.e. the default goals of subprojects are ignored. Since Maven 3,
760774
multiple goals/phases can be separated by whitespace.</description>
761775
<type>String</type>
762776
</field>

maven-api-impl/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ under the License.
2929
<name>Maven API Implementation</name>
3030
<description>Provides the implementation classes for the Maven API</description>
3131

32+
<properties>
33+
<!-- in: DefaultModelValidator, DefaultModelBuilder -->
34+
<checkstyle.violation.ignore>FileLength</checkstyle.violation.ignore>
35+
</properties>
36+
3237
<dependencies>
3338
<dependency>
3439
<groupId>org.apache.maven</groupId>

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

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.io.IOException;
2222
import java.io.InputStream;
2323
import java.lang.reflect.Field;
24+
import java.nio.file.Files;
2425
import java.nio.file.Path;
2526
import java.util.ArrayList;
2627
import java.util.Collection;
@@ -40,6 +41,7 @@
4041
import java.util.stream.Stream;
4142

4243
import org.apache.maven.api.Session;
44+
import org.apache.maven.api.Type;
4345
import org.apache.maven.api.VersionRange;
4446
import org.apache.maven.api.annotations.Nullable;
4547
import org.apache.maven.api.di.Inject;
@@ -305,7 +307,7 @@ private Model readEffectiveModel(
305307
// Maven 3.x is always using 4.0.0 version to load the supermodel, so
306308
// do the same when loading a dependency. The model validator will also
307309
// check that field later.
308-
superModelVersion = "4.0.0";
310+
superModelVersion = MODEL_VERSION_4_0_0;
309311
}
310312
ModelData superData = new ModelData(null, getSuperModel(superModelVersion));
311313

@@ -737,6 +739,32 @@ private Model doReadFileModel(
737739

738740
if (modelSource.getPath() != null) {
739741
model = model.withPomFile(modelSource.getPath());
742+
743+
// subprojects discovery
744+
if (model.getSubprojects().isEmpty()
745+
&& model.getModules().isEmpty()
746+
// only discover subprojects if POM > 4.0.0
747+
&& !MODEL_VERSION_4_0_0.equals(model.getModelVersion())
748+
// and if packaging is POM (we check type, but the session is not yet available,
749+
// we would require the project realm if we want to support extensions
750+
&& Type.POM.equals(model.getPackaging())) {
751+
List<String> subprojects = new ArrayList<>();
752+
try (Stream<Path> files = Files.list(model.getProjectDirectory())) {
753+
for (Path f : files.toList()) {
754+
if (Files.isDirectory(f)) {
755+
Path subproject = modelProcessor.locateExistingPom(f);
756+
if (subproject != null) {
757+
subprojects.add(f.getFileName().toString());
758+
}
759+
}
760+
}
761+
if (!subprojects.isEmpty()) {
762+
model = model.withSubprojects(subprojects);
763+
}
764+
} catch (IOException e) {
765+
problems.add(Severity.FATAL, ModelProblem.Version.V41, "Error discovering subprojects", e);
766+
}
767+
}
740768
}
741769

742770
problems.setSource(model);

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -151,12 +151,16 @@ private void doLoadFullReactor() {
151151
ModelBuilderRequest gaBuildingRequest =
152152
ModelBuilderRequest.build(request, ModelSource.fromPath(pom));
153153
Model rawModel = defaultModelBuilder.readFileModel(gaBuildingRequest, problems);
154-
for (String module : rawModel.getModules()) {
155-
Path moduleFile = defaultModelBuilder
154+
List<String> subprojects = rawModel.getSubprojects();
155+
if (subprojects == null) {
156+
subprojects = rawModel.getModules();
157+
}
158+
for (String subproject : subprojects) {
159+
Path subprojectFile = defaultModelBuilder
156160
.getModelProcessor()
157-
.locateExistingPom(pom.getParent().resolve(module));
158-
if (moduleFile != null) {
159-
toLoad.add(moduleFile);
161+
.locateExistingPom(pom.getParent().resolve(subproject));
162+
if (subprojectFile != null) {
163+
toLoad.add(subprojectFile);
160164
}
161165
}
162166
} catch (ModelBuilderException e) {

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

Lines changed: 63 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
import java.io.File;
2222
import java.util.Arrays;
23-
import java.util.Collections;
2423
import java.util.Deque;
2524
import java.util.HashMap;
2625
import java.util.HashSet;
@@ -65,6 +64,7 @@
6564
import org.apache.maven.api.model.Repository;
6665
import org.apache.maven.api.model.Resource;
6766
import org.apache.maven.api.services.BuilderProblem.Severity;
67+
import org.apache.maven.api.services.ModelBuilder;
6868
import org.apache.maven.api.services.ModelBuilderRequest;
6969
import org.apache.maven.api.services.ModelProblem.Version;
7070
import org.apache.maven.api.services.ModelProblemCollector;
@@ -73,6 +73,8 @@
7373
import org.apache.maven.model.v4.MavenModelVersion;
7474
import org.apache.maven.model.v4.MavenTransformer;
7575

76+
import static org.apache.maven.internal.impl.model.DefaultModelBuilder.NAMESPACE_PREFIX;
77+
7678
/**
7779
*/
7880
@Named
@@ -81,8 +83,7 @@ public class DefaultModelValidator implements ModelValidator {
8183
public static final String BUILD_ALLOW_EXPRESSION_IN_EFFECTIVE_PROJECT_VERSION =
8284
"maven.build.allowExpressionInEffectiveProjectVersion";
8385

84-
public static final List<String> VALID_MODEL_VERSIONS =
85-
Collections.unmodifiableList(Arrays.asList("4.0.0", "4.1.0"));
86+
public static final List<String> VALID_MODEL_VERSIONS = ModelBuilder.VALID_MODEL_VERSIONS;
8687

8788
private static final Pattern EXPRESSION_NAME_PATTERN = Pattern.compile("\\$\\{(.+?)}");
8889
private static final Pattern EXPRESSION_PROJECT_NAME_PATTERN = Pattern.compile("\\$\\{(project.+?)}");
@@ -136,7 +137,6 @@ protected Activation.Builder transformActivation_ActiveByDefault(
136137
protected Activation.Builder transformActivation_File(
137138
Supplier<? extends Activation.Builder> creator, Activation.Builder builder, Activation target) {
138139
stk.push(nextFrame("file", Activation::getFile));
139-
Optional.ofNullable(target.getFile());
140140
try {
141141
return super.transformActivation_File(creator, builder, target);
142142
} finally {
@@ -335,7 +335,7 @@ public void validateFileModel(Model m, ModelBuilderRequest request, ModelProblem
335335
if (request.getValidationLevel() == ModelBuilderRequest.VALIDATION_LEVEL_MINIMAL) {
336336
// profiles: they are essential for proper model building (may contribute profiles, dependencies...)
337337
HashSet<String> minProfileIds = new HashSet<>();
338-
for (org.apache.maven.api.model.Profile profile : m.getProfiles()) {
338+
for (Profile profile : m.getProfiles()) {
339339
if (!minProfileIds.add(profile.getId())) {
340340
addViolation(
341341
problems,
@@ -362,6 +362,61 @@ public void validateFileModel(Model m, ModelBuilderRequest request, ModelProblem
362362
m.getLocation("modules"));
363363
}
364364
}
365+
String modelVersion = m.getModelVersion();
366+
if (modelVersion == null) {
367+
String namespace = m.getNamespaceUri();
368+
if (namespace != null && namespace.startsWith(NAMESPACE_PREFIX)) {
369+
modelVersion = namespace.substring(NAMESPACE_PREFIX.length());
370+
}
371+
}
372+
if (Objects.equals(modelVersion, ModelBuilder.MODEL_VERSION_4_0_0)) {
373+
if (!m.getSubprojects().isEmpty()) {
374+
addViolation(
375+
problems,
376+
Severity.ERROR,
377+
Version.V40,
378+
"subprojects",
379+
null,
380+
"unexpected subprojects element",
381+
m.getLocation("subprojects"));
382+
}
383+
} else {
384+
Set<String> subprojects = new HashSet<>();
385+
for (int i = 0, n = m.getSubprojects().size(); i < n; i++) {
386+
String subproject = m.getSubprojects().get(i);
387+
if (!subprojects.add(subproject)) {
388+
addViolation(
389+
problems,
390+
Severity.ERROR,
391+
Version.V41,
392+
"subprojects.subproject[" + i + "]",
393+
null,
394+
"specifies duplicate subproject " + subproject,
395+
m.getLocation("subprojects"));
396+
}
397+
}
398+
if (!modules.isEmpty()) {
399+
if (subprojects.isEmpty()) {
400+
addViolation(
401+
problems,
402+
Severity.WARNING,
403+
Version.V41,
404+
"modules",
405+
null,
406+
"deprecated modules element, use subprojects instead",
407+
m.getLocation("modules"));
408+
} else {
409+
addViolation(
410+
problems,
411+
Severity.ERROR,
412+
Version.V41,
413+
"modules",
414+
null,
415+
"cannot use both modules and subprojects element",
416+
m.getLocation("modules"));
417+
}
418+
}
419+
}
365420

366421
Severity errOn30 = getSeverity(request, ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_3_0);
367422

@@ -928,7 +983,7 @@ private void validate20RawDependencies(
928983

929984
private void validate20RawDependenciesSelfReferencing(
930985
ModelProblemCollector problems,
931-
org.apache.maven.api.model.Model m,
986+
Model m,
932987
List<Dependency> dependencies,
933988
String prefix,
934989
ModelBuilderRequest request) {
@@ -959,7 +1014,7 @@ private void validate20RawDependenciesSelfReferencing(
9591014

9601015
private void validateEffectiveDependencies(
9611016
ModelProblemCollector problems,
962-
org.apache.maven.api.model.Model m,
1017+
Model m,
9631018
List<Dependency> dependencies,
9641019
boolean management,
9651020
ModelBuilderRequest request) {
@@ -1020,11 +1075,7 @@ private void validateEffectiveDependencies(
10201075
}
10211076

10221077
private void validateEffectiveModelAgainstDependency(
1023-
String prefix,
1024-
ModelProblemCollector problems,
1025-
org.apache.maven.api.model.Model m,
1026-
Dependency d,
1027-
ModelBuilderRequest request) {
1078+
String prefix, ModelProblemCollector problems, Model m, Dependency d, ModelBuilderRequest request) {
10281079
String key = d.getGroupId() + ":" + d.getArtifactId() + ":" + d.getVersion()
10291080
+ (d.getClassifier() != null ? ":" + d.getClassifier() : EMPTY);
10301081
String mKey = m.getGroupId() + ":" + m.getArtifactId() + ":" + m.getVersion();

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ static Model transform(Model model, MavenProject project) {
225225
String packaging = model.getPackaging();
226226
if (POM_PACKAGING.equals(packaging)) {
227227
// raw to consumer transform
228-
model = model.withRoot(false).withModules(null);
228+
model = model.withRoot(false).withModules(null).withSubprojects(null);
229229
if (model.getParent() != null) {
230230
model = model.withParent(model.getParent().withRelativePath(null));
231231
}
@@ -294,6 +294,7 @@ private static boolean isEmpty(Profile profile) {
294294
|| profile.getDependencyManagement().getDependencies().isEmpty())
295295
&& profile.getDistributionManagement() == null
296296
&& profile.getModules().isEmpty()
297+
&& profile.getSubprojects().isEmpty()
297298
&& profile.getProperties().isEmpty()
298299
&& profile.getRepositories().isEmpty()
299300
&& profile.getPluginRepositories().isEmpty()

0 commit comments

Comments
 (0)