aperture_cli/cache/
metadata.rs1use crate::cache::models::{GlobalCacheMetadata, SpecMetadata, CACHE_FORMAT_VERSION};
2use crate::error::Error;
3use crate::fs::FileSystem;
4use std::path::Path;
5
6const CACHE_METADATA_FILE: &str = "cache_metadata.json";
7
8pub struct CacheMetadataManager<'a, F: FileSystem> {
10 fs: &'a F,
11}
12
13impl<'a, F: FileSystem> CacheMetadataManager<'a, F> {
14 pub const fn new(fs: &'a F) -> Self {
15 Self { fs }
16 }
17
18 pub fn load_metadata<P: AsRef<Path>>(
23 &self,
24 cache_dir: P,
25 ) -> Result<GlobalCacheMetadata, Error> {
26 let metadata_path = cache_dir.as_ref().join(CACHE_METADATA_FILE);
27
28 if !self.fs.exists(&metadata_path) {
29 let metadata = GlobalCacheMetadata::default();
31 self.save_metadata(&cache_dir, &metadata)?;
32 return Ok(metadata);
33 }
34
35 let content = self.fs.read_to_string(&metadata_path)?;
36 serde_json::from_str(&content).map_err(|e| Error::InvalidConfig {
37 reason: format!("Failed to parse cache metadata: {e}"),
38 })
39 }
40
41 pub fn save_metadata<P: AsRef<Path>>(
46 &self,
47 cache_dir: P,
48 metadata: &GlobalCacheMetadata,
49 ) -> Result<(), Error> {
50 let metadata_path = cache_dir.as_ref().join(CACHE_METADATA_FILE);
51
52 self.fs.create_dir_all(cache_dir.as_ref())?;
54
55 let content =
56 serde_json::to_string_pretty(metadata).map_err(|e| Error::SerializationError {
57 reason: format!("Failed to serialize cache metadata: {e}"),
58 })?;
59
60 self.fs.write_all(&metadata_path, content.as_bytes())?;
61 Ok(())
62 }
63
64 pub fn check_spec_version<P: AsRef<Path>>(
69 &self,
70 cache_dir: P,
71 spec_name: &str,
72 ) -> Result<bool, Error> {
73 let metadata = self.load_metadata(&cache_dir)?;
74
75 if metadata.cache_format_version != CACHE_FORMAT_VERSION {
77 return Ok(false);
78 }
79
80 Ok(metadata.specs.contains_key(spec_name))
82 }
83
84 pub fn update_spec_metadata<P: AsRef<Path>>(
89 &self,
90 cache_dir: P,
91 spec_name: &str,
92 file_size: u64,
93 ) -> Result<(), Error> {
94 let mut metadata = self.load_metadata(&cache_dir)?;
95
96 let spec_metadata = SpecMetadata {
97 updated_at: chrono::Utc::now().to_rfc3339(),
98 file_size,
99 };
100
101 metadata.specs.insert(spec_name.to_string(), spec_metadata);
102 self.save_metadata(&cache_dir, &metadata)?;
103 Ok(())
104 }
105
106 pub fn remove_spec_metadata<P: AsRef<Path>>(
111 &self,
112 cache_dir: P,
113 spec_name: &str,
114 ) -> Result<(), Error> {
115 let mut metadata = self.load_metadata(&cache_dir)?;
116 metadata.specs.remove(spec_name);
117 self.save_metadata(&cache_dir, &metadata)?;
118 Ok(())
119 }
120
121 pub fn list_cached_specs<P: AsRef<Path>>(&self, cache_dir: P) -> Result<Vec<String>, Error> {
126 let metadata = self.load_metadata(&cache_dir)?;
127 Ok(metadata.specs.keys().cloned().collect())
128 }
129}