Skip to content

Convert paths for MSYS2 and jvm.config placeholders in bin/mvn - #12546

Merged
gnodet merged 2 commits into
apache:masterfrom
Hiteshsai007:mng-msys2-path-conversion
Jul 28, 2026
Merged

Convert paths for MSYS2 and jvm.config placeholders in bin/mvn#12546
gnodet merged 2 commits into
apache:masterfrom
Hiteshsai007:mng-msys2-path-conversion

Conversation

@Hiteshsai007

Copy link
Copy Markdown
Contributor

The launcher already converted POSIX paths to their native Windows form for Cygwin and MinGW (GH-7958), but a few paths still reached the JVM in a mangled or mixed form:

  • uname(1) reports MSYS_NT-* for the MSYS2 shell, which did not match the MINGW* pattern, so no conversion happened at all there. The MSYS2 argument conversion then rewrote the POSIX path into the mixed form D:/a/... instead of D:\a...

  • ${MAVEN_PROJECTBASEDIR} placeholders in .mvn/jvm.config were expanded with the POSIX path, since JvmConfigParser was invoked before the conversion took place. The base directory is now converted upfront and both representations are kept: the POSIX one to locate jvm.config from the shell, the native one for everything handed over to the JVM.

  • -Dlibrary.jline.path was built by appending /lib/jline-native to the already converted MAVEN_HOME, producing C:\maven/lib/jline-native. It is now converted on its own.

Additionally, the output of JvmConfigParser and of the base directory lookup is printed with printf instead of echo. Several POSIX shells (dash and other Almquist derivatives commonly installed as /bin/sh) expand backslash escapes in echo, which corrupts Windows paths, and the conversion is guarded so a missing cygpath(1) warns and falls back to POSIX paths rather than passing empty paths to the JVM.

A shell test covering all of the above is added; it stubs uname, cygpath and java so the Windows-only code paths can be exercised on any platform, and it can be run on any platform or wired into CI.

Fixes GH-12537

Following this checklist to help us incorporate your
contribution quickly and easily:

  • Your pull request should address just one issue, without pulling in other changes.
  • Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
  • Each commit in the pull request should have a meaningful subject line and body.
    Note that commits might be squashed by a maintainer on merge.
  • Write unit tests that match behavioral changes, where the tests fail if the changes to the runtime are not applied.
    This may not always be possible but is a best-practice.
  • Run mvn verify to make sure basic checks pass.
    A more thorough check will be performed on your pull request automatically.
  • You have run the Core IT successfully.

If your pull request is about ~20 lines of code you don't need to sign an
Individual Contributor License Agreement if you are unsure
please ask on the developers list.

To make clear that you license your contribution under
the Apache License Version 2.0, January 2004
you have to acknowledge this by using the following check-box.

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

First review — well-crafted PR! The core changes (MSYS* detection, native basedir split, JLINE_NATIVE_PATH, cygpath safety guard) are all correct and elegant.

Three minor observations:

  1. Debug echo with Windows paths (line 182) — The debug line references $MAVEN_PROJECTBASEDIR_NATIVE but still uses echo. On dash/Almquist shells, echo interprets backslash sequences, so a Windows path like C:\foo\bar could corrupt \f/\b. Consider using printf for consistency with the PR's own rationale for the echo→printf changes elsewhere:

    printf '[DEBUG] Parser arguments: %s %s %s\n' "$MAVEN_HOME/bin/JvmConfigParser.java" "$1" "$MAVEN_PROJECTBASEDIR_NATIVE" >&2
    
  2. Same issue on line 198echo "[DEBUG] JvmConfigParser output: $parser_output" now carries Windows paths in $parser_output. Same backslash risk:

    printf '[DEBUG] JvmConfigParser output: %s\n' "$parser_output" >&2
    
  3. Test not wired into CItest-mvn-path-conversion.sh is standalone. Future changes could regress path handling without anyone running it. Consider hooking it into the build or adding a note about integration.

Overall the approach is solid — the ordering of operations (converting basedir upfront for JvmConfigParser while keeping POSIX form for shell file access) is well thought out, and the test coverage across CYGWIN/MINGW/MSYS variants is comprehensive.

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Claude Code on behalf of gnodet

gnodet added a commit to gnodet/maven that referenced this pull request Jul 27, 2026
The launcher already converted POSIX paths to their native Windows form
for Cygwin and MinGW (apacheGH-7958), but a few paths still reached the JVM in
a mangled or mixed form:

* uname(1) reports MSYS_NT-* for the MSYS2 shell, which did not match the
  MINGW* pattern, so no conversion happened at all there. The MSYS2
  argument conversion then rewrote the POSIX path into the mixed form
  D:/a/... instead of D:\a\...

