docker_wrapper/command/compose/
watch.rs1use crate::command::{CommandExecutor, ComposeCommand, ComposeConfig, DockerCommand};
4use crate::error::Result;
5use async_trait::async_trait;
6
7#[derive(Debug, Clone)]
9pub struct ComposeWatchCommand {
10 pub executor: CommandExecutor,
12 pub config: ComposeConfig,
14 pub services: Vec<String>,
16 pub no_up: bool,
18 pub quiet: bool,
20}
21
22#[derive(Debug, Clone)]
24pub struct ComposeWatchResult {
25 pub stdout: String,
27 pub stderr: String,
29 pub success: bool,
31 pub services: Vec<String>,
33}
34
35impl ComposeWatchCommand {
36 #[must_use]
38 pub fn new() -> Self {
39 Self {
40 executor: CommandExecutor::new(),
41 config: ComposeConfig::new(),
42 services: Vec::new(),
43 no_up: false,
44 quiet: false,
45 }
46 }
47
48 #[must_use]
50 pub fn service(mut self, service: impl Into<String>) -> Self {
51 self.services.push(service.into());
52 self
53 }
54
55 #[must_use]
57 pub fn services<I, S>(mut self, services: I) -> Self
58 where
59 I: IntoIterator<Item = S>,
60 S: Into<String>,
61 {
62 self.services.extend(services.into_iter().map(Into::into));
63 self
64 }
65
66 #[must_use]
68 pub fn no_up(mut self) -> Self {
69 self.no_up = true;
70 self
71 }
72
73 #[must_use]
75 pub fn quiet(mut self) -> Self {
76 self.quiet = true;
77 self
78 }
79}
80
81impl Default for ComposeWatchCommand {
82 fn default() -> Self {
83 Self::new()
84 }
85}
86
87#[async_trait]
88impl DockerCommand for ComposeWatchCommand {
89 type Output = ComposeWatchResult;
90
91 fn get_executor(&self) -> &CommandExecutor {
92 &self.executor
93 }
94
95 fn get_executor_mut(&mut self) -> &mut CommandExecutor {
96 &mut self.executor
97 }
98
99 fn build_command_args(&self) -> Vec<String> {
100 <Self as ComposeCommand>::build_command_args(self)
101 }
102
103 async fn execute(&self) -> Result<Self::Output> {
104 let args = <Self as ComposeCommand>::build_command_args(self);
105 let output = self.execute_command(args).await?;
106
107 Ok(ComposeWatchResult {
108 stdout: output.stdout,
109 stderr: output.stderr,
110 success: output.success,
111 services: self.services.clone(),
112 })
113 }
114}
115
116impl ComposeCommand for ComposeWatchCommand {
117 fn get_config(&self) -> &ComposeConfig {
118 &self.config
119 }
120
121 fn get_config_mut(&mut self) -> &mut ComposeConfig {
122 &mut self.config
123 }
124
125 fn subcommand(&self) -> &'static str {
126 "watch"
127 }
128
129 fn build_subcommand_args(&self) -> Vec<String> {
130 let mut args = Vec::new();
131
132 if self.no_up {
133 args.push("--no-up".to_string());
134 }
135
136 if self.quiet {
137 args.push("--quiet".to_string());
138 }
139
140 args.extend(self.services.clone());
141 args
142 }
143}
144
145impl ComposeWatchResult {
146 #[must_use]
148 pub fn success(&self) -> bool {
149 self.success
150 }
151
152 #[must_use]
154 pub fn services(&self) -> &[String] {
155 &self.services
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162
163 #[test]
164 fn test_compose_watch_basic() {
165 let cmd = ComposeWatchCommand::new();
166 let args = cmd.build_subcommand_args();
167 assert!(args.is_empty());
168
169 let full_args = ComposeCommand::build_command_args(&cmd);
170 assert_eq!(full_args[0], "compose");
171 assert!(full_args.contains(&"watch".to_string()));
172 }
173
174 #[test]
175 fn test_compose_watch_with_options() {
176 let cmd = ComposeWatchCommand::new()
177 .no_up()
178 .quiet()
179 .services(vec!["frontend", "api"]);
180
181 let args = cmd.build_subcommand_args();
182 assert!(args.contains(&"--no-up".to_string()));
183 assert!(args.contains(&"--quiet".to_string()));
184 assert!(args.contains(&"frontend".to_string()));
185 assert!(args.contains(&"api".to_string()));
186 }
187}