Skip to content

internal/winpath: Windows to WSL path translation - #17

Merged
zcsizmadia merged 1 commit into
mainfrom
winpath-translation
Sep 1, 2026
Merged

zcsizmadia merged 1 commit into
mainfrom
winpath-translation

Conversation

@zcsizmadia

Copy link
Copy Markdown
Collaborator

Closes #7. First real v0.1 code, and it implements exactly what Spike A measured rather than what we guessed.

The requirement, from #2: the daemon rejects C:\src:/app and C:/src:/app with invalid mode: /app, and accepts /mnt/c/src:/app. The error comes from the daemon, so the CLI passes the spec through untouched — the proxy must rewrite HostConfig.Binds.

API

  • ToWSL — C:\src → /mnt/c/src. Separator-agnostic (\, /, mixed), drive case-insensitive, idempotent, and POSIX paths pass through unchanged so users who already speak WSL aren''t punished.
  • TranslateBind — parses source:dest[:options] where the source may contain its own colon. This is the case a naive Split(":") gets wrong, and it is precisely how the spike''s failure manifested.
  • TranslateBinds — batch for a create request. Fails loudly on a bad spec rather than dropping a mount, and preserves nil so the re-encoded JSON keeps its shape (null, not []).

Two correctness details worth review:

  • Named volumes are never translated. myvolume:/data must stay a volume; rewriting it would silently convert it into a bind mount against a host directory that doesn''t exist.
  • UNC paths get a typed *ErrUNC naming the fix ("map it to a drive letter first") rather than letting the daemon reject them less legibly. WSL2 reaches Windows files via /mnt/<drive>, and a share has no drive letter.

28 subtests, 98% statement coverage, no I/O — runs on any platform, so CI doesn''t need WSL for this.

One implementation note: the structural checks are plain byte comparisons rather than regexps. A path separator is a backslash, and escaping one through a regexp literal is a bug waiting to happen — it actually bit this file mid-development, and the tests caught it. Byte checks are also clearer for what amounts to "is byte 1 a colon".

🤖 Generated with Claude Code

Implements the translation Spike A proved necessary: the daemon rejects
"C:\src:/app" and "C:/src:/app" with `invalid mode: /app` and accepts
"/mnt/c/src:/app", and the CLI passes the string through untouched, so
the proxy has to rewrite it.

- ToWSL: C:\src -> /mnt/c/src, separator- and case-insensitive,
  idempotent, POSIX paths pass through untouched
- TranslateBind: parses source:dest[:options] with a drive-letter source,
  the case a naive Split(":") gets wrong; named volumes are never
  translated (that would silently turn a volume into a bind mount)
- TranslateBinds: batch for HostConfig.Binds, fails loudly rather than
  dropping a mount, preserves nil so re-encoded JSON keeps its shape
- UNC paths get a typed error naming the fix instead of a daemon rejection

28 subtests, 98% coverage, no I/O so it runs on any platform. Structural
checks are byte comparisons rather than regexps: a separator is a
backslash, and escaping one through a regexp literal is a bug waiting to
happen (it bit this file during development).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@zcsizmadia
zcsizmadia merged commit 38f47ab into main Sep 1, 2026
1 check passed
@zcsizmadia
zcsizmadia deleted the winpath-translation branch September 1, 2026 13:19
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.

Windows→WSL volume path translation

1 participant