Skip to content

allow hooking into push_transfer_progress & pack_progress callbacks #617

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/packbuilder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
94 changes: 92 additions & 2 deletions src/remote_callbacks.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -7,15 +7,19 @@ 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.
///
/// These callbacks are used to manage facilities such as authentication,
/// transfer progress, etc.
pub struct RemoteCallbacks<'a> {
push_progress: Option<Box<PushTransferProgress<'a>>>,
progress: Option<Box<IndexerProgress<'a>>>,
pack_progress: Option<Box<PackProgress<'a>>>,
credentials: Option<Box<Credentials<'a>>>,
sideband_progress: Option<Box<TransportMessage<'a>>>,
update_tips: Option<Box<UpdateTips<'a>>>,
Expand Down Expand Up @@ -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()
Expand All @@ -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,
}
}

Expand Down Expand Up @@ -158,6 +180,26 @@ impl<'a> RemoteCallbacks<'a> {
self.push_update_reference = Some(Box::new(cb) as Box<PushUpdateReference<'a>>);
self
}

/// The callback through which progress of push transfer is monitored
pub fn push_transfer_progress<F>(&mut self, cb: F) -> &mut RemoteCallbacks<'a>
where
F: FnMut(usize, usize, usize) + 'a,
{
self.push_progress = Some(Box::new(cb) as Box<PushTransferProgress<'a>>);
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<F>(&mut self, cb: F) -> &mut RemoteCallbacks<'a>
where
F: FnMut(PackBuilderStage, usize, usize) + 'a,
{
self.pack_progress = Some(Box::new(cb) as Box<PackProgress<'a>>);
self
}
}

impl<'a> Binding for RemoteCallbacks<'a> {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
}