rustPlatform.fetchCargoVendor: dereference symlinks from entire git tree

We accidentally broke the symlink dereferencing logic in https://github.com/NixOS/nixpkgs/pull/379049
After that PR, only symlinks inside the crate subtree got dereferened,
breaking packages which symlink files from a parent directory to the crate subtree

This commit adds a custom ignore function for copytree instead of relying on
ignore_dangling_symlinks=True
This commit is contained in:
TomaSajt 2025-03-15 16:48:57 +01:00 committed by Masum Reza
parent ec505766bb
commit e14998cb44

View file

@ -7,6 +7,7 @@ import shutil
import subprocess import subprocess
import sys import sys
import tomllib import tomllib
from os.path import islink, realpath
from pathlib import Path from pathlib import Path
from typing import Any, TypedDict, cast from typing import Any, TypedDict, cast
from urllib.parse import unquote from urllib.parse import unquote
@ -194,11 +195,41 @@ def find_crate_manifest_in_tree(tree: Path, crate_name: str) -> Path:
def copy_and_patch_git_crate_subtree(git_tree: Path, crate_name: str, crate_out_dir: Path) -> None: def copy_and_patch_git_crate_subtree(git_tree: Path, crate_name: str, crate_out_dir: Path) -> None:
# This function will get called by copytree to decide which entries of a directory should be copied
# We'll copy everything except symlinks that are invalid
def ignore_func(dir_str: str, path_strs: list[str]) -> list[str]:
ignorelist: list[str] = []
dir = Path(realpath(dir_str, strict=True))
for path_str in path_strs:
path = dir / path_str
if not islink(path):
continue
# Filter out cyclic symlinks and symlinks pointing at nonexistant files
try:
target_path = Path(realpath(path, strict=True))
except OSError:
ignorelist.append(path_str)
eprint(f"Failed to resolve symlink, ignoring: {path}")
continue
# Filter out symlinks that point outside of the current crate's base git tree
# This can be useful if the nix build sandbox is turned off and there is a symlink to a common absolute path
if not target_path.is_relative_to(git_tree):
ignorelist.append(path_str)
eprint(f"Symlink points outside of the crate's base git tree, ignoring: {path} -> {target_path}")
continue
return ignorelist
crate_manifest_path = find_crate_manifest_in_tree(git_tree, crate_name) crate_manifest_path = find_crate_manifest_in_tree(git_tree, crate_name)
crate_tree = crate_manifest_path.parent crate_tree = crate_manifest_path.parent
eprint(f"Copying to {crate_out_dir}") eprint(f"Copying to {crate_out_dir}")
shutil.copytree(crate_tree, crate_out_dir, ignore_dangling_symlinks=True) shutil.copytree(crate_tree, crate_out_dir, ignore=ignore_func)
crate_out_dir.chmod(0o755) crate_out_dir.chmod(0o755)
with open(crate_manifest_path, "r") as f: with open(crate_manifest_path, "r") as f: