docker_wrapper/command/context/
rm.rs

1//! Docker context rm command implementation.
2
3use crate::command::{CommandExecutor, CommandOutput, DockerCommand};
4use crate::error::Result;
5use async_trait::async_trait;
6
7/// Docker context rm command builder
8///
9/// Remove one or more Docker contexts.
10///
11/// # Example
12///
13/// ```no_run
14/// use docker_wrapper::{ContextRmCommand, DockerCommand};
15///
16/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
17/// // Remove a context
18/// ContextRmCommand::new("old-context")
19///     .force()
20///     .execute()
21///     .await?;
22/// # Ok(())
23/// # }
24/// ```
25#[derive(Debug, Clone)]
26pub struct ContextRmCommand {
27    /// Contexts to remove
28    contexts: Vec<String>,
29    /// Force removal
30    force: bool,
31    /// Command executor
32    pub executor: CommandExecutor,
33}
34
35impl ContextRmCommand {
36    /// Create a new context rm command
37    #[must_use]
38    pub fn new(context: impl Into<String>) -> Self {
39        Self {
40            contexts: vec![context.into()],
41            force: false,
42            executor: CommandExecutor::new(),
43        }
44    }
45
46    /// Add another context to remove
47    #[must_use]
48    pub fn add_context(mut self, context: impl Into<String>) -> Self {
49        self.contexts.push(context.into());
50        self
51    }
52
53    /// Force removal (don't prompt for confirmation)
54    #[must_use]
55    pub fn force(mut self) -> Self {
56        self.force = true;
57        self
58    }
59}
60
61#[async_trait]
62impl DockerCommand for ContextRmCommand {
63    type Output = CommandOutput;
64
65    fn get_executor(&self) -> &CommandExecutor {
66        &self.executor
67    }
68
69    fn get_executor_mut(&mut self) -> &mut CommandExecutor {
70        &mut self.executor
71    }
72
73    fn build_command_args(&self) -> Vec<String> {
74        let mut args = vec!["context".to_string(), "rm".to_string()];
75
76        if self.force {
77            args.push("--force".to_string());
78        }
79
80        args.extend(self.contexts.clone());
81        args.extend(self.executor.raw_args.clone());
82        args
83    }
84
85    async fn execute(&self) -> Result<Self::Output> {
86        let args = self.build_command_args();
87        self.execute_command(args).await
88    }
89}
90
91/// Extension methods for `ContextRmCommand` output
92impl CommandOutput {
93    /// Get removed context names from output
94    #[must_use]
95    pub fn removed_contexts(&self) -> Vec<String> {
96        self.stdout
97            .lines()
98            .filter_map(|line| {
99                if line.is_empty() {
100                    None
101                } else {
102                    Some(line.trim().to_string())
103                }
104            })
105            .collect()
106    }
107}
108
109#[cfg(test)]
110mod tests {
111    use super::*;
112
113    #[test]
114    fn test_context_rm_single() {
115        let cmd = ContextRmCommand::new("test-context");
116        let args = cmd.build_command_args();
117        assert_eq!(args[0], "context");
118        assert_eq!(args[1], "rm");
119        assert!(args.contains(&"test-context".to_string()));
120    }
121
122    #[test]
123    fn test_context_rm_multiple() {
124        let cmd = ContextRmCommand::new("context1").add_context("context2");
125        let args = cmd.build_command_args();
126        assert!(args.contains(&"context1".to_string()));
127        assert!(args.contains(&"context2".to_string()));
128    }
129
130    #[test]
131    fn test_context_rm_force() {
132        let cmd = ContextRmCommand::new("test-context").force();
133        let args = cmd.build_command_args();
134        assert!(args.contains(&"--force".to_string()));
135    }
136
137    #[test]
138    fn test_removed_contexts_parsing() {
139        let output = CommandOutput {
140            stdout: "context1\ncontext2\n".to_string(),
141            stderr: String::new(),
142            exit_code: 0,
143            success: true,
144        };
145
146        let removed = output.removed_contexts();
147        assert_eq!(removed.len(), 2);
148        assert_eq!(removed[0], "context1");
149        assert_eq!(removed[1], "context2");
150    }
151}