Skip to content

Commit

Permalink
Downgrade model version in consumer/build pom as needed
Browse files Browse the repository at this point in the history
  • Loading branch information
gnodet committed Jun 29, 2023
1 parent aece05f commit 0e5d5ad
Show file tree
Hide file tree
Showing 14 changed files with 693 additions and 29 deletions.
15 changes: 14 additions & 1 deletion api/maven-api-model/src/main/mdo/maven.mdo
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@
</field>
<field xml.attribute="true" xml.tagName="root">
<name>root</name>
<version>4.0.0+</version>
<version>4.1.0+</version>
<description>
<![CDATA[
Indicates that this project is the root project, located in the upper directory of the source tree.
Expand All @@ -225,6 +225,19 @@
<type>boolean</type>
<defaultValue>false</defaultValue>
</field>
<field xml.attribute="true" xml.tagName="downgrade.model.version">
<name>downgradeModelVersion</name>
<version>4.1.0+</version>
<description>
<![CDATA[
Indicates if the build POM for this project should be downgraded to the lowest
compatible version.
<br><b>Since</b>: Maven 4.0.0
]]>
</description>
<type>boolean</type>
<defaultValue>true</defaultValue>
</field>
<field>
<name>inceptionYear</name>
<version>3.0.0+</version>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import org.apache.maven.model.building.TransformerContext;
import org.apache.maven.model.transform.RawToConsumerPomXMLFilterFactory;
import org.apache.maven.model.transform.stax.XmlUtils;
import org.apache.maven.model.v4.MavenModelVersion;
import org.apache.maven.model.v4.MavenStaxWriter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.artifact.ProjectArtifact;
Expand Down Expand Up @@ -74,6 +75,10 @@ public final class ConsumerPomArtifactTransformer {

private static final String BUILD_POM_CLASSIFIER = "build";

private static final String NAMESPACE_FORMAT = "http://maven.apache.org/POM/%s";

private static final String SCHEMA_LOCATION_FORMAT = "https://maven.apache.org/xsd/maven-%s.xsd";

private final Set<Path> toDelete = new CopyOnWriteArraySet<>();

public void injectTransformedArtifacts(MavenProject project, RepositorySystemSession session) throws IOException {
Expand Down Expand Up @@ -193,7 +198,7 @@ private Collection<Artifact> replacePom(Collection<Artifact> artifacts) {
/**
* Consumer POM is transformed from original POM.
*/
private static class ConsumerPomArtifact extends TransformedArtifact {
static class ConsumerPomArtifact extends TransformedArtifact {

private MavenProject project;

Expand All @@ -210,9 +215,19 @@ private ConsumerPomArtifact(MavenProject mavenProject, Path target) {
@Override
public void transform(Path src, Path dest) {
Model model = project.getModel().getDelegate();
transform(model, dest);
}

static void transform(Model model, Path dest) {
boolean isBom = BOM_PACKAGING.equals(model.getPackaging());
Model.Builder builder =
prune(Model.newBuilder(model, true).root(false).parent(null).build(null), model, isBom);
Model.Builder builder = prune(
Model.newBuilder(model, true)
.downgradeModelVersion(false)
.root(false)
.parent(null)
.build(null),
model,
isBom);
if (isBom) {
builder.packaging(POM_PACKAGING);
}
Expand All @@ -221,15 +236,21 @@ public void transform(Path src, Path dest) {
.collect(Collectors.toList()));

Model consumer = builder.build();
String version = new MavenModelVersion().getModelVersion(consumer);
consumer = consumer.withModelVersion(version).withDowngradeModelVersion(true);

try (Writer w = Files.newBufferedWriter(dest)) {
new MavenStaxWriter().write(w, consumer);
MavenStaxWriter writer = new MavenStaxWriter();
writer.setNamespace(String.format(NAMESPACE_FORMAT, version));
writer.setSchemaLocation(String.format(SCHEMA_LOCATION_FORMAT, version));
writer.setAddLocationInformation(false);
writer.write(w, consumer);
} catch (XMLStreamException | IOException e) {
throw new RuntimeException(e);
}
}

private <T extends ModelBase.Builder> T prune(T builder, ModelBase model, boolean isBom) {
static <T extends ModelBase.Builder> T prune(T builder, ModelBase model, boolean isBom) {
builder.properties(null).reporting(null).pluginRepositories(null);
if (model.getDistributionManagement() != null
&& model.getDistributionManagement().getRelocation() != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import org.apache.maven.model.Model;
import org.apache.maven.model.building.TransformerContext;
import org.apache.maven.model.v4.MavenStaxReader;
import org.apache.maven.project.MavenProject;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.SessionData;
Expand All @@ -39,7 +40,7 @@

class ConsumerPomArtifactTransformerTest {
@Test
void transform() throws Exception {
void buildTransform() throws Exception {
Path beforePomFile =
Paths.get("src/test/resources/projects/transform/before.pom").toAbsolutePath();
Path afterPomFile =
Expand All @@ -52,6 +53,21 @@ beforePomFile, new NoTransformerContext())) {
}
}

@Test
void consumerTransform() throws Exception {
Path beforePomFile = Paths.get("src/test/resources/projects/transform/consumer-before.pom")
.toAbsolutePath();
Path afterPomFile = Paths.get("src/test/resources/projects/transform/consumer-after.pom")
.toAbsolutePath();
Path tempFile = Files.createTempFile("", ".pom");
Files.delete(tempFile);
try (InputStream expected = Files.newInputStream(beforePomFile)) {
Model model = new Model(new MavenStaxReader().read(expected));
ConsumerPomArtifactTransformer.ConsumerPomArtifact.transform(model.getDelegate(), tempFile);
}
XmlAssert.assertThat(afterPomFile.toFile()).and(tempFile.toFile()).areIdentical();
}

@Test
void injectTransformedArtifactsWithoutPomShouldNotInjectAnyArtifacts() throws IOException {
MavenProject emptyProject = new MavenProject();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>test</artifactId>
<version>0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>lib</module>
<module>app</module>
</modules>
<profiles>
<profile>
<id>default-active</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>file</id>
<activation>
<file>
<exists>simple.xml</exists>
</file>
</activation>
</profile>
</profiles>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>

<!--
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.
-->

<project xmlns="http://maven.apache.org/POM/4.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 https://maven.apache.org/xsd/maven-4.1.0.xsd"
root="true">
<modelVersion>4.1.0</modelVersion>

<groupId>test</groupId>
<artifactId>test</artifactId>
<version>0.1-SNAPSHOT</version>
<packaging>pom</packaging>

<modules>
<module>lib</module> <!-- the library -->
<module>app</module> <!-- the application -->
</modules>

<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.1</version>
<configuration>
<source> 1.5 </source>
<target xml:space="preserve"> 1.5 </target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>test</id>
</execution>
</executions>
</plugin>
</plugins>
</build>

<profiles>
<profile>
<id>default-active</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</profile>
<profile>
<id>file</id>
<activation>
<file>
<exists>simple.xml</exists>
</file>
</activation>
<properties>
<profile.file>activated</profile.file>
</properties>
</profile>
</profiles>
</project>
4 changes: 4 additions & 0 deletions maven-model-transform/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ under the License.
<name>Maven Model XML Transform</name>

<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-model</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-xml</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* 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.model.transform;

import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import java.util.ArrayList;
import java.util.List;

import org.apache.maven.api.model.Model;
import org.apache.maven.model.transform.stax.BufferingParser;
import org.apache.maven.model.v4.MavenModelVersion;
import org.apache.maven.model.v4.MavenStaxReader;

public class ModelVersionDowngradeXMLFilter extends BufferingParser {

public static final String NAMESPACE_PREFIX = "http://maven.apache.org/POM/";

private final List<Event> buffer = new ArrayList<>();

public ModelVersionDowngradeXMLFilter(XMLStreamReader delegate) {
super(delegate);
}

@Override
protected boolean accept() throws XMLStreamException {
Event e = bufferEvent();
buffer.add(e);
if (e.event == XMLStreamReader.END_DOCUMENT) {
ReplayParser p = new ReplayParser(this);
buffer.forEach(p::pushEvent);
p.next();
String version;
Model model = new MavenStaxReader().read(p, false, null);
if (model.isDowngradeModelVersion()) {
model = model.withDowngradeModelVersion(false);
version = new MavenModelVersion().getModelVersion(model);
} else {
version = model.getModelVersion();
}
int depth = 0;
boolean isModelVersion = false;
for (Event event : buffer) {
event.namespace = NAMESPACE_PREFIX + version;
// rewrite namespace
if (event.namespaces != null) {
for (int i = 0; i < event.namespaces.length; i++) {
if (event.namespaces[i].uri.startsWith(NAMESPACE_PREFIX)) {
event.namespaces[i].uri = event.namespace;
}
}
}
// rewrite xsi:schemaLocation attribute
if (event.attributes != null) {
for (Attribute attribute : event.attributes) {
if (attribute.namespace.equals("http://www.w3.org/2001/XMLSchema-instance")
&& attribute.name.equals("schemaLocation")) {
attribute.value = attribute
.value
.replaceAll(
"\\Q" + NAMESPACE_PREFIX + "\\E[0-9]\\.[0-9]\\.[0-9]",
NAMESPACE_PREFIX + version)
.replaceAll(
"http(s?)://maven\\.apache\\.org/xsd/maven-[0-9]\\.[0-9]\\.[0-9]\\.xsd",
"https://maven.apache.org/xsd/maven-" + version + ".xsd");
}
}
}
// Rewrite modelVersion
if (event.event == XMLStreamReader.START_ELEMENT) {
depth++;
isModelVersion = depth == 2 && event.name.equals("modelVersion");
}
if (event.event == XMLStreamReader.CHARACTERS && isModelVersion) {
event.text = version;
}
if (event.event == XMLStreamReader.END_ELEMENT) {
depth--;
isModelVersion = false;
}
pushEvent(event);
}
}
return false;
}

static class ReplayParser extends BufferingParser {
ReplayParser(XMLStreamReader delegate) {
super(delegate);
}

public void pushEvent(Event e) {
super.pushEvent(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@

public class ModelVersionXMLFilter extends NodeBufferingParser {

private static final Pattern S_FILTER = Pattern.compile("\\s+");
public static final String NAMESPACE_PREFIX = "http://maven.apache.org/POM/";

private static final Pattern S_FILTER = Pattern.compile("\\s+");

public ModelVersionXMLFilter(XMLStreamReader delegate) {
super(delegate, "project");
}
Expand Down
Loading

0 comments on commit 0e5d5ad

Please sign in to comment.