Skip to main content

git_spawn/command/
remote.rs

1//! `git remote` — manage set of tracked repositories.
2
3use crate::command::{CommandExecutor, CommandOutput, GitCommand};
4use crate::error::Result;
5use async_trait::async_trait;
6
7/// Actions supported by `git remote`.
8#[derive(Debug, Clone)]
9pub enum RemoteAction {
10    /// List remotes (`git remote` or `git remote -v`).
11    List {
12        /// Verbose output.
13        verbose: bool,
14    },
15    /// Add a remote: `git remote add <name> <url>`.
16    Add {
17        /// Remote name.
18        name: String,
19        /// Remote URL.
20        url: String,
21    },
22    /// Remove a remote: `git remote remove <name>`.
23    Remove(String),
24    /// Rename a remote: `git remote rename <old> <new>`.
25    Rename {
26        /// Old name.
27        from: String,
28        /// New name.
29        to: String,
30    },
31    /// Set URL: `git remote set-url <name> <url>`.
32    SetUrl {
33        /// Remote name.
34        name: String,
35        /// New URL.
36        url: String,
37    },
38    /// Show remote: `git remote show <name>`.
39    Show(String),
40    /// Prune stale refs: `git remote prune <name>`.
41    Prune(String),
42}
43
44/// Builder for `git remote`.
45#[derive(Debug, Clone)]
46pub struct RemoteCommand {
47    /// Shared executor.
48    pub executor: CommandExecutor,
49    /// Action to perform.
50    pub action: RemoteAction,
51}
52
53impl Default for RemoteCommand {
54    fn default() -> Self {
55        Self {
56            executor: CommandExecutor::default(),
57            action: RemoteAction::List { verbose: false },
58        }
59    }
60}
61
62impl RemoteCommand {
63    /// List remotes.
64    #[must_use]
65    pub fn list() -> Self {
66        Self {
67            action: RemoteAction::List { verbose: false },
68            ..Self::default()
69        }
70    }
71
72    /// List remotes verbosely (`-v`).
73    #[must_use]
74    pub fn list_verbose() -> Self {
75        Self {
76            action: RemoteAction::List { verbose: true },
77            ..Self::default()
78        }
79    }
80
81    /// Add a remote.
82    pub fn add(name: impl Into<String>, url: impl Into<String>) -> Self {
83        Self {
84            action: RemoteAction::Add {
85                name: name.into(),
86                url: url.into(),
87            },
88            ..Self::default()
89        }
90    }
91
92    /// Remove a remote.
93    pub fn remove(name: impl Into<String>) -> Self {
94        Self {
95            action: RemoteAction::Remove(name.into()),
96            ..Self::default()
97        }
98    }
99
100    /// Rename a remote.
101    pub fn rename(from: impl Into<String>, to: impl Into<String>) -> Self {
102        Self {
103            action: RemoteAction::Rename {
104                from: from.into(),
105                to: to.into(),
106            },
107            ..Self::default()
108        }
109    }
110
111    /// Change a remote's URL.
112    pub fn set_url(name: impl Into<String>, url: impl Into<String>) -> Self {
113        Self {
114            action: RemoteAction::SetUrl {
115                name: name.into(),
116                url: url.into(),
117            },
118            ..Self::default()
119        }
120    }
121
122    /// Show a remote.
123    pub fn show(name: impl Into<String>) -> Self {
124        Self {
125            action: RemoteAction::Show(name.into()),
126            ..Self::default()
127        }
128    }
129
130    /// Prune a remote.
131    pub fn prune(name: impl Into<String>) -> Self {
132        Self {
133            action: RemoteAction::Prune(name.into()),
134            ..Self::default()
135        }
136    }
137}
138
139#[async_trait]
140impl GitCommand for RemoteCommand {
141    type Output = CommandOutput;
142    fn get_executor(&self) -> &CommandExecutor {
143        &self.executor
144    }
145    fn get_executor_mut(&mut self) -> &mut CommandExecutor {
146        &mut self.executor
147    }
148    fn build_command_args(&self) -> Vec<String> {
149        let mut args = vec!["remote".to_string()];
150        match &self.action {
151            RemoteAction::List { verbose } => {
152                if *verbose {
153                    args.push("-v".into());
154                }
155            }
156            RemoteAction::Add { name, url } => {
157                args.push("add".into());
158                args.push(name.clone());
159                args.push(url.clone());
160            }
161            RemoteAction::Remove(name) => {
162                args.push("remove".into());
163                args.push(name.clone());
164            }
165            RemoteAction::Rename { from, to } => {
166                args.push("rename".into());
167                args.push(from.clone());
168                args.push(to.clone());
169            }
170            RemoteAction::SetUrl { name, url } => {
171                args.push("set-url".into());
172                args.push(name.clone());
173                args.push(url.clone());
174            }
175            RemoteAction::Show(name) => {
176                args.push("show".into());
177                args.push(name.clone());
178            }
179            RemoteAction::Prune(name) => {
180                args.push("prune".into());
181                args.push(name.clone());
182            }
183        }
184        args
185    }
186    async fn execute(&self) -> Result<CommandOutput> {
187        self.execute_raw().await
188    }
189}