docker_wrapper/command/context/
inspect.rs

1//! Docker context inspect command implementation.
2
3use crate::command::{CommandExecutor, CommandOutput, DockerCommand};
4use crate::error::Result;
5use async_trait::async_trait;
6use serde_json::Value;
7
8/// Docker context inspect command builder
9///
10/// Display detailed information on one or more contexts.
11///
12/// # Example
13///
14/// ```no_run
15/// use docker_wrapper::{ContextInspectCommand, DockerCommand};
16///
17/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
18/// // Inspect a context
19/// let info = ContextInspectCommand::new("production")
20///     .format("{{.Endpoints.docker.Host}}")
21///     .execute()
22///     .await?;
23/// # Ok(())
24/// # }
25/// ```
26#[derive(Debug, Clone)]
27pub struct ContextInspectCommand {
28    /// Contexts to inspect
29    contexts: Vec<String>,
30    /// Format the output
31    format: Option<String>,
32    /// Command executor
33    pub executor: CommandExecutor,
34}
35
36impl ContextInspectCommand {
37    /// Create a new context inspect command
38    #[must_use]
39    pub fn new(context: impl Into<String>) -> Self {
40        Self {
41            contexts: vec![context.into()],
42            format: None,
43            executor: CommandExecutor::new(),
44        }
45    }
46
47    /// Add another context to inspect
48    #[must_use]
49    pub fn add_context(mut self, context: impl Into<String>) -> Self {
50        self.contexts.push(context.into());
51        self
52    }
53
54    /// Format the output using a Go template
55    #[must_use]
56    pub fn format(mut self, template: impl Into<String>) -> Self {
57        self.format = Some(template.into());
58        self
59    }
60}
61
62#[async_trait]
63impl DockerCommand for ContextInspectCommand {
64    type Output = CommandOutput;
65
66    fn get_executor(&self) -> &CommandExecutor {
67        &self.executor
68    }
69
70    fn get_executor_mut(&mut self) -> &mut CommandExecutor {
71        &mut self.executor
72    }
73
74    fn build_command_args(&self) -> Vec<String> {
75        let mut args = vec!["context".to_string(), "inspect".to_string()];
76
77        if let Some(format) = &self.format {
78            args.push("--format".to_string());
79            args.push(format.clone());
80        }
81
82        args.extend(self.contexts.clone());
83        args.extend(self.executor.raw_args.clone());
84        args
85    }
86
87    async fn execute(&self) -> Result<Self::Output> {
88        let args = self.build_command_args();
89        self.execute_command(args).await
90    }
91}
92
93/// Extension methods for `ContextInspectCommand` output
94impl CommandOutput {
95    /// Parse context information as JSON
96    ///
97    /// # Errors
98    ///
99    /// Returns an error if the JSON parsing fails
100    pub fn parse_context_info(&self) -> Result<Vec<Value>> {
101        if self.stdout.trim().is_empty() {
102            return Ok(Vec::new());
103        }
104
105        // Docker returns array of contexts
106        let contexts: Vec<Value> = serde_json::from_str(&self.stdout)?;
107        Ok(contexts)
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114
115    #[test]
116    fn test_context_inspect_single() {
117        let cmd = ContextInspectCommand::new("production");
118        let args = cmd.build_command_args();
119        assert_eq!(args[0], "context");
120        assert_eq!(args[1], "inspect");
121        assert!(args.contains(&"production".to_string()));
122    }
123
124    #[test]
125    fn test_context_inspect_multiple() {
126        let cmd = ContextInspectCommand::new("context1").add_context("context2");
127        let args = cmd.build_command_args();
128        assert!(args.contains(&"context1".to_string()));
129        assert!(args.contains(&"context2".to_string()));
130    }
131
132    #[test]
133    fn test_context_inspect_with_format() {
134        let cmd = ContextInspectCommand::new("production").format("{{.Name}}");
135        let args = cmd.build_command_args();
136        assert!(args.contains(&"--format".to_string()));
137        assert!(args.contains(&"{{.Name}}".to_string()));
138    }
139}