Skip to content

Conversation

@gnodet
Copy link
Contributor

@gnodet gnodet commented Oct 30, 2025

This PR fixes multiple related issues with special character handling in .mvn/jvm.config files by unifying the parsing approach to use JvmConfigParser.java on both Unix and Windows platforms.

Issues Fixed

  • MNG-11363: Pipe symbols (|) in jvm.config cause shell parsing errors
  • MNG-11485: Non-POSIX xargs -0 fails on AIX, FreeBSD, and other systems
  • MNG-11486: sed command fails when paths contain @ symbols

Related PRs

Solution

Instead of using complex shell/batch script parsing with awk, sed, and xargs, this PR uses the existing JvmConfigParser.java on both platforms:

Unix (mvn)

  • Compiles JvmConfigParser.java to a temporary directory
  • Runs the parser to process jvm.config
  • Cleans up temporary files
  • Falls back gracefully if compilation fails

Windows (mvn.cmd)

  • Already used JvmConfigParser.java (no functional changes)
  • Removed debug output
  • Updated comments

Benefits

Correctness: Handles all edge cases reliably (pipes, quotes, @, etc.)
POSIX Compliance: No non-standard tools needed (xargs -0, GNU-specific awk/sed)
Maintainability: Single implementation for both platforms
Consistency: Same behavior on Windows and Unix

Test Coverage

  • MavenITgh11363PipeSymbolsInJvmConfigTest - Tests pipe symbols in jvm.config
  • MavenITgh11485AtSignInJvmConfigTest - Tests @ symbols in jvm.config (important for Jenkins workspaces like workspace/project_PR-350@2)

Performance Impact

Unix script is ~200ms slower (320ms → 520ms for mvn -v) due to Java compilation, but this is acceptable for the correctness and maintainability benefits.

Examples

Pipe symbols (MNG-11363)

# .mvn/jvm.config
-Dhttp.nonProxyHosts=de|*.de|my.company.mirror.de

✅ Now works correctly: de|*.de|my.company.mirror.de

Quoted pipes

# .mvn/jvm.config
-Dprop.with.pipes="value|with|pipes"

✅ Now works correctly: value|with|pipes

@ symbols in paths (MNG-11486)

# .mvn/jvm.config
-Dtest.path=${MAVEN_PROJECTBASEDIR}/workspace@2/test

✅ Now works correctly: /path/to/workspace@2/test

