docker_wrapper/command/network/
inspect.rs

1//! Docker network 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 network inspect command builder
9#[derive(Debug, Clone)]
10pub struct NetworkInspectCommand {
11    /// Networks to inspect
12    networks: Vec<String>,
13    /// Format output
14    format: Option<String>,
15    /// Include verbose information
16    verbose: bool,
17    /// Command executor
18    pub executor: CommandExecutor,
19}
20
21impl NetworkInspectCommand {
22    /// Create a new network inspect command
23    #[must_use]
24    pub fn new(network: impl Into<String>) -> Self {
25        Self {
26            networks: vec![network.into()],
27            format: None,
28            verbose: false,
29            executor: CommandExecutor::new(),
30        }
31    }
32
33    /// Create a new network inspect command for multiple networks
34    #[must_use]
35    pub fn new_multiple(networks: Vec<String>) -> Self {
36        Self {
37            networks,
38            format: None,
39            verbose: false,
40            executor: CommandExecutor::new(),
41        }
42    }
43
44    /// Add a network to inspect
45    #[must_use]
46    pub fn add_network(mut self, network: impl Into<String>) -> Self {
47        self.networks.push(network.into());
48        self
49    }
50
51    /// Set output format
52    #[must_use]
53    pub fn format(mut self, format: impl Into<String>) -> Self {
54        self.format = Some(format.into());
55        self
56    }
57
58    /// Include verbose information
59    #[must_use]
60    pub fn verbose(mut self) -> Self {
61        self.verbose = true;
62        self
63    }
64
65    /// Execute the command
66    ///
67    /// # Errors
68    ///
69    /// Returns an error if the Docker daemon is not running or the command fails
70    pub async fn run(&self) -> Result<NetworkInspectOutput> {
71        self.execute().await.map(NetworkInspectOutput::from)
72    }
73}
74
75#[async_trait]
76impl DockerCommand for NetworkInspectCommand {
77    type Output = CommandOutput;
78
79    fn build_command_args(&self) -> Vec<String> {
80        let mut args = vec!["network".to_string(), "inspect".to_string()];
81
82        if let Some(ref format) = self.format {
83            args.push("--format".to_string());
84            args.push(format.clone());
85        }
86
87        if self.verbose {
88            args.push("--verbose".to_string());
89        }
90
91        for network in &self.networks {
92            args.push(network.clone());
93        }
94
95        args.extend(self.executor.raw_args.clone());
96        args
97    }
98
99    fn get_executor(&self) -> &CommandExecutor {
100        &self.executor
101    }
102
103    fn get_executor_mut(&mut self) -> &mut CommandExecutor {
104        &mut self.executor
105    }
106
107    async fn execute(&self) -> Result<Self::Output> {
108        let args = self.build_command_args();
109        let command_name = args[0].clone();
110        let command_args = args[1..].to_vec();
111        self.executor
112            .execute_command(&command_name, command_args)
113            .await
114    }
115}
116
117/// Output from network inspect command
118#[derive(Debug, Clone)]
119pub struct NetworkInspectOutput {
120    /// JSON data
121    pub json: Option<Value>,
122    /// Raw command output
123    pub raw_output: CommandOutput,
124}
125
126impl From<CommandOutput> for NetworkInspectOutput {
127    fn from(output: CommandOutput) -> Self {
128        let json = if output.stdout.starts_with('[') || output.stdout.starts_with('{') {
129            serde_json::from_str(&output.stdout).ok()
130        } else {
131            None
132        };
133
134        Self {
135            json,
136            raw_output: output,
137        }
138    }
139}
140
141impl NetworkInspectOutput {
142    /// Check if the command was successful
143    #[must_use]
144    pub fn is_success(&self) -> bool {
145        self.raw_output.success
146    }
147
148    /// Get the JSON output
149    #[must_use]
150    pub fn json(&self) -> Option<&Value> {
151        self.json.as_ref()
152    }
153}
154
155#[cfg(test)]
156mod tests {
157    use super::*;
158
159    #[test]
160    fn test_network_inspect_single() {
161        let cmd = NetworkInspectCommand::new("my-network");
162        let args = cmd.build_command_args();
163        assert_eq!(args, vec!["network", "inspect", "my-network"]);
164    }
165
166    #[test]
167    fn test_network_inspect_multiple() {
168        let cmd = NetworkInspectCommand::new_multiple(vec![
169            "network1".to_string(),
170            "network2".to_string(),
171        ]);
172        let args = cmd.build_command_args();
173        assert_eq!(args, vec!["network", "inspect", "network1", "network2"]);
174    }
175
176    #[test]
177    fn test_network_inspect_with_format() {
178        let cmd = NetworkInspectCommand::new("my-network").format("{{.Driver}}");
179        let args = cmd.build_command_args();
180        assert_eq!(
181            args,
182            vec![
183                "network",
184                "inspect",
185                "--format",
186                "{{.Driver}}",
187                "my-network"
188            ]
189        );
190    }
191
192    #[test]
193    fn test_network_inspect_verbose() {
194        let cmd = NetworkInspectCommand::new("my-network").verbose();
195        let args = cmd.build_command_args();
196        assert_eq!(args, vec!["network", "inspect", "--verbose", "my-network"]);
197    }
198}