use std::{
ffi::OsString,
fs::read_dir,
path::{Path, PathBuf},
};
use fxhash::FxHashMap as HashMap;
use itertools::Itertools;
use crate::versions_lookup::{get_search_bundle, NativeDatasetType, SearchBundle};
use crate::{BasicDirEntryInfo, Config, PathData, SnapPoint};
pub fn get_unique_deleted(
config: &Config,
requested_dir: &Path,
) -> Result<Vec<BasicDirEntryInfo>, Box<dyn std::error::Error + Send + Sync + 'static>> {
let selected_datasets = if config.opt_alt_replicated {
vec![
NativeDatasetType::AltReplicated,
NativeDatasetType::MostProximate,
]
} else {
vec![NativeDatasetType::MostProximate]
};
let requested_dir_pathdata = PathData::from(requested_dir);
let unique_deleted: Vec<BasicDirEntryInfo> = vec![&requested_dir_pathdata]
.iter()
.flat_map(|pathdata| {
selected_datasets
.iter()
.flat_map(|dataset_type| get_search_bundle(config, pathdata, dataset_type))
})
.flatten()
.flat_map(|search_bundle| {
get_deleted_per_dataset(config, &requested_dir_pathdata.path_buf, &search_bundle)
})
.flatten()
.filter_map(
|basic_dir_entry_info| match basic_dir_entry_info.path.symlink_metadata() {
Ok(md) => Some((md, basic_dir_entry_info)),
Err(_) => None,
},
)
.filter_map(|(md, basic_dir_entry_info)| match md.modified() {
Ok(modify_time) => Some((modify_time, basic_dir_entry_info)),
Err(_) => None,
})
.into_group_map_by(|(_modify_time, basic_dir_entry_info)| {
basic_dir_entry_info.file_name.clone()
})
.iter()
.filter_map(|(_key, group)| {
group
.iter()
.max_by_key(|(modify_time, _basic_dir_entry_info)| *modify_time)
})
.map(|(_modify_time, basic_dir_entry_info)| basic_dir_entry_info)
.cloned()
.collect();
Ok(unique_deleted)
}
pub fn get_deleted_per_dataset(
config: &Config,
requested_dir: &Path,
search_bundle: &SearchBundle,
) -> Result<Vec<BasicDirEntryInfo>, Box<dyn std::error::Error + Send + Sync + 'static>> {
let unique_local_filenames: HashMap<OsString, BasicDirEntryInfo> = read_dir(&requested_dir)?
.flatten()
.map(|dir_entry| {
(
dir_entry.file_name(),
BasicDirEntryInfo {
file_name: dir_entry.file_name(),
path: dir_entry.path(),
file_type: dir_entry.file_type().ok(),
},
)
})
.collect();
fn read_dir_for_snap_filenames(
snapshot_dir: &Path,
relative_path: &Path,
) -> Result<
HashMap<OsString, BasicDirEntryInfo>,
Box<dyn std::error::Error + Send + Sync + 'static>,
> {
let unique_snap_filenames = read_dir(&snapshot_dir)?
.flatten()
.map(|entry| entry.path())
.map(|path| path.join(relative_path))
.flat_map(|path| read_dir(&path))
.flatten()
.flatten()
.map(|dir_entry| {
(
dir_entry.file_name(),
BasicDirEntryInfo {
file_name: dir_entry.file_name(),
path: dir_entry.path(),
file_type: dir_entry.file_type().ok(),
},
)
})
.collect();
Ok(unique_snap_filenames)
}
fn snap_mounts_for_snap_filenames(
snap_mounts: &[PathBuf],
relative_path: &Path,
) -> Result<
HashMap<OsString, BasicDirEntryInfo>,
Box<dyn std::error::Error + Send + Sync + 'static>,
> {
let unique_snap_filenames = snap_mounts
.iter()
.map(|path| path.join(&relative_path))
.flat_map(|path| read_dir(&path))
.flatten()
.flatten()
.map(|dir_entry| {
(
dir_entry.file_name(),
BasicDirEntryInfo {
file_name: dir_entry.file_name(),
path: dir_entry.path(),
file_type: dir_entry.file_type().ok(),
},
)
})
.collect();
Ok(unique_snap_filenames)
}
let snapshot_dir = &search_bundle.snapshot_dir;
let relative_path = &search_bundle.relative_path;
let unique_snap_filenames: HashMap<OsString, BasicDirEntryInfo> = match &config.snap_point {
SnapPoint::Native(native_datasets) => match native_datasets.map_of_snaps {
Some(_) => match search_bundle.snapshot_mounts.as_ref() {
Some(snap_mounts) => snap_mounts_for_snap_filenames(snap_mounts, relative_path)?,
None => read_dir_for_snap_filenames(snapshot_dir, relative_path)?,
},
None => read_dir_for_snap_filenames(snapshot_dir, relative_path)?,
},
SnapPoint::UserDefined(_) => read_dir_for_snap_filenames(snapshot_dir, relative_path)?,
};
let all_deleted_versions: Vec<BasicDirEntryInfo> = unique_snap_filenames
.into_iter()
.filter(|(file_name, _)| unique_local_filenames.get(file_name).is_none())
.map(|(_file_name, basic_dir_entry_info)| basic_dir_entry_info)
.collect();
Ok(all_deleted_versions)
}