@gnodet gnodet changed the title [MNG-11363] Fix pipe symbol parsing in .mvn/jvm.config Fix pipe symbol parsing in .mvn/jvm.config (fix #11363) Oct 30, 2025
@gnodet gnodet added bug Something isn't working backport-to-4.0.x labels Oct 30, 2025
@gnodet gnodet force-pushed the fix/mng-11363-pipe-symbols-jvm-config branch 2 times, most recently from 465eef5 to bdc5130 Compare November 1, 2025 07:39
@gnodet
Copy link
Contributor Author

gnodet commented Nov 1, 2025

Updated all commit messages to use [gh-11363] instead of [MNG-11363] to follow the correct issue reference format.

@gnodet
Copy link
Contributor Author

gnodet commented Nov 1, 2025

Fixed the integration test failures. The issue was that the previous implementation was escaping pipes in concat_lines but then using eval which still interpreted them as shell operators.

The updated fix:

  1. Uses awk to escape unquoted pipes with backslashes in the concat_lines function
  2. Uses eval with the escaped MAVEN_OPTS to properly handle the pipes

This ensures that pipe symbols in JVM arguments (like -Dhttp.nonProxyHosts=de|*.de) are treated as literal characters rather than shell pipe operators.

All previously failing tests now pass:

  • ✅ MavenITgh11363PipeSymbolsInJvmConfigTest
  • ✅ MavenITmng4559MultipleJvmArgsTest
  • ✅ MavenITmng5889FindBasedir
  • ✅ MavenITmng6223FindBasedir
  • ✅ MavenITmng8598JvmConfigSubstitutionTest

@gnodet gnodet force-pushed the fix/mng-11363-pipe-symbols-jvm-config branch 3 times, most recently from c2acb11 to c246af5 Compare November 3, 2025 19:20
The concat_lines function in the Unix mvn script was using xargs -n 1
which split arguments by whitespace, causing pipe symbols (|) in JVM
arguments to be interpreted as shell command separators.

This fix replaces the problematic implementation with a line-by-line
reader that preserves quoted arguments and special characters while
maintaining all existing functionality:
- Comments are still removed
- Empty lines are still filtered out
- Variable substitution (MAVEN_PROJECTBASEDIR) still works
- Pipe symbols and other special characters are preserved

The Windows mvn.cmd seems too limited, so we use a custom java
class to parse the jvm.config file and process it.

Added integration test to verify pipe symbols in jvm.config work
correctly and don't cause shell parsing errors.
@gnodet gnodet force-pushed the fix/mng-11363-pipe-symbols-jvm-config branch from 4d00db1 to d1dc6f1 Compare November 5, 2025 11:13
@gnodet gnodet requested a review from cstamas November 5, 2025 11:13
Copy link
Member

@cstamas cstamas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One nit: why not use same Java helper on all platforms?

@gnodet
Copy link
Contributor Author

gnodet commented Nov 5, 2025

One nit: why not use same Java helper on all platforms?

Answered in the description.
When doing perfs measurements, running mvn -v went from 320 ms (using awk) to 520 ms (using the java parser).
So I don't think it's better to keep two separate solutions at this point.

@gnodet gnodet force-pushed the fix/mng-11363-pipe-symbols-jvm-config branch from 4442e67 to d1dc6f1 Compare November 6, 2025 12:12
- Always initialize JVM_CONFIG_MAVEN_OPTS to empty to avoid inheriting stale values from environment
- Add debug output to see actual values during IT runs
- This prevents previous test runs from interfering with current test
Write JVM_CONFIG_MAVEN_OPTS and MAVEN_OPTS values to mvn-debug.txt
in the project directory so we can check what values are being used
during IT runs.
- Use random temp directory for each invocation to avoid conflicts
- Capture stderr from Java parser to debug output file
- Clean up temp directory after use
- This ensures complete isolation between different Maven invocations
- Removed debug output to mvn-debug.txt
- Cleaned up error capture logic
- Ready for production use
@gnodet gnodet marked this pull request as draft November 26, 2025 08:40
@gnodet
Copy link
Contributor Author

gnodet commented Nov 26, 2025

The ITs are unstable, especially on windows...

This commit unifies the .mvn/jvm.config parsing approach by using
JvmConfigParser.java on both Unix and Windows platforms, solving
multiple related issues with special character handling.

Issues Fixed:
- MNG-11363: Pipe symbols (|) in jvm.config cause shell parsing errors
- MNG-11485: Non-POSIX xargs -0 fails on AIX, FreeBSD, and other systems
- MNG-11486: sed command fails when paths contain @ symbols

Changes:
- Modified mvn (Unix): Replaced awk/sed pipeline with JvmConfigParser.java
  compilation and execution. This ensures POSIX compliance and handles
  all special characters (pipes, quotes, @, etc.) correctly.
- Modified mvn.cmd (Windows): Removed debug output and updated comments
  to reflect all special characters now handled correctly.
- Added integration test MavenITgh11485AtSignInJvmConfigTest to verify
  @ symbol handling in jvm.config files (important for Jenkins workspaces
  like workspace/project_PR-350@2).

The Java-based parser approach:
- Handles comment removal (both # at start and end-of-line)
- Performs variable substitution (${MAVEN_PROJECTBASEDIR})
- Correctly parses quoted arguments with special characters
- Works consistently across all platforms
- Is POSIX-compliant (no xargs -0, awk, or complex sed needed)

Performance Impact:
Unix script is ~200ms slower (320ms → 520ms for mvn -v) due to Java
compilation, but this is acceptable for the correctness, maintainability,
and cross-platform consistency benefits.

Related PRs:
- Fixes apache#11365 (MNG-11363: pipe symbols)
- Fixes apache#11489 (MNG-11485: POSIX compliance)
- Fixes apache#11499 (MNG-11486: @ symbols in paths)
@gnodet
Copy link
Contributor Author

gnodet commented Dec 2, 2025

@bmarwell this would solve all problems with parsing the jvm.config file I think. At least, make it easier to maintain.

@gnodet gnodet changed the title Fix pipe symbol parsing in .mvn/jvm.config (fix #11363) [MNG-11363][MNG-11485][MNG-11486] Fix special characters in .mvn/jvm.config Dec 2, 2025
set "JVM_CONFIG_PARSER_DIR=%TEMP%\mvn-jvm-parser-%RANDOM%-%RANDOM%"
mkdir "%JVM_CONFIG_PARSER_DIR%"
set "JVM_CONFIG_TEMP=%TEMP%\mvn-jvm-config-%RANDOM%.txt"
"%JAVACMD:java.exe=javac.exe%" -d "%JVM_CONFIG_PARSER_DIR%" "%MAVEN_HOME%\bin\JvmConfigParser.java" >nul 2>&1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as on posix/unix: why run javac? We are on 17 and can easily run single-source files using java.

- Add System.out.flush() after output to ensure data is written before exit
  (fixes non-deterministic test failures on Windows with JDK 25)
- Extract parseJvmConfig() method (package-private) for testability
- Keep System.exit(1) for IOException to prevent Maven from running with
  invalid jvm.config (fail-fast approach)
- Add clear error messages with ERROR: prefix to stderr
- Update Unix script to capture and propagate parser exit code
- Update Windows script to check parser exit code and cleanup properly

This addresses:
- Non-deterministic Windows test failure in MavenITmng4559SpacesInJvmOptsTest
- Testability concerns while maintaining fail-fast behavior
- Clear error reporting for configuration issues
- Replace javac compilation + java execution with single 'java JvmConfigParser.java' command
  (source-launch mode available since JDK 11, Maven requires JDK 17+)
- Simplifies scripts by eliminating temporary directories and compilation step
- Add comprehensive error logging on both Unix and Windows for debugging
  non-deterministic issues (especially on Windows with JDK 25)
- Error messages now include:
  * Exit code
  * jvm.config path
  * Maven basedir
  * Java command used
  * Full parser output (stdout and stderr)
- Windows: Capture stdout and stderr separately for better diagnostics
- Unix: Use sed to indent parser output for clarity

Benefits:
- Simpler, more maintainable scripts
- Faster execution (no compilation step)
- Better error diagnostics for troubleshooting
- Consistent behavior across platforms
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR unifies the parsing of .mvn/jvm.config files across Unix and Windows platforms by introducing a Java-based parser (JvmConfigParser.java) that handles special characters correctly. Previously, shell/batch scripts used awk, sed, and xargs with platform-specific behavior that failed on special characters like pipes (|) and at signs (@).

Key Changes:

  • New JvmConfigParser.java parser handles quotes, pipes, @ symbols, and environment variable substitution
  • Unix mvn script now uses Java source-launch mode (JDK 11+) to run the parser
  • Windows mvn.cmd updated to use the same parser with improved error handling
  • Integration tests added for pipe symbols (MNG-11363) and @ signs (MNG-11485)

Reviewed changes

Copilot reviewed 8 out of 11 changed files in this pull request and generated no comments.

Show a summary per file
File Description
apache-maven/src/assembly/maven/bin/JvmConfigParser.java New Java parser that correctly handles special characters in jvm.config
apache-maven/src/assembly/maven/bin/mvn Unix script updated to use Java parser via source-launch mode
apache-maven/src/assembly/maven/bin/mvn.cmd Windows batch script updated for consistency, improved error handling
apache-maven/src/assembly/component.xml Assembly configuration updated to include .java files in distribution
its/core-it-suite/src/test/java/org/apache/maven/it/MavenITgh11363PipeSymbolsInJvmConfigTest.java Integration test for pipe symbol handling
its/core-it-suite/src/test/java/org/apache/maven/it/MavenITgh11485AtSignInJvmConfigTest.java Integration test for @ sign handling
its/core-it-suite/src/test/resources/gh-11363-pipe-symbols-jvm-config/* Test resources for pipe symbol test
its/core-it-suite/src/test/resources/gh-11485-at-sign/* Test resources for @ sign test

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…nflicts

- Verifier: Save stdout/stderr to separate files (log-stdout.txt,
  log-stderr.txt) when not empty. This captures shell script debug
  output that occurs before Maven starts, which is useful for debugging
  Windows batch script issues on CI.

- MavenITmng6255FixConcatLines: Use different log file names for each
  test method (log-lf.txt, log-crlf.txt) to avoid overwriting when all
  tests share the same resource directory.
Replace temp file approach with direct stdout capture using for /f.
On Windows, temp files created by shell redirection may not be released
immediately after the Java process exits, causing 'file in use' errors
when the batch script tries to read them.

Using 'for /f ... in (`command`)' captures stdout directly without
intermediate temp files, avoiding the locking issue.
- mvn.cmd: Use 'cmd /c' to run JvmConfigParser in a subshell, ensuring
  file handles are properly released before reading the temp file.
  The previous 'for /f' with backticks approach did not correctly
  capture the Java output on Windows.

- mvn, mvn.cmd: Add debug logging controlled by MAVEN_DEBUG_SCRIPT
  environment variable. When set, both scripts will output detailed
  information about jvm.config parsing, including:
  - Path to jvm.config file
  - Java command and arguments
  - Parser exit code and output
  - Final MAVEN_OPTS/JVM_CONFIG_MAVEN_OPTS value

This helps diagnose jvm.config issues on CI systems where the log
files are the primary debugging tool.
- mvn.cmd: Use 'cmd /c' to run JvmConfigParser in a subshell, ensuring
  file handles are properly released before reading the temp file.
  The previous 'for /f' with backticks approach did not correctly
  capture the Java output on Windows.

- mvn, mvn.cmd: Add debug logging controlled by MAVEN_DEBUG_SCRIPT
  environment variable. When set, both scripts will output detailed
  information about jvm.config parsing, including:
  - Path to jvm.config file
  - Java command and arguments
  - Parser exit code and output
  - Final MAVEN_OPTS/JVM_CONFIG_MAVEN_OPTS value
  - Full JVM command line before launching Maven

This helps diagnose jvm.config issues on CI systems where the log
files are the primary debugging tool.
@gnodet gnodet changed the title [MNG-11363][MNG-11485][MNG-11486] Fix special characters in .mvn/jvm.config Fix special characters in .mvn/jvm.config (fix #11363, #11485 and #11486) Dec 4, 2025
@gnodet gnodet marked this pull request as ready for review December 4, 2025 13:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-to-4.0.x bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants