feat: native Windows support - #41
Open
jhodges10 wants to merge 4 commits into
Open
Conversation
drift compiled on Windows already, but nothing it wrote there was portable: `drift check` reported every doc in the repo stale. Two things differed. Repo-relative paths came out of `std.Io.Dir.path.relative` with host separators, so a binding stored as `docs\a.md` never matched the `docs/a.md` that `git ls-files` reports during doc discovery. And Git for Windows turns on `core.autocrlf` by default, so the working tree holds CRLF where Linux holds LF, and every fingerprint that reaches raw bytes changed with the checkout rather than the content — the no-grammar fallback and markdown sections directly, and grammar-based fingerprints too, since a line comment's token text runs to end-of-line and swallows the CR. Normalize both at the boundary: `repo_path.normalize` rewrites a repo-relative path to POSIX separators where it is produced, and `content.normalizeLineEndings` collapses CRLF as working-tree files are read. Absolute paths keep host form — they never leave the process. LF-only content hashes unchanged, so lockfiles written before this stay valid. Also point the integration tests at `drift.exe` explicitly rather than relying on CreateProcess probing for the extension. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`Binding.setField` frees the previous value, so the `old_sig` slice the relink gate holds across `refreshBindingSig` dangles, and `isDocGateBlocked` compares against freed memory. Whether a relink is refused or waved through then depends on what the allocator happened to leave behind — on Windows, `drift link <doc>` refused every anchor in the doc, including ones whose fingerprint had not moved. Dupe the signature into the run arena before restamping. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adds a `test-windows` job on `windows-latest` running the same build, test suite, and `drift lint` as the Linux job. Windows is the one platform where path separators, line endings, and the executable suffix differ, so cross-compiling it without ever running it is what let those bugs sit. Adds `x86_64-windows` and `aarch64-windows` to the CI and release build matrices, cross-compiled from Linux as the other targets are. They ship as `.zip` rather than `.tar.gz` — Windows opens a zip without extra tooling. `.gitattributes` pins the working tree to LF. drift itself no longer cares after the previous commits, but `zig fmt` rejects CRLF, so without this a Windows contributor cannot format the repo. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Author
|
@laulauland I missed your initial response to my github issue, but I just went ahead and did the Windows build! |
- content: skip CRLF normalization for binary-looking content (git's NUL-in-first-8000-bytes heuristic) so a CR-only change in a raw-hash target stays detectable, and early-out on buffers with no CR - docs: qualify the lockfile-compatibility claim (committed-CRLF text re-fingerprints once and needs a relink), document the binary carve-out, and collapse DESIGN.md's restatement of Decision 15 - release workflow: fail loudly when an archive goes missing (if-no-files-found: error, fail_on_unmatched_files) instead of publishing a release without it - ci: build matrix no longer waits on test-windows (it still gates merges as its own status check); strict artifact upload - README: arch-aware Windows download, registry-safe PATH append that preserves REG_EXPAND_SZ entries and dedupes, from-source install that lands on PATH - link: hoist the doc read out of the normalize call argument; drop a redundant lockfile assertion in the integration test - relink drift anchors for the updated docs Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #35.
I have a developer on Windows, so I took you up on the offer to send a PR. drift already compiled on Windows — what it didn't do was produce a
drift.lockthat meant the same thing anywhere else. On a fresh Windows checkout of this repo,drift checkreported every doc stale.What was broken
Path separators. Repo-relative paths come out of
std.Io.Dir.path.relativewith host separators, sodrift link docs/a.md src/b.tsrecordeddoc = "docs\\a.md". Doc discovery matches bindings againstgit ls-files, which is POSIX on every platform, so a binding never matched the doc it was written for.Line endings. Git for Windows enables
core.autocrlfby default, so the working tree holds CRLF where Linux holds LF. Every fingerprint that reaches raw bytes moved with the checkout rather than the content — the no-grammar fallback and markdown sections directly, and grammar-based fingerprints too, since a line comment's token text runs to end-of-line and swallows the\r.Together these accounted for all 26 integration-test failures on Windows.
A relink-gate use-after-free. Chasing the above turned up a real bug that isn't Windows-specific.
Binding.setFieldfrees the previous value, so theold_sigslice the gate holds acrossrefreshBindingSigdangles, andisDocGateBlockedcompares against freed memory. Whether a relink is refused or waved through depends on what the allocator left behind. On Windows it meantdrift link <doc>refused every anchor in a doc, including ones whose fingerprint had not moved. It's the second commit and stands alone if you'd rather take it separately.What's here
src/repo_path.zig— normalizes a repo-relative path to/where it is produced. Absolute paths keep host form; they never leave the process.src/content.zig— collapses CRLF as working-tree files are read. LF-only content hashes unchanged, so existing lockfiles stay valid — no relink needed for anyone on Linux or macOS..gitattributespinning the working tree to LF. drift no longer needs it, butzig fmtrejects CRLF, so without it a Windows contributor can't format the repo. Content is already LF in the index, sogit add --renormalize .is a no-op here.test-windowsCI job onwindows-latestrunning the same build, test suite, anddrift lintas the Linux job. Cross-compiling Windows without ever running it is what let this sit.x86_64-windowsandaarch64-windowsin the CI and release matrices, cross-compiled from Linux like the other targets, packaged as.zipsince Windows opens those without extra tooling.Verification
On Windows 11, Zig 0.16.0:
Both Windows targets cross-compile clean. Test count went 79 → 81 (the 26 Windows failures are gone; the added tests are net-new).
I have not touched the
install.shat drift.fp.dev, so the README points Windows users at the release zip and at building from source. Happy to follow up there if you want it to handle Windows too.🤖 Generated with Claude Code