* ${MAVEN_PROJECTBASEDIR} placeholders in .mvn/jvm.config were expanded
  with the POSIX path, since JvmConfigParser was invoked before the
  conversion took place. The base directory is now converted upfront and
  both representations are kept: the POSIX one to locate jvm.config from
  the shell, the native one for everything handed over to the JVM.

* -Dlibrary.jline.path was built by appending /lib/jline-native to the
  already converted MAVEN_HOME, producing C:\maven/lib/jline-native. It
  is now converted on its own.

Values holding a path are printed with printf rather than echo, including
the debug logging: several POSIX shells (dash and the other Almquist
derivatives commonly installed as /bin/sh) expand backslash escapes in
echo, so C:\tmp\build was emitted with a tab in place of \t. The
conversion is also guarded, so a missing cygpath(1) warns and falls back
to POSIX paths rather than passing empty paths to the JVM.

A shell test covering all of the above is added and wired into the build
through exec-maven-plugin, so mvn verify runs it. It stubs uname, cygpath
and java and runs the launcher with a PATH holding nothing but those
stubs, so the Windows-only code paths are exercised identically on every
platform; keeping the ambient PATH would let the genuine cygpath(1) of an
actual Cygwin/MSYS2 installation be picked up and the missing-cygpath
fallback would never be exercised there.

Related to apacheGH-12537
@Hiteshsai007
Hiteshsai007 force-pushed the mng-msys2-path-conversion branch from 0db12ba to 033146e Compare July 28, 2026 05:35
@Hiteshsai007

Copy link
Copy Markdown
Contributor Author

Thanks for the review, @gnodet — all three points addressed in the force-push to 033146e.

1 & 2 — echoprintf in the debug logging

You were right, and it was a real inconsistency: the PR argued that echo corrupts Windows paths, then kept using echo for the debug output. With MAVEN_DEBUG_SCRIPT=1 under dash, C:\tmp\build was printed as C:<tab>mp\build.

I went slightly wider than the two lines flagged, since the same flaw applied elsewhere in the script. Every statement that interpolates a path now uses printf '%s':

  • [DEBUG] Parser arguments: and [DEBUG] JvmConfigParser output: (the two you pointed out)
  • [DEBUG] Found jvm.config file at: and Running JvmConfigParser with Java:
  • The three error-path lines: jvm.config path:, Maven basedir:, Java command:
  • [DEBUG] Final MAVEN_OPTS:
  • The JAVA_HOME is set to "..." diagnostic — pre-existing, same problem

Three echo calls remain deliberately: a numeric exit code and two literal strings with no interpolation. The rationale comment moved to the top of the script so it governs the whole file rather than sitting at one call site.

3 — Test wired into the build

Rather than just documenting it, the test now runs under mvn verify via exec-maven-plugin, bound to the test phase in a shell-script-tests profile activated on <family>unix</family> (it drives the POSIX bin/mvn; Windows ships mvn.cmd). It honours -DskipTests.

Test coverage

Added an assertion on the debug output that reproduces the exact problem you raised — it fails when those statements are reverted to echo and passes with printf, so this can't silently regress.

Also fixed a bug in the test harness itself that I'd missed: it appended the ambient PATH to the stub directory, so on a real Cygwin/MSYS2 machine the genuine cygpath was picked up and the missing-cygpath fallback was never exercised. The launcher now runs with a PATH containing only the stubs, which makes the result identical on every platform. Consequently the stubs use shell built-ins exclusively.

Now 29 assertions, verified green under sh, dash, bash and busybox sh, and still reporting 13 failures against the unpatched launcher.

One note on scope: this targets master (4.x), whereas #12537 asks specifically for a maven-3.10.x backport, so I've changed the trailer to Related to rather than Fixes. Points 1, 3 and the echo/printf issue apply equally to the 3.x script — happy to open a separate PR against maven-3.10.x if that's useful.

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All three concerns from the previous review are addressed in the new commit:

  1. ✅ Debug echo with $MAVEN_PROJECTBASEDIR_NATIVE now uses printf
  2. ✅ Debug echo with $parser_output now uses printf
  3. ✅ Test is now wired into the build via exec-maven-plugin in a unix-only profile

The architecture is sound — POSIX form for shell file access, Windows-converted form for the JVM. The cygpath safety guard and test coverage (Linux, CYGWIN, MINGW32, MINGW64, MSYS_NT, missing-cygpath fallback, dash/Almquist shell escape handling) are thorough.

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Claude Code on behalf of gnodet

