Skip to content

Fix path compatibility: try direct strip_prefix first, normalize as fallback - #854

Closed
max-sixty wants to merge 14 commits into
mitsuhiko:masterfrom
max-sixty:bazel-windows-compat
Closed

max-sixty wants to merge 14 commits into
mitsuhiko:masterfrom
max-sixty:bazel-windows-compat

Conversation

@max-sixty

Copy link
Copy Markdown
Collaborator

This is an alternative approach to #852 that should work for both Bazel and Windows.

Summary

  • Try direct strip_prefix first (preserves symlinks, works for Bazel)
  • Fall back to normalizing with canonicalize() if that fails (handles Windows path format differences)

The key insight is: try direct first, normalize only if that fails. This is the opposite of the original approach which normalized first (breaking Bazel).

Test plan

  • Local tests pass (93/93)
  • Windows CI passes
  • Bazel integration works (tested previously)

🤖 Generated with Claude Code

max-sixty and others added 14 commits December 30, 2025 23:42
This adds support for the INSTA_PENDING_DIR environment variable, which
allows pending snapshots to be written to a separate directory while
keeping the source tree read-only. This is particularly useful for
hermetic build systems like Bazel.

When INSTA_PENDING_DIR is set:
- Pending snapshots (.snap.new and .pending-snap files) are written to
  the specified directory, preserving the same relative structure as
  the workspace
- cargo-insta correctly discovers and maps these pending snapshots back
  to their target locations in the source tree
- External test paths (e.g., path = "../tests/lib.rs") are rejected
  with a clear error, as they would escape the pending directory

Key changes:
- insta: Add get_pending_dir() and pending_snapshot_path() in env.rs
- insta: Update runtime.rs to use pending_snapshot_path for all
  snapshot file operations
- insta: Create parent directories in snapshot.rs for pending dir
- cargo-insta: Update find_pending_snapshots() in walk.rs to support
  path mapping between pending_root and target_root
- cargo-insta: Simplify load_snapshot_containers() in cli.rs to use
  unified loop for both hermetic and default modes
- cargo-insta: Add comprehensive tests in pending_dir.rs

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
On Windows, paths from different sources may have different formats
(e.g., \\?\ prefix from canonicalize vs. regular paths). This caused
strip_prefix to fail when comparing workspace and snapshot paths.

Fix by canonicalizing both paths before strip_prefix. Fall back to
original paths if canonicalization fails (e.g., for test scenarios
with non-existent paths).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
The previous canonicalization approach failed on Windows because:
1. Canonicalize() fails for non-existent files (new snapshots)
2. When it succeeds, it adds \\?\ extended-length prefix
3. strip_prefix fails when comparing paths with/without the prefix

The fix adds normalize_path() helper that:
- Tries to canonicalize the full path
- Falls back to canonicalizing parent + filename (for env.rs)
- Strips the \\?\ prefix on Windows for consistent comparison

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
The previous fix didn't handle the case where a non-existent file's
parent directories also don't exist yet. On Windows, if part of the
path contains 8.3 short names (e.g., RUNNER~1 for runneradmin),
canonicalization of the existing workspace directory would convert
to long names while the snapshot path stayed in short name form.

The fix walks up the path tree to find the first existing ancestor,
canonicalizes it (which resolves 8.3 names to long names), then
appends the remaining path components.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Remove the complex path normalization code and try direct strip_prefix.
If both paths come from consistent sources, they should match without
any normalization. Let's see if Windows CI passes without it.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…equired

Clarify in doc comments that this complexity exists because Windows paths
from different sources have incompatible formats, and without normalization
strip_prefix silently fails causing snapshots to go to wrong locations.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
The previous implementation used canonicalize() as a fallback for
strip_prefix, but this caused issues with Bazel's symlinked execroot.

Testing shows direct strip_prefix works without the normalization
fallback. If Windows CI fails, we can add back a targeted fix.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…allback

This preserves symlinks for Bazel's execroot (where direct strip works)
while still handling Windows path format differences (where normalization
is needed). The key insight is: try direct first, normalize only if that fails.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This test creates a symlinked workspace (like Bazel's execroot) and
verifies that INSTA_PENDING_DIR works correctly without following
symlinks. This would have caught the bug reported in PR mitsuhiko#852.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@max-sixty

Copy link
Copy Markdown
Collaborator Author

Consolidated into #852

@max-sixty max-sixty closed this Jan 3, 2026
@max-sixty
max-sixty deleted the bazel-windows-compat branch January 3, 2026 22:11
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.

1 participant