Skip to content

Skip macOS AppleDouble sidecar files during .data directory installation#18835

Open
qqgjyx wants to merge 2 commits intoastral-sh:mainfrom
qqgjyx:fix/skip-exfat-apple-double-sidecars
Open

Skip macOS AppleDouble sidecar files during .data directory installation#18835
qqgjyx wants to merge 2 commits intoastral-sh:mainfrom
qqgjyx:fix/skip-exfat-apple-double-sidecars

Conversation

@qqgjyx
Copy link
Copy Markdown

@qqgjyx qqgjyx commented Apr 3, 2026

On exFAT (and FAT32, SMB), macOS creates ._* AppleDouble sidecar files for every file that carries extended attributes. During .data directory installation, move_folder_recorded() walks the directory with WalkDir and picks up these ghost files that aren't in the wheel's RECORD — then errors out with a RECORD mismatch.

This adds an is_apple_double check to skip ._* entries in both move_folder_recorded() and the install_data() scripts loop.

Confirmed with jupyterlab-pygments==0.3.0 on macOS 26 + exFAT — wheel contains zero ._ files but uv sync fails because macOS creates them during the copy.

Closes #18790. See also rust-lang/rust#154692.

Test plan

  • test_is_apple_double: verifies the helper against various filenames
  • test_move_folder_recorded_skips_apple_double: creates a .data directory with a real file + a ._ sidecar not in RECORD, confirms only the real file is moved
  • Manual: COPYFILE_DISABLE=1 uv sync with jupyterlab-pygments on exFAT now succeeds

On non-native filesystems (exFAT, FAT32, SMB), macOS creates `._*` sidecar
files to store extended attributes. These appear in directory listings during
`WalkDir`/`read_dir` but are not part of the wheel RECORD, causing
installation failures.

Closes astral-sh#18790
Copilot AI review requested due to automatic review settings April 3, 2026 00:53
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to prevent macOS AppleDouble ._* sidecar files from breaking wheel .data directory installation by skipping those entries during .data moves and script installation, avoiding RECORD mismatch errors on exFAT/FAT32/SMB.

Changes:

  • Add an is_apple_double helper to detect ._* AppleDouble sidecar files.
  • Skip ._* entries during move_folder_recorded() directory walks and .data/scripts installation loops.
  • Add unit tests for the helper and for skipping AppleDouble entries during .data moves.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +363 to +366
// Skip macOS AppleDouble resource fork sidecar files (`._*`).
if is_apple_double(src) {
continue;
}
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skipping ._* entries here prevents the immediate RECORD lookup error, but it can leave stale RECORD entries behind when the wheel itself contains AppleDouble files (those entries will never be updated, and the .data directory is removed after install). This results in an installed RECORD that references non-existent .data/.../._* paths and shows up in uv pip show --files. Consider either (a) only skipping ._* files that are not present in RECORD, or (b) treating AppleDouble as invalid content and pruning matching RECORD entries before writing the final RECORD (may require taking &mut Vec<RecordEntry> instead of a slice).

Copilot uses AI. Check for mistakes.
Comment on lines 642 to +644

// Skip macOS AppleDouble resource fork sidecar files (`._*`).
if is_apple_double(&file.path()) {
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as move_folder_recorded: skipping ._* script entries avoids install-time failures, but if a wheel includes AppleDouble files in .data/scripts, their RECORD rows will remain and end up pointing at paths that no longer exist after .data is deleted. Recommend pruning ._* entries from the RECORD (or only skipping those not in RECORD) to keep the final RECORD consistent.

Suggested change
// Skip macOS AppleDouble resource fork sidecar files (`._*`).
if is_apple_double(&file.path()) {
let file_path = file.path();
// Skip macOS AppleDouble resource fork sidecar files (`._*`).
// If such a file was listed in RECORD, remove it so the final
// installed RECORD does not reference a path that was never installed.
if is_apple_double(&file_path) {
record.remove(&file_path);

Copilot uses AI. Check for mistakes.
Comment on lines +28 to +30
/// On non-native filesystems (exFAT, FAT32, SMB), macOS stores extended attributes as `._`
/// sidecar files. These appear in directory listings but are not part of the wheel contents
/// and must be skipped during installation to avoid RECORD mismatches.
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The doc comment says AppleDouble sidecars are "not part of the wheel contents", but the issue description notes that some wheels can include ._* entries in the archive/RECORD. It may be clearer to describe them as "not intended package content" and note that they can be either created by macOS during file operations or (incorrectly) present in wheels built on macOS.

Suggested change
/// On non-native filesystems (exFAT, FAT32, SMB), macOS stores extended attributes as `._`
/// sidecar files. These appear in directory listings but are not part of the wheel contents
/// and must be skipped during installation to avoid RECORD mismatches.
/// On non-native filesystems (exFAT, FAT32, SMB), macOS may store extended attributes as `._`
/// sidecar files during file operations. These files are not intended package content, but may
/// also be incorrectly present in wheels built on macOS, and must be skipped during
/// installation to avoid RECORD mismatches.

Copilot uses AI. Check for mistakes.
Comment on lines +31 to +35
fn is_apple_double(path: &Path) -> bool {
path.file_name()
.and_then(|n| n.to_str())
.is_some_and(|n| n.starts_with("._"))
}
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This helper is only applied to .data moves and .data/scripts handling. If the intent is to fully close #18790 (which also reports runtime import failures from ._*.py under purelib/platlib), AppleDouble files elsewhere in the install tree can still be created or extracted and remain in site-packages. Either adjust the PR/issue closure scope, or extend filtering/cleanup to the main wheel extraction/linking path so ._* files never land in site-packages.

Copilot uses AI. Check for mistakes.
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.

uv sync fails on exFAT (macOS): ._ AppleDouble files break .data directory extraction and runtime imports

2 participants