use crate::GLOBAL_CONFIG;
use crate::data::paths::{BasicDirEntryInfo, PathData};
use crate::lookup::versions::{ProximateDatasetAndOptAlts, RelativePathAndSnapMounts};
use hashbrown::{HashMap, HashSet};
use std::ffi::OsStr;
use std::ffi::OsString;
use std::fs::FileType;
use std::path::Path;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DeletedFiles {
inner: Vec<BasicDirEntryInfo>,
}
impl Default for DeletedFiles {
fn default() -> Self {
Self { inner: Vec::new() }
}
}
impl From<&Path> for DeletedFiles {
fn from(requested_dir: &Path) -> Self {
let Some(mut deleted_files) = Self::unique_pseudo_live_versions(requested_dir) else {
return Self::default();
};
if deleted_files.is_empty() {
return Self::default();
}
if let Ok(read_dir) = std::fs::read_dir(requested_dir) {
let live_paths: HashSet<OsString> =
read_dir.flatten().map(|entry| entry.file_name()).collect();
if !live_paths.is_empty() {
deleted_files.retain(|k, _v| !live_paths.contains(k));
}
}
let deleted_file_names = deleted_files.into_values().collect();
Self {
inner: deleted_file_names,
}
}
}
impl DeletedFiles {
#[inline(always)]
pub fn into_inner(self) -> Vec<BasicDirEntryInfo> {
self.inner
}
#[inline(always)]
fn unique_pseudo_live_versions<'a>(
requested_dir: &'a Path,
) -> Option<HashMap<OsString, BasicDirEntryInfo>> {
let path_data = PathData::without_styling(requested_dir, None);
let Ok(prox_opt_alts) = ProximateDatasetAndOptAlts::new(&GLOBAL_CONFIG, &path_data) else {
return None;
};
prox_opt_alts
.into_search_bundles()
.map(|search_bundle| Self::snapshot_paths_for_directory(&requested_dir, search_bundle))
.reduce(|mut acc, next| {
acc.extend(next);
acc
})
}
#[inline(always)]
fn snapshot_paths_for_directory<'a>(
pseudo_live_dir: &'a Path,
search_bundle: RelativePathAndSnapMounts<'a>,
) -> HashMap<OsString, BasicDirEntryInfo> {
search_bundle
.snap_mounts()
.into_iter()
.map(|path| path.join(search_bundle.relative_path()))
.flat_map(std::fs::read_dir)
.flatten()
.flatten()
.filter_map(|dir_entry| {
dir_entry
.file_type()
.ok()
.map(|file_type| (dir_entry, file_type))
})
.map(|(dir_entry, file_type)| {
let file_name = dir_entry.file_name();
let basic_info =
Self::into_pseudo_live_version(&file_name, pseudo_live_dir, Some(file_type));
(file_name, basic_info)
})
.collect()
}
#[inline(always)]
fn into_pseudo_live_version<'a>(
file_name: &OsStr,
pseudo_live_dir: &'a Path,
opt_filetype: Option<FileType>,
) -> BasicDirEntryInfo {
let path = pseudo_live_dir.join(file_name);
BasicDirEntryInfo::new(&path, opt_filetype)
}
}