[v3, windows] Fix generate bindings failing with "Access is denied" when Vite dev server is running#5561
Conversation
…e output directory (#5515) The atomic directory swap introduced in #5367 (RemoveAll+Rename) fails on Windows with "Access is denied" when a file watcher such as Vite's dev server is running: the watcher holds an open handle on the watched bindings directory, so deleting it leaves the name in delete-pending state and the subsequent rename over it is rejected. Keep generating into the dot-prefixed temp directory (still invisible to chokidar during generation), but install the result by syncing files into the output directory instead of replacing the directory itself: - the output directory is never deleted or renamed, so Windows watcher handles are never violated (#5515) - the directory delete+recreate cascade that caused the chokidar rename-event loop still never happens (#3976) - unchanged files are left untouched, so the dev server only reloads files that actually changed File operations retry briefly with backoff on Windows to ride out transient locks from watchers and antivirus scanners. Fixes #5515
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
WalkthroughThis PR replaces the atomic directory swap (rename) in bindings generation with a file-by-file synchronization approach (syncDirs), adds Windows-aware retry/backoff, integrates it into GenerateBindings, adds tests, and records a changelog entry for the Windows fix. ChangesBindings sync implementation and integration
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 golangci-lint (2.12.2)level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies" Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
This PR fixes a Windows-specific regression where wails3 generate bindings fails with “Access is denied” when the bindings directory is being watched (e.g. by Vite/chokidar). It replaces the previous “atomic directory swap” install step with a per-file sync into the existing output directory to avoid deleting/renaming a watched directory.
Changes:
- Install generated bindings by syncing files into the existing output directory (instead of
RemoveAll+Renameover the directory) to avoid Windows watcher handle conflicts. - Add
syncDirsutility with Windows retry/backoff for transient file locks. - Add unit tests covering update/delete behavior, type mismatches, and “identical content leaves mtimes untouched”.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| v3/UNRELEASED_CHANGELOG.md | Adds a changelog entry for the Windows “Access is denied” bindings fix. |
| v3/internal/commands/bindings.go | Switches bindings installation step from directory swap to syncDirs(...). |
| v3/internal/commands/bindings_sync.go | Implements directory syncing logic + Windows retry/backoff helper. |
| v3/internal/commands/bindings_sync_test.go | Adds unit tests for the sync behavior and mtime preservation for unchanged files. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Handle the output path existing as a regular file: clear it and move the generated tree into place (with test) - Fall back to remove+rename in replaceFile for destinations that os.Rename cannot replace on Windows (read-only attribute) - Retry the final temp directory removal like other file operations - Use 0o755 for created directories, consistent with the rest of the package
Bundles content from the failed alpha.99 release (tag pushed but no GitHub release created due to token misconfiguration) together with the alpha.100 cycle. Includes: - MacWebviewPreferences WKWebView extensions (#5549) - generate bindings "Access is denied" fix on Windows (#5561) - Linux frameless JS resize / scrollbar edge detection fix (#5368) - Windows updater cross-volume rename fallback (#5560)
Description
Fixes #5515 — a regression introduced in v3.0.0-alpha.96 by #5367.
The atomic directory swap from #5367 (
os.RemoveAll+os.Rename) fails on Windows when a file watcher such as Vite's dev server is running: the watcher holds an open handle on the watchedbindingsdirectory (viaReadDirectoryChangesW), so deleting it leaves the name in delete-pending state and the subsequent rename over it is rejected withAccess is denied.The fix
Bindings are still generated into a dot-prefixed sibling temp directory (invisible to chokidar during generation, as before), but the result is now installed by syncing files into the output directory instead of replacing the directory itself:
If the output directory doesn't exist at all, the whole tree is still moved with a single rename (fast path).
Type of change
How Has This Been Tested?
syncDirscovering: no pre-existing destination, update+stale-delete with unchanged files verified untouched (mtime preserved), file↔directory type mismatches, and fully identical content.wails3and rangenerate bindings -cleanagainstv3/examples/bindingtwice — second run over existing output with planted stale files/dirs. Stale entries were removed, unchanged files kept their original mtimes (i.e. were not rewritten), and no temp directories were left behind.go test ./internal/commands/passes;go vetclean.The Windows-with-Vite-running scenario from the issue would be good to confirm on a Windows machine, but the failing operation (rename over a watched directory) is structurally eliminated rather than retried around.
Checklist:
v3/UNRELEASED_CHANGELOG.mdSummary by CodeRabbit
Bug Fixes
Tests