use std::path::Path;
use serde::{Deserialize, Serialize};
use super::{GRAPH_CACHE_VERSION, GraphCacheManifest};
use crate::graph::ModuleGraph;
const GRAPH_CACHE_FILE: &str = "graph-cache.bin";
#[derive(Serialize, Deserialize)]
pub struct GraphCacheStore {
pub version: u32,
pub manifest: GraphCacheManifest,
pub graph: ModuleGraph,
}
impl GraphCacheStore {
#[must_use]
pub fn load(cache_dir: &Path) -> Option<Self> {
let cache_file = cache_dir.join(GRAPH_CACHE_FILE);
let data = std::fs::read(&cache_file).ok()?;
let mut store: Self = match postcard::from_bytes(&data) {
Ok(store) => store,
Err(_) => {
tracing::info!(
"Graph cache format upgraded, rebuilding (one-time cost after version bump)"
);
return None;
}
};
if store.version != GRAPH_CACHE_VERSION {
tracing::info!(
"Graph cache format upgraded, rebuilding (one-time cost after version bump)"
);
return None;
}
store.graph.reconstruct_namespace_imported();
Some(store)
}
pub fn save(&self, cache_dir: &Path) {
if let Err(error) = std::fs::create_dir_all(cache_dir) {
tracing::debug!("Failed to create graph cache dir: {error}");
return;
}
if let Err(error) = write_cache_gitignore(cache_dir) {
tracing::debug!("Failed to write graph cache .gitignore: {error}");
}
let encoded = match postcard::to_allocvec(self) {
Ok(bytes) => bytes,
Err(error) => {
tracing::debug!("Failed to encode graph cache: {error}");
return;
}
};
let cache_file = cache_dir.join(GRAPH_CACHE_FILE);
if let Err(error) = atomic_write(&cache_file, &encoded) {
tracing::debug!("Failed to write graph cache: {error}");
}
}
}
fn write_cache_gitignore(cache_dir: &Path) -> std::io::Result<()> {
std::fs::write(cache_dir.join(".gitignore"), "*\n")
}
fn atomic_write(cache_file: &Path, data: &[u8]) -> std::io::Result<()> {
let tmp_file = match cache_file.file_name() {
Some(name) => cache_file.with_file_name({
let mut s = name.to_os_string();
s.push(".tmp");
s
}),
None => {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"graph cache file path has no filename component",
));
}
};
{
use std::io::Write as _;
let mut f = std::fs::File::create(&tmp_file)?;
f.write_all(data)?;
let _ = f.sync_all();
}
std::fs::rename(&tmp_file, cache_file)
}