docker_wrapper/compose/
rm.rs1use crate::compose::{ComposeCommandV2 as ComposeCommand, ComposeConfig};
4use crate::error::Result;
5use async_trait::async_trait;
6
7#[derive(Debug, Clone, Default)]
11#[allow(clippy::struct_excessive_bools)]
12pub struct ComposeRmCommand {
13 pub config: ComposeConfig,
15 pub force: bool,
17 pub stop: bool,
19 pub volumes: bool,
21 pub all: bool,
23 pub services: Vec<String>,
25}
26
27#[derive(Debug, Clone)]
29pub struct RmResult {
30 pub output: String,
32 pub success: bool,
34}
35
36impl ComposeRmCommand {
37 #[must_use]
39 pub fn new() -> Self {
40 Self::default()
41 }
42
43 #[must_use]
45 pub fn file<P: Into<std::path::PathBuf>>(mut self, file: P) -> Self {
46 self.config.files.push(file.into());
47 self
48 }
49
50 #[must_use]
52 pub fn project_name(mut self, name: impl Into<String>) -> Self {
53 self.config.project_name = Some(name.into());
54 self
55 }
56
57 #[must_use]
59 pub fn force(mut self) -> Self {
60 self.force = true;
61 self
62 }
63
64 #[must_use]
66 pub fn stop(mut self) -> Self {
67 self.stop = true;
68 self
69 }
70
71 #[must_use]
73 pub fn volumes(mut self) -> Self {
74 self.volumes = true;
75 self
76 }
77
78 #[must_use]
80 pub fn all(mut self) -> Self {
81 self.all = true;
82 self
83 }
84
85 #[must_use]
87 pub fn service(mut self, service: impl Into<String>) -> Self {
88 self.services.push(service.into());
89 self
90 }
91
92 #[must_use]
94 pub fn services<I, S>(mut self, services: I) -> Self
95 where
96 I: IntoIterator<Item = S>,
97 S: Into<String>,
98 {
99 self.services.extend(services.into_iter().map(Into::into));
100 self
101 }
102
103 fn build_args(&self) -> Vec<String> {
104 let mut args = vec!["rm".to_string()];
105
106 if self.force {
108 args.push("--force".to_string());
109 }
110 if self.stop {
111 args.push("--stop".to_string());
112 }
113 if self.volumes {
114 args.push("--volumes".to_string());
115 }
116 if self.all {
117 args.push("--all".to_string());
118 }
119
120 args.extend(self.services.clone());
122
123 args
124 }
125}
126
127#[async_trait]
128impl ComposeCommand for ComposeRmCommand {
129 type Output = RmResult;
130
131 fn get_config(&self) -> &ComposeConfig {
132 &self.config
133 }
134
135 fn get_config_mut(&mut self) -> &mut ComposeConfig {
136 &mut self.config
137 }
138
139 async fn execute_compose(&self, args: Vec<String>) -> Result<Self::Output> {
140 let output = self.execute_compose_command(args).await?;
141
142 Ok(RmResult {
143 output: output.stdout,
144 success: output.success,
145 })
146 }
147
148 async fn execute(&self) -> Result<Self::Output> {
149 let args = self.build_args();
150 self.execute_compose(args).await
151 }
152}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157
158 #[test]
159 fn test_rm_command_basic() {
160 let cmd = ComposeRmCommand::new();
161 let args = cmd.build_args();
162 assert_eq!(args[0], "rm");
163 }
164
165 #[test]
166 fn test_rm_command_with_force() {
167 let cmd = ComposeRmCommand::new().force().stop();
168 let args = cmd.build_args();
169 assert!(args.contains(&"--force".to_string()));
170 assert!(args.contains(&"--stop".to_string()));
171 }
172
173 #[test]
174 fn test_rm_command_with_services() {
175 let cmd = ComposeRmCommand::new().service("web").service("db");
176 let args = cmd.build_args();
177 assert!(args.contains(&"web".to_string()));
178 assert!(args.contains(&"db".to_string()));
179 }
180
181 #[test]
182 fn test_rm_command_with_volumes() {
183 let cmd = ComposeRmCommand::new().volumes().all();
184 let args = cmd.build_args();
185 assert!(args.contains(&"--volumes".to_string()));
186 assert!(args.contains(&"--all".to_string()));
187 }
188}