use std::fs;
use std::path::PathBuf;
use crate::cache::caches::{get_cache_name, RegistrySubCache, RegistrySuperCache};
use rayon::prelude::*;
pub(crate) struct RegistryPkgCache {
name: String,
path: PathBuf,
size: Option<u64>,
number_of_files: Option<usize>,
files_calculated: bool, files: Vec<PathBuf>,
}
impl RegistrySubCache for RegistryPkgCache {
fn new(path: PathBuf) -> Self {
Self {
name: get_cache_name(&path),
path,
size: None,
number_of_files: None,
files_calculated: false,
files: vec![],
}
}
fn name(&self) -> &str {
&self.name
}
fn path(&self) -> &PathBuf {
&self.path
}
#[inline]
fn invalidate(&mut self) {
self.size = None;
self.files_calculated = false;
self.number_of_files = None;
self.files = vec![];
}
fn known_to_be_empty(&mut self) {
self.size = Some(0);
self.files_calculated = true;
self.number_of_files = Some(0);
self.files = Vec::new();
}
fn total_size(&mut self) -> u64 {
match self.size {
Some(size) => size,
None => {
if self.path.is_dir() {
let total_size = self
.files()
.par_iter()
.filter(|f| f.is_file())
.map(|f| {
fs::metadata(f)
.unwrap_or_else(|_| panic!("Failed to get size of file: '{:?}'", f))
.len()
})
.sum();
self.size = Some(total_size);
total_size
} else {
self.known_to_be_empty();
0
}
}
}
}
fn files(&mut self) -> &[PathBuf] {
if self.files_calculated {
} else if self.path_exists() {
let collection = fs::read_dir(&self.path)
.unwrap_or_else(|_| panic!("Failed to read directory (repo): '{:?}'", &self.path))
.map(|cratepath| cratepath.unwrap().path())
.collect::<Vec<_>>();
self.files_calculated = true;
self.number_of_files = Some(collection.len());
self.files = collection;
} else {
self.files = Vec::new();
self.files_calculated = true;
self.number_of_files = Some(0);
}
&self.files
}
fn number_of_files(&mut self) -> usize {
if let Some(number) = self.number_of_files {
number
} else {
let _ = self.files();
if let Some(n) = self.number_of_files {
n
} else {
unreachable!("registry_pkg_cache: self.files is None!");
}
}
}
fn files_sorted(&mut self) -> &[PathBuf] {
let _ = self.files(); self.files.sort();
self.files()
}
fn items(&mut self) -> &[PathBuf] {
self.files()
}
fn number_of_items(&mut self) -> usize {
self.number_of_files()
}
}
pub(crate) struct RegistryPkgCaches {
#[allow(unused)]
path: PathBuf,
caches: Vec<RegistryPkgCache>,
#[allow(unused)]
number_of_caches: usize,
total_size: Option<u64>,
total_number_of_files: Option<usize>,
items: Vec<PathBuf>,
}
impl RegistrySuperCache for RegistryPkgCaches {
type SubCache = RegistryPkgCache;
fn new(path: PathBuf) -> Self {
if !path.exists() {
return Self {
path,
number_of_caches: 0,
caches: vec![],
total_number_of_files: None,
total_size: None,
items: Vec::new(),
};
}
let cache_dirs = std::fs::read_dir(&path)
.unwrap_or_else(|_| panic!("failed to read directory {}", path.display()));
#[allow(clippy::manual_filter_map)]
let caches = cache_dirs
.map(|direntry| direntry.unwrap().path())
.filter(|p| p.is_dir() && p.file_name().unwrap().to_str().unwrap().contains('-'))
.map(RegistryPkgCache::new)
.collect::<Vec<RegistryPkgCache>>();
Self {
path,
number_of_caches: caches.len(),
caches,
total_number_of_files: None,
total_size: None,
items: Vec::new(),
}
}
fn caches(&mut self) -> &mut Vec<Self::SubCache> {
&mut self.caches
}
fn invalidate(&mut self) {
self.number_of_caches = 0;
self.total_size = None;
self.total_number_of_files = None;
self.caches
.iter_mut()
.for_each(RegistrySubCache::invalidate);
}
fn files(&mut self) -> Vec<PathBuf> {
let mut all_files = Vec::new();
for cache in &mut self.caches {
all_files.extend(cache.files().to_vec());
}
all_files
}
fn files_sorted(&mut self) -> Vec<PathBuf> {
let mut files_sorted = self.files();
files_sorted.sort();
files_sorted
}
fn total_size(&mut self) -> u64 {
if let Some(size) = self.total_size {
size
} else {
let total_size = self
.caches
.iter_mut()
.map(RegistrySubCache::total_size)
.sum();
self.total_size = Some(total_size);
total_size
}
}
fn number_of_subcaches(&mut self) -> usize {
self.caches.len()
}
fn total_number_of_files(&mut self) -> usize {
if let Some(number) = self.total_number_of_files {
number
} else {
let number = self
.caches
.iter_mut()
.map(RegistrySubCache::number_of_files)
.sum();
self.total_number_of_files = Some(number);
number
}
}
fn items(&mut self) -> &[PathBuf] {
self.items = self
.caches()
.iter_mut()
.flat_map(RegistrySubCache::items)
.cloned()
.collect::<Vec<PathBuf>>();
&self.items
}
fn number_of_items(&mut self) -> usize {
self.items().len()
}
}