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 }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Download built Maven
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: built-maven
|
||||
path: built-maven/
|
||||
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
|
@ -119,6 +113,14 @@ jobs:
|
|||
distribution: 'temurin'
|
||||
# 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
|
||||
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>
|
||||
</configuration>
|
||||
</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>
|
||||
</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 org.apache.maven.api.spi.ModelParser;
|
||||
import org.apache.maven.model.Model;
|
||||
import org.apache.maven.model.composition.DefaultDependencyManagementImporter;
|
||||
import org.apache.maven.model.composition.DependencyManagementImporter;
|
||||
|
@ -215,7 +216,11 @@ public class DefaultModelBuilderFactory {
|
|||
}
|
||||
|
||||
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() {
|
||||
|
|
|
@ -27,10 +27,18 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
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.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.model.io.ModelParseException;
|
||||
import org.apache.maven.model.io.ModelReader;
|
||||
import org.apache.maven.model.locator.ModelLocator;
|
||||
import org.eclipse.sisu.Typed;
|
||||
|
@ -65,11 +73,14 @@ import org.eclipse.sisu.Typed;
|
|||
@Typed(ModelProcessor.class)
|
||||
public class DefaultModelProcessor implements ModelProcessor {
|
||||
|
||||
private final Collection<ModelParser> modelParsers;
|
||||
private final ModelLocator modelLocator;
|
||||
private final ModelReader modelReader;
|
||||
|
||||
@Inject
|
||||
public DefaultModelProcessor(ModelLocator modelLocator, ModelReader modelReader) {
|
||||
public DefaultModelProcessor(
|
||||
Collection<ModelParser> modelParsers, ModelLocator modelLocator, ModelReader modelReader) {
|
||||
this.modelParsers = modelParsers;
|
||||
this.modelLocator = modelLocator;
|
||||
this.modelReader = modelReader;
|
||||
}
|
||||
|
@ -81,7 +92,15 @@ public class DefaultModelProcessor implements ModelProcessor {
|
|||
|
||||
public Path locatePom(Path projectDirectory) {
|
||||
// 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)) {
|
||||
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) {
|
||||
// Note that the ModelProcessor#locatePom never returns null
|
||||
File f = modelLocator.locateExistingPom(projectDirectory.toFile());
|
||||
Path pom = f != null ? f.toPath() : 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);
|
||||
}
|
||||
|
@ -109,7 +135,28 @@ public class DefaultModelProcessor implements ModelProcessor {
|
|||
if (pomFile == null && source instanceof org.apache.maven.building.FileSource) {
|
||||
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(
|
||||
|
@ -137,6 +184,8 @@ public class DefaultModelProcessor implements ModelProcessor {
|
|||
try (InputStream in = input) {
|
||||
org.apache.maven.api.model.Model model = read(null, in, null, options);
|
||||
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