eazygit/commands/git_commands/
remote.rs1use crate::commands::{Command, CommandResult};
6use crate::services::GitService;
7use crate::app::{AppState, Action, reducer};
8use crate::errors::CommandError;
9use crate::commands::git_commands::utils::to_ssh_url;
10use tracing::instrument;
11
12pub struct RemotePruneCommand {
14 pub remote: String,
15}
16
17impl Command for RemotePruneCommand {
18 #[instrument(skip(self, git, state), fields(remote = %self.remote))]
19 fn execute(
20 &self,
21 git: &GitService,
22 state: &AppState,
23 ) -> Result<CommandResult, CommandError> {
24 let mut new_state = state.clone();
25 let remote = if self.remote.is_empty() { "origin" } else { self.remote.as_str() };
26 new_state = reducer(new_state, Action::SetOpStatus(Some(format!("remote prune {}…", remote))));
27 match git.remote_prune(&state.repo_path, remote) {
28 Ok(output) => {
29 new_state = reducer(new_state, Action::AppendOpLog(format!("remote prune {} ok", remote)));
30 if !output.trim().is_empty() {
31 new_state = reducer(new_state, Action::AppendOpLog(output));
32 }
33 new_state = reducer(new_state, Action::SetFeedback(Some(format!("Pruned stale tracking on {}", remote))));
34 new_state = reducer(new_state, Action::SetRefreshing(true));
35 }
36 Err(e) => {
37 new_state = reducer(new_state, Action::AppendOpLog(format!("remote prune error: {e}")));
38 new_state = reducer(new_state, Action::SetStatusError(Some(format!("remote prune error: {e}"))));
39 }
40 }
41 new_state = reducer(new_state, Action::SetOpStatus(None));
42 Ok(CommandResult::StateUpdate(new_state))
43 }
44}
45
46pub struct ShowRemoteUrlCommand {
48 pub remote: String,
49}
50
51impl Command for ShowRemoteUrlCommand {
52 #[instrument(skip(self, git, state), fields(remote = %self.remote))]
53 fn execute(
54 &self,
55 git: &GitService,
56 state: &AppState,
57 ) -> Result<CommandResult, CommandError> {
58 let mut new_state = state.clone();
59 new_state = reducer(new_state, Action::SetOpStatus(Some(format!("remote url {}…", self.remote))));
60 match git.remote_url(&state.repo_path, &self.remote) {
61 Ok(url) => {
62 new_state = reducer(new_state, Action::AppendOpLog(format!("{} url: {}", self.remote, url)));
63 new_state = reducer(new_state, Action::SetFeedback(Some(format!("{} url: {}", self.remote, url))));
64 }
65 Err(e) => {
66 new_state = reducer(new_state, Action::AppendOpLog(format!("remote url error: {e}")));
67 new_state = reducer(new_state, Action::SetStatusError(Some(format!("remote url error: {e}"))));
68 }
69 }
70 new_state = reducer(new_state, Action::SetOpStatus(None));
71 Ok(CommandResult::StateUpdate(new_state))
72 }
73}
74
75pub struct SetRemoteSshCommand {
77 pub remote: String,
78}
79
80impl Command for SetRemoteSshCommand {
81 #[instrument(skip(self, git, state), fields(remote = %self.remote))]
82 fn execute(
83 &self,
84 git: &GitService,
85 state: &AppState,
86 ) -> Result<CommandResult, CommandError> {
87 let mut new_state = state.clone();
88 let remote = self.remote.as_str();
89 new_state = reducer(new_state, Action::SetOpStatus(Some(format!("ensure ssh remote {}…", remote))));
90 match git.remote_url(&state.repo_path, remote) {
91 Ok(url) => {
92 if url.starts_with("git@") || url.starts_with("ssh://") {
93 new_state = reducer(new_state, Action::AppendOpLog(format!("{} already SSH: {}", remote, url)));
94 new_state = reducer(new_state, Action::SetFeedback(Some(format!("{} already SSH", remote))));
95 } else if let Some(ssh_url) = to_ssh_url(&url) {
96 match git.set_remote_url(&state.repo_path, remote, &ssh_url) {
97 Ok(_) => {
98 new_state = reducer(new_state, Action::AppendOpLog(format!("{} -> {}", url, ssh_url)));
99 new_state = reducer(new_state, Action::SetFeedback(Some(format!("Set {} to SSH", remote))));
100 }
101 Err(e) => {
102 new_state = reducer(new_state, Action::AppendOpLog(format!("set-url error: {e}")));
103 new_state = reducer(new_state, Action::SetStatusError(Some(format!("set-url error: {e}"))));
104 }
105 }
106 } else {
107 new_state = reducer(new_state, Action::AppendOpLog(format!("cannot convert to ssh: {}", url)));
108 new_state = reducer(new_state, Action::SetStatusError(Some("cannot convert remote to ssh".into())));
109 }
110 }
111 Err(e) => {
112 new_state = reducer(new_state, Action::AppendOpLog(format!("remote url error: {e}")));
113 new_state = reducer(new_state, Action::SetStatusError(Some(format!("remote url error: {e}"))));
114 }
115 }
116 new_state = reducer(new_state, Action::SetOpStatus(None));
117 Ok(CommandResult::StateUpdate(new_state))
118 }
119}
120
121pub struct AutoFetchCommand {
123 pub remote: String,
124}
125
126impl Command for AutoFetchCommand {
127 #[instrument(skip(self, git, state), fields(remote = %self.remote))]
128 fn execute(
129 &self,
130 git: &GitService,
131 state: &AppState,
132 ) -> Result<CommandResult, CommandError> {
133 let mut new_state = state.clone();
134 let remote = if self.remote.is_empty() { "origin" } else { self.remote.as_str() };
135 new_state = reducer(new_state, Action::SetOpStatus(Some(format!("fetching {}…", remote))));
136 match git.fetch_dry_run(&state.repo_path, remote) {
137 Ok(output) => {
138 if !output.trim().is_empty() {
139 for line in output.lines() {
140 new_state = reducer(new_state, Action::AppendOpLog(line.to_string()));
141 }
142 } else {
143 new_state = reducer(new_state, Action::AppendOpLog(format!("fetch {}: up to date", remote)));
144 }
145 new_state = reducer(new_state, Action::SetRefreshing(true));
146 }
147 Err(e) => {
148 new_state = reducer(new_state, Action::AppendOpLog(format!("fetch error: {e}")));
149 new_state = reducer(new_state, Action::SetStatusError(Some(format!("fetch error: {e}"))));
150 }
151 }
152 new_state = reducer(new_state, Action::SetOpStatus(None));
153 Ok(CommandResult::StateUpdate(new_state))
154 }
155}
156