Skip to content

fix(task): convert PATH to /cygdrive form for Cygwin bash tasks#10147

Merged
jdx merged 2 commits into
jdx:mainfrom
JamBalaya56562:fix-cygwin-cygdrive-path
May 31, 2026
Merged

fix(task): convert PATH to /cygdrive form for Cygwin bash tasks#10147
jdx merged 2 commits into
jdx:mainfrom
JamBalaya56562:fix-cygwin-cygdrive-path

Conversation

@JamBalaya56562
Copy link
Copy Markdown
Contributor

Problem

PR #9547 added Windows→Unix PATH conversion so mise launched from PowerShell can spawn a POSIX shell (bash -c) for a task with a usable PATH. It unconditionally emits the MSYS2 / Git Bash /c/foo form, but Cygwin expects /cygdrive/c/foo — so Cygwin users' PATH was corrupted and binaries like cygpath became command not found.

Reported in #9950. Cygwin was intentionally out of scope in #9547; this is the follow-up.

Fix

  • Detect Cygwin bash by a cygwin / cygwin64 / cygwin32 path segment in the resolved bash path. Detection runs after bash resolution, so it sees the real exe (C:\cygwin64\bin\bash.exe, or a MISE_BASH_PATH pointing there). Segment-matching avoids false positives like my-cygwinish-tools.
  • Thread a drive_prefix through windows_path_list_to_unix: "" for MSYS2 / Git Bash (/c/..., unchanged) and /cygdrive for Cygwin (/cygdrive/c/...).
  • A non-default cygdrive mount (configured in /etc/fstab) can be supplied via MISE_CYGDRIVE_PREFIX (e.g. /mnt); mise does not parse fstab. A trailing / is trimmed, so MISE_CYGDRIVE_PREFIX=/ collapses to the MSYS /c/... form.

Pure Rust, no subprocess (no cygpath fork). Windows-only and bash-path-based; MSYSTEM is not consulted since PowerShell-launched mise inherits none.

Out of scope (intentional)

  • Parsing /etc/fstab — replaced by the explicit MISE_CYGDRIVE_PREFIX escape hatch.
  • Auto-adding Cygwin to bash_candidates() — would change bash auto-selection for users who have both Git Bash and Cygwin installed. Cygwin users pick their bash via MISE_BASH_PATH or PATH; this fix ensures PATH is formatted correctly for whichever bash is chosen.

Tests

  • src/path.rs: Cygwin conversion (basic, forward-slash, drive-letter case, spaces, UNC / already-unix passthrough, empty, relative), custom prefix, and is_cygwin_shell detection (true/false incl. the false-positive guard).
  • src/task/task_executor.rs: maybe_convert_env_for_msys_shell routes Cygwin → /cygdrive, Git Bash → /c/ (unchanged), and honors MISE_CYGDRIVE_PREFIX.
  • e2e-win/task.Tests.ps1: skippable Cygwin e2e asserting the task PATH contains /cygdrive/.

28 unit tests pass locally on x86_64-pc-windows-msvc. CHANGELOG.md is git-cliff-generated, so left untouched.

🤖 Generated with Claude Code

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for Cygwin bash on Windows by detecting Cygwin paths and converting the PATH environment variable to the /cygdrive/c/... format instead of the Git Bash /c/... format. It also allows overriding the default prefix via the MISE_CYGDRIVE_PREFIX environment variable, accompanied by documentation updates and tests. The review feedback focuses on performance optimizations, specifically suggesting allocation-free implementations for path segment matching in is_cygwin_shell and prefix resolution in msys_drive_prefix_for.

Comment thread src/path.rs Outdated
Comment thread src/task/task_executor.rs Outdated
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 30, 2026

Greptile Summary

