containerd_store/
types.rs

1use std::fmt;
2use std::path::PathBuf;
3
4use serde::{Deserialize, Serialize};
5use thiserror::Error;
6
7#[derive(Debug, Error)]
8pub enum StoreError {
9    #[error("BoltDB open error: {0}")]
10    DbOpen(String),
11    #[error("BoltDB access error: {0}")]
12    Db(String),
13    #[error("Containerd images bucket not found (namespace: {0})")]
14    ImagesBucketMissing(String),
15    #[error("Image not found: {0}")]
16    ImageNotFound(String),
17    #[error("Descriptor missing for image: {0}")]
18    DescriptorMissing(String),
19    #[error("Invalid UTF-8 in key/value: {0}")]
20    Utf8(String),
21    #[error("Invalid digest format: {0}")]
22    Digest(String),
23    #[error("IO error: {0}")]
24    Io(#[from] std::io::Error),
25    #[error("JSON parse error: {0}")]
26    Json(#[from] serde_json::Error),
27}
28
29pub type Result<T> = std::result::Result<T, StoreError>;
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct Descriptor {
33    pub media_type: String,
34    pub digest: String,
35    pub size: i64,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct ImageEntry {
40    pub name: String,
41    pub target: Descriptor,
42    pub created_at: Option<String>,
43    pub updated_at: Option<String>,
44}
45
46#[derive(Debug, Clone)]
47pub struct ResolvedImage {
48    pub entry: ImageEntry,
49    pub manifest_path: PathBuf,
50}
51
52#[derive(Debug, Clone)]
53pub struct ManifestInfo {
54    pub config_digest: Option<String>,
55    pub layer_digests: Vec<String>,
56    pub raw: Vec<u8>,
57}
58
59#[derive(Debug, Clone)]
60pub struct PortableImageExport {
61    pub manifest_digest: String,
62    pub blobs_root: PathBuf,
63    pub copied: Vec<String>,
64}
65
66#[derive(Debug, Clone)]
67pub struct DigestRef {
68    pub algo: String,
69    pub hex: String,
70}
71
72impl fmt::Display for DigestRef {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        write!(f, "{}:{}", self.algo, self.hex)
75    }
76}
77
78impl DigestRef {
79    pub fn parse(d: &str) -> Result<Self> {
80        let mut parts = d.splitn(2, ':');
81        let algo = parts
82            .next()
83            .ok_or_else(|| StoreError::Digest("missing algo".into()))?;
84        let hex = parts
85            .next()
86            .ok_or_else(|| StoreError::Digest("missing hex".into()))?;
87        if algo.is_empty() || hex.is_empty() {
88            return Err(StoreError::Digest("empty digest parts".into()));
89        }
90        Ok(DigestRef {
91            algo: algo.to_string(),
92            hex: hex.to_string(),
93        })
94    }
95
96    pub fn path_under(&self, root: &PathBuf) -> PathBuf {
97        root.join(&self.algo).join(&self.hex)
98    }
99}