Commit ab6d80c
fix(cli): normalize Windows drive-letter paths in
* fix(cli): normalize Windows drive-letter paths to forward slashes in `wheels new`
`wheels new <name>` fails on a fresh Scoop install with:
[ERROR] Error: lucee.runtime.exp.NativeException:
there is no Resource provider available with the name [c],
available resource providers are [ftp, zip, tar, tgz, http, https, ram, s3]
before any module output appears. Reported by Risto on Windows 11 via
Scoop after #2766 + the manifest fix landed (which unblocked `wheels new`
routing to the wheels module in the first place — see scoop-wheels
direct-push 30ea6e5 + 6cf06fc, 2026-05-28).
## Root cause
`Module.init()` receives `cwd` from LuCLI as the JVM's `user.dir`,
which on Windows is `C:\Users\<name>` with backslashes. The early
`wheels new` code path then constructs paths like:
targetDir = variables.cwd & "/" & appName
= "C:\Users\cy" & "/" & "blog"
= "C:\Users\cy/blog" # mixed slashes!
Lucee 7's `ResourceUtil` runs a URI scheme-detection regex
(`^[a-zA-Z][a-zA-Z0-9+.-]*:`) BEFORE its Windows drive-letter
special case in this code path. The regex matches `c:` from
`C:\Users\cy/blog`, extracts "c" as the scheme, looks for a
matching resource provider, finds none (only `ftp`, `zip`,
`tar`, `tgz`, `http`, `https`, `ram`, `s3` are registered),
and throws. The same call with pure backslashes (`C:\Users\cy\blog`)
works because Lucee's Windows path detection kicks in earlier;
the same call with pure forward slashes (`C:/Users/cy/blog`)
works for the same reason.
The other suspect site is `resolveProjectRoot()` /
`resolveFrameworkSource()`, where `java.io.File.getCanonicalPath()`
returns backslashes (Windows native) and we concat with
`/vendor/wheels`. Same mixed-slash pattern, same crash.
Mac/Linux are unaffected because paths never start with a
letter-colon prefix. The bug has been latent in the Scoop install
since day one but was masked by the `-Dlucli.binary.name=wheels`
omission (scoop-wheels 30ea6e5) — until that was fixed, no
Windows `wheels new` invocation reached the wheels module at all.
## Fix
Two-layer defense:
1. **Normalize all backslashes to forward slashes** before any
path-existence check. `$normalizePath()` runs on `variables.cwd`
in `init()` and on every `File.getCanonicalPath()` result in
`resolveProjectRoot()` and `resolveFrameworkSource()`. Forward-
slash-only paths bypass the URI scheme ambiguity because
`C:/...` matches Lucee's Windows-path detection before its
URI-scheme regex.
2. **`$safeDirExists()` / `$safeFileExists()` wrappers** with a
`java.io.File`-based fallback. If anything still slips through
normalization (a path the user provided via `WHEELS_FRAMEWORK_PATH`,
a mapping, etc.), `directoryExists()` throws the same
NativeException — we catch it and fall back to
`new java.io.File(path).isDirectory()`, which is OS-native and
has no concept of URI schemes.
Layer 1 prevents the throw in the first place; layer 2 prevents the
crash if layer 1 is incomplete. Both layers are no-ops on Mac/Linux
(no backslashes to normalize; `directoryExists` doesn't throw).
## Scope
Limited to the early `wheels new` path: `init()`,
`resolveProjectRoot()`, `scaffoldNewApp()`'s first `directoryExists`,
and `resolveFrameworkSource()`'s three `directoryExists` calls. Once
the framework source is located and we enter the recursive
`copyTemplateDir()` loop, paths are constructed from the (already
normalized) `targetDir` so they inherit forward slashes — no
additional changes needed there.
## Verification
- Smoke-tested on macOS by overwriting `~/.wheels/modules/wheels/Module.cfc`
with the patched version: `wheels new test-patched` scaffolded
successfully with identical output to unpatched.
- Windows verification pending — patched Module.cfc to be hand-delivered
to Risto for drop-in test against his Scoop install before this PR
merges.
Refs scoop-wheels manifest update 30ea6e5 (binary.name fix that
unmasked this bug).
Signed-off-by: Peter Amiri <peter@alurium.com>
* refactor(cli): drop unused $safeFileExists, document #2835 in CHANGELOG
Address wheels-bot review on #2835:
- $safeFileExists was added beside $safeDirExists but never wired to a
call site; the Windows path fix only checks directories. Remove the
dead helper; re-add with its java.io.File fallback if a file-existence
check ever needs it.
- Add an [Unreleased] "### Fixed" CHANGELOG entry for the drive-letter
URI misparse fix.
$safeDirExists and its 8 call sites are unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Peter Amiri <peter@alurium.com>
---------
Signed-off-by: Peter Amiri <peter@alurium.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>wheels new (#2835)1 parent 6318bee commit ab6d80c
2 files changed
Lines changed: 68 additions & 12 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
32 | 32 | | |
33 | 33 | | |
34 | 34 | | |
| 35 | + | |
35 | 36 | | |
36 | 37 | | |
37 | 38 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
27 | 39 | | |
28 | | - | |
| 40 | + | |
29 | 41 | | |
30 | 42 | | |
31 | | - | |
| 43 | + | |
32 | 44 | | |
33 | 45 | | |
34 | 46 | | |
35 | 47 | | |
36 | 48 | | |
37 | 49 | | |
38 | 50 | | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
39 | 83 | | |
40 | 84 | | |
41 | 85 | | |
| |||
4505 | 4549 | | |
4506 | 4550 | | |
4507 | 4551 | | |
| 4552 | + | |
| 4553 | + | |
| 4554 | + | |
4508 | 4555 | | |
4509 | 4556 | | |
4510 | | - | |
| 4557 | + | |
4511 | 4558 | | |
4512 | 4559 | | |
4513 | 4560 | | |
| |||
5225 | 5272 | | |
5226 | 5273 | | |
5227 | 5274 | | |
5228 | | - | |
5229 | | - | |
| 5275 | + | |
| 5276 | + | |
5230 | 5277 | | |
5231 | 5278 | | |
5232 | 5279 | | |
| |||
5239 | 5286 | | |
5240 | 5287 | | |
5241 | 5288 | | |
5242 | | - | |
| 5289 | + | |
5243 | 5290 | | |
5244 | 5291 | | |
5245 | 5292 | | |
5246 | 5293 | | |
5247 | 5294 | | |
5248 | 5295 | | |
| 5296 | + | |
| 5297 | + | |
| 5298 | + | |
5249 | 5299 | | |
5250 | 5300 | | |
5251 | 5301 | | |
5252 | 5302 | | |
5253 | | - | |
| 5303 | + | |
5254 | 5304 | | |
5255 | 5305 | | |
5256 | | - | |
| 5306 | + | |
5257 | 5307 | | |
5258 | 5308 | | |
5259 | 5309 | | |
| |||
5444 | 5494 | | |
5445 | 5495 | | |
5446 | 5496 | | |
5447 | | - | |
| 5497 | + | |
| 5498 | + | |
| 5499 | + | |
| 5500 | + | |
5448 | 5501 | | |
5449 | | - | |
5450 | | - | |
| 5502 | + | |
| 5503 | + | |
5451 | 5504 | | |
5452 | 5505 | | |
5453 | 5506 | | |
| |||
5457 | 5510 | | |
5458 | 5511 | | |
5459 | 5512 | | |
5460 | | - | |
| 5513 | + | |
| 5514 | + | |
| 5515 | + | |
5461 | 5516 | | |
5462 | 5517 | | |
5463 | 5518 | | |
| |||
0 commit comments