Files
incre/native/src/cache.rs
Tommy Parnell 9973df7b42 init
2021-05-10 09:14:30 -04:00

111 lines
3.2 KiB
Rust

use std::path::Path;
use std::collections::HashSet;
use std::time::SystemTime;
use std::io;
use std::fs;
use serde::{Serialize, Deserialize};
use std::hash::{Hash, Hasher};
use metrohash::{MetroHash};
#[derive(Serialize, Deserialize)]
pub struct CachedEntry {
pub files: HashSet<CachedFile>,
}
impl CachedEntry {
pub fn new(files: HashSet<CachedFile>) -> CachedEntry {
CachedEntry {
files,
}
}
// todo Error handle better
pub fn from_file(path: &str) -> io::Result<CachedEntry> {
println!("Attempting to read {}", path);
// Path::new(path).exists()
fs::metadata(path)?;
let file = fs::read_to_string(path)?;
Ok(serde_json::from_str(&file)?)
}
pub fn was_changed(&self) -> io::Result<bool> {
let mut changed = false;
for cached_file in self.files.iter() {
if cached_file.was_changed()? {
changed = true;
break;
}
}
Ok(changed)
}
pub fn is_empty(&self) -> bool {
self.files.is_empty()
}
pub fn write(&self, name: &str, cache_dir: &str) -> io::Result<()> {
let cached_entry_filename = format!("{}", name);
let cached_directory_path = Path::new(cache_dir);
if !cached_directory_path.exists() {
fs::create_dir(cached_directory_path)?
}
let cached_entry_path = cached_directory_path.join(cached_entry_filename);
let f = std::io::BufWriter::new(fs::File::create(&cached_entry_path)?);
serde_json::to_writer(f, self)?;
Ok(())
}
}
#[derive(Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct CachedFile {
path: String,
size: u64,
modified: SystemTime,
hash: u64,
}
impl CachedFile {
pub fn from_filename(filename: &str) -> io::Result<CachedFile> {
let file_metadata = fs::metadata(filename)?;
let size = file_metadata.len();
let modified = file_metadata.modified()?;
// TODO: find async way to read file.
let hash = calculate_hash(&fs::read(filename)?);
Ok(CachedFile {
path: filename.to_string(),
size,
modified,
hash,
})
}
pub fn was_changed(&self) -> io::Result<bool> {
let mut changed = false;
// println!("Checking if {} has changed", &self.path);
match fs::metadata(&self.path) {
Ok(file_metadata) => {
let size = file_metadata.len();
let modified = file_metadata.modified()?;
if self.size != size || self.modified != modified {
let hash = calculate_hash(&fs::read(&self.path)?);
if self.hash != hash {
changed = true;
}
}
}
// means previously cached file cannot be read
// most likely due to the entrypoint of an npm module
// being changed.
Err(_) => {
changed = true;
}
}
Ok(changed)
}
}
fn calculate_hash<T: Hash>(t: &T) -> u64 {
let mut s = MetroHash::new();
t.hash(&mut s);
s.finish()
}