upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/bin
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2024-09-12 13:36:38 +0100
committerDanConwayDev <DanConwayDev@protonmail.com>2024-09-12 14:15:45 +0100
commit1a38f98807a3244b77d2525136f3d6976f61dcc4 (patch)
treec130b934285f6f20501f2eaa432cc46342c0c348 /src/bin
parentf5bd964718fc063a07af442e93f65fb8239f8228 (diff)
fix(remote): improve fetch & list status updates
to bring them more into line to the native git client
Diffstat (limited to 'src/bin')
-rw-r--r--src/bin/git_remote_nostr/fetch.rs132
-rw-r--r--src/bin/git_remote_nostr/list.rs50
2 files changed, 87 insertions, 95 deletions
diff --git a/src/bin/git_remote_nostr/fetch.rs b/src/bin/git_remote_nostr/fetch.rs
index b74e432..1b19347 100644
--- a/src/bin/git_remote_nostr/fetch.rs
+++ b/src/bin/git_remote_nostr/fetch.rs
@@ -187,81 +187,83 @@ fn fetch_from_git_server_url(
187 let mut fetch_options = git2::FetchOptions::new(); 187 let mut fetch_options = git2::FetchOptions::new();
188 let mut remote_callbacks = git2::RemoteCallbacks::new(); 188 let mut remote_callbacks = git2::RemoteCallbacks::new();
189 remote_callbacks.sideband_progress(|data| { 189 remote_callbacks.sideband_progress(|data| {
190 let _ = term.clear_last_lines(1); 190 if let Ok(data) = str::from_utf8(data) {
191 let _ = term.write_line(format!("remote: {}", str::from_utf8(data).unwrap()).as_str()); 191 let data = data
192 true 192 .split(['\n', '\r'])
193 }); 193 .find(|line| !line.is_empty())
194 remote_callbacks.transfer_progress(|stats| { 194 .unwrap_or("");
195 let _ = term.clear_last_lines(1); 195 if !data.is_empty() {
196 if stats.received_objects() == stats.total_objects() { 196 let s = format!("remote: {data}");
197 let _ = term.write_line( 197 let _ = term.clear_last_lines(1);
198 format!( 198 let _ = term.write_line(s.as_str());
199 "Resolving deltas {}/{}\r", 199 if !s.contains('%') || s.contains("100%") {
200 stats.indexed_deltas(), 200 // print it twice so the next sideband_progress doesn't delete it
201 stats.total_deltas() 201 let _ = term.write_line(s.as_str());
202 ) 202 }
203 .as_str(), 203 }
204 );
205 } else if stats.total_objects() > 0 {
206 let _ = term.write_line(
207 format!(
208 "Received {}/{} objects ({}) in {} bytes\r",
209 stats.received_objects(),
210 stats.total_objects(),
211 stats.indexed_objects(),
212 stats.received_bytes()
213 )
214 .as_str(),
215 );
216 } 204 }
217 true 205 true
218 }); 206 });
207 remote_callbacks.transfer_progress(
208 #[allow(clippy::cast_precision_loss)]
209 |stats| {
210 let _ = term.clear_last_lines(1);
211 report_on_transfer_progress(&stats, term, false);
212 true
213 },
214 );
215
219 if !dont_authenticate { 216 if !dont_authenticate {
220 remote_callbacks.credentials(auth.credentials(&git_config)); 217 remote_callbacks.credentials(auth.credentials(&git_config));
221 } 218 }
222 fetch_options.remote_callbacks(remote_callbacks); 219 fetch_options.remote_callbacks(remote_callbacks);
220 term.write_line("")?;
223 git_server_remote.download(oids, Some(&mut fetch_options))?; 221 git_server_remote.download(oids, Some(&mut fetch_options))?;
224 { 222
225 let stats = git_server_remote.stats(); 223 report_on_transfer_progress(&git_server_remote.stats(), term, true);
226 if stats.local_objects() > 0 { 224
227 term.write_line(
228 format!(
229 "\rReceived {}/{} objects in {} bytes (used {} local \
230 objects)",
231 stats.indexed_objects(),
232 stats.total_objects(),
233 stats.received_bytes(),
234 stats.local_objects()
235 )
236 .as_str(),
237 )?;
238 } else {
239 term.write_line(
240 format!(
241 "\rReceived {}/{} objects in {} bytes",
242 stats.indexed_objects(),
243 stats.total_objects(),
244 stats.received_bytes()
245 )
246 .as_str(),
247 )?;
248 }
249 }
250 git_server_remote.disconnect()?; 225 git_server_remote.disconnect()?;
251 Ok(()) 226 Ok(())
252} 227}
253 228
254fn fetch_from_git_server_url_unauthenticated( 229#[allow(clippy::cast_precision_loss)]
255 git_repo: &Repository, 230#[allow(clippy::float_cmp)]
256 oids: &[String], 231fn report_on_transfer_progress(stats: &git2::Progress<'_>, term: &console::Term, complete: bool) {
257 git_server_url: &str, 232 let total = stats.total_objects() as f64;
258) -> Result<()> { 233 if total == 0.0 {
259 let mut git_server_remote = git_repo.remote_anonymous(git_server_url)?; 234 return;
260 let mut fetch_options = git2::FetchOptions::new(); 235 }
261 let remote_callbacks = git2::RemoteCallbacks::new(); 236 let received = stats.received_objects() as f64;
262 // TODO status update callback 237 let percentage = (received / total) * 100.0;
263 fetch_options.remote_callbacks(remote_callbacks); 238
264 git_server_remote.download(oids, Some(&mut fetch_options))?; 239 // Get the total received bytes
265 git_server_remote.disconnect()?; 240 let received_bytes = stats.received_bytes() as f64;
266 Ok(()) 241
242 // Determine whether to use KiB or MiB
243 let (size, unit) = if received_bytes >= (1024.0 * 1024.0) {
244 // Convert to MiB
245 (received_bytes / (1024.0 * 1024.0), "MiB")
246 } else {
247 // Convert to KiB
248 (received_bytes / 1024.0, "KiB")
249 };
250
251 // Format the output for receiving objects
252 if received < total || complete {
253 let _ = term.write_line(
254 format!(
255 "Receiving objects: {percentage:.0}% ({received}/{total}) {size:.2} {unit}, done.\r"
256 )
257 .as_str(),
258 );
259 }
260 if received == total || complete {
261 let indexed_deltas = stats.indexed_deltas() as f64;
262 let total_deltas = stats.total_deltas() as f64;
263 let percentage = (indexed_deltas / total_deltas) * 100.0;
264 let _ = term.write_line(
265 format!("Resolving deltas: {percentage:.0}% ({indexed_deltas}/{total_deltas}) done.\r")
266 .as_str(),
267 );
268 }
267} 269}
diff --git a/src/bin/git_remote_nostr/list.rs b/src/bin/git_remote_nostr/list.rs
index d3682ec..7dded6b 100644
--- a/src/bin/git_remote_nostr/list.rs
+++ b/src/bin/git_remote_nostr/list.rs
@@ -164,19 +164,25 @@ pub fn list_from_remote(
164 164
165 for protocol in &protocols_to_attempt { 165 for protocol in &protocols_to_attempt {
166 term.write_line( 166 term.write_line(
167 format!("fetching {} ref list over {protocol}...", server_url.short_name(),).as_str(), 167 format!(
168 "fetching {} ref list over {protocol}...",
169 server_url.short_name(),
170 )
171 .as_str(),
168 )?; 172 )?;
169 173
170 let formatted_url = server_url.format_as(protocol, &decoded_nostr_url.user)?; 174 let formatted_url = server_url.format_as(protocol, &decoded_nostr_url.user)?;
171 let res = if [ServerProtocol::UnauthHttps, ServerProtocol::UnauthHttp].contains(protocol) { 175 let res = list_from_remote_url(
172 list_from_remote_url_unauthenticated(git_repo, &formatted_url) 176 git_repo,
173 } else { 177 &formatted_url,
174 list_from_remote_url(git_repo, &formatted_url) 178 [ServerProtocol::UnauthHttps, ServerProtocol::UnauthHttp].contains(protocol),
175 }; 179 term,
180 );
176 181
177 match res { 182 match res {
178 Ok(state) => { 183 Ok(state) => {
179 remote_state = Some(state); 184 remote_state = Some(state);
185 term.clear_last_lines(1)?;
180 if !failed_protocols.is_empty() { 186 if !failed_protocols.is_empty() {
181 term.write_line( 187 term.write_line(
182 format!( 188 format!(
@@ -189,6 +195,7 @@ pub fn list_from_remote(
189 break; 195 break;
190 } 196 }
191 Err(error) => { 197 Err(error) => {
198 term.clear_last_lines(1)?;
192 term.write_line( 199 term.write_line(
193 format!("list: {formatted_url} failed over {protocol}: {error}").as_str(), 200 format!("list: {formatted_url} failed over {protocol}: {error}").as_str(),
194 )?; 201 )?;
@@ -201,7 +208,6 @@ pub fn list_from_remote(
201 } 208 }
202 } 209 }
203 } 210 }
204 term.clear_last_lines(1)?;
205 } 211 }
206 if let Some(remote_state) = remote_state { 212 if let Some(remote_state) = remote_state {
207 Ok(remote_state) 213 Ok(remote_state)
@@ -221,31 +227,11 @@ pub fn list_from_remote(
221 } 227 }
222} 228}
223 229
224fn list_from_remote_url_unauthenticated(
225 git_repo: &Repo,
226 git_server_remote_url: &str,
227) -> Result<HashMap<String, String>> {
228 let mut git_server_remote = git_repo.git_repo.remote_anonymous(git_server_remote_url)?;
229 let remote_callbacks = git2::RemoteCallbacks::new();
230 git_server_remote.connect_auth(git2::Direction::Fetch, Some(remote_callbacks), None)?;
231 let mut state = HashMap::new();
232 for head in git_server_remote.list()? {
233 if let Some(symbolic_reference) = head.symref_target() {
234 state.insert(
235 head.name().to_string(),
236 format!("ref: {symbolic_reference}"),
237 );
238 } else {
239 state.insert(head.name().to_string(), head.oid().to_string());
240 }
241 }
242 git_server_remote.disconnect()?;
243 Ok(state)
244}
245
246fn list_from_remote_url( 230fn list_from_remote_url(
247 git_repo: &Repo, 231 git_repo: &Repo,
248 git_server_remote_url: &str, 232 git_server_remote_url: &str,
233 dont_authenticate: bool,
234 term: &console::Term,
249) -> Result<HashMap<String, String>> { 235) -> Result<HashMap<String, String>> {
250 let git_config = git_repo.git_repo.config()?; 236 let git_config = git_repo.git_repo.config()?;
251 237
@@ -253,8 +239,12 @@ fn list_from_remote_url(
253 // authentication may be required 239 // authentication may be required
254 let auth = GitAuthenticator::default(); 240 let auth = GitAuthenticator::default();
255 let mut remote_callbacks = git2::RemoteCallbacks::new(); 241 let mut remote_callbacks = git2::RemoteCallbacks::new();
256 remote_callbacks.credentials(auth.credentials(&git_config)); 242 if !dont_authenticate {
243 remote_callbacks.credentials(auth.credentials(&git_config));
244 }
245 term.write_line("list: connecting...")?;
257 git_server_remote.connect_auth(git2::Direction::Fetch, Some(remote_callbacks), None)?; 246 git_server_remote.connect_auth(git2::Direction::Fetch, Some(remote_callbacks), None)?;
247 term.clear_last_lines(1)?;
258 let mut state = HashMap::new(); 248 let mut state = HashMap::new();
259 for head in git_server_remote.list()? { 249 for head in git_server_remote.list()? {
260 if let Some(symbolic_reference) = head.symref_target() { 250 if let Some(symbolic_reference) = head.symref_target() {