This PR fixes Cygwin PATH corruption when mise is launched from PowerShell and spawns a Cygwin bash task: it detects Cygwin bash by a cygwin/cygwin64/cygwin32 path segment, then converts the task PATH to Cygwin's /cygdrive/c/... form instead of the MSYS2/Git Bash /c/... form already in use.

  • windows_path_list_to_unix now accepts a drive_prefix parameter (\"\" for MSYS2, \"/cygdrive\" for Cygwin, or a custom value from MISE_CYGDRIVE_PREFIX), and msys_drive_prefix_for selects the right prefix at the spawn boundary.
  • is_cygwin_shell performs whole-segment, case-insensitive matching on the resolved bash path so substrings like my-cygwinish-tools don't trigger false positives.
  • MISE_CYGDRIVE_PREFIX is validated to be absolute; a relative value (e.g. mnt) is rejected with a warning and falls back to /cygdrive rather than silently producing broken PATH entries.

Confidence Score: 5/5

Safe to merge — the change is Windows-only, narrowly scoped to PATH conversion at the bash spawn boundary, and does not touch any shared non-Windows codepaths.

The detection logic is well-guarded (whole-segment matching, case-insensitive), the drive_prefix plumbing is mechanically straightforward, and MISE_CYGDRIVE_PREFIX validation correctly rejects relative values. Unit tests cover the main happy paths and edge cases. The only gap is a missing assertion for the cygwin32 segment in the detection tests, which is a minor oversight with no runtime impact.

No files require special attention.

Important Files Changed

Filename Overview
src/path.rs Adds drive_prefix parameter to windows_path_list_to_unix/append_single_windows_path_to_unix and new is_cygwin_shell helper; logic is correct, but cygwin32 segment detection has no unit-test coverage in the new test suite.
src/task/task_executor.rs Adds msys_drive_prefix_for to select the right cygdrive prefix before calling windows_path_list_to_unix; task-env checked before process-env, invalid relative prefix is rejected with a warning, and edge cases (/ collapsing to MSYS form) are covered by tests.
docs/troubleshooting.md New Cygwin section added with detection explanation, MISE_BASH_PATH/MISE_CYGDRIVE_PREFIX usage, and the absolute-prefix requirement; accurate and complete.
e2e-win/task.Tests.ps1 New Cygwin e2e test correctly skips when Cygwin is absent, saves/restores all overridden env vars, and pins MISE_CYGDRIVE_PREFIX to /cygdrive so the assertion is stable across developer machines.

Reviews (5): Last reviewed commit: "fix(task): address review feedback on Cy..." | Re-trigger Greptile

Comment thread docs/troubleshooting.md
Comment thread src/task/task_executor.rs Outdated
@JamBalaya56562 JamBalaya56562 force-pushed the fix-cygwin-cygdrive-path branch 2 times, most recently from f9eafb8 to 6898c7c Compare May 31, 2026 03:59
JamBalaya56562 and others added 2 commits May 31, 2026 13:32
PR jdx#9547 converts a Windows-form PATH (C:\foo;D:\bar) to Unix form when
mise on Windows spawns a bash task, but always emitted the MSYS2 / Git
Bash `/c/foo` style. Cygwin expects `/cygdrive/c/foo`, so PATH was
corrupted and tools like cygpath became "command not found".

Detect Cygwin bash via a `cygwin` / `cygwin64` / `cygwin32` segment in the
resolved bash path and convert PATH using the `/cygdrive` prefix. A
non-default cygdrive mount (configured in /etc/fstab) can be supplied via
MISE_CYGDRIVE_PREFIX; mise does not parse fstab. MSYS2 / Git Bash
behaviour is unchanged.

Reported in discussion jdx#9950.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- is_cygwin_shell: split on both separators with eq_ignore_ascii_case
  (allocation-free; drops the lowercase/replace temporaries)
- msys_drive_prefix_for: trim the trailing slash in place via truncate, and
  reject a non-absolute MISE_CYGDRIVE_PREFIX (e.g. `mnt`) with a warning,
  falling back to the default `/cygdrive` instead of emitting relative PATH
  entries that bash silently ignores
- docs: mention the `cygwin32` segment and that the prefix must be absolute
- tests: relative-prefix rejection and `MISE_CYGDRIVE_PREFIX=/` -> MSYS form

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@JamBalaya56562 JamBalaya56562 force-pushed the fix-cygwin-cygdrive-path branch from 6898c7c to e05d406 Compare May 31, 2026 04:40
@jdx jdx merged commit 183a637 into jdx:main May 31, 2026
33 checks passed
@JamBalaya56562 JamBalaya56562 deleted the fix-cygwin-cygdrive-path branch May 31, 2026 13:07
@lewis-yeung
Copy link
Copy Markdown

@JamBalaya56562 A non-default cygdrive mount point is available not only in Cygwin Bash, but ALSO in Git Bash. The following code unconditionally assumes that a specific segment exists in the Bash executable path, and excludes Git Bash cases which are STILL BROKEN. :(

mise/src/path.rs

Lines 242 to 246 in 310e325

s.split(['/', '\\']).any(|seg| {
seg.eq_ignore_ascii_case("cygwin")
|| seg.eq_ignore_ascii_case("cygwin64")
|| seg.eq_ignore_ascii_case("cygwin32")
})

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.

3 participants