docker_wrapper/command/system/
df.rs1use crate::command::{CommandExecutor, DockerCommand};
4use crate::error::Result;
5use async_trait::async_trait;
6use serde::Deserialize;
7
8#[derive(Debug, Clone, Deserialize)]
10#[serde(rename_all = "PascalCase")]
11pub struct ImageUsage {
12 #[serde(default)]
14 pub total_count: usize,
15
16 #[serde(default)]
18 pub active: usize,
19
20 #[serde(default)]
22 pub size: i64,
23
24 #[serde(default)]
26 pub reclaimable_size: i64,
27}
28
29#[derive(Debug, Clone, Deserialize)]
31#[serde(rename_all = "PascalCase")]
32pub struct ContainerUsage {
33 #[serde(default)]
35 pub total_count: usize,
36
37 #[serde(default)]
39 pub running: usize,
40
41 #[serde(default)]
43 pub paused: usize,
44
45 #[serde(default)]
47 pub stopped: usize,
48
49 #[serde(default)]
51 pub size: i64,
52
53 #[serde(default)]
55 pub reclaimable_size: i64,
56}
57
58#[derive(Debug, Clone, Deserialize)]
60#[serde(rename_all = "PascalCase")]
61pub struct VolumeUsage {
62 #[serde(default)]
64 pub total_count: usize,
65
66 #[serde(default)]
68 pub active: usize,
69
70 #[serde(default)]
72 pub size: i64,
73
74 #[serde(default)]
76 pub reclaimable_size: i64,
77}
78
79#[derive(Debug, Clone, Deserialize)]
81#[serde(rename_all = "PascalCase")]
82pub struct BuildCacheUsage {
83 #[serde(default)]
85 pub total_count: usize,
86
87 #[serde(default)]
89 pub active: usize,
90
91 #[serde(default)]
93 pub size: i64,
94
95 #[serde(default)]
97 pub reclaimable_size: i64,
98}
99
100#[derive(Debug, Clone, Deserialize)]
102#[serde(rename_all = "PascalCase")]
103pub struct DiskUsage {
104 pub images: Vec<ImageInfo>,
106
107 pub containers: Vec<ContainerInfo>,
109
110 pub volumes: Vec<VolumeInfo>,
112
113 #[serde(default)]
115 pub build_cache: Vec<BuildCacheInfo>,
116}
117
118#[derive(Debug, Clone, Deserialize)]
120#[serde(rename_all = "PascalCase")]
121pub struct ImageInfo {
122 #[serde(rename = "ID")]
124 pub id: String,
125
126 #[serde(default)]
128 pub repository: String,
129
130 #[serde(default)]
132 pub tag: String,
133
134 #[serde(default)]
136 pub created: i64,
137
138 #[serde(default)]
140 pub size: i64,
141
142 #[serde(default)]
144 pub shared_size: i64,
145
146 #[serde(default)]
148 pub virtual_size: i64,
149
150 #[serde(default)]
152 pub containers: i32,
153}
154
155#[derive(Debug, Clone, Deserialize)]
157#[serde(rename_all = "PascalCase")]
158pub struct ContainerInfo {
159 #[serde(rename = "ID")]
161 pub id: String,
162
163 #[serde(default)]
165 pub names: Vec<String>,
166
167 #[serde(default)]
169 pub image: String,
170
171 #[serde(default)]
173 pub created: i64,
174
175 #[serde(default)]
177 pub state: String,
178
179 #[serde(default)]
181 pub status: String,
182
183 #[serde(default, rename = "SizeRw")]
185 pub size_rw: i64,
186
187 #[serde(default, rename = "SizeRootFs")]
189 pub size_root_fs: i64,
190}
191
192#[derive(Debug, Clone, Deserialize)]
194#[serde(rename_all = "PascalCase")]
195pub struct VolumeInfo {
196 pub name: String,
198
199 #[serde(default)]
201 pub driver: String,
202
203 #[serde(default)]
205 pub mount_point: String,
206
207 #[serde(default)]
209 pub created_at: String,
210
211 #[serde(default)]
213 pub size: i64,
214
215 #[serde(default, rename = "RefCount")]
217 pub ref_count: i32,
218}
219
220#[derive(Debug, Clone, Deserialize)]
222#[serde(rename_all = "PascalCase")]
223pub struct BuildCacheInfo {
224 #[serde(rename = "ID")]
226 pub id: String,
227
228 #[serde(default)]
230 pub parent: String,
231
232 #[serde(default, rename = "Type")]
234 pub cache_type: String,
235
236 #[serde(default)]
238 pub description: String,
239
240 #[serde(default)]
242 pub created_at: String,
243
244 #[serde(default)]
246 pub last_used_at: String,
247
248 #[serde(default)]
250 pub usage_count: i64,
251
252 #[serde(default)]
254 pub size: i64,
255
256 #[serde(default)]
258 pub in_use: bool,
259
260 #[serde(default)]
262 pub shared: bool,
263}
264
265#[derive(Debug, Clone)]
269pub struct SystemDfCommand {
270 verbose: bool,
272
273 format: Option<String>,
275
276 pub executor: CommandExecutor,
278}
279
280impl SystemDfCommand {
281 #[must_use]
283 pub fn new() -> Self {
284 Self {
285 verbose: false,
286 format: None,
287 executor: CommandExecutor::new(),
288 }
289 }
290
291 #[must_use]
293 pub fn verbose(mut self) -> Self {
294 self.verbose = true;
295 self
296 }
297
298 #[must_use]
300 pub fn format(mut self, template: impl Into<String>) -> Self {
301 self.format = Some(template.into());
302 self
303 }
304
305 pub async fn run(&self) -> Result<DiskUsage> {
311 self.execute().await
312 }
313}
314
315impl Default for SystemDfCommand {
316 fn default() -> Self {
317 Self::new()
318 }
319}
320
321#[async_trait]
322impl DockerCommand for SystemDfCommand {
323 type Output = DiskUsage;
324
325 fn build_command_args(&self) -> Vec<String> {
326 let mut args = vec!["system".to_string(), "df".to_string()];
327
328 if self.verbose {
329 args.push("--verbose".to_string());
330 }
331
332 args.push("--format".to_string());
334 args.push("json".to_string());
335
336 args.extend(self.executor.raw_args.clone());
337 args
338 }
339
340 fn get_executor(&self) -> &CommandExecutor {
341 &self.executor
342 }
343
344 fn get_executor_mut(&mut self) -> &mut CommandExecutor {
345 &mut self.executor
346 }
347
348 async fn execute(&self) -> Result<Self::Output> {
349 let args = self.build_command_args();
350 let command_name = args[0].clone();
351 let command_args = args[1..].to_vec();
352 let output = self
353 .executor
354 .execute_command(&command_name, command_args)
355 .await?;
356 let stdout = &output.stdout;
357
358 let usage: DiskUsage =
360 serde_json::from_str(stdout).map_err(|e| crate::error::Error::ParseError {
361 message: format!("Failed to parse disk usage: {e}"),
362 })?;
363
364 Ok(usage)
365 }
366}
367
368#[cfg(test)]
369mod tests {
370 use super::*;
371
372 #[test]
373 fn test_system_df_builder() {
374 let cmd = SystemDfCommand::new().verbose();
375
376 let args = cmd.build_command_args();
377 assert_eq!(args[0], "system");
378 assert!(args.contains(&"df".to_string()));
379 assert!(args.contains(&"--verbose".to_string()));
380 assert!(args.contains(&"--format".to_string()));
381 assert!(args.contains(&"json".to_string()));
382 }
383}