diff --git a/apache-maven/src/assembly/maven/bin/mvn b/apache-maven/src/assembly/maven/bin/mvn
index 6fd203348f43..139492a947e0 100755
--- a/apache-maven/src/assembly/maven/bin/mvn
+++ b/apache-maven/src/assembly/maven/bin/mvn
@@ -165,10 +165,14 @@ find_file_argument_basedir() {
)
}
-# concatenates all lines of a file
+# concatenates all lines of a file and replaces variables
concat_lines() {
if [ -f "$1" ]; then
- echo "`tr -s '\r\n' ' ' < "$1"`"
+ # First transform line endings to spaces
+ content=$(tr -s '\r\n' ' ' < "$1")
+ # Handle both ${var} and $var formats, only substitute MAVEN_PROJECTBASEDIR
+ echo "$content" | sed -e "s|\${MAVEN_PROJECTBASEDIR}|$MAVEN_PROJECTBASEDIR|g" \
+ -e "s|\$MAVEN_PROJECTBASEDIR|$MAVEN_PROJECTBASEDIR|g"
fi
}
diff --git a/apache-maven/src/assembly/maven/bin/mvn.cmd b/apache-maven/src/assembly/maven/bin/mvn.cmd
index d64073c400f8..f6b802e505e7 100644
--- a/apache-maven/src/assembly/maven/bin/mvn.cmd
+++ b/apache-maven/src/assembly/maven/bin/mvn.cmd
@@ -176,7 +176,13 @@ cd /d "%EXEC_DIR%"
if not exist "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadJvmConfig
@setlocal EnableExtensions EnableDelayedExpansion
-for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_OPTS=!JVM_CONFIG_MAVEN_OPTS! %%a
+set JVM_CONFIG_MAVEN_OPTS=
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do (
+ set "line=%%a"
+ set "line=!line:$MAVEN_PROJECTBASEDIR=%MAVEN_PROJECTBASEDIR%!"
+ set "line=!line:${MAVEN_PROJECTBASEDIR}=%MAVEN_PROJECTBASEDIR%!"
+ set JVM_CONFIG_MAVEN_OPTS=!JVM_CONFIG_MAVEN_OPTS! !line!
+)
@endlocal & set MAVEN_OPTS=%MAVEN_OPTS% %JVM_CONFIG_MAVEN_OPTS%
:endReadJvmConfig
diff --git a/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng8598JvmConfigSubstitutionTest.java b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng8598JvmConfigSubstitutionTest.java
new file mode 100644
index 000000000000..9c2399fd4841
--- /dev/null
+++ b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng8598JvmConfigSubstitutionTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.it;
+
+import java.io.File;
+import java.util.Properties;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * This is a test set for MNG-8598:
+ * Verify that ${MAVEN_PROJECTBASEDIR} and $MAVEN_PROJECTBASEDIR in .mvn/jvm.config are properly
+ * substituted with the actual project base directory.
+ */
+public class MavenITmng8598JvmConfigSubstitutionTest extends AbstractMavenIntegrationTestCase {
+ public MavenITmng8598JvmConfigSubstitutionTest() {
+ super("[4.0.0-rc-4,)");
+ }
+
+ @Test
+ public void testProjectBasedirSubstitution() throws Exception {
+ File testDir = extractResources("/mng-8598");
+
+ Verifier verifier = newVerifier(testDir.getAbsolutePath());
+ verifier.addCliArgument(
+ "-Dexpression.outputFile=" + new File(testDir, "target/pom.properties").getAbsolutePath());
+ verifier.setForkJvm(true); // custom .mvn/jvm.config
+ verifier.addCliArgument("validate");
+ verifier.execute();
+ verifier.verifyErrorFreeLog();
+
+ Properties props = verifier.loadProperties("target/pom.properties");
+ String expectedPath = testDir.getAbsolutePath().replace('\\', '/');
+ assertEquals(
+ expectedPath + "/curated",
+ props.getProperty("project.properties.curatedPathProp").replace('\\', '/'));
+ assertEquals(
+ expectedPath + "/simple",
+ props.getProperty("project.properties.simplePathProp").replace('\\', '/'));
+ }
+}
diff --git a/its/core-it-suite/src/test/java/org/apache/maven/it/TestSuiteOrdering.java b/its/core-it-suite/src/test/java/org/apache/maven/it/TestSuiteOrdering.java
index 8404b80183ea..1d948a9468fa 100644
--- a/its/core-it-suite/src/test/java/org/apache/maven/it/TestSuiteOrdering.java
+++ b/its/core-it-suite/src/test/java/org/apache/maven/it/TestSuiteOrdering.java
@@ -101,6 +101,7 @@ public TestSuiteOrdering() {
* the tests are to finishing. Newer tests are also more likely to fail, so this is
* a fail fast technique as well.
*/
+ suite.addTestSuite(MavenITmng8598JvmConfigSubstitutionTest.class);
suite.addTestSuite(MavenITmng8653AfterAndEachPhasesWithConcurrentBuilderTest.class);
suite.addTestSuite(MavenITmng5668AfterPhaseExecutionTest.class);
suite.addTestSuite(MavenITmng8648ProjectStartedEventsTest.class);
diff --git a/its/core-it-suite/src/test/resources/mng-8598/.mvn/jvm.config b/its/core-it-suite/src/test/resources/mng-8598/.mvn/jvm.config
new file mode 100644
index 000000000000..2109a0e0d1f0
--- /dev/null
+++ b/its/core-it-suite/src/test/resources/mng-8598/.mvn/jvm.config
@@ -0,0 +1,2 @@
+-DcuratedPath=${MAVEN_PROJECTBASEDIR}/curated
+-DsimplePath=$MAVEN_PROJECTBASEDIR/simple
\ No newline at end of file
diff --git a/its/core-it-suite/src/test/resources/mng-8598/pom.xml b/its/core-it-suite/src/test/resources/mng-8598/pom.xml
new file mode 100644
index 000000000000..a7c12be7453a
--- /dev/null
+++ b/its/core-it-suite/src/test/resources/mng-8598/pom.xml
@@ -0,0 +1,39 @@
+
+
+ 4.0.0
+
+ org.apache.maven.its.mng8598
+ jvm-config-substitution
+ 1.0
+ pom
+
+
+ ${curatedPath}
+ ${simplePath}
+
+
+
+
+
+ org.apache.maven.its.plugins
+ maven-it-plugin-expression
+ 2.1-SNAPSHOT
+
+
+
+ eval
+
+ validate
+
+ ${expression.outputFile}
+
+ project/properties/curatedPathProp
+ project/properties/simplePathProp
+
+
+
+
+
+
+
+