use super::VFS;
use crate::{NormalizedPath, VfsFile, paths::normalized_safe_key};
use rayon::prelude::*;
use std::path::{Path, PathBuf};
use walkdir::WalkDir;
pub struct DirectoryDiff<'vfs> {
pub conflicts: Vec<(PathBuf, VfsFile, &'vfs VfsFile)>,
pub additions: Vec<(PathBuf, VfsFile)>,
}
impl VFS {
pub fn diff_directory<P: AsRef<Path> + Sync>(&self, dir: P) -> DirectoryDiff<'_> {
let dir = dir.as_ref().to_path_buf();
let entries: Vec<(NormalizedPath, PathBuf, VfsFile)> = WalkDir::new(&dir)
.follow_links(true)
.into_iter()
.filter_map(|entry| match entry {
Ok(entry) if entry.file_type().is_file() => Some(entry),
Ok(_) => None,
Err(err) => {
eprintln!(
"vfstool: warning: failed to walk '{}': {err}",
dir.display()
);
None
}
})
.par_bridge()
.filter_map(|entry| {
let relative = entry
.path()
.strip_prefix(&dir)
.map_or_else(|_| entry.path().to_path_buf(), PathBuf::from);
let normalized = normalized_safe_key(&relative)?;
Some((
normalized.clone(),
crate::paths::key_to_path_buf_lossy(&normalized),
VfsFile::from(entry.path()),
))
})
.collect();
let mut conflicts = Vec::new();
let mut additions = Vec::new();
for (lookup_key, key, incoming) in entries {
match self.file_map.get(&lookup_key) {
Some(existing) => conflicts.push((key, incoming, existing)),
None => additions.push((key, incoming)),
}
}
DirectoryDiff {
conflicts,
additions,
}
}
}