1use std::collections::HashMap;
2use std::fs;
3use std::path::{Path, PathBuf};
4
5use crate::error::{Error, Result};
6
7fn config_dir() -> PathBuf {
9 dirs::config_dir()
10 .unwrap_or_else(|| PathBuf::from("~/.config"))
11 .join("git-side")
12}
13
14fn cache_file() -> PathBuf {
16 config_dir().join("cache")
17}
18
19fn paths_file() -> PathBuf {
21 config_dir().join("paths")
22}
23
24fn ensure_config_dir() -> Result<()> {
26 let dir = config_dir();
27 if !dir.exists() {
28 fs::create_dir_all(&dir).map_err(|e| Error::CreateDir {
29 path: dir,
30 source: e,
31 })?;
32 }
33 Ok(())
34}
35
36fn read_kv_file(path: &Path) -> Result<HashMap<String, String>> {
38 if !path.exists() {
39 return Ok(HashMap::new());
40 }
41
42 let content = fs::read_to_string(path).map_err(|e| Error::ReadFile {
43 path: path.to_path_buf(),
44 source: e,
45 })?;
46
47 let mut map = HashMap::new();
48 for line in content.lines() {
49 let line = line.trim();
50 if line.is_empty() || line.starts_with('#') {
51 continue;
52 }
53 if let Some((key, value)) = line.split_once('=') {
54 map.insert(key.to_string(), value.to_string());
55 }
56 }
57 Ok(map)
58}
59
60fn write_kv_file(path: &Path, map: &HashMap<String, String>) -> Result<()> {
62 ensure_config_dir()?;
63
64 let content: String = map
65 .iter()
66 .map(|(k, v)| format!("{k}={v}"))
67 .collect::<Vec<_>>()
68 .join("\n");
69
70 fs::write(path, content).map_err(|e| Error::WriteFile {
71 path: path.to_path_buf(),
72 source: e,
73 })
74}
75
76#[must_use]
78pub fn hash_path(path: &Path) -> String {
79 use std::collections::hash_map::DefaultHasher;
80 use std::hash::{Hash, Hasher};
81
82 let mut hasher = DefaultHasher::new();
83 path.hash(&mut hasher);
84 format!("{:016x}", hasher.finish())
85}
86
87pub fn cache_lookup(path_hash: &str) -> Result<Option<String>> {
93 let map = read_kv_file(&cache_file())?;
94 Ok(map.get(path_hash).cloned())
95}
96
97pub fn cache_store(path_hash: &str, root_sha: &str) -> Result<()> {
103 let mut map = read_kv_file(&cache_file())?;
104 map.insert(path_hash.to_string(), root_sha.to_string());
105 write_kv_file(&cache_file(), &map)
106}
107
108pub fn paths_lookup(root_sha: &str) -> Result<Option<PathBuf>> {
114 let map = read_kv_file(&paths_file())?;
115 Ok(map.get(root_sha).map(PathBuf::from))
116}
117
118pub fn paths_store(root_sha: &str, base_path: &Path) -> Result<()> {
124 let mut map = read_kv_file(&paths_file())?;
125 map.insert(
126 root_sha.to_string(),
127 base_path.to_string_lossy().to_string(),
128 );
129 write_kv_file(&paths_file(), &map)
130}
131
132#[must_use]
134pub fn default_base_path() -> PathBuf {
135 dirs::data_local_dir()
136 .unwrap_or_else(|| PathBuf::from("~/.local/share"))
137 .join("git-side")
138}