1use crate::index::SearchIndex;
4use crate::xml::{read_index_file, write_index_file};
5use anyhow::Result;
6use std::path::{Path, PathBuf};
7
8pub const DEFAULT_CACHE_DIR: &str = ".rlean-search";
9pub const DEFAULT_CACHE_FILE: &str = "index.xml.gz";
11
12pub fn default_cache_path(root: impl AsRef<Path>) -> PathBuf {
13 root.as_ref()
14 .join(DEFAULT_CACHE_DIR)
15 .join(DEFAULT_CACHE_FILE)
16}
17
18pub fn load_cache(path: impl AsRef<Path>, expected_hash: Option<&str>) -> Result<Option<SearchIndex>> {
20 let path = path.as_ref();
21 if !path.exists() {
22 return Ok(None);
23 }
24 let doc = read_index_file(path)?;
25 if let Some(exp) = expected_hash {
26 if doc.source_hash != exp {
27 tracing::info!("cache hash mismatch; rebuilding");
28 return Ok(None);
29 }
30 }
31 Ok(Some(SearchIndex::from_document(doc)))
32}
33
34pub fn save_cache(path: impl AsRef<Path>, index: &SearchIndex) -> Result<()> {
35 write_index_file(path.as_ref(), &index.doc)
36}
37
38pub fn load_or_build(
40 paths: &[impl AsRef<Path>],
41 cache_path: impl AsRef<Path>,
42 force_rebuild: bool,
43) -> Result<SearchIndex> {
44 if !force_rebuild {
45 if let Some(idx) = load_cache(cache_path.as_ref(), None)? {
46 if !idx.is_empty() || paths.is_empty() {
48 return Ok(idx);
49 }
50 }
51 }
52 let idx = crate::index::build_index(paths)?;
53 save_cache(cache_path.as_ref(), &idx)?;
54 Ok(idx)
55}