@gnodet

gnodet commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

The macOS CI failures (all 22 assertion failures in test-mvn-path-conversion.sh) are caused by a double-slash in the temp directory path.

Root cause: On macOS, $TMPDIR ends with a trailing / (e.g. /var/folders/.../T/). When the test runs mktemp -d "${TMPDIR}/mvn-path-conversion.XXXXXX", it produces a path with // (e.g. .../T//mvn-path-conversion.XNBzZw). The pwd builtin inside the mvn launcher normalizes this to a single /, so every assertion comparing the test's $project_dir / $maven_home against the actual launcher output mismatches.

Fix: Normalize work_dir through cd/pwd right after mktemp:

work_dir=`mktemp -d "${TMPDIR:-/tmp}/mvn-path-conversion.XXXXXX"`
work_dir=`cd "$work_dir" && pwd`

I've opened #12563 with this one-line fix applied on top of this PR's commit.

On macOS the $TMPDIR variable ends with a trailing slash, so
mktemp -d "${TMPDIR}/mvn-path-conversion.XXXXXX" produces a path
containing a double slash (e.g. .../T//mvn-path-conversion.XNBzZw).
The pwd(1) calls inside the mvn launcher collapse the double slash,
causing all 22 path assertions to fail on macOS CI runners.

Resolve the work directory through cd/pwd right after creation so
the test's reference paths stay in sync with the launcher output.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Hiteshsai007

Copy link
Copy Markdown
Contributor Author

The macOS failures were a bug in my test harness (double slash from mktemp when TMPDIR has a trailing slash), not the launcher — which is why only macOS was affected while Linux and Windows passed.

@gnodet has fixed it in #12563, which includes my commit 033146e plus the normalisation. Happy to close this in favour of that PR, or to push the one-line fix here if you'd prefer to keep this one — whichever is easier for you.

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

New commit (afcb7db) looks good — normalizes the temp dir path through cd/pwd after mktemp to avoid the double-slash issue on macOS where $TMPDIR ends with a trailing slash. Clean fix. Prior APPROVE still stands.

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Claude Code on behalf of gnodet

gnodet added a commit to gnodet/maven that referenced this pull request Jul 28, 2026
@gnodet
gnodet merged commit 6338672 into apache:master Jul 28, 2026
22 checks passed
@github-actions

Copy link
Copy Markdown

@gnodet Please assign appropriate label to PR according to the type of change.

@github-actions github-actions Bot added this to the 4.1.0 milestone Jul 28, 2026
gnodet added a commit that referenced this pull request Jul 28, 2026
…vn (#12567)

Backport of #12546 to the 3.10.x branch. Adapted for the different script
location (src/bin/mvn vs src/assembly/maven/bin/mvn) and the simpler
jvm.config handling (no JvmConfigParser on this branch).

Key changes:
- Detect MSYS2 (MSYS_NT-*) alongside MinGW in uname matching
- Guard against missing cygpath(1) — warn and fall back to POSIX paths
- Convert all paths (MAVEN_HOME, CLASSWORLDS_JAR, MAVEN_PROJECTBASEDIR,
  jline-native) for both Cygwin and MinGW/MSYS2, not just Cygwin
- Convert jline-native path separately to avoid mixed separators
- Use printf instead of echo for values holding paths (avoid backslash
  expansion in dash/ash)
- Add shell test covering Cygwin, MinGW, MSYS2, and missing-cygpath
  fallback, wired into the build via exec-maven-plugin

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
gnodet added a commit that referenced this pull request Jul 28, 2026
#12568)

Backport of #12546 to the 3.9.x branch. Adapted for the different script
location (src/bin/mvn vs src/assembly/maven/bin/mvn), the simpler
jvm.config handling (no JvmConfigParser on this branch), and jansi-native
instead of jline-native.

Key changes:
- Detect MSYS2 (MSYS_NT-*) alongside MinGW in uname matching
- Guard against missing cygpath(1) — warn and fall back to POSIX paths
- Convert all paths (MAVEN_HOME, CLASSWORLDS_JAR, MAVEN_PROJECTBASEDIR,
  jansi-native) for both Cygwin and MinGW/MSYS2, not just Cygwin
- Convert jansi-native path separately to avoid mixed separators
- Use printf instead of echo for values holding paths (avoid backslash
  expansion in dash/ash)
- Add shell test covering Cygwin, MinGW, MSYS2, and missing-cygpath
  fallback, wired into the build via exec-maven-plugin

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Backport #7958 (MNG-7205) to the 3.x line: convert paths for MinGW in bin/mvn

2 participants