Skip to content

Commit fffdf0e

Browse files
kamilkrzywanskikkrzywanskignodet
authored
[MNG-8694] Fix version interpolation and ternary operator (#2272)
Use the interpolator service instead of regexp for version interpolation and fix the interpolator to properly support both `:+` and `:-` in the same expression to support a ternary operator. When processing ternary expressions like ${release:+${foo}:-${bar}} or ${versionCore}${release:+-DEVELOPER}, the DefaultInterpolator was incorrectly continuing to process subsequent operators after a decision had been made on the first operator. This fix adds a break statement after each successful operator evaluation to stop processing any remaining operators once a decision has been made, ensuring that: 1. When 'release' is true and 'foo' is empty, correctly evaluates to an empty string 2. When 'release' is true, correctly evaluates to just Added test cases to verify both scenarios. --------- Co-authored-by: kkrzywanski <[email protected]> Co-authored-by: Guillaume Nodet <[email protected]>
1 parent 3330cdb commit fffdf0e

File tree

5 files changed

+84
-24
lines changed

5 files changed

+84
-24
lines changed

impl/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.apache.maven.api.model.InputLocation;
2929
import org.apache.maven.api.model.InputSource;
3030
import org.apache.maven.artifact.Artifact;
31+
import org.apache.maven.execution.MavenSession;
3132
import org.apache.maven.impl.InternalSession;
3233
import org.apache.maven.internal.impl.DefaultProject;
3334
import org.apache.maven.internal.impl.InternalMavenSession;
@@ -511,6 +512,21 @@ public void testBuildParentVersionRangeExternallyWithChildRevisionExpression() t
511512
assertEquals("1.0-SNAPSHOT", mp.getVersion());
512513
}
513514

