1use std::collections::BTreeSet;
2use std::io::{self, Write};
3use std::path::Path;
4
5pub struct OwnedImages {
6 pub digests: BTreeSet<String>,
7 pub references: BTreeSet<String>,
8}
9
10impl OwnedImages {
11 pub fn load(path: &Path) -> Self {
12 let mut digests = BTreeSet::new();
13 let mut references = BTreeSet::new();
14 if let Ok(content) = std::fs::read_to_string(path) {
15 for line in content.lines() {
16 let mut parts = line.splitn(2, '\t');
17 let reference = parts.next().unwrap_or("").trim();
18 let digest = parts.next().unwrap_or("").trim();
19 if !reference.is_empty() && !digest.is_empty() {
20 references.insert(reference.to_string());
21 digests.insert(digest.to_string());
22 }
23 }
24 }
25 Self {
26 digests,
27 references,
28 }
29 }
30
31 pub fn is_empty(&self) -> bool {
32 self.digests.is_empty()
33 }
34}
35
36pub fn record(path: &Path, reference: &str, digest: &str) -> io::Result<()> {
39 if path.exists() {
40 let content = std::fs::read_to_string(path)?;
41 if content
42 .lines()
43 .any(|line| line.split_once('\t').map(|x| x.1).unwrap_or("").trim() == digest)
44 {
45 return Ok(());
46 }
47 }
48 if let Some(parent) = path.parent() {
49 std::fs::create_dir_all(parent)?;
50 }
51 let mut f = std::fs::OpenOptions::new()
52 .create(true)
53 .append(true)
54 .open(path)?;
55 writeln!(f, "{}\t{}", reference, digest)
56}
57
58pub fn remove_by_digest(path: &Path, digest: &str) -> io::Result<()> {
60 if !path.exists() {
61 return Ok(());
62 }
63 let content = std::fs::read_to_string(path)?;
64 let new_content: String = content
65 .lines()
66 .filter(|line| line.split_once('\t').map(|x| x.1).unwrap_or("").trim() != digest)
67 .map(|line| format!("{line}\n"))
68 .collect();
69 std::fs::write(path, new_content)
70}