mirror of https://github.com/astral-sh/uv
## Summary The assumption that all tags are listed under a flat `.git/ref/tags` structure was wrong. Git creates a hierarchy of directories for tags containing slashes. To fix the cache key calculation, we need to recursively traverse all files under that folder instead. ## Test Plan 1. Create an `uv` project with git-tag cache-keys; 2. Add any tag with slash; 3. Run `uv sync` and see uv_cache_info error in verbose log; 4. `uv sync` doesn't trigger reinstall on next tag addition or removal; 5. With fix applied, reinstall triggers on every tag update and there are no errors in the log. Fixes #10467 --------- Co-authored-by: Sergei Nizovtsev <sergei.nizovtsev@eqvilent.com> Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
This commit is contained in:
parent
7269273458
commit
051aaa5fe5
|
|
@ -4739,6 +4739,7 @@ dependencies = [
|
||||||
"thiserror 2.0.11",
|
"thiserror 2.0.11",
|
||||||
"toml",
|
"toml",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
|
|
@ -23,3 +23,4 @@ serde = { workspace = true, features = ["derive"] }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
toml = { workspace = true }
|
toml = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
|
walkdir = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use tracing::warn;
|
||||||
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub(crate) enum GitInfoError {
|
pub(crate) enum GitInfoError {
|
||||||
#[error("The repository at {0} is missing a `.git` directory")]
|
#[error("The repository at {0} is missing a `.git` directory")]
|
||||||
|
|
@ -80,24 +83,27 @@ impl Tags {
|
||||||
.find(|git_dir| git_dir.exists())
|
.find(|git_dir| git_dir.exists())
|
||||||
.ok_or_else(|| GitInfoError::MissingGitDir(path.to_path_buf()))?;
|
.ok_or_else(|| GitInfoError::MissingGitDir(path.to_path_buf()))?;
|
||||||
|
|
||||||
let git_refs_path =
|
let git_tags_path = git_refs(&git_dir)
|
||||||
git_refs(&git_dir).ok_or_else(|| GitInfoError::MissingRefs(git_dir.clone()))?;
|
.ok_or_else(|| GitInfoError::MissingRefs(git_dir.clone()))?
|
||||||
|
.join("tags");
|
||||||
|
|
||||||
let mut tags = BTreeMap::new();
|
let mut tags = BTreeMap::new();
|
||||||
|
|
||||||
// Map each tag to its commit.
|
// Map each tag to its commit.
|
||||||
let read_dir = match fs_err::read_dir(git_refs_path.join("tags")) {
|
for entry in WalkDir::new(&git_tags_path).contents_first(true) {
|
||||||
Ok(read_dir) => read_dir,
|
let entry = match entry {
|
||||||
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
|
Ok(entry) => entry,
|
||||||
return Ok(Self(tags));
|
Err(err) => {
|
||||||
}
|
warn!("Failed to read Git tags: {err}");
|
||||||
Err(err) => return Err(err.into()),
|
continue;
|
||||||
};
|
}
|
||||||
for entry in read_dir {
|
};
|
||||||
let entry = entry?;
|
|
||||||
let path = entry.path();
|
let path = entry.path();
|
||||||
if let Some(tag) = path.file_name().and_then(|name| name.to_str()) {
|
if !entry.file_type().is_file() {
|
||||||
let commit = fs_err::read_to_string(&path)?.trim().to_string();
|
continue;
|
||||||
|
}
|
||||||
|
if let Ok(Some(tag)) = path.strip_prefix(&git_tags_path).map(|name| name.to_str()) {
|
||||||
|
let commit = fs_err::read_to_string(path)?.trim().to_string();
|
||||||
|
|
||||||
// The commit should be 40 hexadecimal characters.
|
// The commit should be 40 hexadecimal characters.
|
||||||
if commit.len() != 40 {
|
if commit.len() != 40 {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue