-
Notifications
You must be signed in to change notification settings - Fork 2
/
image.rs
119 lines (111 loc) · 4.47 KB
/
image.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use bollard::models::{ImageInspect, ImageSummary};
use once_cell::sync::Lazy;
use regex::Regex;
use crate::error;
/// Image struct that contains all information that may be needed by a function.
/// It's designed to be passed around between functions
#[derive(Clone, Debug)]
pub struct Image {
pub reference: String,
pub registry: Option<String>,
pub repository: Option<String>,
pub tag: Option<String>,
pub local_digests: Option<Vec<String>>,
pub remote_digest: Option<String>,
}
impl Image {
/// Creates an populates the fields of an Image object based on the ImageSummary from the Docker daemon
pub async fn from_summary(image: ImageSummary) -> Option<Self> {
if !image.repo_tags.is_empty() && !image.repo_digests.is_empty() {
let mut image = Image {
reference: image.repo_tags[0].clone(),
registry: None,
repository: None,
tag: None,
local_digests: Some(
image
.repo_digests
.clone()
.iter()
.map(|digest| digest.split('@').collect::<Vec<&str>>()[1].to_string())
.collect(),
),
remote_digest: None,
};
let (registry, repository, tag) = image.split();
image.registry = Some(registry);
image.repository = Some(repository);
image.tag = Some(tag);
return Some(image);
}
None
}
pub async fn from_inspect(image: ImageInspect) -> Option<Self> {
if image.repo_tags.is_some()
&& !image.repo_tags.as_ref().unwrap().is_empty()
&& image.repo_digests.is_some()
&& !image.repo_digests.as_ref().unwrap().is_empty()
{
let mut image = Image {
reference: image.repo_tags.as_ref().unwrap()[0].clone(),
registry: None,
repository: None,
tag: None,
local_digests: Some(
image
.repo_digests
.unwrap()
.clone()
.iter()
.map(|digest| digest.split('@').collect::<Vec<&str>>()[1].to_string())
.collect(),
),
remote_digest: None,
};
let (registry, repository, tag) = image.split();
image.registry = Some(registry);
image.repository = Some(repository);
image.tag = Some(tag);
return Some(image);
}
None
}
/// Takes an image and splits it into registry, repository and tag, based on the reference.
/// For example, `ghcr.io/sergi0g/cup:latest` becomes `['ghcr.io', 'sergi0g/cup', 'latest']`.
pub fn split(&self) -> (String, String, String) {
match RE.captures(&self.reference) {
Some(c) => {
let registry = match c.name("registry") {
Some(registry) => registry.as_str().to_owned(),
None => String::from("registry-1.docker.io"),
};
return (
registry.clone(),
match c.name("repository") {
Some(repository) => {
let repo = repository.as_str().to_owned();
if !repo.contains('/') && registry == "registry-1.docker.io" {
format!("library/{}", repo)
} else {
repo
}
}
None => error!("Failed to parse image {}", &self.reference),
},
match c.name("tag") {
Some(tag) => tag.as_str().to_owned(),
None => String::from("latest"),
},
);
}
None => error!("Failed to parse image {}", &self.reference),
}
}
}
/// Regex to match Docker image references against, so registry, repository and tag can be extracted.
static RE: Lazy<Regex> = Lazy::new(|| {
Regex::new(
r#"^(?P<name>(?:(?P<registry>(?:(?:localhost|[\w-]+(?:\.[\w-]+)+)(?::\d+)?)|[\w]+:\d+)/)?(?P<repository>[a-z0-9_.-]+(?:/[a-z0-9_.-]+)*))(?::(?P<tag>[\w][\w.-]{0,127}))?$"#, // From https://regex101.com/r/nmSDPA/1
)
.unwrap()
});