fastskill_core/core/
build_cache.rs1use crate::core::service::ServiceError;
4use chrono::Utc;
5use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7use std::path::Path;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct BuildCache {
12 pub version: String,
13 #[serde(default)]
14 pub last_build: Option<String>,
15 #[serde(default)]
16 pub skills: HashMap<String, SkillCacheEntry>,
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct SkillCacheEntry {
21 pub version: String,
22 #[serde(skip_serializing_if = "Option::is_none")]
23 pub previous_version: Option<String>,
24 #[serde(skip_serializing_if = "Option::is_none")]
25 pub hash: Option<String>,
26 #[serde(skip_serializing_if = "Option::is_none")]
27 pub last_packaged: Option<String>,
28 #[serde(skip_serializing_if = "Option::is_none")]
29 pub artifact_path: Option<String>,
30 #[serde(skip_serializing_if = "Option::is_none")]
31 pub git_commit: Option<String>,
32}
33
34impl Default for BuildCache {
35 fn default() -> Self {
36 Self {
37 version: "1.0".to_string(),
38 last_build: None,
39 skills: HashMap::new(),
40 }
41 }
42}
43
44impl BuildCache {
45 pub fn load(cache_path: &Path) -> Result<Self, ServiceError> {
47 if !cache_path.exists() {
48 return Ok(Self::default());
49 }
50
51 let content = std::fs::read_to_string(cache_path).map_err(ServiceError::Io)?;
52
53 let cache: BuildCache = serde_json::from_str(&content)
54 .map_err(|e| ServiceError::Custom(format!("Failed to parse build cache: {}", e)))?;
55
56 Ok(cache)
57 }
58
59 pub fn save(&self, cache_path: &Path) -> Result<(), ServiceError> {
61 if let Some(parent) = cache_path.parent() {
63 std::fs::create_dir_all(parent).map_err(ServiceError::Io)?;
64 }
65
66 let content = serde_json::to_string_pretty(self)
67 .map_err(|e| ServiceError::Custom(format!("Failed to serialize build cache: {}", e)))?;
68
69 std::fs::write(cache_path, content).map_err(ServiceError::Io)?;
70
71 Ok(())
72 }
73
74 pub fn update_skill(
76 &mut self,
77 skill_id: &str,
78 version: &str,
79 hash: &str,
80 artifact_path: &Path,
81 git_commit: Option<&str>,
82 ) {
83 let previous_version = self.skills.get(skill_id).map(|e| e.version.clone());
84
85 let entry = SkillCacheEntry {
86 version: version.to_string(),
87 previous_version,
88 hash: Some(hash.to_string()),
89 last_packaged: Some(Utc::now().to_rfc3339()),
90 artifact_path: Some(artifact_path.to_string_lossy().to_string()),
91 git_commit: git_commit.map(|s| s.to_string()),
92 };
93
94 self.skills.insert(skill_id.to_string(), entry);
95 self.last_build = Some(Utc::now().to_rfc3339());
96 }
97
98 pub fn get_cached_version(&self, skill_id: &str) -> Option<String> {
100 self.skills.get(skill_id).map(|e| e.version.clone())
101 }
102
103 pub fn get_cached_hash(&self, skill_id: &str) -> Option<String> {
105 self.skills.get(skill_id).and_then(|e| e.hash.clone())
106 }
107}