Repository navigation
Fix rx.asset(shared=True) crash on Windows without Developer Mode - #7703
AP24110011695 wants to merge 3 commits into
Conversation
rx.asset(shared=True) crashed on Windows without Developer Mode (or admin rights): creating the symlink raises WinError 1314 and nothing handled it, so the whole app failed to compile with a cryptic error. When symlink creation is denied, stage the link as a hardlink, which shares the source content on the same drive, and as a copy when the source lives on another drive. The content check in _links_to now also recognizes hardlinks (same inode) and copies (same digest), so a second link is still a no-op for file watchers, and an edited source re-copies on the next compile instead of serving stale content.
There was a problem hiding this comment.
All reported issues were addressed across 4 files
Reply with feedback, questions, or to request a fix.
View guided diff | Re-trigger cubic
[Medium impact] The PR appears safe to merge; the previous stale-copy finding is fixed and no new actionable issue was found. SummaryMakes
AP24110011695 deferred cleanup of assets from removed modules to #7705 because fallback files need source-tracking information. Greptile accepted that follow-up. Reviews (3) · Last reviewed commit: "fix(assets): compare copied assets by co..." · Reviewed by Greptile |
Address the review findings on PR reflex-dev#7703: - A read-only source made every fallback path break later compiles: a hardlink shares the read-only bit, and copy2 mirrors it, and Windows refuses to replace a read-only destination. Read-only sources now go straight to a copy, which is made writable so the next compile can replace it. Regression test included. - The copy check hashed both files in full on every compile; compare size and mtime (copy2 preserves both) instead, so an unchanged copy costs no file reads while an edited source still re-copies. - Document the copy fallback as 'when hardlinking is unavailable' (cross-drive, FAT32) rather than cross-drive only. - Assert an unchanged copy is left alone in the copy fallback test, mirroring the hardlink test.
There was a problem hiding this comment.
All reported issues were addressed across 4 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
View guided diff | Re-trigger cubic
…path Address the re-review findings on PR reflex-dev#7703: size and mtime are not content identity - a same-size rewrite that preserves the timestamp (archive restore, timestamp-preserving tools) passed as unchanged and kept serving stale bytes. Equal sizes are now compared by digest; the size pre-check keeps the edited-source case on stats alone.
Merging this PR will regress 1 benchmark3 warnings
Warning Please fix the performance issues or acknowledge them on CodSpeed. Performance Changes
Tip Investigate this regression by commenting Comparing |
|
The ubuntu 3.12 unit-tests failure is a timing-threshold flake unrelated to the change: |
|
Same read on this report: |
All Submissions:
Type of change
Description
On Windows without Developer Mode (or admin rights), creating a symlink raises
OSError: [WinError 1314] A required privilege is not held by the client._link_shared_assethandles Windows rename races meticulously but not symlink-creation denial, sorx.asset(path="x.js", shared=True)— reached from any component render — crashes the whole app compile on a default Windows machine. Reproduced on Windows 10 x64, Python 3.12, current main:No GitHub issue found for this; the docs make no mention of a Windows requirement.
Fix
When symlink creation is denied, stage the link as a hardlink (shares the source content, no privileges needed on the same drive), and as a copy when that is also denied (source on another drive). The existing atomic staged-rename and retry logic is unchanged — it operates on
tmp_fileeither way._links_tois extended so the idempotency guarantee survives the fallbacks: a hardlink matches by inode (Path.samefile), a copy by content digest (_content_digest). That preserves two behaviors callers rely on: a second link is a no-op so file watchers see no change, and an edited source re-copies on the next compile instead of serving stale content forever.Tests
3 new tests in
tests/units/assets/test_assets.py, all platform-independent (symlink denial is simulated by monkeypatchingos.symlink, matching the file's existing competing-process pattern):test_link_shared_asset_hardlink_fallback— content shared, idempotent second call (inode unchanged). Failed before this PR (OSError 1314 propagates), passes after.test_link_shared_asset_copy_fallback— copy created whenos.linkis also denied. Failed before (same), passes after.test_link_shared_asset_copy_refreshes_edited_source— edited source re-copies. Failed before, passes after.Validated end-to-end on a real Windows machine without Developer Mode:
_link_shared_assetpreviously raised 1314, now produces a working hardlink; 5 previously-failing tests in the file (which link through the product path) now pass locally too. The 12 remaining local failures all create symlinks inside the tests themselves and pass on Linux CI.ruff check/ruff format --checkclean;pyrightclean.Docs
docs/assets/overview.mdalert updated with the Windows fallback behavior.Changes To Core Features:
After these steps, you're ready to open a pull request.