This is an automated email from the ASF dual-hosted git repository. gnodet pushed a commit to branch subprojects in repository https://gitbox.apache.org/repos/asf/maven.git
commit 89cd556e1555a5a2db8badaec8d7e271f0ae2ca6 Author: Guillaume Nodet <[email protected]> AuthorDate: Sun Aug 11 23:37:18 2024 +0200 Introduce subprojects, deprecate modules, discover subprojects --- .../apache/maven/api/services/ModelBuilder.java | 6 ++- .../apache/maven/api/services/ModelProblem.java | 3 +- api/maven-api-model/src/main/mdo/maven.mdo | 13 ++++++- .../internal/impl/model/DefaultModelBuilder.java | 30 ++++++++++++++- .../internal/impl/model/DefaultModelValidator.java | 4 ++ .../impl/DefaultConsumerPomBuilder.java | 1 + .../maven/project/DefaultProjectBuilder.java | 44 ++++++++++++---------- .../org/apache/maven/project/MavenProject.java | 3 ++ .../project/DefaultMavenProjectBuilderTest.java | 14 +++++++ .../projects/subprojects-discover/child/pom.xml | 8 ++++ .../projects/subprojects-discover/pom.xml | 6 +++ 11 files changed, 109 insertions(+), 23 deletions(-) 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 aa828d349d..236b31db4c 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 @@ -25,7 +25,11 @@ import org.apache.maven.api.model.Model; public interface ModelBuilder extends Service { - List<String> VALID_MODEL_VERSIONS = List.of("4.0.0", "4.1.0"); + String MODEL_VERSION_4_0_0 = "4.0.0"; + + String MODEL_VERSION_4_1_0 = "4.0.0"; + + List<String> VALID_MODEL_VERSIONS = List.of(MODEL_VERSION_4_0_0, MODEL_VERSION_4_1_0); ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilderException; 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 0e20dbee98..f15fe0db01 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 @@ -35,7 +35,8 @@ public interface ModelProblem extends BuilderProblem { V20, V30, V31, - V40 + V40, + V41 } /** diff --git a/api/maven-api-model/src/main/mdo/maven.mdo b/api/maven-api-model/src/main/mdo/maven.mdo index 5b22bc9194..54894b3692 100644 --- a/api/maven-api-model/src/main/mdo/maven.mdo +++ b/api/maven-api-model/src/main/mdo/maven.mdo @@ -527,7 +527,18 @@ <fields> <field xdoc.separator="blank"> <name>modules</name> - <version>4.0.0+</version> + <version>4.0.0/4.1.0</version> + <description> + @deprecated Use {@link #subprojects} instead. + </description> + <association> + <type>String</type> + <multiplicity>*</multiplicity> + </association> + </field> + <field xdoc.separator="blank"> + <name>subprojects</name> + <version>4.1.0</version> <description>The subprojects (formerly called modules) to build as a part of this project. Each subproject listed is a relative path to the directory containing the subproject. To be consistent with the way default URLs are calculated from parent, it is recommended 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 c723950e61..3839704d46 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 @@ -21,6 +21,7 @@ package org.apache.maven.internal.impl.model; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; +import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; @@ -40,6 +41,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.maven.api.Session; +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; @@ -305,7 +307,7 @@ public class DefaultModelBuilder implements ModelBuilder { // 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 = "4.0.0"; + superModelVersion = MODEL_VERSION_4_0_0; } ModelData superData = new ModelData(null, getSuperModel(superModelVersion)); @@ -737,6 +739,32 @@ public class DefaultModelBuilder implements ModelBuilder { if (modelSource.getPath() != null) { model = model.withPomFile(modelSource.getPath()); + + // 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<String> subprojects = new ArrayList<>(); + try (Stream<Path> 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) { + problems.add(Severity.FATAL, ModelProblem.Version.V41, "Error discovering subprojects", e); + } + } } problems.setSource(model); 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 30dab0bd7c..5a0912536b 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 @@ -644,6 +644,10 @@ public class DefaultModelValidator implements ModelValidator { validateStringNotEmpty("packaging", problems, Severity.ERROR, Version.BASE, m.getPackaging(), m); + // TODO: if the model is a 4.1.0: + // * modules should be empty, else issue a warning + // * validate subprojects + if (!m.getModules().isEmpty()) { if (!"pom".equals(m.getPackaging())) { addViolation( 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 c0ef5bcf3e..dbf7be1afb 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 @@ -294,6 +294,7 @@ class DefaultConsumerPomBuilder implements ConsumerPomBuilder { || profile.getDependencyManagement().getDependencies().isEmpty()) && profile.getDistributionManagement() == null && profile.getModules().isEmpty() + && profile.getSubprojects().isEmpty() && profile.getProperties().isEmpty() && profile.getRepositories().isEmpty() && profile.getPluginRepositories().isEmpty() 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 ddd26688bc..a6dae088e5 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 @@ -121,6 +121,7 @@ import org.slf4j.LoggerFactory; public class DefaultProjectBuilder implements ProjectBuilder { public static final String BUILDER_PARALLELISM = "maven.projectBuilder.parallelism"; public static final int DEFAULT_BUILDER_PARALLELISM = Runtime.getRuntime().availableProcessors() / 2 + 1; + private static final String POM_4_0_0 = "4.0.0"; private final Logger logger = LoggerFactory.getLogger(getClass()); private final ModelBuilder modelBuilder; @@ -275,7 +276,7 @@ public class DefaultProjectBuilder implements ProjectBuilder { boolean root; - List<InterimResult> modules = Collections.emptyList(); + List<InterimResult> subprojects = Collections.emptyList(); ProjectBuildingResult projectBuildingResult; @@ -629,20 +630,24 @@ public class DefaultProjectBuilder implements ProjectBuilder { if (recursive) { File basedir = pomFile.getParentFile(); - List<File> moduleFiles = new ArrayList<>(); - for (String module : model.getModules()) { - if (module == null || module.isEmpty()) { + List<String> subprojects = model.getSubprojects(); + if (subprojects.isEmpty()) { + subprojects = model.getModules(); + } + List<File> subprojectFiles = new ArrayList<>(); + for (String subproject : subprojects) { + if (subproject == null || subproject.isEmpty()) { continue; } - module = module.replace('\\', File.separatorChar).replace('/', File.separatorChar); + subproject = subproject.replace('\\', File.separatorChar).replace('/', File.separatorChar); - Path modulePath = modelProcessor.locateExistingPom(new File(basedir, module).toPath()); - File moduleFile = modulePath != null ? modulePath.toFile() : null; + Path subprojectPath = modelProcessor.locateExistingPom(new File(basedir, subproject).toPath()); + File subprojectFile = subprojectPath != null ? subprojectPath.toFile() : null; - if (moduleFile == null) { + if (subprojectFile == null) { ModelProblem problem = new org.apache.maven.internal.impl.model.DefaultModelProblem( - "Child module " + moduleFile + " of " + pomFile + " does not exist", + "Child subproject " + subprojectFile + " of " + pomFile + " does not exist", ModelProblem.Severity.ERROR, ModelProblem.Version.BASE, model, @@ -656,23 +661,24 @@ public class DefaultProjectBuilder implements ProjectBuilder { if (Os.IS_WINDOWS) { // we don't canonicalize on unix to avoid interfering with symlinks try { - moduleFile = moduleFile.getCanonicalFile(); + subprojectFile = subprojectFile.getCanonicalFile(); } catch (IOException e) { - moduleFile = moduleFile.getAbsoluteFile(); + subprojectFile = subprojectFile.getAbsoluteFile(); } } else { - moduleFile = new File(moduleFile.toURI().normalize()); + subprojectFile = new File(subprojectFile.toURI().normalize()); } - if (aggregatorFiles.contains(moduleFile)) { + if (aggregatorFiles.contains(subprojectFile)) { StringBuilder buffer = new StringBuilder(256); for (File aggregatorFile : aggregatorFiles) { buffer.append(aggregatorFile).append(" -> "); } - buffer.append(moduleFile); + buffer.append(subprojectFile); ModelProblem problem = new org.apache.maven.internal.impl.model.DefaultModelProblem( - "Child module " + moduleFile + " of " + pomFile + " forms aggregation cycle " + buffer, + "Child subproject " + subprojectFile + " of " + pomFile + " forms aggregation cycle " + + buffer, ModelProblem.Severity.ERROR, ModelProblem.Version.BASE, model, @@ -684,11 +690,11 @@ public class DefaultProjectBuilder implements ProjectBuilder { continue; } - moduleFiles.add(moduleFile); + subprojectFiles.add(subprojectFile); } - if (!moduleFiles.isEmpty()) { - interimResult.modules = build(projectIndex, moduleFiles, aggregatorFiles, false, recursive); + if (!subprojectFiles.isEmpty()) { + interimResult.subprojects = build(projectIndex, subprojectFiles, aggregatorFiles, false, recursive); } } @@ -780,7 +786,7 @@ public class DefaultProjectBuilder implements ProjectBuilder { iarte)); } - List<ProjectBuildingResult> results = build(projectIndex, interimResult.modules); + List<ProjectBuildingResult> results = build(projectIndex, interimResult.subprojects); project.setExecutionRoot(interimResult.root); project.setCollectedProjects( diff --git a/maven-core/src/main/java/org/apache/maven/project/MavenProject.java b/maven-core/src/main/java/org/apache/maven/project/MavenProject.java index 42b08f5288..e155609de5 100644 --- a/maven-core/src/main/java/org/apache/maven/project/MavenProject.java +++ b/maven-core/src/main/java/org/apache/maven/project/MavenProject.java @@ -708,6 +708,9 @@ public class MavenProject implements Cloneable { } public List<String> getModules() { + if (!getModel().getDelegate().getSubprojects().isEmpty()) { + return getModel().getDelegate().getSubprojects(); + } return getModel().getModules(); } 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 97152f5e4e..116d8a88cd 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 @@ -405,4 +405,18 @@ class DefaultMavenProjectBuilderTest extends AbstractMavenProjectTestCase { assertEquals("1.0-SNAPSHOT", mp.getVersion()); } + + @Test + public void testSubprojectDiscovery() throws Exception { + File pom = getTestFile("src/test/resources/projects/subprojects-discover/pom.xml"); + ProjectBuildingRequest configuration = newBuildingRequest(); + + List<ProjectBuildingResult> results = projectBuilder.build(List.of(pom), true, configuration); + assertEquals(2, results.size()); + MavenProject p1 = results.get(0).getProject(); + MavenProject p2 = results.get(1).getProject(); + MavenProject parent = p1.getArtifactId().equals("parent") ? p1 : p2; + MavenProject child = p1.getArtifactId().equals("parent") ? p2 : p1; + assertEquals(List.of("child"), parent.getModel().getDelegate().getSubprojects()); + } } diff --git a/maven-core/src/test/resources/projects/subprojects-discover/child/pom.xml b/maven-core/src/test/resources/projects/subprojects-discover/child/pom.xml new file mode 100644 index 0000000000..4ec6c2320f --- /dev/null +++ b/maven-core/src/test/resources/projects/subprojects-discover/child/pom.xml @@ -0,0 +1,8 @@ +<project xmlns="http://maven.apache.org/POM/4.1.0"> + <parent> + <groupId>subprojects-discover</groupId> + <artifactId>parent</artifactId> + </parent> + <artifactId>child</artifactId> + <packaging>jar</packaging> +</project> diff --git a/maven-core/src/test/resources/projects/subprojects-discover/pom.xml b/maven-core/src/test/resources/projects/subprojects-discover/pom.xml new file mode 100644 index 0000000000..6567ad58f2 --- /dev/null +++ b/maven-core/src/test/resources/projects/subprojects-discover/pom.xml @@ -0,0 +1,6 @@ +<project xmlns="http://maven.apache.org/POM/4.1.0"> + <groupId>subprojects-discover</groupId> + <artifactId>parent</artifactId> + <version>1</version> + <packaging>pom</packaging> +</project>
