Skip to main content

candle_graph/
analysis_cache.rs

1//! Optional on-disk cache for analyzed [`crate::model_ir::ModelIr`] documents.
2//!
3//! Enabled when `CANDLE_GRAPH_CACHE=1` or `--cache` is passed. Cache files live under
4//! `CANDLE_GRAPH_CACHE_DIR` (default: `$XDG_CACHE_HOME/candle-graph` or `/tmp/candle-graph-cache`).
5
6use std::path::{Path, PathBuf};
7
8use anyhow::{Context, Result};
9
10use crate::model_ir::ModelIr;
11
12pub fn cache_enabled(explicit: bool) -> bool {
13    explicit || std::env::var("CANDLE_GRAPH_CACHE")
14        .map(|value| matches!(value.as_str(), "1" | "true" | "yes"))
15        .unwrap_or(false)
16}
17
18pub fn cache_dir() -> PathBuf {
19    std::env::var("CANDLE_GRAPH_CACHE_DIR")
20        .map(PathBuf::from)
21        .or_else(|_| {
22            std::env::var("XDG_CACHE_HOME")
23                .map(|home| PathBuf::from(home).join("candle-graph"))
24                .or_else(|_| std::env::var("HOME").map(|home| PathBuf::from(home).join(".cache/candle-graph")))
25        })
26        .unwrap_or_else(|_| PathBuf::from("/tmp/candle-graph-cache"))
27}
28
29pub fn cache_path(analysis_id: &str) -> PathBuf {
30    let safe = analysis_id
31        .chars()
32        .map(|c| if c.is_ascii_alphanumeric() { c } else { '_' })
33        .collect::<String>();
34    cache_dir().join(format!("{safe}.json"))
35}
36
37pub fn load(path: &Path) -> Result<Option<ModelIr>> {
38    if !path.is_file() {
39        return Ok(None);
40    }
41    let text = std::fs::read_to_string(path)
42        .with_context(|| format!("reading analysis cache {}", path.display()))?;
43    let model: ModelIr =
44        serde_json::from_str(&text).context("parsing cached model IR")?;
45    Ok(Some(model))
46}
47
48pub fn save(path: &Path, model: &ModelIr) -> Result<()> {
49    if let Some(parent) = path.parent() {
50        std::fs::create_dir_all(parent)
51            .with_context(|| format!("creating cache dir {}", parent.display()))?;
52    }
53    let text = serde_json::to_string(model).context("serializing model IR for cache")?;
54    std::fs::write(path, text).with_context(|| format!("writing analysis cache {}", path.display()))?;
55    Ok(())
56}