aperture_cli/cache/
metadata.rs1use crate::cache::models::{GlobalCacheMetadata, SpecMetadata, CACHE_FORMAT_VERSION};
2use crate::constants;
3use crate::error::Error;
4use crate::fs::FileSystem;
5use std::path::Path;
6
7pub struct CacheMetadataManager<'a, F: FileSystem> {
9 fs: &'a F,
10}
11
12impl<'a, F: FileSystem> CacheMetadataManager<'a, F> {
13 pub const fn new(fs: &'a F) -> Self {
14 Self { fs }
15 }
16
17 pub fn load_metadata<P: AsRef<Path>>(
22 &self,
23 cache_dir: P,
24 ) -> Result<GlobalCacheMetadata, Error> {
25 let metadata_path = cache_dir.as_ref().join(constants::CACHE_METADATA_FILENAME);
26
27 if !self.fs.exists(&metadata_path) {
28 let metadata = GlobalCacheMetadata::default();
30 self.save_metadata(&cache_dir, &metadata)?;
31 return Ok(metadata);
32 }
33
34 let content = self.fs.read_to_string(&metadata_path)?;
35 serde_json::from_str(&content)
36 .map_err(|e| Error::invalid_config(format!("Failed to parse cache metadata: {e}")))
37 }
38
39 pub fn save_metadata<P: AsRef<Path>>(
44 &self,
45 cache_dir: P,
46 metadata: &GlobalCacheMetadata,
47 ) -> Result<(), Error> {
48 let metadata_path = cache_dir.as_ref().join(constants::CACHE_METADATA_FILENAME);
49
50 self.fs.create_dir_all(cache_dir.as_ref())?;
52
53 let content = serde_json::to_string_pretty(metadata).map_err(|e| {
54 Error::serialization_error(format!("Failed to serialize cache metadata: {e}"))
55 })?;
56
57 self.fs.write_all(&metadata_path, content.as_bytes())?;
58 Ok(())
59 }
60
61 pub fn check_spec_version<P: AsRef<Path>>(
66 &self,
67 cache_dir: P,
68 spec_name: &str,
69 ) -> Result<bool, Error> {
70 let metadata = self.load_metadata(&cache_dir)?;
71
72 if metadata.cache_format_version != CACHE_FORMAT_VERSION {
74 return Ok(false);
75 }
76
77 Ok(metadata.specs.contains_key(spec_name))
79 }
80
81 pub fn update_spec_metadata<P: AsRef<Path>>(
86 &self,
87 cache_dir: P,
88 spec_name: &str,
89 file_size: u64,
90 ) -> Result<(), Error> {
91 let mut metadata = self.load_metadata(&cache_dir)?;
92
93 let spec_metadata = SpecMetadata {
94 updated_at: chrono::Utc::now().to_rfc3339(),
95 file_size,
96 };
97
98 metadata.specs.insert(spec_name.to_string(), spec_metadata);
99 self.save_metadata(&cache_dir, &metadata)?;
100 Ok(())
101 }
102
103 pub fn remove_spec_metadata<P: AsRef<Path>>(
108 &self,
109 cache_dir: P,
110 spec_name: &str,
111 ) -> Result<(), Error> {
112 let mut metadata = self.load_metadata(&cache_dir)?;
113 metadata.specs.remove(spec_name);
114 self.save_metadata(&cache_dir, &metadata)?;
115 Ok(())
116 }
117
118 pub fn list_cached_specs<P: AsRef<Path>>(&self, cache_dir: P) -> Result<Vec<String>, Error> {
123 let metadata = self.load_metadata(&cache_dir)?;
124 Ok(metadata.specs.keys().cloned().collect())
125 }
126}