docker_wrapper/command/builder/
inspect.rs

1//! Docker buildx inspect command implementation.
2
3use crate::command::{CommandExecutor, CommandOutput, DockerCommand};
4use crate::error::Result;
5use async_trait::async_trait;
6
7/// Result of buildx inspect command
8#[derive(Debug, Clone)]
9pub struct BuildxInspectResult {
10    /// The name of the builder
11    pub name: Option<String>,
12    /// The driver used by the builder
13    pub driver: Option<String>,
14    /// The status of the builder
15    pub status: Option<String>,
16    /// Platforms supported by the builder
17    pub platforms: Vec<String>,
18    /// Raw output from the command
19    pub output: String,
20    /// Whether the command succeeded
21    pub success: bool,
22}
23
24impl BuildxInspectResult {
25    /// Parse the buildx inspect output
26    fn parse(output: &CommandOutput) -> Self {
27        let stdout = &output.stdout;
28        let mut name = None;
29        let mut driver = None;
30        let mut status = None;
31        let mut platforms = Vec::new();
32
33        for line in stdout.lines() {
34            let line = line.trim();
35            if line.starts_with("Name:") {
36                name = Some(line.trim_start_matches("Name:").trim().to_string());
37            } else if line.starts_with("Driver:") {
38                driver = Some(line.trim_start_matches("Driver:").trim().to_string());
39            } else if line.starts_with("Status:") {
40                status = Some(line.trim_start_matches("Status:").trim().to_string());
41            } else if line.starts_with("Platforms:") {
42                let platform_str = line.trim_start_matches("Platforms:").trim();
43                platforms = platform_str
44                    .split(',')
45                    .map(|s| s.trim().to_string())
46                    .filter(|s| !s.is_empty())
47                    .collect();
48            }
49        }
50
51        Self {
52            name,
53            driver,
54            status,
55            platforms,
56            output: stdout.clone(),
57            success: output.success,
58        }
59    }
60}
61
62/// Docker buildx inspect command builder
63///
64/// Inspects a builder instance.
65///
66/// # Example
67///
68/// ```rust,no_run
69/// use docker_wrapper::{DockerCommand, BuildxInspectCommand};
70///
71/// # #[tokio::main]
72/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
73/// let result = BuildxInspectCommand::new()
74///     .bootstrap()
75///     .execute()
76///     .await?;
77///
78/// if let Some(name) = &result.name {
79///     println!("Builder: {}", name);
80/// }
81/// println!("Platforms: {:?}", result.platforms);
82/// # Ok(())
83/// # }
84/// ```
85#[derive(Debug, Clone, Default)]
86pub struct BuildxInspectCommand {
87    /// The builder name to inspect (optional, defaults to current)
88    name: Option<String>,
89    /// Ensure builder has booted before inspecting
90    bootstrap: bool,
91    /// Command executor
92    pub executor: CommandExecutor,
93}
94
95impl BuildxInspectCommand {
96    /// Create a new buildx inspect command
97    #[must_use]
98    pub fn new() -> Self {
99        Self::default()
100    }
101
102    /// Set the builder name to inspect
103    #[must_use]
104    pub fn name(mut self, name: impl Into<String>) -> Self {
105        self.name = Some(name.into());
106        self
107    }
108
109    /// Ensure builder has booted before inspecting
110    #[must_use]
111    pub fn bootstrap(mut self) -> Self {
112        self.bootstrap = true;
113        self
114    }
115
116    /// Build the command arguments
117    fn build_args(&self) -> Vec<String> {
118        let mut args = vec!["buildx".to_string(), "inspect".to_string()];
119
120        if self.bootstrap {
121            args.push("--bootstrap".to_string());
122        }
123
124        if let Some(ref name) = self.name {
125            args.push(name.clone());
126        }
127
128        args.extend(self.executor.raw_args.clone());
129
130        args
131    }
132}
133
134#[async_trait]
135impl DockerCommand for BuildxInspectCommand {
136    type Output = BuildxInspectResult;
137
138    fn get_executor(&self) -> &CommandExecutor {
139        &self.executor
140    }
141
142    fn get_executor_mut(&mut self) -> &mut CommandExecutor {
143        &mut self.executor
144    }
145
146    fn build_command_args(&self) -> Vec<String> {
147        self.build_args()
148    }
149
150    async fn execute(&self) -> Result<Self::Output> {
151        let args = self.build_args();
152        let output = self.execute_command(args).await?;
153        Ok(BuildxInspectResult::parse(&output))
154    }
155}
156
157#[cfg(test)]
158mod tests {
159    use super::*;
160
161    #[test]
162    fn test_buildx_inspect_basic() {
163        let cmd = BuildxInspectCommand::new();
164        let args = cmd.build_args();
165        assert_eq!(args, vec!["buildx", "inspect"]);
166    }
167
168    #[test]
169    fn test_buildx_inspect_with_name() {
170        let cmd = BuildxInspectCommand::new().name("mybuilder");
171        let args = cmd.build_args();
172        assert!(args.contains(&"mybuilder".to_string()));
173    }
174
175    #[test]
176    fn test_buildx_inspect_with_bootstrap() {
177        let cmd = BuildxInspectCommand::new().bootstrap();
178        let args = cmd.build_args();
179        assert!(args.contains(&"--bootstrap".to_string()));
180    }
181
182    #[test]
183    fn test_buildx_inspect_all_options() {
184        let cmd = BuildxInspectCommand::new().name("mybuilder").bootstrap();
185        let args = cmd.build_args();
186        assert!(args.contains(&"--bootstrap".to_string()));
187        assert!(args.contains(&"mybuilder".to_string()));
188    }
189
190    #[test]
191    fn test_buildx_inspect_result_parse() {
192        let output = CommandOutput {
193            stdout: "Name:   mybuilder\nDriver: docker-container\nStatus: running\nPlatforms: linux/amd64, linux/arm64".to_string(),
194            stderr: String::new(),
195            exit_code: 0,
196            success: true,
197        };
198        let result = BuildxInspectResult::parse(&output);
199        assert_eq!(result.name, Some("mybuilder".to_string()));
200        assert_eq!(result.driver, Some("docker-container".to_string()));
201        assert_eq!(result.status, Some("running".to_string()));
202        assert_eq!(result.platforms, vec!["linux/amd64", "linux/arm64"]);
203    }
204}