docker_wrapper/command/network/
inspect.rs1use crate::command::{CommandExecutor, CommandOutput, DockerCommand};
4use crate::error::Result;
5use async_trait::async_trait;
6use serde_json::Value;
7
8#[derive(Debug, Clone)]
10pub struct NetworkInspectCommand {
11 networks: Vec<String>,
13 format: Option<String>,
15 verbose: bool,
17 pub executor: CommandExecutor,
19}
20
21impl NetworkInspectCommand {
22 #[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 #[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 #[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 #[must_use]
53 pub fn format(mut self, format: impl Into<String>) -> Self {
54 self.format = Some(format.into());
55 self
56 }
57
58 #[must_use]
60 pub fn verbose(mut self) -> Self {
61 self.verbose = true;
62 self
63 }
64
65 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#[derive(Debug, Clone)]
119pub struct NetworkInspectOutput {
120 pub json: Option<Value>,
122 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 #[must_use]
144 pub fn is_success(&self) -> bool {
145 self.raw_output.success
146 }
147
148 #[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}