docker_wrapper/command/
rename.rs

1//! Docker rename command implementation.
2//!
3//! This module provides the `docker rename` command for renaming containers.
4
5use super::{CommandExecutor, CommandOutput, DockerCommand};
6use crate::error::Result;
7use async_trait::async_trait;
8
9/// Docker rename command builder
10///
11/// Rename a container.
12///
13/// # Example
14///
15/// ```no_run
16/// use docker_wrapper::RenameCommand;
17///
18/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
19/// // Rename a container
20/// let result = RenameCommand::new("old-name", "new-name")
21///     .run()
22///     .await?;
23///
24/// if result.success() {
25///     println!("Container renamed successfully");
26/// }
27/// # Ok(())
28/// # }
29/// ```
30#[derive(Debug, Clone)]
31pub struct RenameCommand {
32    /// Current container name or ID
33    old_name: String,
34    /// New container name
35    new_name: String,
36    /// Command executor
37    pub executor: CommandExecutor,
38}
39
40impl RenameCommand {
41    /// Create a new rename command
42    ///
43    /// # Example
44    ///
45    /// ```
46    /// use docker_wrapper::RenameCommand;
47    ///
48    /// let cmd = RenameCommand::new("old-container", "new-container");
49    /// ```
50    #[must_use]
51    pub fn new(old_name: impl Into<String>, new_name: impl Into<String>) -> Self {
52        Self {
53            old_name: old_name.into(),
54            new_name: new_name.into(),
55            executor: CommandExecutor::new(),
56        }
57    }
58
59    /// Execute the rename command
60    ///
61    /// # Errors
62    /// Returns an error if:
63    /// - The Docker daemon is not running
64    /// - The container doesn't exist
65    /// - The new name is already in use
66    /// - The container is running (some Docker versions)
67    ///
68    /// # Example
69    ///
70    /// ```no_run
71    /// use docker_wrapper::RenameCommand;
72    ///
73    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
74    /// let result = RenameCommand::new("web-server", "api-server")
75    ///     .run()
76    ///     .await?;
77    ///
78    /// if result.success() {
79    ///     println!("Container renamed from '{}' to '{}'",
80    ///              result.old_name(), result.new_name());
81    /// }
82    /// # Ok(())
83    /// # }
84    /// ```
85    pub async fn run(&self) -> Result<RenameResult> {
86        let output = self.execute().await?;
87
88        Ok(RenameResult {
89            output,
90            old_name: self.old_name.clone(),
91            new_name: self.new_name.clone(),
92        })
93    }
94}
95
96#[async_trait]
97impl DockerCommand for RenameCommand {
98    type Output = CommandOutput;
99
100    fn get_executor(&self) -> &CommandExecutor {
101        &self.executor
102    }
103
104    fn get_executor_mut(&mut self) -> &mut CommandExecutor {
105        &mut self.executor
106    }
107
108    fn build_command_args(&self) -> Vec<String> {
109        let mut args = vec!["rename".to_string()];
110        args.push(self.old_name.clone());
111        args.push(self.new_name.clone());
112        args.extend(self.executor.raw_args.clone());
113        args
114    }
115
116    async fn execute(&self) -> Result<Self::Output> {
117        let args = self.build_command_args();
118        let command_name = args[0].clone();
119        let command_args = args[1..].to_vec();
120        self.executor
121            .execute_command(&command_name, command_args)
122            .await
123    }
124}
125
126/// Result from the rename command
127#[derive(Debug, Clone)]
128pub struct RenameResult {
129    /// Raw command output
130    pub output: CommandOutput,
131    /// Original container name
132    pub old_name: String,
133    /// New container name
134    pub new_name: String,
135}
136
137impl RenameResult {
138    /// Check if the rename was successful
139    #[must_use]
140    pub fn success(&self) -> bool {
141        self.output.success
142    }
143
144    /// Get the original container name
145    #[must_use]
146    pub fn old_name(&self) -> &str {
147        &self.old_name
148    }
149
150    /// Get the new container name
151    #[must_use]
152    pub fn new_name(&self) -> &str {
153        &self.new_name
154    }
155
156    /// Get the raw command output
157    #[must_use]
158    pub fn output(&self) -> &CommandOutput {
159        &self.output
160    }
161}
162
163#[cfg(test)]
164mod tests {
165    use super::*;
166
167    #[test]
168    fn test_rename_basic() {
169        let cmd = RenameCommand::new("old-container", "new-container");
170        let args = cmd.build_command_args();
171        assert_eq!(args, vec!["rename", "old-container", "new-container"]);
172    }
173
174    #[test]
175    fn test_rename_with_id() {
176        let cmd = RenameCommand::new("abc123", "my-new-container");
177        let args = cmd.build_command_args();
178        assert_eq!(args, vec!["rename", "abc123", "my-new-container"]);
179    }
180
181    #[test]
182    fn test_rename_result() {
183        let result = RenameResult {
184            output: CommandOutput {
185                stdout: String::new(),
186                stderr: String::new(),
187                exit_code: 0,
188                success: true,
189            },
190            old_name: "old-name".to_string(),
191            new_name: "new-name".to_string(),
192        };
193
194        assert!(result.success());
195        assert_eq!(result.old_name(), "old-name");
196        assert_eq!(result.new_name(), "new-name");
197    }
198
199    #[test]
200    fn test_command_name() {
201        let _cmd = RenameCommand::new("old", "new");
202        // Test that builder produces valid rename command
203    }
204}