diff --git a/src/packbuilder.rs b/src/packbuilder.rs index 06bf41dc7a..1cdb0fe7cb 100644 --- a/src/packbuilder.rs +++ b/src/packbuilder.rs @@ -6,6 +6,7 @@ use std::slice; use crate::util::Binding; use crate::{panic, raw, Buf, Error, Oid, Repository, Revwalk}; +#[derive(PartialEq, Eq, Clone, Debug, Copy)] /// Stages that are reported by the `PackBuilder` progress callback. pub enum PackBuilderStage { /// Adding objects to the pack diff --git a/src/remote_callbacks.rs b/src/remote_callbacks.rs index ae741be399..bcc73e85e9 100644 --- a/src/remote_callbacks.rs +++ b/src/remote_callbacks.rs @@ -1,4 +1,4 @@ -use libc::{c_char, c_int, c_uint, c_void}; +use libc::{c_char, c_int, c_uint, c_void, size_t}; use std::ffi::{CStr, CString}; use std::mem; use std::ptr; @@ -7,7 +7,9 @@ use std::str; use crate::cert::Cert; use crate::util::Binding; -use crate::{panic, raw, Cred, CredentialType, Error, IndexerProgress, Oid, Progress}; +use crate::{ + panic, raw, Cred, CredentialType, Error, IndexerProgress, Oid, PackBuilderStage, Progress, +}; /// A structure to contain the callbacks which are invoked when a repository is /// being updated or downloaded. @@ -15,7 +17,9 @@ use crate::{panic, raw, Cred, CredentialType, Error, IndexerProgress, Oid, Progr /// These callbacks are used to manage facilities such as authentication, /// transfer progress, etc. pub struct RemoteCallbacks<'a> { + push_progress: Option>>, progress: Option>>, + pack_progress: Option>>, credentials: Option>>, sideband_progress: Option>>, update_tips: Option>>, @@ -56,6 +60,22 @@ pub type CertificateCheck<'a> = dyn FnMut(&Cert<'_>, &str) -> bool + 'a; /// was rejected by the remote server with a reason why. pub type PushUpdateReference<'a> = dyn FnMut(&str, Option<&str>) -> Result<(), Error> + 'a; +/// Callback for push transfer progress +/// +/// Parameters: +/// * current +/// * total +/// * bytes +pub type PushTransferProgress<'a> = dyn FnMut(usize, usize, usize) + 'a; + +/// Callback for pack progress +/// +/// Parameters: +/// * stage +/// * current +/// * total +pub type PackProgress<'a> = dyn FnMut(PackBuilderStage, usize, usize) + 'a; + impl<'a> Default for RemoteCallbacks<'a> { fn default() -> Self { Self::new() @@ -68,10 +88,12 @@ impl<'a> RemoteCallbacks<'a> { RemoteCallbacks { credentials: None, progress: None, + pack_progress: None, sideband_progress: None, update_tips: None, certificate_check: None, push_update_reference: None, + push_progress: None, } } @@ -158,6 +180,26 @@ impl<'a> RemoteCallbacks<'a> { self.push_update_reference = Some(Box::new(cb) as Box>); self } + + /// The callback through which progress of push transfer is monitored + pub fn push_transfer_progress(&mut self, cb: F) -> &mut RemoteCallbacks<'a> + where + F: FnMut(usize, usize, usize) + 'a, + { + self.push_progress = Some(Box::new(cb) as Box>); + self + } + + /// Function to call with progress information during pack building. + /// Be aware that this is called inline with pack building operations, + /// so performance may be affected. + pub fn pack_progress(&mut self, cb: F) -> &mut RemoteCallbacks<'a> + where + F: FnMut(PackBuilderStage, usize, usize) + 'a, + { + self.pack_progress = Some(Box::new(cb) as Box>); + self + } } impl<'a> Binding for RemoteCallbacks<'a> { @@ -188,6 +230,12 @@ impl<'a> Binding for RemoteCallbacks<'a> { if self.push_update_reference.is_some() { callbacks.push_update_reference = Some(push_update_reference_cb); } + if self.push_progress.is_some() { + callbacks.push_transfer_progress = Some(push_transfer_progress_cb); + } + if self.pack_progress.is_some() { + callbacks.pack_progress = Some(pack_progress_cb); + } if self.update_tips.is_some() { let f: extern "C" fn( *const c_char, @@ -360,3 +408,45 @@ extern "C" fn push_update_reference_cb( }) .unwrap_or(-1) } + +extern "C" fn push_transfer_progress_cb( + progress: c_uint, + total: c_uint, + bytes: size_t, + data: *mut c_void, +) -> c_int { + panic::wrap(|| unsafe { + let payload = &mut *(data as *mut RemoteCallbacks<'_>); + let callback = match payload.push_progress { + Some(ref mut c) => c, + None => return 0, + }; + + callback(progress as usize, total as usize, bytes as usize); + + 0 + }) + .unwrap_or(-1) +} + +extern "C" fn pack_progress_cb( + stage: raw::git_packbuilder_stage_t, + current: c_uint, + total: c_uint, + data: *mut c_void, +) -> c_int { + panic::wrap(|| unsafe { + let payload = &mut *(data as *mut RemoteCallbacks<'_>); + let callback = match payload.pack_progress { + Some(ref mut c) => c, + None => return 0, + }; + + let stage = Binding::from_raw(stage); + + callback(stage, current as usize, total as usize); + + 0 + }) + .unwrap_or(-1) +}