You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by gn...@apache.org on 2023/08/28 13:36:07 UTC

[maven] 01/01: A few improvements

This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch MNG-7836-Support-alternative-syntaxes-for-POMs
in repository https://gitbox.apache.org/repos/asf/maven.git

commit f1b7bf238763ccfa063474e1aa01c8dfd0e00ac2
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Fri Aug 25 09:33:36 2023 +0200

    A few improvements
    
    * change ModelParser to return an Optional<Source> instead of Path
    * add a ModelParser@locateAndParse method
    * move located pom existence check into a ModelLocator#locateExistingPom
    This abstract the "pom.xml" file notion a bit more
---
 .../org/apache/maven/api/services/PathSource.java  | 43 ++++++++++++-------
 .../java/org/apache/maven/api/spi/ModelParser.java | 22 ++++++++--
 .../ConsumerPomArtifactTransformer.java            | 20 +++++----
 .../maven/project/DefaultProjectBuilder.java       | 10 ++---
 .../collector/MultiModuleCollectionStrategy.java   |  9 ++--
 .../main/java/org/apache/maven/cli/MavenCli.java   | 13 ++----
 maven-model-builder/pom.xml                        |  1 +
 .../maven/model/building/DefaultModelBuilder.java  |  3 +-
 .../model/building/DefaultModelProcessor.java      | 48 ++++++++++++++++------
 .../model/building/DefaultTransformerContext.java  |  4 +-
 .../maven/model/building/FileModelSource.java      |  8 ++--
 .../maven/model/locator/DefaultModelLocator.java   | 17 +++++++-
 .../apache/maven/model/locator/ModelLocator.java   | 10 +++++
 .../maven/model/transform/ParentXMLFilter.java     |  8 +---
 14 files changed, 145 insertions(+), 71 deletions(-)

diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/locator/DefaultModelLocator.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/PathSource.java
similarity index 54%
copy from maven-model-builder/src/main/java/org/apache/maven/model/locator/DefaultModelLocator.java
copy to api/maven-api-core/src/main/java/org/apache/maven/api/services/PathSource.java
index cc6f915a4d..9a5c925976 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/locator/DefaultModelLocator.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/PathSource.java
@@ -16,24 +16,39 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.model.locator;
+package org.apache.maven.api.services;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Objects;
 
-import java.io.File;
+import org.apache.maven.api.annotations.Nonnull;
 
