1use std::collections::BTreeMap;
7use std::io;
8use std::path::Path;
9
10pub const FILE_NAME: &str = "shield.lock";
11
12const HEADER: &str = "\
13# shield.lock — just-shield가 박제한 태그→SHA 대응. 직접 수정하지 말 것.
14# 갱신: just-shield lock
15";
16
17#[derive(Default)]
19pub struct Lockfile {
20 pub entries: BTreeMap<String, String>,
21}
22
23impl Lockfile {
24 pub fn key(repo: &str, git_ref: &str) -> String {
25 format!("{repo}@{git_ref}")
26 }
27
28 pub fn get(&self, repo: &str, git_ref: &str) -> Option<&str> {
29 self.entries
30 .get(&Self::key(repo, git_ref))
31 .map(|s| s.as_str())
32 }
33}
34
35pub fn load(root: &Path) -> io::Result<Option<Lockfile>> {
37 let path = root.join(FILE_NAME);
38 if !path.is_file() {
39 return Ok(None);
40 }
41 let content = std::fs::read_to_string(path)?;
42 let mut entries = BTreeMap::new();
43 for line in content.lines() {
44 let line = line.trim();
45 if line.is_empty() || line.starts_with('#') {
46 continue;
47 }
48 if let Some((key, sha)) = line.split_once(' ') {
49 entries.insert(key.to_string(), sha.trim().to_string());
50 }
51 }
52 Ok(Some(Lockfile { entries }))
53}
54
55pub fn save(root: &Path, lockfile: &Lockfile) -> io::Result<()> {
57 let mut out = String::from(HEADER);
58 for (key, sha) in &lockfile.entries {
59 out.push_str(&format!("{key} {sha}\n"));
60 }
61 std::fs::write(root.join(FILE_NAME), out)
62}