summaryrefslogtreecommitdiffstats
path: root/asyncgit/src/sync/remotes/callbacks.rs
diff options
context:
space:
mode:
Diffstat (limited to 'asyncgit/src/sync/remotes/callbacks.rs')
-rw-r--r--asyncgit/src/sync/remotes/callbacks.rs404
1 files changed, 202 insertions, 202 deletions
diff --git a/asyncgit/src/sync/remotes/callbacks.rs b/asyncgit/src/sync/remotes/callbacks.rs
index 4f8b82c5..6cf39923 100644
--- a/asyncgit/src/sync/remotes/callbacks.rs
+++ b/asyncgit/src/sync/remotes/callbacks.rs
@@ -5,219 +5,219 @@ use crate::{error::Result, sync::cred::BasicAuthCredential};
use crossbeam_channel::Sender;
use git2::{Cred, Error as GitError, RemoteCallbacks};
use std::sync::{
- atomic::{AtomicBool, Ordering},
- Arc, Mutex,
+ atomic::{AtomicBool, Ordering},
+ Arc, Mutex,
};
///
#[derive(Default, Clone)]
pub struct CallbackStats {
- pub push_rejected_msg: Option<(String, String)>,
+ pub push_rejected_msg: Option<(String, String)>,
}
///
#[derive(Clone)]
pub struct Callbacks {
- sender: Option<Sender<ProgressNotification>>,
- basic_credential: Option<BasicAuthCredential>,
- stats: Arc<Mutex<CallbackStats>>,
- first_call_to_credentials: Arc<AtomicBool>,
+ sender: Option<Sender<ProgressNotification>>,
+ basic_credential: Option<BasicAuthCredential>,
+ stats: Arc<Mutex<CallbackStats>>,
+ first_call_to_credentials: Arc<AtomicBool>,
}
impl Callbacks {
- ///
- pub fn new(
- sender: Option<Sender<ProgressNotification>>,
- basic_credential: Option<BasicAuthCredential>,
- ) -> Self {
- let stats = Arc::new(Mutex::new(CallbackStats::default()));
-
- Self {
- sender,
- basic_credential,
- stats,
- first_call_to_credentials: Arc::new(AtomicBool::new(
- true,
- )),
- }
- }
-
- ///
- pub fn get_stats(&self) -> Result<CallbackStats> {
- let stats = self.stats.lock()?;
- Ok(stats.clone())
- }
-
- ///
- pub fn callbacks<'a>(&self) -> RemoteCallbacks<'a> {
- let mut callbacks = RemoteCallbacks::new();
-
- let this = self.clone();
- callbacks.push_transfer_progress(
- move |current, total, bytes| {
- this.push_transfer_progress(current, total, bytes);
- },
- );
-
- let this = self.clone();
- callbacks.update_tips(move |name, a, b| {
- this.update_tips(name, a, b);
- true
- });
-
- let this = self.clone();
- callbacks.transfer_progress(move |p| {
- this.transfer_progress(&p);
- true
- });
-
- let this = self.clone();
- callbacks.pack_progress(move |stage, current, total| {
- this.pack_progress(stage, total, current);
- });
-
- let this = self.clone();
- callbacks.push_update_reference(move |reference, msg| {
- this.push_update_reference(reference, msg);
- Ok(())
- });
-
- let this = self.clone();
- callbacks.credentials(
- move |url, username_from_url, allowed_types| {
- this.credentials(
- url,
- username_from_url,
- allowed_types,
- )
- },
- );
-
- callbacks
- }
-
- fn push_update_reference(
- &self,
- reference: &str,
- msg: Option<&str>,
- ) {
- log::debug!(
- "push_update_reference: '{}' {:?}",
- reference,
- msg
- );
-
- if let Ok(mut stats) = self.stats.lock() {
- stats.push_rejected_msg = msg
- .map(|msg| (reference.to_string(), msg.to_string()));
- }
- }
-
- fn pack_progress(
- &self,
- stage: git2::PackBuilderStage,
- total: usize,
- current: usize,
- ) {
- log::debug!("packing: {:?} - {}/{}", stage, current, total);
- self.sender.clone().map(|sender| {
- sender.send(ProgressNotification::Packing {
- stage,
- total,
- current,
- })
- });
- }
-
- fn transfer_progress(&self, p: &git2::Progress) {
- log::debug!(
- "transfer: {}/{}",
- p.received_objects(),
- p.total_objects()
- );
- self.sender.clone().map(|sender| {
- sender.send(ProgressNotification::Transfer {
- objects: p.received_objects(),
- total_objects: p.total_objects(),
- })
- });
- }
-
- fn update_tips(&self, name: &str, a: git2::Oid, b: git2::Oid) {
- log::debug!("update tips: '{}' [{}] [{}]", name, a, b);
- self.sender.clone().map(|sender| {
- sender.send(ProgressNotification::UpdateTips {
- name: name.to_string(),
- a: a.into(),
- b: b.into(),
- })
- });
- }
-
- fn push_transfer_progress(
- &self,
- current: usize,
- total: usize,
- bytes: usize,
- ) {
- log::debug!("progress: {}/{} ({} B)", current, total, bytes,);
- self.sender.clone().map(|sender| {
- sender.send(ProgressNotification::PushTransfer {
- current,
- total,
- bytes,
- })
- });
- }
-
- // If credentials are bad, we don't ask the user to re-fill their creds. We push an error and they will be able to restart their action (for example a push) and retype their creds.
- // This behavior is explained in a issue on git2-rs project : https://github.com/rust-lang/git2-rs/issues/347
- // An implementation reference is done in cargo : https://github.com/rust-lang/cargo/blob/9fb208dddb12a3081230a5fd8f470e01df8faa25/src/cargo/sources/git/utils.rs#L588
- // There is also a guide about libgit2 authentication : https://libgit2.org/docs/guides/authentication/
- fn credentials(
- &self,
- url: &str,
- username_from_url: Option<&str>,
- allowed_types: git2::CredentialType,
- ) -> std::result::Result<Cred, GitError> {
- log::debug!(
- "creds: '{}' {:?} ({:?})",
- url,
- username_from_url,
- allowed_types
- );
-
- // This boolean is used to avoid multiple calls to credentials callback.
- if self.first_call_to_credentials.load(Ordering::Relaxed) {
- self.first_call_to_credentials
- .store(false, Ordering::Relaxed);
- } else {
- return Err(GitError::from_str("Bad credentials."));
- }
-
- match &self.basic_credential {
- _ if allowed_types.is_ssh_key() => {
- match username_from_url {
- Some(username) => {
- Cred::ssh_key_from_agent(username)
- }
- None => Err(GitError::from_str(
- " Couldn't extract username from url.",
- )),
- }
- }
- Some(BasicAuthCredential {
- username: Some(user),
- password: Some(pwd),
- }) if allowed_types.is_user_pass_plaintext() => {
- Cred::userpass_plaintext(user, pwd)
- }
- Some(BasicAuthCredential {
- username: Some(user),
- password: _,
- }) if allowed_types.is_username() => Cred::username(user),
- _ if allowed_types.is_default() => Cred::default(),
- _ => Err(GitError::from_str("Couldn't find credentials")),
- }
- }
+ ///
+ pub fn new(
+ sender: Option<Sender<ProgressNotification>>,
+ basic_credential: Option<BasicAuthCredential>,
+ ) -> Self {
+ let stats = Arc::new(Mutex::new(CallbackStats::default()));
+
+ Self {
+ sender,
+ basic_credential,
+ stats,
+ first_call_to_credentials: Arc::new(AtomicBool::new(
+ true,
+ )),
+ }
+ }
+
+ ///
+ pub fn get_stats(&self) -> Result<CallbackStats> {
+ let stats = self.stats.lock()?;
+ Ok(stats.clone())
+ }
+
+ ///
+ pub fn callbacks<'a>(&self) -> RemoteCallbacks<'a> {
+ let mut callbacks = RemoteCallbacks::new();
+
+ let this = self.clone();
+ callbacks.push_transfer_progress(
+ move |current, total, bytes| {
+ this.push_transfer_progress(current, total, bytes);
+ },
+ );
+
+ let this = self.clone();
+ callbacks.update_tips(move |name, a, b| {
+ this.update_tips(name, a, b);
+ true
+ });
+
+ let this = self.clone();
+ callbacks.transfer_progress(move |p| {
+ this.transfer_progress(&p);
+ true
+ });
+
+ let this = self.clone();
+ callbacks.pack_progress(move |stage, current, total| {
+ this.pack_progress(stage, total, current);
+ });
+
+ let this = self.clone();
+ callbacks.push_update_reference(move |reference, msg| {
+ this.push_update_reference(reference, msg);
+ Ok(())
+ });
+
+ let this = self.clone();
+ callbacks.credentials(
+ move |url, username_from_url, allowed_types| {
+ this.credentials(
+ url,
+ username_from_url,
+ allowed_types,
+ )
+ },
+ );
+
+ callbacks
+ }
+
+ fn push_update_reference(
+ &self,
+ reference: &str,
+ msg: Option<&str>,
+ ) {
+ log::debug!(
+ "push_update_reference: '{}' {:?}",
+ reference,
+ msg
+ );
+
+ if let Ok(mut stats) = self.stats.lock() {
+ stats.push_rejected_msg = msg
+ .map(|msg| (reference.to_string(), msg.to_string()));
+ }
+ }
+
+ fn pack_progress(
+ &self,
+ stage: git2::PackBuilderStage,
+ total: usize,
+ current: usize,
+ ) {
+ log::debug!("packing: {:?} - {}/{}", stage, current, total);
+ self.sender.clone().map(|sender| {
+ sender.send(ProgressNotification::Packing {
+ stage,
+ total,
+ current,
+ })
+ });
+ }
+
+ fn transfer_progress(&self, p: &git2::Progress) {
+ log::debug!(
+ "transfer: {}/{}",
+ p.received_objects(),
+ p.total_objects()
+ );
+ self.sender.clone().map(|sender| {
+ sender.send(ProgressNotification::Transfer {
+ objects: p.received_objects(),
+ total_objects: p.total_objects(),
+ })
+ });
+ }
+
+ fn update_tips(&self, name: &str, a: git2::Oid, b: git2::Oid) {
+ log::debug!("update tips: '{}' [{}] [{}]", name, a, b);
+ self.sender.clone().map(|sender| {
+ sender.send(ProgressNotification::UpdateTips {
+ name: name.to_string(),
+ a: a.into(),
+ b: b.into(),
+ })
+ });
+ }
+
+ fn push_transfer_progress(
+ &self,
+ current: usize,
+ total: usize,
+ bytes: usize,
+ ) {
+ log::debug!("progress: {}/{} ({} B)", current, total, bytes,);
+ self.sender.clone().map(|sender| {
+ sender.send(ProgressNotification::PushTransfer {
+ current,
+ total,
+ bytes,
+ })
+ });
+ }
+
+ // If credentials are bad, we don't ask the user to re-fill their creds. We push an error and they will be able to restart their action (for example a push) and retype their creds.
+ // This behavior is explained in a issue on git2-rs project : https://github.com/rust-lang/git2-rs/issues/347
+ // An implementation reference is done in cargo : https://github.com/rust-lang/cargo/blob/9fb208dddb12a3081230a5fd8f470e01df8faa25/src/cargo/sources/git/utils.rs#L588
+ // There is also a guide about libgit2 authentication : https://libgit2.org/docs/guides/authentication/
+ fn credentials(
+ &self,
+ url: &str,
+ username_from_url: Option<&str>,
+ allowed_types: git2::CredentialType,
+ ) -> std::result::Result<Cred, GitError> {
+ log::debug!(
+ "creds: '{}' {:?} ({:?})",
+ url,
+ username_from_url,
+ allowed_types
+ );
+
+ // This boolean is used to avoid multiple calls to credentials callback.
+ if self.first_call_to_credentials.load(Ordering::Relaxed) {
+ self.first_call_to_credentials
+ .store(false, Ordering::Relaxed);
+ } else {
+ return Err(GitError::from_str("Bad credentials."));
+ }
+
+ match &self.basic_credential {
+ _ if allowed_types.is_ssh_key() => {
+ match username_from_url {
+ Some(username) => {
+ Cred::ssh_key_from_agent(username)
+ }
+ None => Err(GitError::from_str(
+ " Couldn't extract username from url.",
+ )),
+ }
+ }
+ Some(BasicAuthCredential {
+ username: Some(user),
+ password: Some(pwd),
+ }) if allowed_types.is_user_pass_plaintext() => {
+ Cred::userpass_plaintext(user, pwd)
+ }
+ Some(BasicAuthCredential {
+ username: Some(user),
+ password: _,
+ }) if allowed_types.is_username() => Cred::username(user),
+ _ if allowed_types.is_default() => Cred::default(),
+ _ => Err(GitError::from_str("Couldn't find credentials")),
+ }
+ }
}