diff --git a/asyncgit/src/cached/branchname.rs b/asyncgit/src/cached/branchname.rs index 8464458a..50ec7975 100644 --- a/asyncgit/src/cached/branchname.rs +++ b/asyncgit/src/cached/branchname.rs @@ -1,4 +1,7 @@ -use crate::{error::Result, sync}; +use crate::{ + error::Result, + sync::{self, branch::get_branch_name}, +}; use sync::Head; /// @@ -38,7 +41,7 @@ impl BranchName { } fn fetch(&mut self, head: Head) -> Result { - let name = sync::get_branch_name(self.repo_path.as_str())?; + let name = get_branch_name(self.repo_path.as_str())?; self.last_result = Some((head, name.clone())); Ok(name) } diff --git a/asyncgit/src/push.rs b/asyncgit/src/push.rs index 42d8ebc9..38990685 100644 --- a/asyncgit/src/push.rs +++ b/asyncgit/src/push.rs @@ -1,7 +1,10 @@ -use crate::sync::cred::BasicAuthCredential; use crate::{ error::{Error, Result}, - sync, AsyncNotification, CWD, + sync::{ + cred::BasicAuthCredential, remotes::push::push, + remotes::push::ProgressNotification, + }, + AsyncNotification, CWD, }; use crossbeam_channel::{unbounded, Receiver, Sender}; use git2::PackBuilderStage; @@ -11,7 +14,6 @@ use std::{ thread, time::Duration, }; -use sync::ProgressNotification; use thread::JoinHandle; /// @@ -162,7 +164,7 @@ impl AsyncPush { arc_progress, ); - let res = sync::push( + let res = push( CWD, params.remote.as_str(), params.branch.as_str(), diff --git a/asyncgit/src/sync/mod.rs b/asyncgit/src/sync/mod.rs index 57c9235d..a5122f68 100644 --- a/asyncgit/src/sync/mod.rs +++ b/asyncgit/src/sync/mod.rs @@ -3,7 +3,7 @@ //TODO: remove once we have this activated on the toplevel #![deny(clippy::expect_used)] -mod branch; +pub mod branch; mod commit; mod commit_details; mod commit_files; @@ -14,14 +14,13 @@ mod hooks; mod hunks; mod ignore; mod logwalker; -mod remotes; +pub mod remotes; mod reset; mod stash; pub mod status; mod tags; pub mod utils; -pub(crate) use branch::get_branch_name; pub use branch::{ branch_compare_upstream, checkout_branch, create_branch, delete_branch, get_branches_to_display, rename_branch, @@ -40,10 +39,7 @@ pub use hooks::{ pub use hunks::{reset_hunk, stage_hunk, unstage_hunk}; pub use ignore::add_to_ignore; pub use logwalker::LogWalker; -pub use remotes::{ - fetch_origin, get_default_remote, get_remotes, push, - ProgressNotification, -}; +pub use remotes::{fetch_origin, get_default_remote, get_remotes}; pub use reset::{reset_stage, reset_workdir}; pub use stash::{get_stashes, stash_apply, stash_drop, stash_save}; pub use tags::{get_tags, CommitTags, Tags}; diff --git a/asyncgit/src/sync/remotes/mod.rs b/asyncgit/src/sync/remotes/mod.rs new file mode 100644 index 00000000..dbe2fc3c --- /dev/null +++ b/asyncgit/src/sync/remotes/mod.rs @@ -0,0 +1,177 @@ +//! + +pub(crate) mod push; + +use crate::{ + error::{Error, Result}, + sync::utils, +}; +use git2::{FetchOptions, Repository}; +use push::remote_callbacks; +use scopetime::scope_time; + +/// origin +pub const DEFAULT_REMOTE_NAME: &str = "origin"; + +/// +pub fn get_remotes(repo_path: &str) -> Result> { + scope_time!("get_remotes"); + + let repo = utils::repo(repo_path)?; + let remotes = repo.remotes()?; + let remotes: Vec = + remotes.iter().flatten().map(String::from).collect(); + + Ok(remotes) +} + +/// tries to find origin or the only remote that is defined if any +/// in case of multiple remotes and none named *origin* we fail +pub fn get_default_remote(repo_path: &str) -> Result { + let repo = utils::repo(repo_path)?; + get_default_remote_in_repo(&repo) +} + +/// see `get_default_remote` +pub(crate) fn get_default_remote_in_repo( + repo: &Repository, +) -> Result { + scope_time!("get_default_remote_in_repo"); + + let remotes = repo.remotes()?; + + // if `origin` exists return that + let found_origin = remotes.iter().any(|r| { + r.map(|r| r == DEFAULT_REMOTE_NAME).unwrap_or_default() + }); + if found_origin { + return Ok(DEFAULT_REMOTE_NAME.into()); + } + + //if only one remote exists pick that + if remotes.len() == 1 { + let first_remote = remotes + .iter() + .next() + .flatten() + .map(String::from) + .ok_or_else(|| { + Error::Generic("no remote found".into()) + })?; + + return Ok(first_remote); + } + + //inconclusive + Err(Error::NoDefaultRemoteFound) +} + +/// +pub fn fetch_origin(repo_path: &str, branch: &str) -> Result { + scope_time!("fetch_origin"); + + let repo = utils::repo(repo_path)?; + let mut remote = + repo.find_remote(&get_default_remote_in_repo(&repo)?)?; + + let mut options = FetchOptions::new(); + options.remote_callbacks(remote_callbacks(None, None)); + + remote.fetch(&[branch], Some(&mut options), None)?; + + Ok(remote.stats().received_bytes()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::sync::tests::debug_cmd_print; + use tempfile::TempDir; + + #[test] + fn test_smoke() { + let td = TempDir::new().unwrap(); + + debug_cmd_print( + td.path().as_os_str().to_str().unwrap(), + "git clone https://github.com/extrawurst/brewdump.git", + ); + + let repo_path = td.path().join("brewdump"); + let repo_path = repo_path.as_os_str().to_str().unwrap(); + + let remotes = get_remotes(repo_path).unwrap(); + + assert_eq!(remotes, vec![String::from("origin")]); + + fetch_origin(repo_path, "master").unwrap(); + } + + #[test] + fn test_default_remote() { + let td = TempDir::new().unwrap(); + + debug_cmd_print( + td.path().as_os_str().to_str().unwrap(), + "git clone https://github.com/extrawurst/brewdump.git", + ); + + debug_cmd_print( + td.path().as_os_str().to_str().unwrap(), + "cd brewdump && git remote add second https://github.com/extrawurst/brewdump.git", + ); + + let repo_path = td.path().join("brewdump"); + let repo_path = repo_path.as_os_str().to_str().unwrap(); + + let remotes = get_remotes(repo_path).unwrap(); + + assert_eq!( + remotes, + vec![String::from("origin"), String::from("second")] + ); + + let first = get_default_remote_in_repo( + &utils::repo(repo_path).unwrap(), + ) + .unwrap(); + assert_eq!(first, String::from("origin")); + } + + #[test] + fn test_default_remote_out_of_order() { + let td = TempDir::new().unwrap(); + + debug_cmd_print( + td.path().as_os_str().to_str().unwrap(), + "git clone https://github.com/extrawurst/brewdump.git", + ); + + debug_cmd_print( + td.path().as_os_str().to_str().unwrap(), + "cd brewdump && git remote rename origin alternate", + ); + + debug_cmd_print( + td.path().as_os_str().to_str().unwrap(), + "cd brewdump && git remote add origin https://github.com/extrawurst/brewdump.git", + ); + + let repo_path = td.path().join("brewdump"); + let repo_path = repo_path.as_os_str().to_str().unwrap(); + + //NOTE: aparently remotes are not chronolically sorted but alphabetically + let remotes = get_remotes(repo_path).unwrap(); + + assert_eq!( + remotes, + vec![String::from("alternate"), String::from("origin")] + ); + + let first = get_default_remote_in_repo( + &utils::repo(repo_path).unwrap(), + ) + .unwrap(); + assert_eq!(first, String::from("origin")); + } +} diff --git a/asyncgit/src/sync/remotes.rs b/asyncgit/src/sync/remotes/push.rs similarity index 72% rename from asyncgit/src/sync/remotes.rs rename to asyncgit/src/sync/remotes/push.rs index 05c446c9..2b046ca8 100644 --- a/asyncgit/src/sync/remotes.rs +++ b/asyncgit/src/sync/remotes/push.rs @@ -1,23 +1,21 @@ -//! - -use super::{branch::branch_set_upstream, CommitId}; +use super::utils; use crate::{ - error::{Error, Result}, - sync::cred::BasicAuthCredential, - sync::utils, + error::Result, + sync::{ + branch::branch_set_upstream, cred::BasicAuthCredential, + CommitId, + }, }; use crossbeam_channel::Sender; use git2::{ - Cred, Error as GitError, FetchOptions, PackBuilderStage, - PushOptions, RemoteCallbacks, Repository, + Cred, Error as GitError, PackBuilderStage, PushOptions, + RemoteCallbacks, }; use scopetime::scope_time; -pub const DEFAULT_REMOTE_NAME: &str = "origin"; - /// #[derive(Debug, Clone)] -pub enum ProgressNotification { +pub(crate) enum ProgressNotification { /// UpdateTips { /// @@ -57,76 +55,7 @@ pub enum ProgressNotification { } /// -pub fn get_remotes(repo_path: &str) -> Result> { - scope_time!("get_remotes"); - - let repo = utils::repo(repo_path)?; - let remotes = repo.remotes()?; - let remotes: Vec = - remotes.iter().flatten().map(String::from).collect(); - - Ok(remotes) -} - -/// tries to find origin or the only remote that is defined if any -/// in case of multiple remotes and none named *origin* we fail -pub fn get_default_remote(repo_path: &str) -> Result { - let repo = utils::repo(repo_path)?; - get_default_remote_in_repo(&repo) -} - -/// see `get_default_remote` -pub(crate) fn get_default_remote_in_repo( - repo: &Repository, -) -> Result { - scope_time!("get_default_remote_in_repo"); - - let remotes = repo.remotes()?; - - // if `origin` exists return that - let found_origin = remotes.iter().any(|r| { - r.map(|r| r == DEFAULT_REMOTE_NAME).unwrap_or_default() - }); - if found_origin { - return Ok(DEFAULT_REMOTE_NAME.into()); - } - - //if only one remote exists pick that - if remotes.len() == 1 { - let first_remote = remotes - .iter() - .next() - .flatten() - .map(String::from) - .ok_or_else(|| { - Error::Generic("no remote found".into()) - })?; - - return Ok(first_remote); - } - - //inconclusive - Err(Error::NoDefaultRemoteFound) -} - -/// -pub fn fetch_origin(repo_path: &str, branch: &str) -> Result { - scope_time!("fetch_origin"); - - let repo = utils::repo(repo_path)?; - let mut remote = - repo.find_remote(&get_default_remote_in_repo(&repo)?)?; - - let mut options = FetchOptions::new(); - options.remote_callbacks(remote_callbacks(None, None)); - - remote.fetch(&[branch], Some(&mut options), None)?; - - Ok(remote.stats().received_bytes()) -} - -/// -pub fn push( +pub(crate) fn push( repo_path: &str, remote: &str, branch: &str, @@ -161,7 +90,7 @@ pub fn push( Ok(()) } -fn remote_callbacks<'a>( +pub(crate) fn remote_callbacks<'a>( sender: Option>, basic_credential: Option, ) -> RemoteCallbacks<'a> { @@ -278,101 +207,15 @@ fn remote_callbacks<'a>( #[cfg(test)] mod tests { + use git2::Repository; + use super::*; use crate::sync::{ self, - tests::{debug_cmd_print, repo_init, repo_init_bare}, + tests::{repo_init, repo_init_bare}, LogWalker, }; use std::{fs::File, io::Write, path::Path}; - use tempfile::TempDir; - - #[test] - fn test_smoke() { - let td = TempDir::new().unwrap(); - - debug_cmd_print( - td.path().as_os_str().to_str().unwrap(), - "git clone https://github.com/extrawurst/brewdump.git", - ); - - let repo_path = td.path().join("brewdump"); - let repo_path = repo_path.as_os_str().to_str().unwrap(); - - let remotes = get_remotes(repo_path).unwrap(); - - assert_eq!(remotes, vec![String::from("origin")]); - - fetch_origin(repo_path, "master").unwrap(); - } - - #[test] - fn test_default_remote() { - let td = TempDir::new().unwrap(); - - debug_cmd_print( - td.path().as_os_str().to_str().unwrap(), - "git clone https://github.com/extrawurst/brewdump.git", - ); - - debug_cmd_print( - td.path().as_os_str().to_str().unwrap(), - "cd brewdump && git remote add second https://github.com/extrawurst/brewdump.git", - ); - - let repo_path = td.path().join("brewdump"); - let repo_path = repo_path.as_os_str().to_str().unwrap(); - - let remotes = get_remotes(repo_path).unwrap(); - - assert_eq!( - remotes, - vec![String::from("origin"), String::from("second")] - ); - - let first = get_default_remote_in_repo( - &utils::repo(repo_path).unwrap(), - ) - .unwrap(); - assert_eq!(first, String::from("origin")); - } - - #[test] - fn test_default_remote_out_of_order() { - let td = TempDir::new().unwrap(); - - debug_cmd_print( - td.path().as_os_str().to_str().unwrap(), - "git clone https://github.com/extrawurst/brewdump.git", - ); - - debug_cmd_print( - td.path().as_os_str().to_str().unwrap(), - "cd brewdump && git remote rename origin alternate", - ); - - debug_cmd_print( - td.path().as_os_str().to_str().unwrap(), - "cd brewdump && git remote add origin https://github.com/extrawurst/brewdump.git", - ); - - let repo_path = td.path().join("brewdump"); - let repo_path = repo_path.as_os_str().to_str().unwrap(); - - //NOTE: aparently remotes are not chronolically sorted but alphabetically - let remotes = get_remotes(repo_path).unwrap(); - - assert_eq!( - remotes, - vec![String::from("alternate"), String::from("origin")] - ); - - let first = get_default_remote_in_repo( - &utils::repo(repo_path).unwrap(), - ) - .unwrap(); - assert_eq!(first, String::from("origin")); - } #[test] fn test_force_push() {