docker_wrapper/command/manifest/
annotate.rs1use crate::command::{CommandExecutor, CommandOutput, DockerCommand};
4use crate::error::Result;
5use async_trait::async_trait;
6
7#[derive(Debug, Clone)]
9pub struct ManifestAnnotateResult {
10 pub manifest_list: String,
12 pub manifest: String,
14 pub output: String,
16 pub success: bool,
18}
19
20impl ManifestAnnotateResult {
21 fn parse(manifest_list: &str, manifest: &str, output: &CommandOutput) -> Self {
23 Self {
24 manifest_list: manifest_list.to_string(),
25 manifest: manifest.to_string(),
26 output: output.stdout.clone(),
27 success: output.success,
28 }
29 }
30}
31
32#[derive(Debug, Clone)]
55pub struct ManifestAnnotateCommand {
56 manifest_list: String,
58 manifest: String,
60 arch: Option<String>,
62 os: Option<String>,
64 os_features: Vec<String>,
66 os_version: Option<String>,
68 variant: Option<String>,
70 pub executor: CommandExecutor,
72}
73
74impl ManifestAnnotateCommand {
75 #[must_use]
82 pub fn new(manifest_list: impl Into<String>, manifest: impl Into<String>) -> Self {
83 Self {
84 manifest_list: manifest_list.into(),
85 manifest: manifest.into(),
86 arch: None,
87 os: None,
88 os_features: Vec::new(),
89 os_version: None,
90 variant: None,
91 executor: CommandExecutor::new(),
92 }
93 }
94
95 #[must_use]
97 pub fn arch(mut self, arch: impl Into<String>) -> Self {
98 self.arch = Some(arch.into());
99 self
100 }
101
102 #[must_use]
104 pub fn os(mut self, os: impl Into<String>) -> Self {
105 self.os = Some(os.into());
106 self
107 }
108
109 #[must_use]
111 pub fn os_feature(mut self, feature: impl Into<String>) -> Self {
112 self.os_features.push(feature.into());
113 self
114 }
115
116 #[must_use]
118 pub fn os_version(mut self, version: impl Into<String>) -> Self {
119 self.os_version = Some(version.into());
120 self
121 }
122
123 #[must_use]
125 pub fn variant(mut self, variant: impl Into<String>) -> Self {
126 self.variant = Some(variant.into());
127 self
128 }
129
130 fn build_args(&self) -> Vec<String> {
132 let mut args = vec!["manifest".to_string(), "annotate".to_string()];
133
134 if let Some(ref arch) = self.arch {
135 args.push("--arch".to_string());
136 args.push(arch.clone());
137 }
138
139 if let Some(ref os) = self.os {
140 args.push("--os".to_string());
141 args.push(os.clone());
142 }
143
144 for feature in &self.os_features {
145 args.push("--os-features".to_string());
146 args.push(feature.clone());
147 }
148
149 if let Some(ref version) = self.os_version {
150 args.push("--os-version".to_string());
151 args.push(version.clone());
152 }
153
154 if let Some(ref variant) = self.variant {
155 args.push("--variant".to_string());
156 args.push(variant.clone());
157 }
158
159 args.push(self.manifest_list.clone());
160 args.push(self.manifest.clone());
161
162 args.extend(self.executor.raw_args.clone());
163
164 args
165 }
166}
167
168#[async_trait]
169impl DockerCommand for ManifestAnnotateCommand {
170 type Output = ManifestAnnotateResult;
171
172 fn get_executor(&self) -> &CommandExecutor {
173 &self.executor
174 }
175
176 fn get_executor_mut(&mut self) -> &mut CommandExecutor {
177 &mut self.executor
178 }
179
180 fn build_command_args(&self) -> Vec<String> {
181 self.build_args()
182 }
183
184 async fn execute(&self) -> Result<Self::Output> {
185 let args = self.build_args();
186 let output = self.execute_command(args).await?;
187 Ok(ManifestAnnotateResult::parse(
188 &self.manifest_list,
189 &self.manifest,
190 &output,
191 ))
192 }
193}
194
195#[cfg(test)]
196mod tests {
197 use super::*;
198
199 #[test]
200 fn test_manifest_annotate_basic() {
201 let cmd = ManifestAnnotateCommand::new("myapp:latest", "myapp:latest-amd64");
202 let args = cmd.build_args();
203 assert_eq!(
204 args,
205 vec!["manifest", "annotate", "myapp:latest", "myapp:latest-amd64"]
206 );
207 }
208
209 #[test]
210 fn test_manifest_annotate_with_arch() {
211 let cmd = ManifestAnnotateCommand::new("myapp:latest", "myapp:latest-arm64").arch("arm64");
212 let args = cmd.build_args();
213 assert!(args.contains(&"--arch".to_string()));
214 assert!(args.contains(&"arm64".to_string()));
215 }
216
217 #[test]
218 fn test_manifest_annotate_with_os() {
219 let cmd = ManifestAnnotateCommand::new("myapp:latest", "myapp:latest-amd64").os("linux");
220 let args = cmd.build_args();
221 assert!(args.contains(&"--os".to_string()));
222 assert!(args.contains(&"linux".to_string()));
223 }
224
225 #[test]
226 fn test_manifest_annotate_with_variant() {
227 let cmd = ManifestAnnotateCommand::new("myapp:latest", "myapp:latest-arm64").variant("v8");
228 let args = cmd.build_args();
229 assert!(args.contains(&"--variant".to_string()));
230 assert!(args.contains(&"v8".to_string()));
231 }
232
233 #[test]
234 fn test_manifest_annotate_all_options() {
235 let cmd = ManifestAnnotateCommand::new("myapp:latest", "myapp:latest-arm64")
236 .arch("arm64")
237 .os("linux")
238 .os_feature("sse4")
239 .os_version("1.0")
240 .variant("v8");
241 let args = cmd.build_args();
242 assert!(args.contains(&"--arch".to_string()));
243 assert!(args.contains(&"--os".to_string()));
244 assert!(args.contains(&"--os-features".to_string()));
245 assert!(args.contains(&"--os-version".to_string()));
246 assert!(args.contains(&"--variant".to_string()));
247 }
248}