1use crate::command::{CommandExecutor, CommandOutput, GitCommand};
4use crate::error::{Error, Result};
5use async_trait::async_trait;
6
7#[derive(Debug, Clone, Default)]
9pub struct MvCommand {
10 pub executor: CommandExecutor,
12 pub source: Option<String>,
14 pub destination: Option<String>,
16 pub force: bool,
18 pub skip_missing: bool,
20 pub dry_run: bool,
22 pub verbose: bool,
24}
25
26impl MvCommand {
27 pub fn new(src: impl Into<String>, dst: impl Into<String>) -> Self {
29 Self {
30 source: Some(src.into()),
31 destination: Some(dst.into()),
32 ..Self::default()
33 }
34 }
35 pub fn force(&mut self) -> &mut Self {
37 self.force = true;
38 self
39 }
40 pub fn skip_missing(&mut self) -> &mut Self {
42 self.skip_missing = true;
43 self
44 }
45 pub fn dry_run(&mut self) -> &mut Self {
47 self.dry_run = true;
48 self
49 }
50 pub fn verbose(&mut self) -> &mut Self {
52 self.verbose = true;
53 self
54 }
55}
56
57#[async_trait]
58impl GitCommand for MvCommand {
59 type Output = CommandOutput;
60 fn get_executor(&self) -> &CommandExecutor {
61 &self.executor
62 }
63 fn get_executor_mut(&mut self) -> &mut CommandExecutor {
64 &mut self.executor
65 }
66 fn build_command_args(&self) -> Vec<String> {
67 let mut args = vec!["mv".to_string()];
68 if self.force {
69 args.push("--force".into());
70 }
71 if self.skip_missing {
72 args.push("-k".into());
73 }
74 if self.dry_run {
75 args.push("--dry-run".into());
76 }
77 if self.verbose {
78 args.push("--verbose".into());
79 }
80 if let Some(s) = &self.source {
81 args.push(s.clone());
82 }
83 if let Some(d) = &self.destination {
84 args.push(d.clone());
85 }
86 args
87 }
88 async fn execute(&self) -> Result<CommandOutput> {
89 if self.source.is_none() || self.destination.is_none() {
90 return Err(Error::invalid_config("mv requires source and destination"));
91 }
92 self.execute_raw().await
93 }
94}