diff --git a/apache-maven/src/assembly/maven/bin/mvn b/apache-maven/src/assembly/maven/bin/mvn
index 59cb66a9cc07..8559d47af557 100755
--- a/apache-maven/src/assembly/maven/bin/mvn
+++ b/apache-maven/src/assembly/maven/bin/mvn
@@ -171,20 +171,18 @@ concat_lines() {
# First convert all CR to LF using tr
tr '\r' '\n' < "$1" | \
sed -e '/^$/d' -e 's/#.*$//' | \
+ # Replace LF with NUL for xargs
+ tr '\n' '\0' | \
# Split into words and process each argument
- xargs -n 1 | \
+ # Use -0 with NUL to avoid special behaviour on quotes
+ xargs -n 1 -0 | \
while read -r arg; do
# Replace variables first
arg=$(echo "$arg" | sed \
-e "s@\${MAVEN_PROJECTBASEDIR}@$MAVEN_PROJECTBASEDIR@g" \
-e "s@\$MAVEN_PROJECTBASEDIR@$MAVEN_PROJECTBASEDIR@g")
- # Add quotes only if argument contains spaces and isn't already quoted
- if echo "$arg" | grep -q " " && ! echo "$arg" | grep -q "^\".*\"$"; then
- echo "\"$arg\""
- else
- echo "$arg"
- fi
+ echo "$arg"
done | \
tr '\n' ' '
fi
diff --git a/apache-maven/src/assembly/maven/bin/mvn.cmd b/apache-maven/src/assembly/maven/bin/mvn.cmd
index 1d50c0ec323a..a3e8600df3d1 100644
--- a/apache-maven/src/assembly/maven/bin/mvn.cmd
+++ b/apache-maven/src/assembly/maven/bin/mvn.cmd
@@ -35,6 +35,10 @@ title %0
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%"=="on" echo %MAVEN_BATCH_ECHO%
+@REM Clear/define a variable for any options to be inserted via script
+@REM We want to avoid trying to parse the external MAVEN_OPTS variable
+SET INTERNAL_MAVEN_OPTS=
+
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%"=="" goto skipRc
if exist "%PROGRAMDATA%\mavenrc.cmd" call "%PROGRAMDATA%\mavenrc.cmd" %*
@@ -204,7 +208,7 @@ for /F "usebackq tokens=* delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.conf
)
)
)
-@endlocal & set "MAVEN_OPTS=%MAVEN_OPTS% %JVM_CONFIG_MAVEN_OPTS%"
+@endlocal & set JVM_CONFIG_MAVEN_OPTS=%JVM_CONFIG_MAVEN_OPTS%
:endReadJvmConfig
@@ -224,7 +228,7 @@ if "%~1"=="--debug" (
echo Error: Unable to autodetect the YJP library location. Please set YJPLIB variable >&2
exit /b 1
)
- set "MAVEN_OPTS=-agentpath:%YJPLIB%=onexit=snapshot,onexit=memory,tracing,onlylocal %MAVEN_OPTS%"
+ set "INTERNAL_MAVEN_OPTS=-agentpath:%YJPLIB%=onexit=snapshot,onexit=memory,tracing,onlylocal %INTERNAL_MAVEN_OPTS%"
) else if "%~1"=="--enc" (
set "MAVEN_MAIN_CLASS=org.apache.maven.cling.MavenEncCling"
) else if "%~1"=="--shell" (
@@ -248,7 +252,9 @@ set LAUNCHER_CLASS=org.codehaus.plexus.classworlds.launcher.Launcher
if "%MAVEN_MAIN_CLASS%"=="" @set MAVEN_MAIN_CLASS=org.apache.maven.cling.MavenCling
"%JAVACMD%" ^
+ %INTERNAL_MAVEN_OPTS% ^
%MAVEN_OPTS% ^
+ %JVM_CONFIG_MAVEN_OPTS% ^
%MAVEN_DEBUG_OPTS% ^
--enable-native-access=ALL-UNNAMED ^
-classpath %LAUNCHER_JAR% ^
diff --git a/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITgh10937QuotedPipesInMavenOptsTest.java b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITgh10937QuotedPipesInMavenOptsTest.java
new file mode 100644
index 000000000000..45445cb4248e
--- /dev/null
+++ b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITgh10937QuotedPipesInMavenOptsTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.nio.file.Path;
+import java.util.Properties;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * This is a test set for gh-10937.
+ */
+class MavenITgh10937QuotedPipesInMavenOptsTest extends AbstractMavenIntegrationTestCase {
+
+ MavenITgh10937QuotedPipesInMavenOptsTest() {
+ super("[3.0.0,)");
+ }
+
+ /**
+ * Verify the dependency management of the consumer POM is computed correctly
+ */
+ @Test
+ void testIt() throws Exception {
+ Path basedir =
+ extractResources("/gh-10937-pipes-maven-opts").getAbsoluteFile().toPath();
+
+ Verifier verifier = newVerifier(basedir.toString());
+ verifier.setEnvironmentVariable("MAVEN_OPTS", "-Dprop.maven-opts=\"foo|bar\"");
+ verifier.addCliArguments("validate");
+ verifier.execute();
+ verifier.verifyErrorFreeLog();
+
+ Properties props = verifier.loadProperties("target/pom.properties");
+ assertEquals("foo|bar", props.getProperty("project.properties.pom.prop.jvm-opts"));
+ assertEquals("foo|bar", props.getProperty("project.properties.pom.prop.maven-opts"));
+ }
+}
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 00d6ce115694..d931454b0636 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
@@ -103,6 +103,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(MavenITgh10937QuotedPipesInMavenOptsTest.class);
suite.addTestSuite(MavenITgh2532DuplicateDependencyEffectiveModelTest.class);
suite.addTestSuite(MavenITmng8736ConcurrentFileActivationTest.class);
suite.addTestSuite(MavenITmng8744CIFriendlyTest.class);
diff --git a/its/core-it-suite/src/test/resources/gh-10937-pipes-maven-opts/.mvn/jvm.config b/its/core-it-suite/src/test/resources/gh-10937-pipes-maven-opts/.mvn/jvm.config
new file mode 100644
index 000000000000..a5d1264486f8
--- /dev/null
+++ b/its/core-it-suite/src/test/resources/gh-10937-pipes-maven-opts/.mvn/jvm.config
@@ -0,0 +1,2 @@
+# One comment
+-Dprop.jvm-opts="foo|bar"
diff --git a/its/core-it-suite/src/test/resources/gh-10937-pipes-maven-opts/pom.xml b/its/core-it-suite/src/test/resources/gh-10937-pipes-maven-opts/pom.xml
new file mode 100644
index 000000000000..d1ef2ca102f2
--- /dev/null
+++ b/its/core-it-suite/src/test/resources/gh-10937-pipes-maven-opts/pom.xml
@@ -0,0 +1,59 @@
+
+
+
+ 4.0.0
+
+ org.apache.maven.its.gh10937
+ test
+ 1.0
+
+ Maven Integration Test :: GH-10937
+ Verify that JVM args can contain pipes.
+
+
+ ${prop.maven-opts}
+ ${prop.jvm-opts}
+
+
+
+
+
+ org.apache.maven.its.plugins
+ maven-it-plugin-expression
+ 2.1-SNAPSHOT
+
+
+ test
+
+ eval
+
+ validate
+
+ target/pom.properties
+
+ project/properties
+
+
+
+
+
+
+
+