mirror of
				https://github.com/astral-sh/uv.git
				synced 2025-10-29 19:17:26 +00:00 
			
		
		
		
	|  4d82e88863 
		
			Some checks are pending
		
		
	 CI / Determine changes (push) Waiting to run CI / lint (push) Waiting to run CI / cargo clippy | ubuntu (push) Blocked by required conditions CI / cargo clippy | windows (push) Blocked by required conditions CI / cargo dev generate-all (push) Blocked by required conditions CI / cargo shear (push) Waiting to run CI / mkdocs (push) Waiting to run CI / cargo test | ubuntu (push) Blocked by required conditions CI / cargo test | macos (push) Blocked by required conditions CI / cargo test | windows (push) Blocked by required conditions CI / check windows trampoline | aarch64 (push) Blocked by required conditions CI / check windows trampoline | i686 (push) Blocked by required conditions CI / check windows trampoline | x86_64 (push) Blocked by required conditions CI / test windows trampoline | i686 (push) Blocked by required conditions CI / test windows trampoline | x86_64 (push) Blocked by required conditions CI / typos (push) Waiting to run CI / check system | alpine (push) Blocked by required conditions CI / build binary | linux libc (push) Blocked by required conditions CI / build binary | linux aarch64 (push) Blocked by required conditions CI / build binary | linux musl (push) Blocked by required conditions CI / build binary | macos aarch64 (push) Blocked by required conditions CI / build binary | macos x86_64 (push) Blocked by required conditions CI / build binary | windows x86_64 (push) Blocked by required conditions CI / build binary | windows aarch64 (push) Blocked by required conditions CI / cargo build (msrv) (push) Blocked by required conditions CI / build binary | freebsd (push) Blocked by required conditions CI / smoke test | linux aarch64 (push) Blocked by required conditions CI / ecosystem test | pydantic/pydantic-core (push) Blocked by required conditions CI / ecosystem test | prefecthq/prefect (push) Blocked by required conditions CI / ecosystem test | pallets/flask (push) Blocked by required conditions CI / smoke test | linux (push) Blocked by required conditions CI / smoke test | macos (push) Blocked by required conditions CI / smoke test | windows x86_64 (push) Blocked by required conditions CI / smoke test | windows aarch64 (push) Blocked by required conditions CI / integration test | conda on ubuntu (push) Blocked by required conditions CI / integration test | deadsnakes python3.9 on ubuntu (push) Blocked by required conditions CI / integration test | free-threaded on windows (push) Blocked by required conditions CI / integration test | aarch64 windows implicit (push) Blocked by required conditions CI / integration test | aarch64 windows explicit (push) Blocked by required conditions CI / integration test | pypy on ubuntu (push) Blocked by required conditions CI / integration test | pypy on windows (push) Blocked by required conditions CI / integration test | graalpy on ubuntu (push) Blocked by required conditions CI / integration test | graalpy on windows (push) Blocked by required conditions CI / integration test | pyodide on ubuntu (push) Blocked by required conditions CI / integration test | github actions (push) Blocked by required conditions CI / integration test | free-threaded python on github actions (push) Blocked by required conditions CI / integration test | determine publish changes (push) Blocked by required conditions CI / integration test | registries (push) Blocked by required conditions CI / integration test | uv publish (push) Blocked by required conditions CI / integration test | uv_build (push) Blocked by required conditions CI / check cache | ubuntu (push) Blocked by required conditions CI / check cache | macos aarch64 (push) Blocked by required conditions CI / check system | python on debian (push) Blocked by required conditions CI / check system | python on fedora (push) Blocked by required conditions CI / check system | python on ubuntu (push) Blocked by required conditions CI / check system | python on rocky linux 8 (push) Blocked by required conditions CI / check system | python on rocky linux 9 (push) Blocked by required conditions CI / check system | pyston (push) Blocked by required conditions CI / check system | python on macos aarch64 (push) Blocked by required conditions CI / check system | homebrew python on macos aarch64 (push) Blocked by required conditions CI / check system | conda3.11 on windows x86-64 (push) Blocked by required conditions CI / check system | conda3.8 on windows x86-64 (push) Blocked by required conditions CI / check system | amazonlinux (push) Blocked by required conditions CI / check system | embedded python3.10 on windows x86-64 (push) Blocked by required conditions CI / benchmarks | walltime aarch64 linux (push) Blocked by required conditions CI / benchmarks | instrumented (push) Blocked by required conditions CI / check system | graalpy on ubuntu (push) Blocked by required conditions CI / check system | pypy on ubuntu (push) Blocked by required conditions CI / check system | python on macos x86-64 (push) Blocked by required conditions CI / check system | python3.10 on windows x86-64 (push) Blocked by required conditions CI / check system | python3.10 on windows x86 (push) Blocked by required conditions CI / check system | python3.13 on windows x86-64 (push) Blocked by required conditions CI / check system | x86-64 python3.13 on windows aarch64 (push) Blocked by required conditions CI / check system | aarch64 python3.13 on windows aarch64 (push) Blocked by required conditions CI / check system | windows registry (push) Blocked by required conditions CI / check system | python3.12 via chocolatey (push) Blocked by required conditions CI / check system | python3.9 via pyenv (push) Blocked by required conditions CI / check system | python3.13 (push) Blocked by required conditions CI / check system | conda3.11 on macos aarch64 (push) Blocked by required conditions CI / check system | conda3.8 on macos aarch64 (push) Blocked by required conditions CI / check system | conda3.11 on linux x86-64 (push) Blocked by required conditions CI / check system | conda3.8 on linux x86-64 (push) Blocked by required conditions ## Summary There's some inconsistent behaviour in handling symlinks when `cache-key` is a glob or a file path. This PR attempts to address that. - When cache-key is a path, [`Path::metadata()`](https://doc.rust-lang.org/std/path/struct.Path.html#method.metadata) is used to check if it's a file or not. According to the docs: > This function will traverse symbolic links to query information about the destination file. So, if the target file is a symlink, it will be resolved and the metadata will be queried for the underlying file. - When cache-key is a glob, `globwalk` is used, specifically allowing for symlinks: ```rust .file_type(globwalk::FileType::FILE | globwalk::FileType::SYMLINK) ``` - However, without enabling link following, `DirEntry::metadata()` will return an equivalent of `Path::symlink_metadata()` (and not `Path::metadata()`), which will have a file type that looks like ```rust FileType { is_file: false, is_dir: false, is_symlink: true, .. } ``` - Then, there's a check for `metadata.is_file()` which fails and complains that the target entry "is a directory when file was expected". - TLDR: glob cache-keys don't work with symlinks. ## Solutions Option 1 (current PR): follow symlinks. Option 2 (also doable): don't follow symlinks, but resolve the resulting target entry manually in case its file type is a symlink. However, this would be a little weird and unobvious in that we resolve files but not directories for some reason. Also, symlinking directories is pretty useful if you want to symlink directories of local dependencies that are not under the project's path. ## Test Plan This has been tested manually: ```rust fn main() { for follow_links in [false, true] { let walker = globwalk::GlobWalkerBuilder::from_patterns(".", &["a/*"]) .file_type(globwalk::FileType::FILE | globwalk::FileType::SYMLINK) .follow_links(follow_links) .build() .unwrap(); let entry = walker.into_iter().next().unwrap().unwrap(); dbg!(&entry); dbg!(entry.file_type()); dbg!(entry.path_is_symlink()); dbg!(entry.path()); let meta = entry.metadata().unwrap(); dbg!(meta.is_file()); } let path = std::path::PathBuf::from("./a/b"); dbg!(path.metadata().unwrap().file_type()); dbg!(path.symlink_metadata().unwrap().file_type()); } ``` Current behaviour (glob cache-key, don't follow links): ``` [src/main.rs:9:9] &entry = DirEntry("./a/b") [src/main.rs:10:9] entry.file_type() = FileType { is_file: false, is_dir: false, is_symlink: true, .. } [src/main.rs:11:9] entry.path_is_symlink() = true [src/main.rs:12:9] entry.path() = "./a/b" [src/main.rs:14:9] meta.is_file() = false ``` Glob cache-key, follow links: ``` [src/main.rs:9:9] &entry = DirEntry("./a/b") [src/main.rs:10:9] entry.file_type() = FileType { is_file: true, is_dir: false, is_symlink: false, .. } [src/main.rs:11:9] entry.path_is_symlink() = true [src/main.rs:12:9] entry.path() = "./a/b" [src/main.rs:14:9] meta.is_file() = true ``` Using `path.metadata()` for a non-glob cache key: ``` [src/main.rs:18:5] path.metadata().unwrap().file_type() = FileType { is_file: true, is_dir: false, is_symlink: false, .. } [src/main.rs:19:5] path.symlink_metadata().unwrap().file_type() = FileType { is_file: false, is_dir: false, is_symlink: true, .. } ``` | ||
|---|---|---|
| .. | ||
| src | ||
| Cargo.toml | ||