515+
@Test
516+
public void testParentVersionResolvedFromNestedProperties() throws Exception {
517+
File f1 = getTestFile("src/test/resources/projects/pom-parent-version-from-nested-properties/pom.xml");
518+
ProjectBuildingRequest request = newBuildingRequest();
519+
MavenSession session =
520+
InternalMavenSession.from(request.getRepositorySession()).getMavenSession();
521+
522+
MavenProject mp = projectBuilder.build(f1, request).getProject();
523+
assertEquals("0.1.0-DEVELOPER", mp.getVersion());
524+
525+
session.getUserProperties().put("release", "true");
526+
mp = projectBuilder.build(f1, request).getProject();
527+
assertEquals("0.1.0", mp.getVersion());
528+
}
529+
514530
@Test
515531
public void testSubprojectDiscovery() throws Exception {
516532
File pom = getTestFile("src/test/resources/projects/subprojects-discover/pom.xml");
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<project xmlns="http://maven.apache.org/POM/4.1.0"
2+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 http://maven.apache.org/xsd/maven-4.1.0.xsd"
4+
root="true">
5+
<modelVersion>4.1.0</modelVersion>
6+
7+
<groupId>gid</groupId>
8+
<artifactId>aid</artifactId>
9+
<version>${revision}</version>
10+
<packaging>pom</packaging>
11+
12+
<properties>
13+
<versionCore>0.1.0</versionCore>
14+
<revision>${versionCore}${release:+:--DEVELOPER}</revision>
15+
</properties>
16+
17+
</project>

impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultInterpolator.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,10 +334,14 @@ private static String processSubstitution(
334334
if (":+".equals(op)) {
335335
if (substValue != null && !substValue.isEmpty()) {
336336
substValue = processedOpValue;
337+
// Skip any remaining operators since we've made a decision
338+
break;
337339
}
338340
} else if (":-".equals(op)) {
339341
if (substValue == null || substValue.isEmpty()) {
340342
substValue = processedOpValue;
343+
// Skip any remaining operators since we've made a decision
344+
break;
341345
}
342346
} else {
343347
throw new InterpolatorException("Bad substitution operator in: ${" + org + "}");

impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@
4343
import java.util.concurrent.atomic.AtomicReference;
4444
import java.util.function.Supplier;
4545
import java.util.function.UnaryOperator;
46-
import java.util.regex.Matcher;
47-
import java.util.regex.Pattern;
4846
import java.util.stream.Collectors;
4947
import java.util.stream.Stream;
5048

@@ -247,8 +245,6 @@ public ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilder
247245
}
248246

249247
protected class ModelBuilderSessionState implements ModelProblemCollector {
250-
private static final Pattern REGEX = Pattern.compile("\\$\\{([^}]+)}");
251-
252248
final Session session;
253249
final ModelBuilderRequest request;
254250
final DefaultModelBuilderResult result;
@@ -585,26 +581,7 @@ private Dependency inferDependencyVersion(Model model, Dependency dep) {
585581
}
586582

587583
String replaceCiFriendlyVersion(Map<String, String> properties, String version) {
588-
// TODO: we're using a simple regex here, but we should probably use
589-
// a proper interpolation service to do the replacements
590-
// once one is available in maven-api-impl
591-
// https://issues.apache.org/jira/browse/MNG-8262
592-
if (version != null) {
593-
Matcher matcher = REGEX.matcher(version);
594-
if (matcher.find()) {
595-
StringBuilder result = new StringBuilder();
596-
do {
597-
// extract the key inside ${}
598-
String key = matcher.group(1);
599-
// get replacement from the map, or use the original ${xy} if not found
600-
String replacement = properties.getOrDefault(key, "\\" + matcher.group(0));
601-
matcher.appendReplacement(result, replacement);
602-
} while (matcher.find());
603-
matcher.appendTail(result); // Append the remaining part of the string
604-
return result.toString();
605-
}
606-
}
607-
return version;
584+
return version != null ? interpolator.interpolate(version, properties::get) : null;
608585
}
609586

610587
private void buildBuildPom() throws ModelBuilderException {

impl/maven-impl/src/test/java/org/apache/maven/impl/model/DefaultInterpolatorTest.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,52 @@ void testExpansion() {
169169
assertEquals("", props.get("c_cp"));
170170
}
171171

172+
@Test
173+
void testTernary() {
174+
Map<String, String> props;
175+
176+
props = new LinkedHashMap<>();
177+
props.put("foo", "-FOO");
178+
props.put("bar", "-BAR");
179+
props.put("version", "1.0${release:+${foo}:-${bar}}");
180+
performSubstitution(props);
181+
assertEquals("1.0-BAR", props.get("version"));
182+
183+
props = new LinkedHashMap<>();
184+
props.put("release", "true");
185+
props.put("foo", "-FOO");
186+
props.put("bar", "-BAR");
187+
props.put("version", "1.0${release:+${foo}:-${bar}}");
188+
performSubstitution(props);
189+
assertEquals("1.0-FOO", props.get("version"));
190+
191+
props = new LinkedHashMap<>();
192+
props.put("foo", "");
193+
props.put("bar", "-BAR");
194+
props.put("version", "1.0${release:+${foo}:-${bar}}");
195+
performSubstitution(props);
196+
assertEquals("1.0-BAR", props.get("version"));
197+
198+
props = new LinkedHashMap<>();
199+
props.put("release", "true");
200+
props.put("foo", "");
201+
props.put("bar", "-BAR");
202+
props.put("version", "1.0${release:+${foo}:-${bar}}");
203+
performSubstitution(props);
204+
assertEquals("1.0", props.get("version"));
205+
206+
props = new LinkedHashMap<>();
207+
props.put("version", "1.0${release:+:--BAR}");
208+
performSubstitution(props);
209+
assertEquals("1.0-BAR", props.get("version"));
210+
211+
props = new LinkedHashMap<>();
212+
props.put("release", "true");
213+
props.put("version", "1.0${release:+:--BAR}");
214+
performSubstitution(props);
215+
assertEquals("1.0", props.get("version"));
216+
}
217+
172218
@Test
173219
void testXdg() {
174220
Map<String, String> props;

0 commit comments

Comments
 (0)