docker_wrapper/command/context/
use_context.rs

1//! Docker context use command implementation.
2
3use crate::command::{CommandExecutor, CommandOutput, DockerCommand};
4use crate::error::Result;
5use async_trait::async_trait;
6
7/// Docker context use command builder
8///
9/// Switch to a different Docker context.
10///
11/// # Example
12///
13/// ```no_run
14/// use docker_wrapper::{ContextUseCommand, DockerCommand};
15///
16/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
17/// // Switch to production context
18/// ContextUseCommand::new("production")
19///     .execute()
20///     .await?;
21/// # Ok(())
22/// # }
23/// ```
24#[derive(Debug, Clone)]
25pub struct ContextUseCommand {
26    /// Context name to switch to
27    name: String,
28    /// Command executor
29    pub executor: CommandExecutor,
30}
31
32impl ContextUseCommand {
33    /// Create a new context use command
34    #[must_use]
35    pub fn new(name: impl Into<String>) -> Self {
36        Self {
37            name: name.into(),
38            executor: CommandExecutor::new(),
39        }
40    }
41}
42
43#[async_trait]
44impl DockerCommand for ContextUseCommand {
45    type Output = CommandOutput;
46
47    fn get_executor(&self) -> &CommandExecutor {
48        &self.executor
49    }
50
51    fn get_executor_mut(&mut self) -> &mut CommandExecutor {
52        &mut self.executor
53    }
54
55    fn build_command_args(&self) -> Vec<String> {
56        let mut args = vec!["context".to_string(), "use".to_string(), self.name.clone()];
57
58        args.extend(self.executor.raw_args.clone());
59        args
60    }
61
62    async fn execute(&self) -> Result<Self::Output> {
63        let args = self.build_command_args();
64        self.execute_command(args).await
65    }
66}
67
68/// Extension methods for `ContextUseCommand` output
69impl CommandOutput {
70    /// Check if context switch was successful
71    #[must_use]
72    pub fn context_switched(&self) -> bool {
73        self.exit_code == 0 && self.stderr.is_empty()
74    }
75
76    /// Get the name of the context that was switched to
77    pub fn switched_to_context(&self) -> Option<String> {
78        if self.context_switched() {
79            // The output typically contains the context name
80            self.stdout.split_whitespace().last().map(String::from)
81        } else {
82            None
83        }
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90
91    #[test]
92    fn test_context_use_basic() {
93        let cmd = ContextUseCommand::new("production");
94        let args = cmd.build_command_args();
95        assert_eq!(args[0], "context");
96        assert_eq!(args[1], "use");
97        assert_eq!(args[2], "production");
98    }
99
100    #[test]
101    fn test_context_switched() {
102        let output = CommandOutput {
103            stdout: "Current context is now \"production\"".to_string(),
104            stderr: String::new(),
105            exit_code: 0,
106            success: true,
107        };
108
109        assert!(output.context_switched());
110        assert_eq!(
111            output.switched_to_context(),
112            Some("\"production\"".to_string())
113        );
114    }
115}