Skip to main content

bv_core/
owned_images.rs

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
36/// Append a `reference\tdigest` line to the owned-images file.
37/// Idempotent: no-ops if the digest is already recorded.
38pub 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
58/// Remove the line whose digest column matches `digest`.
59pub 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}