This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to branch maven-4.0.x in repository https://gitbox.apache.org/repos/asf/maven.git
commit 00a83b6a944ea05db889a6d5cc9f565856fed152 Author: Martin Desruisseaux <[email protected]> AuthorDate: Sat Oct 25 17:08:29 2025 +0200 When the value of `<targetPath>` is a relative directory, the specification in `maven.mdo` requires that we resolve against `${project.build.outputDirectory}`, which is not `baseDir`. Also modify the specification for resolving against `${project.build.testOutputDirectory}` if the scope is test and `${project.build.directory}` is the scope is neither main or test. Add a `Project.getOutputDirectory(ProjectScope)` for avoiding the need to repeat the same code in the plugins. --- .../main/java/org/apache/maven/api/Project.java | 30 ++++++++ .../main/java/org/apache/maven/api/SourceRoot.java | 23 ++++++ .../java/org/apache/maven/api/SourceRootTest.java | 89 ++++++++++++++++++++++ api/maven-api-model/src/main/mdo/maven.mdo | 12 ++- .../maven/project/DefaultProjectBuilder.java | 12 ++- .../org/apache/maven/impl/DefaultSourceRoot.java | 16 ++-- .../apache/maven/impl/DefaultSourceRootTest.java | 65 +++++++++++++++- 7 files changed, 237 insertions(+), 10 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 8e989ad4ae..2fb4f4f7ba 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 @@ -24,6 +24,7 @@ import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.annotations.Nullable; import org.apache.maven.api.model.Build; import org.apache.maven.api.model.Model; import org.apache.maven.api.model.Profile; @@ -172,6 +173,35 @@ default Build getBuild() { @Nonnull Path getBasedir(); + /** + * Returns the directory where files generated by the build are placed. + * The directory depends on the scope: + * + * <ul> + * <li>If {@link ProjectScope#MAIN}, returns the directory where compiled application classes are placed.</li> + * <li>If {@link ProjectScope#TEST}, returns the directory where compiled test classes are placed.</li> + * <li>Otherwise (including {@code null}), returns the parent directory where all generated files are placed.</li> + * </ul> + * + * @param scope the scope of the generated files for which to get the directory, or {@code null} for all + * @return the output directory of files that are generated for the given scope + * + * @see SourceRoot#targetPath(Project) + */ + @Nonnull + default Path getOutputDirectory(@Nullable ProjectScope scope) { + String dir; + Build build = getBuild(); + if (scope == ProjectScope.MAIN) { + dir = build.getOutputDirectory(); + } else if (scope == ProjectScope.TEST) { + dir = build.getTestOutputDirectory(); + } else { + dir = build.getDirectory(); + } + return getBasedir().resolve(dir); + } + /** * {@return the project direct dependencies (directly specified or inherited)}. */ diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/SourceRoot.java b/api/maven-api-core/src/main/java/org/apache/maven/api/SourceRoot.java index 0abd9bbe6d..dc08a6f24c 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/SourceRoot.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/SourceRoot.java @@ -24,6 +24,8 @@ import java.util.List; import java.util.Optional; +import org.apache.maven.api.annotations.Nonnull; + /** * A root directory of source files. * The sources may be Java main classes, test classes, resources or anything else identified by the scope. @@ -152,6 +154,27 @@ default Optional<Path> targetPath() { return Optional.empty(); } + /** + * {@return the explicit target path resolved against the default target path} + * Invoking this method is equivalent to getting the default output directory + * by a call to {@code project.getOutputDirectory(scope())}, then resolving the + * {@linkplain #targetPath() target path} (if present) against that default directory. + * Note that if the target path is absolute, the result is that target path unchanged. + * + * @param project the project to use for getting default directories + * + * @see Project#getOutputDirectory(ProjectScope) + */ + @Nonnull + default Path targetPath(@Nonnull Project project) { + Optional<Path> targetPath = targetPath(); + // The test for `isAbsolute()` is a small optimization for avoiding the call to `getOutputDirectory(…)`. + return targetPath.filter(Path::isAbsolute).orElseGet(() -> { + Path base = project.getOutputDirectory(scope()); + return targetPath.map(base::resolve).orElse(base); + }); + } + /** * {@return whether resources are filtered to replace tokens with parameterized values} * The default value is {@code false}. diff --git a/api/maven-api-core/src/test/java/org/apache/maven/api/SourceRootTest.java b/api/maven-api-core/src/test/java/org/apache/maven/api/SourceRootTest.java new file mode 100644 index 0000000000..a316550aee --- /dev/null +++ b/api/maven-api-core/src/test/java/org/apache/maven/api/SourceRootTest.java @@ -0,0 +1,89 @@ +/* + * 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; + +import java.nio.file.Path; +import java.nio.file.PathMatcher; +import java.util.Collection; +import java.util.Optional; + +import org.apache.maven.api.model.Build; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class SourceRootTest implements SourceRoot { + private ProjectScope scope; + + private Language language; + + private String moduleName; + + @Override + public ProjectScope scope() { + return (scope != null) ? scope : SourceRoot.super.scope(); + } + + @Override + public Language language() { + return (language != null) ? language : SourceRoot.super.language(); + } + + @Override + public Optional<String> module() { + return Optional.ofNullable(moduleName); + } + + @Override + public PathMatcher matcher(Collection<String> defaultIncludes, boolean useDefaultExcludes) { + return null; // Not used for this test. + } + + @Test + void testDirectory() { + assertEquals(Path.of("src", "main", "java"), directory()); + + scope = ProjectScope.TEST; + assertEquals(Path.of("src", "test", "java"), directory()); + + moduleName = "org.foo"; + assertEquals(Path.of("src", "org.foo", "test", "java"), directory()); + } + + @Test + void testTargetPath() { + Build build = mock(Build.class); + when(build.getDirectory()).thenReturn("target"); + when(build.getOutputDirectory()).thenReturn("target/classes"); + when(build.getTestOutputDirectory()).thenReturn("target/test-classes"); + + Project project = mock(Project.class); + when(project.getBuild()).thenReturn(build); + when(project.getBasedir()).thenReturn(Path.of("myproject")); + when(project.getOutputDirectory(any(ProjectScope.class))).thenCallRealMethod(); + + assertEquals(Path.of("myproject", "target", "classes"), targetPath(project)); + + scope = ProjectScope.TEST; + assertEquals(Path.of("myproject", "target", "test-classes"), targetPath(project)); + } +} diff --git a/api/maven-api-model/src/main/mdo/maven.mdo b/api/maven-api-model/src/main/mdo/maven.mdo index 6222040050..653b355f3f 100644 --- a/api/maven-api-model/src/main/mdo/maven.mdo +++ b/api/maven-api-model/src/main/mdo/maven.mdo @@ -2129,8 +2129,16 @@ <description> <