1use crate::git::GitRepo;
9use crate::output::VersionVariables;
10use rust_i18n::t;
11use sha1::{Digest, Sha1};
12use std::path::{Path, PathBuf};
13
14pub fn compute_key(repo: &GitRepo, config_path: Option<&Path>, overrides: &[String]) -> String {
22 let mut hasher = Sha1::new();
23
24 for line in repo.refs_snapshot().unwrap_or_default() {
26 hasher.update(line.as_bytes());
27 hasher.update(b"\n");
28 }
29 hasher.update(b"--head--");
30 hasher.update(repo.head_ref_name().as_bytes());
32 if let Ok(head) = repo.head_commit() {
33 hasher.update(head.sha.as_bytes());
34 }
35 hasher.update(b"--config--");
36 if let Some(p) = config_path {
38 if let Ok(content) = std::fs::read_to_string(p) {
39 hasher.update(content.as_bytes());
40 }
41 }
42 hasher.update(b"--override--");
43 for o in overrides {
45 hasher.update(o.as_bytes());
46 hasher.update(b"\n");
47 }
48
49 let digest = hasher.finalize();
50 let mut hex = String::with_capacity(40);
51 for b in digest {
52 hex.push_str(&format!("{b:02x}"));
53 }
54 hex
55}
56
57fn cache_file(repo: &GitRepo, key: &str) -> PathBuf {
59 repo.git_dir()
60 .join("gitversion_cache")
61 .join(format!("{key}.json"))
62}
63
64pub fn load(repo: &GitRepo, key: &str) -> Option<VersionVariables> {
66 let path = cache_file(repo, key);
67 if !path.is_file() {
68 log::debug!("cache miss: {}", path.display());
69 return None;
70 }
71 match std::fs::read_to_string(&path)
72 .ok()
73 .and_then(|s| serde_json::from_str(&s).ok())
74 {
75 Some(vars) => {
76 log::debug!("{}", t!("cache.hit", path = path.display()));
77 Some(vars)
78 }
79 None => {
80 log::warn!("{}", t!("cache.corrupt", path = path.display()));
81 let _ = std::fs::remove_file(&path);
82 None
83 }
84 }
85}
86
87pub fn store(repo: &GitRepo, key: &str, vars: &VersionVariables) {
89 let path = cache_file(repo, key);
90 if let Some(parent) = path.parent() {
91 if std::fs::create_dir_all(parent).is_err() {
92 return;
93 }
94 }
95 match serde_json::to_string_pretty(vars) {
96 Ok(json) => {
97 if let Err(e) = std::fs::write(&path, json) {
98 log::warn!(
99 "{}",
100 t!("cache.write_failed", path = path.display(), error = e)
101 );
102 } else {
103 log::debug!("cache write: {}", path.display());
104 }
105 }
106 Err(e) => log::warn!("{}", t!("cache.serialize_failed", error = e)),
107 }
108}