-/**
- * Locates a POM file within a project base directory.
- *
- * @author Benjamin Bentmann
- */
-@Named
-@Singleton
-public class DefaultModelLocator implements ModelLocator {
+public class PathSource implements Source {
+
+    private final Path path;
+
+    public PathSource(@Nonnull Path path) {
+        this.path = Objects.requireNonNull(path);
+    }
+
+    @Nonnull
+    @Override
+    public Path getPath() {
+        return path;
+    }
+
+    @Nonnull
+    @Override
+    public InputStream getInputStream() throws IOException {
+        return Files.newInputStream(path);
+    }
 
+    @Nonnull
     @Override
-    public File locatePom(File projectDirectory) {
-        return new File(projectDirectory, "pom.xml");
+    public String getLocation() {
+        return path.toString();
     }
 }
diff --git a/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ModelParser.java b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ModelParser.java
index af78d66a81..3c47fa01a2 100644
--- a/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ModelParser.java
+++ b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ModelParser.java
@@ -20,6 +20,7 @@ package org.apache.maven.api.spi;
 
 import java.nio.file.Path;
 import java.util.Map;
+import java.util.Optional;
 
 import org.apache.maven.api.annotations.Experimental;
 import org.apache.maven.api.annotations.Nonnull;
@@ -40,16 +41,31 @@ public interface ModelParser {
      * @param dir the directory to locate the pom for, never {@code null}
      * @return the located pom or <code>null</code> if none was found by this parser
      */
-    @Nullable
-    Path locatePom(@Nonnull Path dir);
+    @Nonnull
+    Optional<Source> locate(@Nonnull Path dir);
 
     /**
      * Parse the model.
      *
      * @param source the source to parse, never {@code null}
+     * @param options possible parsing options, may be {@code null}
      * @return the parsed {@link Model}, never {@code null}
      * @throws ModelParserException if the model cannot be parsed
      */
     @Nonnull
-    Model parse(@Nonnull Source source, Map<String, ?> options) throws ModelParserException;
+    Model parse(@Nonnull Source source, @Nullable Map<String, ?> options) throws ModelParserException;
+
+    /**
+     * Locate and parse the model in the specified directory.
+     * This is equivalent to {@code locate(dir).map(s -> parse(s, options))}.
+     *
+     * @param dir the directory to locate the pom for, never {@code null}
+     * @param options possible parsing options, may be {@code null}
+     * @return an optional parsed {@link Model} or {@code null} if none could be found
+     * @throws ModelParserException if the located model cannot be parsd
+     */
+    default Optional<Model> locateAndParse(@Nonnull Path dir, @Nullable Map<String, ?> options)
+            throws ModelParserException {
+        return locate(dir).map(s -> parse(s, options));
+    }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/internal/transformation/ConsumerPomArtifactTransformer.java b/maven-core/src/main/java/org/apache/maven/internal/transformation/ConsumerPomArtifactTransformer.java
index 30f7fb050e..af76f348ca 100644
--- a/maven-core/src/main/java/org/apache/maven/internal/transformation/ConsumerPomArtifactTransformer.java
+++ b/maven-core/src/main/java/org/apache/maven/internal/transformation/ConsumerPomArtifactTransformer.java
@@ -39,10 +39,10 @@ import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.function.BiConsumer;
 
 import org.apache.maven.api.model.Model;
+import org.apache.maven.api.services.Source;
 import org.apache.maven.api.spi.ModelParser;
 import org.apache.maven.feature.Features;
 import org.apache.maven.model.building.DefaultBuildPomXMLFilterFactory;
-import org.apache.maven.model.building.FileSource;
 import org.apache.maven.model.building.TransformerContext;
 import org.apache.maven.model.transform.RawToConsumerPomXMLFilterFactory;
 import org.apache.maven.model.transform.stax.XmlUtils;
@@ -196,13 +196,19 @@ public final class ConsumerPomArtifactTransformer {
      * The actual transformation: visible for testing.
      */
     void transform(Path pomFile, Path destPomFile, TransformerContext context) throws IOException, XMLStreamException {
-        ModelParser parser = modelParsers.values().stream()
-                .filter(p -> pomFile.equals(p.locatePom(pomFile.getParent())))
-                .findAny()
-                .orElse(null);
-        if (parser != null) {
+        ModelParser parser = null;
+        Source source = null;
+        for (ModelParser p : modelParsers.values()) {
+            source = p.locate(pomFile).orElse(null);
+            if (source != null) {
+                parser = p;
+                break;
+            }
+        }
+
+        if (source != null) {
             try (OutputStream output = Files.newOutputStream(destPomFile)) {
-                Model model = parser.parse(new FileSource(pomFile), null);
+                Model model = parser.parse(source, null);
                 // transform
                 model = model.withRoot(false).withModules(null);
                 if (model.getParent() != null) {
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 b5effa9d06..8470f928ba 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
@@ -497,15 +497,11 @@ public class DefaultProjectBuilder implements ProjectBuilder {
 
                 module = module.replace('\\', File.separatorChar).replace('/', File.separatorChar);
 
-                File moduleFile = new File(basedir, module);
+                File moduleFile = modelProcessor.locateExistingPom(new File(basedir, module));
 
-                if (moduleFile.isDirectory()) {
-                    moduleFile = modelProcessor.locatePom(moduleFile);
-                }
-
-                if (!moduleFile.isFile()) {
+                if (moduleFile == null) {
                     ModelProblem problem = new DefaultModelProblem(
-                            "Child module " + moduleFile + " of " + pomFile + " does not exist",
+                            "Child module " + module + " of " + pomFile + " does not exist",
                             ModelProblem.Severity.ERROR,
                             ModelProblem.Version.BASE,
                             model,
diff --git a/maven-core/src/main/java/org/apache/maven/project/collector/MultiModuleCollectionStrategy.java b/maven-core/src/main/java/org/apache/maven/project/collector/MultiModuleCollectionStrategy.java
index fa38120f49..9f81694d40 100644
--- a/maven-core/src/main/java/org/apache/maven/project/collector/MultiModuleCollectionStrategy.java
+++ b/maven-core/src/main/java/org/apache/maven/project/collector/MultiModuleCollectionStrategy.java
@@ -97,15 +97,16 @@ public class MultiModuleCollectionStrategy implements ProjectCollectionStrategy
     }
 
     private File getMultiModuleProjectPomFile(MavenExecutionRequest request) {
-        if (request.getPom().getParentFile().equals(request.getMultiModuleProjectDirectory())) {
+        File multiModuleProjectDirectory = request.getMultiModuleProjectDirectory();
+        if (request.getPom().getParentFile().equals(multiModuleProjectDirectory)) {
             return request.getPom();
         } else {
-            File multiModuleProjectPom = modelLocator.locatePom(request.getMultiModuleProjectDirectory());
-            if (!multiModuleProjectPom.exists()) {
+            File multiModuleProjectPom = modelLocator.locateExistingPom(multiModuleProjectDirectory);
+            if (multiModuleProjectPom == null) {
                 LOGGER.info(
                         "Maven detected that the requested POM file is part of a multi-module project, "
                                 + "but could not find a pom.xml file in the multi-module root directory '{}'.",
-                        request.getMultiModuleProjectDirectory());
+                        multiModuleProjectDirectory);
                 LOGGER.info("The reactor is limited to all projects under: "
                         + request.getPom().getParent());
                 return request.getPom();
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
index 847bfcec06..743d120c84 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
@@ -1354,18 +1354,11 @@ public class MavenCli {
             current = resolveFile(new File(alternatePomFile), workingDirectory);
         }
 
-        File pom;
-        if (current.isDirectory() && modelProcessor != null) {
-            pom = modelProcessor.locatePom(current);
+        if (modelProcessor != null) {
+            return modelProcessor.locateExistingPom(current);
         } else {
-            pom = current;
+            return current.isFile() ? current : null;
         }
-
-        if (pom.isFile()) {
-            return pom;
-        }
-
-        return null;
     }
 
     // Visible for testing
diff --git a/maven-model-builder/pom.xml b/maven-model-builder/pom.xml
index 0263f6074a..4ce96867f7 100644
--- a/maven-model-builder/pom.xml
+++ b/maven-model-builder/pom.xml
@@ -142,6 +142,7 @@ under the License.
               <exclude>org.apache.maven.model.interpolation.StringSearchModelInterpolator</exclude>
               <exclude>org.apache.maven.model.interpolation.StringVisitorModelInterpolator</exclude>
               <exclude>org.apache.maven.model.io.DefaultModelReader#DefaultModelReader():CONSTRUCTOR_REMOVED</exclude>
+              <exclude>org.apache.maven.model.locator.ModelLocator#locateExistingPom(java.io.File):METHOD_NEW_DEFAULT</exclude>
               <exclude>org.apache.maven.model.management.DefaultDependencyManagementInjector$ManagementModelMerger</exclude>
               <exclude>org.apache.maven.model.management.DefaultPluginManagementInjector$ManagementModelMerger</exclude>
               <exclude>org.apache.maven.model.merge.MavenModelMerger</exclude>
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
index fd5d2ffabb..8a62478344 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
@@ -1888,7 +1888,8 @@ public class DefaultModelBuilder implements ModelBuilder {
             return new TransformerContext() {
                 @Override
                 public Path locate(Path path) {
-                    return modelProcessor.locatePom(path.toFile()).toPath();
+                    File file = modelProcessor.locateExistingPom(path.toFile());
+                    return file != null ? file.toPath() : null;
                 }
 
                 @Override
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelProcessor.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelProcessor.java
index ee702e05d1..12410d4855 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelProcessor.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelProcessor.java
@@ -26,14 +26,13 @@ import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Reader;
-import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.stream.Collectors;
+import java.util.Optional;
 
 import org.apache.maven.api.model.Model;
 import org.apache.maven.api.spi.ModelParser;
@@ -95,13 +94,36 @@ public class DefaultModelProcessor implements ModelProcessor {
         // Note that the ModelProcessor#locatePom never returns null
         // while the ModelParser#locatePom needs to return an existing path!
         Path pom = modelParsers.stream()
-                .map(m -> m.locatePom(projectDirectory))
+                .map(m -> m.locate(projectDirectory)
+                        .map(org.apache.maven.api.services.Source::getPath)
+                        .orElse(null))
                 .filter(Objects::nonNull)
-                .filter(Files::exists)
                 .findFirst()
                 .orElseGet(
                         () -> modelLocator.locatePom(projectDirectory.toFile()).toPath());
-        if (!pom.getParent().equals(projectDirectory)) {
+        if (!pom.equals(projectDirectory) && !pom.getParent().equals(projectDirectory)) {
+            throw new IllegalArgumentException("The POM found does not belong to the given directory: " + pom);
+        }
+        return pom;
+    }
+
+    public File locateExistingPom(File projectDirectory) {
+        Path path = locateExistingPom(projectDirectory.toPath());
+        return path != null ? path.toFile() : null;
+    }
+
+    public Path locateExistingPom(Path projectDirectory) {
+        // Note that the ModelProcessor#locatePom never returns null
+        // while the ModelParser#locatePom needs to return an existing path!
+        Path pom = modelParsers.stream()
+                .map(m -> m.locate(projectDirectory).map(s -> s.getPath()).orElse(null))
+                .filter(Objects::nonNull)
+                .findFirst()
+                .orElseGet(() -> {
+                    File f = modelLocator.locateExistingPom(projectDirectory.toFile());
+                    return f != null ? f.toPath() : null;
+                });
+        if (pom != null && !pom.equals(projectDirectory) && !pom.getParent().equals(projectDirectory)) {
             throw new IllegalArgumentException("The POM found does not belong to the given directory: " + pom);
         }
         return pom;
@@ -118,15 +140,17 @@ public class DefaultModelProcessor implements ModelProcessor {
         }
         if (pomFile != null) {
             Path projectDirectory = pomFile.getParent();
-            Path path = pomFile;
-            List<ModelParser> parsers = modelParsers.stream()
-                    .filter(p -> path.equals(p.locatePom(projectDirectory)))
-                    .collect(Collectors.toList());
+            //            Path path = pomFile;
+            //            List<ModelParser> parsers = modelParsers.stream()
+            //                    .filter(p -> path.equals(p.locatePom(projectDirectory)))
+            //                    .collect(Collectors.toList());
             List<ModelParserException> exceptions = new ArrayList<>();
-            for (ModelParser parser : parsers) {
+            for (ModelParser parser : modelParsers) {
                 try {
-                    Model model = parser.parse(new FileSource(pomFile), options);
-                    return model.withPomFile(pomFile);
+                    Optional<Model> model = parser.locateAndParse(projectDirectory, options);
+                    if (model.isPresent()) {
+                        return model.get().withPomFile(pomFile);
+                    }
                 } catch (ModelParserException e) {
                     exceptions.add(e);
                 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultTransformerContext.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultTransformerContext.java
index c4f77dd0b6..37198174a7 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultTransformerContext.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultTransformerContext.java
@@ -18,6 +18,7 @@
  */
 package org.apache.maven.model.building;
 
+import java.io.File;
 import java.nio.file.Path;
 import java.util.Map;
 import java.util.Objects;
@@ -101,7 +102,8 @@ class DefaultTransformerContext implements TransformerContext {
 
     @Override
     public Path locate(Path path) {
-        return modelLocator.locatePom(path.toFile()).toPath();
+        File file = modelLocator.locateExistingPom(path.toFile());
+        return file != null ? file.toPath() : null;
     }
 
     static class GAKey {
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/FileModelSource.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/FileModelSource.java
index 92a059bbe6..30fd8e4b3c 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/FileModelSource.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/FileModelSource.java
@@ -55,13 +55,11 @@ public class FileModelSource extends FileSource implements ModelSource3 {
     public ModelSource3 getRelatedSource(ModelLocator locator, String relPath) {
         relPath = relPath.replace('\\', File.separatorChar).replace('/', File.separatorChar);
 
-        File relatedPom = new File(getFile().getParentFile(), relPath);
+        File path = new File(getFile().getParentFile(), relPath);
 
-        if (relatedPom.isDirectory() && locator != null) {
-            relatedPom = locator.locatePom(relatedPom);
-        }
+        File relatedPom = locator.locateExistingPom(path);
 
-        if (relatedPom.isFile() && relatedPom.canRead()) {
+        if (relatedPom != null) {
             return new FileModelSource(relatedPom.toPath().normalize().toFile());
         }
 
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/locator/DefaultModelLocator.java b/maven-model-builder/src/main/java/org/apache/maven/model/locator/DefaultModelLocator.java
index cc6f915a4d..5224b9e172 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/locator/DefaultModelLocator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/locator/DefaultModelLocator.java
@@ -34,6 +34,21 @@ public class DefaultModelLocator implements ModelLocator {
 
     @Override
     public File locatePom(File projectDirectory) {
-        return new File(projectDirectory, "pom.xml");
+        return projectDirectory != null ? projectDirectory : new File(".");
+    }
+
+    @Override
+    public File locateExistingPom(File project) {
+        if (project == null || project.isDirectory()) {
+            project = locatePom(project);
+        }
+        if (project.isDirectory()) {
+            File pom = new File(project, "pom.xml");
+            return pom.isFile() ? pom : null;
+        } else if (project.isFile()) {
+            return project;
+        } else {
+            return null;
+        }
     }
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/locator/ModelLocator.java b/maven-model-builder/src/main/java/org/apache/maven/model/locator/ModelLocator.java
index f9202cebcc..d4b04c6912 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/locator/ModelLocator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/locator/ModelLocator.java
@@ -38,4 +38,14 @@ public interface ModelLocator {
      * @return The path to the (possibly non-existent) POM file, never {@code null}.
      */
     File locatePom(File projectDirectory);
+
+    /**
+     * Returns the file containing the pom or null if a pom can not be found at the given file or in the given directory.
+     */
+    default File locateExistingPom(File project) {
+        if (project == null || project.isDirectory()) {
+            project = locatePom(project);
+        }
+        return project.isFile() ? project : null;
+    }
 }
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/ParentXMLFilter.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/ParentXMLFilter.java
index 1f791e473f..545427c60a 100644
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/ParentXMLFilter.java
+++ b/maven-model-transform/src/main/java/org/apache/maven/model/transform/ParentXMLFilter.java
@@ -20,7 +20,6 @@ package org.apache.maven.model.transform;
 
 import javax.xml.stream.XMLStreamReader;
 
-import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.List;
@@ -134,12 +133,9 @@ class ParentXMLFilter extends NodeBufferingParser {
     }
 
     protected Optional<RelativeProject> resolveRelativePath(Path relativePath, String groupId, String artifactId) {
-        Path pomPath = projectPath.resolve(relativePath).normalize();
-        if (Files.isDirectory(pomPath) && modelLocator != null) {
-            pomPath = modelLocator.apply(pomPath);
-        }
+        Path pomPath = modelLocator.apply(projectPath.resolve(relativePath).normalize());
 
-        if (pomPath == null || !Files.isRegularFile(pomPath)) {
+        if (pomPath == null) {
             return Optional.empty();
         }