Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MNG-8210] Replace Maven "module" term by "subproject" #1651

Merged
merged 5 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@
boolean projectRequired() default true;

/**
* if the Mojo uses the Maven project and its child modules.
* @return uses the Maven project and its child modules
* if the Mojo uses the Maven project and its subprojects.
* @return uses the Maven project and its subprojectss
gnodet marked this conversation as resolved.
Show resolved Hide resolved
*/
boolean aggregator() default false;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@

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";
gnodet marked this conversation as resolved.
Show resolved Hide resolved

List<String> VALID_MODEL_VERSIONS = List.of(MODEL_VERSION_4_0_0, MODEL_VERSION_4_1_0);

ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilderException;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ enum Version {
V20,
V30,
V31,
V40
V40,
V41
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

/**
* A Source specific to load POMs. The {@link #resolve(ModelLocator, String)} method
* will be used to find POMs for children modules.
* will be used to find POMs for subprojects.
*
* @since 4.0.0
*/
Expand Down
25 changes: 18 additions & 7 deletions api/maven-api-model/src/main/mdo/maven.mdo
Original file line number Diff line number Diff line change
Expand Up @@ -527,11 +527,22 @@
<fields>
<field xdoc.separator="blank">
<name>modules</name>
<version>4.0.0+</version>
<description>The modules (sometimes called subprojects) to build as a part of this
project. Each module listed is a relative path to the directory containing the module.
To be consistent with the way default urls are calculated from parent, it is recommended
to have module names match artifact ids.</description>
<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
to have subproject names match artifact ids.</description>
<association>
<type>String</type>
<multiplicity>*</multiplicity>
Expand Down Expand Up @@ -755,8 +766,8 @@
<name>defaultGoal</name>
<version>3.0.0+</version>
<description>The default goal (or phase in Maven 2) to execute when none is specified for
the project. Note that in case of a multi-module build, only the default goal of the top-level
project is relevant, i.e. the default goals of child modules are ignored. Since Maven 3,
the project. Note that in case of a build with subprojects, only the default goal of the top-level
project is relevant, i.e. the default goals of subprojects are ignored. Since Maven 3,
multiple goals/phases can be separated by whitespace.</description>
<type>String</type>
</field>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
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;
Expand All @@ -40,6 +41,7 @@
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;
Expand Down Expand Up @@ -305,7 +307,7 @@ private Model readEffectiveModel(
// 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));

Expand Down Expand Up @@ -737,6 +739,32 @@ private Model doReadFileModel(

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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,10 @@ public void validateEffectiveModel(Model m, ModelBuilderRequest request, ModelPr

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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ private static boolean isEmpty(Profile profile) {
|| profile.getDependencyManagement().getDependencies().isEmpty())
&& profile.getDistributionManagement() == null
&& profile.getModules().isEmpty()
&& profile.getSubprojects().isEmpty()
&& profile.getProperties().isEmpty()
&& profile.getRepositories().isEmpty()
&& profile.getPluginRepositories().isEmpty()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@
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";
gnodet marked this conversation as resolved.
Show resolved Hide resolved

private final Logger logger = LoggerFactory.getLogger(getClass());
private final ModelBuilder modelBuilder;
Expand Down Expand Up @@ -275,7 +276,7 @@ static class InterimResult {

boolean root;

List<InterimResult> modules = Collections.emptyList();
List<InterimResult> subprojects = Collections.emptyList();

ProjectBuildingResult projectBuildingResult;

Expand Down Expand Up @@ -629,20 +630,24 @@ private InterimResult build(

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,
Expand All @@ -656,23 +661,24 @@ private InterimResult build(
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,
Expand All @@ -684,11 +690,11 @@ private InterimResult build(
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);
}
}

Expand Down Expand Up @@ -780,7 +786,7 @@ private List<ProjectBuildingResult> doBuild(Map<File, MavenProject> projectIndex
iarte));
}

List<ProjectBuildingResult> results = build(projectIndex, interimResult.modules);
List<ProjectBuildingResult> results = build(projectIndex, interimResult.subprojects);

project.setExecutionRoot(interimResult.root);
project.setCollectedProjects(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,9 @@ public List<Plugin> getBuildPlugins() {
}

public List<String> getModules() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deprecate it? Or maybe does not matter, as in API 4 plugins have no reach to this class?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I was assuming this change targets 4.x api and plugins, so I would not care about the v3 api.

if (!getModel().getDelegate().getSubprojects().isEmpty()) {
return getModel().getDelegate().getSubprojects();
}
return getModel().getModules();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -405,4 +405,18 @@ public void testBuildParentVersionRangeExternallyWithChildRevisionExpression() t

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());
}
}
Original file line number Diff line number Diff line change
@@ -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>
Original file line number Diff line number Diff line change
@@ -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>