mirror of https://github.com/apache/maven.git
[MNG-7836] Support alternative syntaxes for POMs (#1197)
The IT associated with this PR is using the Maven model to generate a hocon POM parser. This requires the maven-api-model module to attach the POM as an artifact, and the maven.yml change so that the model is present in the local repository.
This commit is contained in:
parent
dd2f1214d6
commit
f24266eb64
|
@ -106,12 +106,6 @@ jobs:
|
||||||
ref: ${{ env.REPO_BRANCH }}
|
ref: ${{ env.REPO_BRANCH }}
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Download built Maven
|
|
||||||
uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: built-maven
|
|
||||||
path: built-maven/
|
|
||||||
|
|
||||||
- name: Set up JDK
|
- name: Set up JDK
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
|
@ -119,6 +113,14 @@ jobs:
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
# cache: 'maven' - don't use cache for integration tests
|
# cache: 'maven' - don't use cache for integration tests
|
||||||
|
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
path: maven/
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: Build Maven
|
||||||
|
run: mvn install -e -B -V -DdistributionFileName=apache-maven -DskipTests -f maven/pom.xml
|
||||||
|
|
||||||
- name: Running integration tests
|
- name: Running integration tests
|
||||||
shell: bash
|
shell: bash
|
||||||
run: mvn install -e -B -V -Prun-its,embedded -DmavenDistro="$GITHUB_WORKSPACE/built-maven/apache-maven-bin.zip" -f maven-integration-testing/pom.xml
|
run: mvn install -e -B -V -Prun-its,embedded -DmavenDistro="$GITHUB_WORKSPACE/maven/apache-maven/target/apache-maven-bin.zip" -f maven-integration-testing/pom.xml
|
||||||
|
|
|
@ -76,6 +76,26 @@ under the License.
|
||||||
</excludes>
|
</excludes>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>build-helper-maven-plugin</artifactId>
|
||||||
|
<version>3.4.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>attach-artifact</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<artifacts>
|
||||||
|
<artifact>
|
||||||
|
<file>${basedir}/src/main/mdo/maven.mdo</file>
|
||||||
|
<type>mdo</type>
|
||||||
|
</artifact>
|
||||||
|
</artifacts>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* 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.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;
|
||||||
|
import org.apache.maven.api.annotations.Nullable;
|
||||||
|
import org.apache.maven.api.model.Model;
|
||||||
|
import org.apache.maven.api.services.Source;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@code ModelParser} interface is used to locate and read {@link Model}s from the file system.
|
||||||
|
* This allows plugging in additional syntaxes for the main model read by Maven when building a project.
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public interface ModelParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locates the pom in the given directory.
|
||||||
|
*
|
||||||
|
* @param dir the directory to locate the pom for, never {@code null}
|
||||||
|
* @return a {@code Source} pointing to the located pom or an empty {@code Optional} if none was found by this parser
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
Optional<Source> locate(@Nonnull Path dir);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the model obtained previously by a previous call to {@link #locate(Path)}.
|
||||||
|
*
|
||||||
|
* @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, @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 parsed
|
||||||
|
*/
|
||||||
|
default Optional<Model> locateAndParse(@Nonnull Path dir, @Nullable Map<String, ?> options)
|
||||||
|
throws ModelParserException {
|
||||||
|
return locate(dir).map(s -> parse(s, options));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* 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.spi;
|
||||||
|
|
||||||
|
import org.apache.maven.api.annotations.Experimental;
|
||||||
|
import org.apache.maven.api.services.MavenException;
|
||||||
|
|
||||||
|
@Experimental
|
||||||
|
public class ModelParserException extends MavenException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The one-based index of the line containing the error.
|
||||||
|
*/
|
||||||
|
private final int lineNumber;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The one-based index of the column containing the error.
|
||||||
|
*/
|
||||||
|
private final int columnNumber;
|
||||||
|
|
||||||
|
public ModelParserException() {
|
||||||
|
this(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModelParserException(String message) {
|
||||||
|
this(message, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModelParserException(String message, Throwable cause) {
|
||||||
|
this(message, -1, -1, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModelParserException(String message, int lineNumber, int columnNumber, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
this.lineNumber = lineNumber;
|
||||||
|
this.columnNumber = columnNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModelParserException(Throwable cause) {
|
||||||
|
this(null, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLineNumber() {
|
||||||
|
return lineNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColumnNumber() {
|
||||||
|
return columnNumber;
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,6 +20,7 @@ package org.apache.maven.model.building;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.apache.maven.api.spi.ModelParser;
|
||||||
import org.apache.maven.model.Model;
|
import org.apache.maven.model.Model;
|
||||||
import org.apache.maven.model.composition.DefaultDependencyManagementImporter;
|
import org.apache.maven.model.composition.DefaultDependencyManagementImporter;
|
||||||
import org.apache.maven.model.composition.DependencyManagementImporter;
|
import org.apache.maven.model.composition.DependencyManagementImporter;
|
||||||
|
@ -215,7 +216,11 @@ public class DefaultModelBuilderFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ModelProcessor newModelProcessor() {
|
protected ModelProcessor newModelProcessor() {
|
||||||
return new DefaultModelProcessor(newModelLocator(), newModelReader());
|
return new DefaultModelProcessor(Arrays.asList(newModelParsers()), newModelLocator(), newModelReader());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ModelParser[] newModelParsers() {
|
||||||
|
return new ModelParser[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ModelLocator newModelLocator() {
|
protected ModelLocator newModelLocator() {
|
||||||
|
|
|
@ -27,10 +27,18 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.apache.maven.api.model.Model;
|
||||||
|
import org.apache.maven.api.spi.ModelParser;
|
||||||
|
import org.apache.maven.api.spi.ModelParserException;
|
||||||
import org.apache.maven.building.Source;
|
import org.apache.maven.building.Source;
|
||||||
|
import org.apache.maven.model.io.ModelParseException;
|
||||||
import org.apache.maven.model.io.ModelReader;
|
import org.apache.maven.model.io.ModelReader;
|
||||||
import org.apache.maven.model.locator.ModelLocator;
|
import org.apache.maven.model.locator.ModelLocator;
|
||||||
import org.eclipse.sisu.Typed;
|
import org.eclipse.sisu.Typed;
|
||||||
|
@ -65,11 +73,14 @@ import org.eclipse.sisu.Typed;
|
||||||
@Typed(ModelProcessor.class)
|
@Typed(ModelProcessor.class)
|
||||||
public class DefaultModelProcessor implements ModelProcessor {
|
public class DefaultModelProcessor implements ModelProcessor {
|
||||||
|
|
||||||
|
private final Collection<ModelParser> modelParsers;
|
||||||
private final ModelLocator modelLocator;
|
private final ModelLocator modelLocator;
|
||||||
private final ModelReader modelReader;
|
private final ModelReader modelReader;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public DefaultModelProcessor(ModelLocator modelLocator, ModelReader modelReader) {
|
public DefaultModelProcessor(
|
||||||
|
Collection<ModelParser> modelParsers, ModelLocator modelLocator, ModelReader modelReader) {
|
||||||
|
this.modelParsers = modelParsers;
|
||||||
this.modelLocator = modelLocator;
|
this.modelLocator = modelLocator;
|
||||||
this.modelReader = modelReader;
|
this.modelReader = modelReader;
|
||||||
}
|
}
|
||||||
|
@ -81,7 +92,15 @@ public class DefaultModelProcessor implements ModelProcessor {
|
||||||
|
|
||||||
public Path locatePom(Path projectDirectory) {
|
public Path locatePom(Path projectDirectory) {
|
||||||
// Note that the ModelProcessor#locatePom never returns null
|
// Note that the ModelProcessor#locatePom never returns null
|
||||||
Path pom = modelLocator.locatePom(projectDirectory.toFile()).toPath();
|
// while the ModelParser#locatePom needs to return an existing path!
|
||||||
|
Path pom = modelParsers.stream()
|
||||||
|
.map(m -> m.locate(projectDirectory)
|
||||||
|
.map(org.apache.maven.api.services.Source::getPath)
|
||||||
|
.orElse(null))
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.findFirst()
|
||||||
|
.orElseGet(
|
||||||
|
() -> modelLocator.locatePom(projectDirectory.toFile()).toPath());
|
||||||
if (!pom.equals(projectDirectory) && !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);
|
throw new IllegalArgumentException("The POM found does not belong to the given directory: " + pom);
|
||||||
}
|
}
|
||||||
|
@ -95,8 +114,15 @@ public class DefaultModelProcessor implements ModelProcessor {
|
||||||
|
|
||||||
public Path locateExistingPom(Path projectDirectory) {
|
public Path locateExistingPom(Path projectDirectory) {
|
||||||
// Note that the ModelProcessor#locatePom never returns null
|
// Note that the ModelProcessor#locatePom never returns null
|
||||||
File f = modelLocator.locateExistingPom(projectDirectory.toFile());
|
// while the ModelParser#locatePom needs to return an existing path!
|
||||||
Path pom = f != null ? f.toPath() : null;
|
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)) {
|
if (pom != null && !pom.equals(projectDirectory) && !pom.getParent().equals(projectDirectory)) {
|
||||||
throw new IllegalArgumentException("The POM found does not belong to the given directory: " + pom);
|
throw new IllegalArgumentException("The POM found does not belong to the given directory: " + pom);
|
||||||
}
|
}
|
||||||
|
@ -109,7 +135,28 @@ public class DefaultModelProcessor implements ModelProcessor {
|
||||||
if (pomFile == null && source instanceof org.apache.maven.building.FileSource) {
|
if (pomFile == null && source instanceof org.apache.maven.building.FileSource) {
|
||||||
pomFile = ((org.apache.maven.building.FileSource) source).getFile().toPath();
|
pomFile = ((org.apache.maven.building.FileSource) source).getFile().toPath();
|
||||||
}
|
}
|
||||||
return readXmlModel(pomFile, input, reader, options);
|
if (pomFile != null) {
|
||||||
|
Path projectDirectory = pomFile.getParent();
|
||||||
|
List<ModelParserException> exceptions = new ArrayList<>();
|
||||||
|
for (ModelParser parser : modelParsers) {
|
||||||
|
try {
|
||||||
|
Optional<Model> model = parser.locateAndParse(projectDirectory, options);
|
||||||
|
if (model.isPresent()) {
|
||||||
|
return model.get().withPomFile(pomFile);
|
||||||
|
}
|
||||||
|
} catch (ModelParserException e) {
|
||||||
|
exceptions.add(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return readXmlModel(pomFile, null, null, options);
|
||||||
|
} catch (IOException e) {
|
||||||
|
exceptions.forEach(e::addSuppressed);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return readXmlModel(pomFile, input, reader, options);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private org.apache.maven.api.model.Model readXmlModel(
|
private org.apache.maven.api.model.Model readXmlModel(
|
||||||
|
@ -137,6 +184,8 @@ public class DefaultModelProcessor implements ModelProcessor {
|
||||||
try (InputStream in = input) {
|
try (InputStream in = input) {
|
||||||
org.apache.maven.api.model.Model model = read(null, in, null, options);
|
org.apache.maven.api.model.Model model = read(null, in, null, options);
|
||||||
return new org.apache.maven.model.Model(model);
|
return new org.apache.maven.model.Model(model);
|
||||||
|
} catch (ModelParserException e) {
|
||||||
|
throw new ModelParseException("Unable to read model: " + e, e.getLineNumber(), e.getColumnNumber(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue