|
@@ -248,11 +248,12 @@ fn glob_match(pat: &str, name: &str) -> bool {
|
|
|
|
|
|
|
|
pub fn compute_dir_checksum(dir: &Path) -> Result<String> {
|
|
pub fn compute_dir_checksum(dir: &Path) -> Result<String> {
|
|
|
let mut hasher = Sha256::new();
|
|
let mut hasher = Sha256::new();
|
|
|
- let mut entries: Vec<_> = Vec::new();
|
|
|
|
|
|
|
+ let mut entries: Vec<(String, Vec<u8>)> = Vec::new();
|
|
|
|
|
|
|
|
for entry in walkdir::WalkDir::new(dir).sort_by_file_name() {
|
|
for entry in walkdir::WalkDir::new(dir).sort_by_file_name() {
|
|
|
let entry = entry?;
|
|
let entry = entry?;
|
|
|
- if entry.file_type().is_dir() {
|
|
|
|
|
|
|
+ let file_type = entry.file_type();
|
|
|
|
|
+ if file_type.is_dir() {
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
let rel = entry
|
|
let rel = entry
|
|
@@ -261,17 +262,33 @@ pub fn compute_dir_checksum(dir: &Path) -> Result<String> {
|
|
|
.unwrap_or(entry.path())
|
|
.unwrap_or(entry.path())
|
|
|
.to_string_lossy()
|
|
.to_string_lossy()
|
|
|
.to_string();
|
|
.to_string();
|
|
|
- entries.push((rel, entry.path().to_path_buf()));
|
|
|
|
|
|
|
+ if file_type.is_symlink() {
|
|
|
|
|
+ // A symlink hashes as its dotted target text, never followed:
|
|
|
|
|
+ // build contexts may link a directory (e.g. an upstream `vllm ->
|
|
|
|
|
+ // .submodules/spark-agent/vllm`), and opening it reads a
|
|
|
|
|
+ // directory (EISDIR) or drags a whole tree into the digest.
|
|
|
|
|
+ // The upload tar dereferences links, so the shipped bytes and
|
|
|
|
|
+ // the digest stay independent concerns.
|
|
|
|
|
+ let target = std::fs::read_link(entry.path())?;
|
|
|
|
|
+ entries.push((
|
|
|
|
|
+ rel,
|
|
|
|
|
+ format!("symlink\0{}", target.to_string_lossy()).into_bytes(),
|
|
|
|
|
+ ));
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ if !file_type.is_file() {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ let mut buf = Vec::new();
|
|
|
|
|
+ std::fs::File::open(entry.path())?.read_to_end(&mut buf)?;
|
|
|
|
|
+ entries.push((rel, buf));
|
|
|
}
|
|
}
|
|
|
entries.sort_by(|a, b| a.0.cmp(&b.0));
|
|
entries.sort_by(|a, b| a.0.cmp(&b.0));
|
|
|
|
|
|
|
|
- for (rel, path) in &entries {
|
|
|
|
|
- let mut file = std::fs::File::open(path)?;
|
|
|
|
|
- let mut buf = Vec::new();
|
|
|
|
|
- file.read_to_end(&mut buf)?;
|
|
|
|
|
|
|
+ for (rel, buf) in &entries {
|
|
|
hasher.update(rel.as_bytes());
|
|
hasher.update(rel.as_bytes());
|
|
|
hasher.update(b"\0");
|
|
hasher.update(b"\0");
|
|
|
- hasher.update(&buf);
|
|
|
|
|
|
|
+ hasher.update(buf);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
let hash = hasher.finalize();
|
|
let hash = hasher.finalize();
|