diff --git a/CHANGELOG.md b/CHANGELOG.md index 3499ef963c..ad231d8d32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ The way this works got changed and simplified ([See docs](https://github.com/ext - dedicated fuzzy finder up/down keys to allow vim overrides ([#993](https://github.com/extrawurst/gitui/pull/993)) - pull will also download tags ([#1013](https://github.com/extrawurst/gitui/pull/1013)) - allow editing file from filetree ([#989](https://github.com/extrawurst/gitui/pull/989)) +- support bare repos (new `workdir` argument) ([#1026](https://github.com/extrawurst/gitui/pull/1026)) ### Fixed - honor options (for untracked files) in `stage_all` command ([#933](https://github.com/extrawurst/gitui/issues/933)) diff --git a/Makefile b/Makefile index 000e19e03a..f73bd94207 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ .PHONY: debug build-release release-linux-musl test clippy clippy-pedantic install install-debug ARGS=-l -# ARGS=-l -d +# ARGS=-l -d ~/code/git-bare-test.git -w ~/code/git-bare-test profile: cargo run --features=timing,pprof -- ${ARGS} diff --git a/asyncgit/src/blame.rs b/asyncgit/src/blame.rs index 0804aadc56..3599864657 100644 --- a/asyncgit/src/blame.rs +++ b/asyncgit/src/blame.rs @@ -1,8 +1,8 @@ use crate::{ error::Result, hash, - sync::{self, FileBlame}, - AsyncGitNotification, CWD, + sync::{self, FileBlame, RepoPath}, + AsyncGitNotification, }; use crossbeam_channel::Sender; use std::{ @@ -34,12 +34,17 @@ pub struct AsyncBlame { last: Arc>>>, sender: Sender, pending: Arc, + repo: RepoPath, } impl AsyncBlame { /// - pub fn new(sender: &Sender) -> Self { + pub fn new( + repo: RepoPath, + sender: &Sender, + ) -> Self { Self { + repo, current: Arc::new(Mutex::new(Request(0, None))), last: Arc::new(Mutex::new(None)), sender: sender.clone(), @@ -96,11 +101,13 @@ impl AsyncBlame { let arc_last = Arc::clone(&self.last); let sender = self.sender.clone(); let arc_pending = Arc::clone(&self.pending); + let repo = self.repo.clone(); self.pending.fetch_add(1, Ordering::Relaxed); rayon_core::spawn(move || { let notify = Self::get_blame_helper( + &repo, params, &arc_last, &arc_current, @@ -130,6 +137,7 @@ impl AsyncBlame { } fn get_blame_helper( + repo_path: &RepoPath, params: BlameParams, arc_last: &Arc< Mutex>>, @@ -138,7 +146,7 @@ impl AsyncBlame { hash: u64, ) -> Result { let file_blame = - sync::blame::blame_file(CWD, ¶ms.file_path)?; + sync::blame::blame_file(repo_path, ¶ms.file_path)?; let mut notify = false; { diff --git a/asyncgit/src/cached/branchname.rs b/asyncgit/src/cached/branchname.rs index d5c53546f0..3b77ab344e 100644 --- a/asyncgit/src/cached/branchname.rs +++ b/asyncgit/src/cached/branchname.rs @@ -1,28 +1,27 @@ use crate::{ error::Result, - sync::{self, branch::get_branch_name}, + sync::{self, branch::get_branch_name, RepoPathRef}, }; use sync::Head; /// pub struct BranchName { last_result: Option<(Head, String)>, - repo_path: String, + repo: RepoPathRef, } impl BranchName { /// - pub fn new(path: &str) -> Self { + pub const fn new(repo: RepoPathRef) -> Self { Self { - repo_path: path.to_string(), + repo, last_result: None, } } /// pub fn lookup(&mut self) -> Result { - let current_head = - sync::get_head_tuple(self.repo_path.as_str())?; + let current_head = sync::get_head_tuple(&self.repo.borrow())?; if let Some((last_head, branch_name)) = self.last_result.as_ref() @@ -41,7 +40,7 @@ impl BranchName { } fn fetch(&mut self, head: Head) -> Result { - let name = get_branch_name(self.repo_path.as_str())?; + let name = get_branch_name(&self.repo.borrow())?; self.last_result = Some((head, name.clone())); Ok(name) } diff --git a/asyncgit/src/commit_files.rs b/asyncgit/src/commit_files.rs index 2323592460..17a0c2b224 100644 --- a/asyncgit/src/commit_files.rs +++ b/asyncgit/src/commit_files.rs @@ -1,7 +1,7 @@ use crate::{ error::Result, - sync::{self, CommitId}, - AsyncGitNotification, StatusItem, CWD, + sync::{self, CommitId, RepoPath}, + AsyncGitNotification, StatusItem, }; use crossbeam_channel::Sender; use std::sync::{ @@ -42,12 +42,17 @@ pub struct AsyncCommitFiles { Arc>>>, sender: Sender, pending: Arc, + repo: RepoPath, } impl AsyncCommitFiles { /// - pub fn new(sender: &Sender) -> Self { + pub fn new( + repo: RepoPath, + sender: &Sender, + ) -> Self { Self { + repo, current: Arc::new(Mutex::new(None)), sender: sender.clone(), pending: Arc::new(AtomicUsize::new(0)), @@ -89,11 +94,12 @@ impl AsyncCommitFiles { let arc_current = Arc::clone(&self.current); let sender = self.sender.clone(); let arc_pending = Arc::clone(&self.pending); + let repo = self.repo.clone(); self.pending.fetch_add(1, Ordering::Relaxed); rayon_core::spawn(move || { - Self::fetch_helper(params, &arc_current) + Self::fetch_helper(&repo, params, &arc_current) .expect("failed to fetch"); arc_pending.fetch_sub(1, Ordering::Relaxed); @@ -107,13 +113,17 @@ impl AsyncCommitFiles { } fn fetch_helper( + repo_path: &RepoPath, params: CommitFilesParams, arc_current: &Arc< Mutex>>, >, ) -> Result<()> { - let res = - sync::get_commit_files(CWD, params.id, params.other)?; + let res = sync::get_commit_files( + repo_path, + params.id, + params.other, + )?; log::trace!("get_commit_files: {:?} ({})", params, res.len()); diff --git a/asyncgit/src/diff.rs b/asyncgit/src/diff.rs index bedc9e2dde..e52dea1ef2 100644 --- a/asyncgit/src/diff.rs +++ b/asyncgit/src/diff.rs @@ -1,8 +1,8 @@ use crate::{ error::Result, hash, - sync::{self, diff::DiffOptions, CommitId}, - AsyncGitNotification, FileDiff, CWD, + sync::{self, diff::DiffOptions, CommitId, RepoPath}, + AsyncGitNotification, FileDiff, }; use crossbeam_channel::Sender; use std::{ @@ -51,12 +51,17 @@ pub struct AsyncDiff { last: Arc>>>, sender: Sender, pending: Arc, + repo: RepoPath, } impl AsyncDiff { /// - pub fn new(sender: &Sender) -> Self { + pub fn new( + repo: RepoPath, + sender: &Sender, + ) -> Self { Self { + repo, current: Arc::new(Mutex::new(Request(0, None))), last: Arc::new(Mutex::new(None)), sender: sender.clone(), @@ -109,11 +114,13 @@ impl AsyncDiff { let arc_last = Arc::clone(&self.last); let sender = self.sender.clone(); let arc_pending = Arc::clone(&self.pending); + let repo = self.repo.clone(); self.pending.fetch_add(1, Ordering::Relaxed); rayon_core::spawn(move || { let notify = Self::get_diff_helper( + &repo, params, &arc_last, &arc_current, @@ -143,6 +150,7 @@ impl AsyncDiff { } fn get_diff_helper( + repo_path: &RepoPath, params: DiffParams, arc_last: &Arc< Mutex>>, @@ -152,24 +160,24 @@ impl AsyncDiff { ) -> Result { let res = match params.diff_type { DiffType::Stage => sync::diff::get_diff( - CWD, + repo_path, ¶ms.path, true, Some(params.options), )?, DiffType::WorkDir => sync::diff::get_diff( - CWD, + repo_path, ¶ms.path, false, Some(params.options), )?, DiffType::Commit(id) => sync::diff::get_diff_commit( - CWD, + repo_path, id, params.path.clone(), )?, DiffType::Commits(ids) => sync::diff::get_diff_commits( - CWD, + repo_path, ids, params.path.clone(), )?, diff --git a/asyncgit/src/fetch_job.rs b/asyncgit/src/fetch_job.rs index 0daf667e44..e0d9d8edb6 100644 --- a/asyncgit/src/fetch_job.rs +++ b/asyncgit/src/fetch_job.rs @@ -3,9 +3,9 @@ use crate::{ asyncjob::{AsyncJob, RunParams}, error::Result, - sync::cred::BasicAuthCredential, sync::remotes::fetch_all, - AsyncGitNotification, ProgressPercent, CWD, + sync::{cred::BasicAuthCredential, RepoPath}, + AsyncGitNotification, ProgressPercent, }; use std::sync::{Arc, Mutex}; @@ -16,18 +16,21 @@ enum JobState { } /// -#[derive(Clone, Default)] +#[derive(Clone)] pub struct AsyncFetchJob { state: Arc>>, + repo: RepoPath, } /// impl AsyncFetchJob { /// pub fn new( + repo: RepoPath, basic_credential: Option, ) -> Self { Self { + repo, state: Arc::new(Mutex::new(Some(JobState::Request( basic_credential, )))), @@ -61,8 +64,11 @@ impl AsyncJob for AsyncFetchJob { *state = state.take().map(|state| match state { JobState::Request(basic_credentials) => { //TODO: support progress - let result = - fetch_all(CWD, &basic_credentials, &None); + let result = fetch_all( + &self.repo, + &basic_credentials, + &None, + ); JobState::Response(result) } diff --git a/asyncgit/src/lib.rs b/asyncgit/src/lib.rs index 2df5bdc9a5..061a784a75 100644 --- a/asyncgit/src/lib.rs +++ b/asyncgit/src/lib.rs @@ -94,9 +94,6 @@ pub enum AsyncGitNotification { Fetch, } -/// current working directory `./` -pub static CWD: &str = "./"; - /// helper function to calculate the hash of an arbitrary type that implements the `Hash` trait pub fn hash(v: &T) -> u64 { let mut hasher = DefaultHasher::new(); diff --git a/asyncgit/src/pull.rs b/asyncgit/src/pull.rs index 30562835f5..f23a8aebb1 100644 --- a/asyncgit/src/pull.rs +++ b/asyncgit/src/pull.rs @@ -3,8 +3,9 @@ use crate::{ sync::{ cred::BasicAuthCredential, remotes::{fetch, push::ProgressNotification}, + RepoPath, }, - AsyncGitNotification, RemoteProgress, CWD, + AsyncGitNotification, RemoteProgress, }; use crossbeam_channel::{unbounded, Sender}; use std::{ @@ -33,12 +34,17 @@ pub struct AsyncPull { last_result: Arc>>, progress: Arc>>, sender: Sender, + repo: RepoPath, } impl AsyncPull { /// - pub fn new(sender: &Sender) -> Self { + pub fn new( + repo: RepoPath, + sender: &Sender, + ) -> Self { Self { + repo, state: Arc::new(Mutex::new(None)), last_result: Arc::new(Mutex::new(None)), progress: Arc::new(Mutex::new(None)), @@ -79,6 +85,7 @@ impl AsyncPull { let arc_res = Arc::clone(&self.last_result); let arc_progress = Arc::clone(&self.progress); let sender = self.sender.clone(); + let repo = self.repo.clone(); thread::spawn(move || { let (progress_sender, receiver) = unbounded(); @@ -91,7 +98,7 @@ impl AsyncPull { ); let res = fetch( - CWD, + &repo, ¶ms.branch, params.basic_credential, Some(progress_sender.clone()), diff --git a/asyncgit/src/push.rs b/asyncgit/src/push.rs index 4bd88a38f8..7165c30e0d 100644 --- a/asyncgit/src/push.rs +++ b/asyncgit/src/push.rs @@ -2,9 +2,9 @@ use crate::{ error::{Error, Result}, sync::{ cred::BasicAuthCredential, remotes::push::push, - remotes::push::ProgressNotification, + remotes::push::ProgressNotification, RepoPath, }, - AsyncGitNotification, RemoteProgress, CWD, + AsyncGitNotification, RemoteProgress, }; use crossbeam_channel::{unbounded, Sender}; use std::{ @@ -37,12 +37,17 @@ pub struct AsyncPush { last_result: Arc>>, progress: Arc>>, sender: Sender, + repo: RepoPath, } impl AsyncPush { /// - pub fn new(sender: &Sender) -> Self { + pub fn new( + repo: RepoPath, + sender: &Sender, + ) -> Self { Self { + repo, state: Arc::new(Mutex::new(None)), last_result: Arc::new(Mutex::new(None)), progress: Arc::new(Mutex::new(None)), @@ -83,6 +88,7 @@ impl AsyncPush { let arc_res = Arc::clone(&self.last_result); let arc_progress = Arc::clone(&self.progress); let sender = self.sender.clone(); + let repo = self.repo.clone(); thread::spawn(move || { let (progress_sender, receiver) = unbounded(); @@ -95,7 +101,7 @@ impl AsyncPush { ); let res = push( - CWD, + &repo, params.remote.as_str(), params.branch.as_str(), params.force, diff --git a/asyncgit/src/push_tags.rs b/asyncgit/src/push_tags.rs index aadd36c008..0740def1bf 100644 --- a/asyncgit/src/push_tags.rs +++ b/asyncgit/src/push_tags.rs @@ -3,8 +3,9 @@ use crate::{ sync::{ cred::BasicAuthCredential, remotes::tags::{push_tags, PushTagsProgress}, + RepoPath, }, - AsyncGitNotification, RemoteProgress, CWD, + AsyncGitNotification, RemoteProgress, }; use crossbeam_channel::{unbounded, Sender}; use std::{ @@ -31,12 +32,17 @@ pub struct AsyncPushTags { last_result: Arc>>, progress: Arc>>, sender: Sender, + repo: RepoPath, } impl AsyncPushTags { /// - pub fn new(sender: &Sender) -> Self { + pub fn new( + repo: RepoPath, + sender: &Sender, + ) -> Self { Self { + repo, state: Arc::new(Mutex::new(None)), last_result: Arc::new(Mutex::new(None)), progress: Arc::new(Mutex::new(None)), @@ -77,6 +83,7 @@ impl AsyncPushTags { let arc_res = Arc::clone(&self.last_result); let arc_progress = Arc::clone(&self.progress); let sender = self.sender.clone(); + let repo = self.repo.clone(); thread::spawn(move || { let (progress_sender, receiver) = unbounded(); @@ -89,7 +96,7 @@ impl AsyncPushTags { ); let res = push_tags( - CWD, + &repo, params.remote.as_str(), params.basic_credential.clone(), Some(progress_sender), diff --git a/asyncgit/src/remote_tags.rs b/asyncgit/src/remote_tags.rs index 9b17b3d615..365eb766e5 100644 --- a/asyncgit/src/remote_tags.rs +++ b/asyncgit/src/remote_tags.rs @@ -4,8 +4,11 @@ use crate::{ asyncjob::{AsyncJob, RunParams}, error::Result, sync::cred::BasicAuthCredential, - sync::remotes::{get_default_remote, tags_missing_remote}, - AsyncGitNotification, CWD, + sync::{ + remotes::{get_default_remote, tags_missing_remote}, + RepoPath, + }, + AsyncGitNotification, }; use std::sync::{Arc, Mutex}; @@ -16,18 +19,21 @@ enum JobState { } /// -#[derive(Clone, Default)] +#[derive(Clone)] pub struct AsyncRemoteTagsJob { state: Arc>>, + repo: RepoPath, } /// impl AsyncRemoteTagsJob { /// pub fn new( + repo: RepoPath, basic_credential: Option, ) -> Self { Self { + repo, state: Arc::new(Mutex::new(Some(JobState::Request( basic_credential, )))), @@ -60,10 +66,10 @@ impl AsyncJob for AsyncRemoteTagsJob { if let Ok(mut state) = self.state.lock() { *state = state.take().map(|state| match state { JobState::Request(basic_credential) => { - let result = - get_default_remote(CWD).and_then(|remote| { + let result = get_default_remote(&self.repo) + .and_then(|remote| { tags_missing_remote( - CWD, + &self.repo, &remote, basic_credential, ) diff --git a/asyncgit/src/revlog.rs b/asyncgit/src/revlog.rs index e746b236de..d133c6aac4 100644 --- a/asyncgit/src/revlog.rs +++ b/asyncgit/src/revlog.rs @@ -1,7 +1,7 @@ use crate::{ error::Result, - sync::{utils::repo, CommitId, LogWalker, LogWalkerFilter}, - AsyncGitNotification, CWD, + sync::{repo, CommitId, LogWalker, LogWalkerFilter, RepoPath}, + AsyncGitNotification, }; use crossbeam_channel::Sender; use git2::Oid; @@ -33,6 +33,7 @@ pub struct AsyncLog { pending: Arc, background: Arc, filter: Option, + repo: RepoPath, } static LIMIT_COUNT: usize = 3000; @@ -42,10 +43,12 @@ static SLEEP_BACKGROUND: Duration = Duration::from_millis(1000); impl AsyncLog { /// pub fn new( + repo: RepoPath, sender: &Sender, filter: Option, ) -> Self { Self { + repo, current: Arc::new(Mutex::new(Vec::new())), sender: sender.clone(), pending: Arc::new(AtomicBool::new(false)), @@ -102,7 +105,7 @@ impl AsyncLog { /// fn head_changed(&self) -> Result { - if let Ok(head) = repo(CWD)?.head() { + if let Ok(head) = repo(&self.repo)?.head() { if let Some(head) = head.target() { return Ok(head != self.current_head()?.into()); } @@ -128,15 +131,16 @@ impl AsyncLog { let sender = self.sender.clone(); let arc_pending = Arc::clone(&self.pending); let arc_background = Arc::clone(&self.background); + let filter = self.filter.clone(); + let repo = self.repo.clone(); self.pending.store(true, Ordering::Relaxed); - let filter = self.filter.clone(); - rayon_core::spawn(move || { scope_time!("async::revlog"); Self::fetch_helper( + &repo, &arc_current, &arc_background, &sender, @@ -153,13 +157,14 @@ impl AsyncLog { } fn fetch_helper( + repo_path: &RepoPath, arc_current: &Arc>>, arc_background: &Arc, sender: &Sender, filter: Option, ) -> Result<()> { let mut entries = Vec::with_capacity(LIMIT_COUNT); - let r = repo(CWD)?; + let r = repo(repo_path)?; let mut walker = LogWalker::new(&r, LIMIT_COUNT)?.filter(filter); loop { diff --git a/asyncgit/src/status.rs b/asyncgit/src/status.rs index 384d240948..b73e5a6ba0 100644 --- a/asyncgit/src/status.rs +++ b/asyncgit/src/status.rs @@ -1,8 +1,10 @@ use crate::{ error::Result, hash, - sync::{self, status::StatusType, ShowUntrackedFilesConfig}, - AsyncGitNotification, StatusItem, CWD, + sync::{ + self, status::StatusType, RepoPath, ShowUntrackedFilesConfig, + }, + AsyncGitNotification, StatusItem, }; use crossbeam_channel::Sender; use std::{ @@ -56,12 +58,17 @@ pub struct AsyncStatus { last: Arc>, sender: Sender, pending: Arc, + repo: RepoPath, } impl AsyncStatus { /// - pub fn new(sender: Sender) -> Self { + pub fn new( + repo: RepoPath, + sender: Sender, + ) -> Self { Self { + repo, current: Arc::new(Mutex::new(Request(0, None))), last: Arc::new(Mutex::new(Status::default())), sender, @@ -115,11 +122,13 @@ impl AsyncStatus { let arc_pending = Arc::clone(&self.pending); let status_type = params.status_type; let config = params.config; + let repo = self.repo.clone(); self.pending.fetch_add(1, Ordering::Relaxed); rayon_core::spawn(move || { let ok = Self::fetch_helper( + &repo, status_type, config, hash_request, @@ -141,13 +150,14 @@ impl AsyncStatus { } fn fetch_helper( + repo: &RepoPath, status_type: StatusType, config: Option, hash_request: u64, arc_current: &Arc>>, arc_last: &Arc>, ) -> Result<()> { - let res = Self::get_status(status_type, config)?; + let res = Self::get_status(repo, status_type, config)?; log::trace!( "status fetched: {} (type: {:?})", hash_request, @@ -170,12 +180,13 @@ impl AsyncStatus { } fn get_status( + repo: &RepoPath, status_type: StatusType, config: Option, ) -> Result { Ok(Status { items: sync::status::get_status( - CWD, + repo, status_type, config, )?, diff --git a/asyncgit/src/sync/blame.rs b/asyncgit/src/sync/blame.rs index c9e3c1c6fe..9243ee4ac9 100644 --- a/asyncgit/src/sync/blame.rs +++ b/asyncgit/src/sync/blame.rs @@ -1,9 +1,9 @@ //! Sync git API for fetching a file blame -use super::{utils, CommitId}; +use super::{utils, CommitId, RepoPath}; use crate::{ error::{Error, Result}, - sync::get_commits_info, + sync::{get_commits_info, repository::repo}, }; use scopetime::scope_time; use std::collections::{HashMap, HashSet}; @@ -54,12 +54,12 @@ fn fixup_windows_path(path: &str) -> String { /// pub fn blame_file( - repo_path: &str, + repo_path: &RepoPath, file_path: &str, ) -> Result { scope_time!("blame_file"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let commit_id = utils::get_head_repo(&repo)?; @@ -142,9 +142,9 @@ pub fn blame_file( #[cfg(test)] mod tests { use super::*; - use crate::error::Result; - use crate::sync::{ - commit, stage_add_file, tests::repo_init_empty, + use crate::{ + error::Result, + sync::{commit, stage_add_file, tests::repo_init_empty}, }; use std::{ fs::{File, OpenOptions}, @@ -157,7 +157,8 @@ mod tests { let file_path = Path::new("foo"); let (_td, repo) = repo_init_empty()?; let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); assert!(matches!(blame_file(&repo_path, "foo"), Err(_))); @@ -237,7 +238,8 @@ mod tests { let file_path = Path::new("bar\\foo"); let (_td, repo) = repo_init_empty().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); std::fs::create_dir(&root.join("bar")).unwrap(); diff --git a/asyncgit/src/sync/branch/merge_commit.rs b/asyncgit/src/sync/branch/merge_commit.rs index fcabf915cd..e7987544f5 100644 --- a/asyncgit/src/sync/branch/merge_commit.rs +++ b/asyncgit/src/sync/branch/merge_commit.rs @@ -3,7 +3,7 @@ use super::BranchType; use crate::{ error::{Error, Result}, - sync::{merge_msg, utils, CommitId}, + sync::{merge_msg, repository::repo, CommitId, RepoPath}, }; use git2::Commit; use scopetime::scope_time; @@ -12,12 +12,12 @@ use scopetime::scope_time; /// if we did not create conflicts we create a merge commit and return the commit id. /// Otherwise we return `None` pub fn merge_upstream_commit( - repo_path: &str, + repo_path: &RepoPath, branch_name: &str, ) -> Result> { scope_time!("merge_upstream_commit"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let branch = repo.find_branch(branch_name, BranchType::Local)?; let upstream = branch.upstream()?; @@ -130,7 +130,7 @@ mod test { ); push( - clone1_dir.path().to_str().unwrap(), + &clone1_dir.path().to_str().unwrap().into(), "origin", "master", false, @@ -152,28 +152,36 @@ mod test { //push should fail since origin diverged assert!(push( - clone2_dir, "origin", "master", false, false, None, None, + &clone2_dir.into(), + "origin", + "master", + false, + false, + None, + None.into(), ) .is_err()); //lets fetch from origin - let bytes = fetch(clone2_dir, "master", None, None).unwrap(); + let bytes = + fetch(&clone2_dir.into(), "master", None, None).unwrap(); assert!(bytes > 0); //we should be one commit behind assert_eq!( - branch_compare_upstream(clone2_dir, "master") + branch_compare_upstream(&clone2_dir.into(), "master") .unwrap() .behind, 1 ); let merge_commit = - merge_upstream_commit(clone2_dir, "master") + merge_upstream_commit(&clone2_dir.into(), "master") .unwrap() .unwrap(); - let state = crate::sync::repo_state(clone2_dir).unwrap(); + let state = + crate::sync::repo_state(&clone2_dir.into()).unwrap(); assert_eq!(state, RepoState::Clean); assert!(!clone2.head_detached().unwrap()); @@ -185,9 +193,11 @@ mod test { assert_eq!(commits[2], commit1); //verify commit msg - let details = - crate::sync::get_commit_details(clone2_dir, merge_commit) - .unwrap(); + let details = crate::sync::get_commit_details( + &clone2_dir.into(), + merge_commit.into(), + ) + .unwrap(); assert_eq!( details.message.unwrap().combine(), String::from("Merge remote-tracking branch 'refs/remotes/origin/master'") @@ -214,12 +224,12 @@ mod test { ); debug_cmd_print( - clone2_dir.path().to_str().unwrap(), + &clone2_dir.path().to_str().unwrap().into(), "git status", ); push( - clone1_dir.path().to_str().unwrap(), + &clone1_dir.path().to_str().unwrap().into(), "origin", "master", false, @@ -239,7 +249,7 @@ mod test { ); let bytes = fetch( - clone2_dir.path().to_str().unwrap(), + &clone2_dir.path().to_str().unwrap().into(), "master", None, None, @@ -248,7 +258,7 @@ mod test { assert!(bytes > 0); let res = merge_upstream_commit( - clone2_dir.path().to_str().unwrap(), + &clone2_dir.path().to_str().unwrap().into(), "master", ) .unwrap(); @@ -257,7 +267,7 @@ mod test { assert_eq!(res, None); let state = crate::sync::repo_state( - clone2_dir.path().to_str().unwrap(), + &clone2_dir.path().to_str().unwrap().into(), ) .unwrap(); diff --git a/asyncgit/src/sync/branch/merge_ff.rs b/asyncgit/src/sync/branch/merge_ff.rs index f4e94d99b9..dbe3be4011 100644 --- a/asyncgit/src/sync/branch/merge_ff.rs +++ b/asyncgit/src/sync/branch/merge_ff.rs @@ -3,18 +3,18 @@ use super::BranchType; use crate::{ error::{Error, Result}, - sync::utils, + sync::{repository::repo, RepoPath}, }; use scopetime::scope_time; /// pub fn branch_merge_upstream_fastforward( - repo_path: &str, + repo_path: &RepoPath, branch: &str, ) -> Result<()> { scope_time!("branch_merge_upstream"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let branch = repo.find_branch(branch, BranchType::Local)?; let upstream = branch.upstream()?; @@ -76,7 +76,7 @@ pub mod test { write_commit_file(&clone1, "test.txt", "test", "commit1"); push( - clone1_dir.path().to_str().unwrap(), + &clone1_dir.path().to_str().unwrap().into(), "origin", "master", false, @@ -88,7 +88,7 @@ pub mod test { // clone2 debug_cmd_print( - clone2_dir.path().to_str().unwrap(), + &clone2_dir.path().to_str().unwrap().into(), "git pull --ff", ); @@ -100,7 +100,7 @@ pub mod test { ); push( - clone2_dir.path().to_str().unwrap(), + &clone2_dir.path().to_str().unwrap().into(), "origin", "master", false, @@ -113,7 +113,7 @@ pub mod test { // clone1 again let bytes = fetch( - clone1_dir.path().to_str().unwrap(), + &clone1_dir.path().to_str().unwrap().into(), "master", None, None, @@ -122,7 +122,7 @@ pub mod test { assert!(bytes > 0); let bytes = fetch( - clone1_dir.path().to_str().unwrap(), + &clone1_dir.path().to_str().unwrap().into(), "master", None, None, @@ -131,7 +131,7 @@ pub mod test { assert_eq!(bytes, 0); branch_merge_upstream_fastforward( - clone1_dir.path().to_str().unwrap(), + &clone1_dir.path().to_str().unwrap().into(), "master", ) .unwrap(); diff --git a/asyncgit/src/sync/branch/merge_rebase.rs b/asyncgit/src/sync/branch/merge_rebase.rs index 271ee03f2a..dce5ab1bf4 100644 --- a/asyncgit/src/sync/branch/merge_rebase.rs +++ b/asyncgit/src/sync/branch/merge_rebase.rs @@ -2,19 +2,22 @@ use crate::{ error::{Error, Result}, - sync::{rebase::conflict_free_rebase, utils, CommitId}, + sync::{ + rebase::conflict_free_rebase, repository::repo, CommitId, + RepoPath, + }, }; use git2::BranchType; use scopetime::scope_time; /// trys merging current branch with its upstrema using rebase pub fn merge_upstream_rebase( - repo_path: &str, + repo_path: &RepoPath, branch_name: &str, ) -> Result { scope_time!("merge_upstream_rebase"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; if super::get_branch_name_repo(&repo)? != branch_name { return Err(Error::Generic(String::from( "can only rebase in head branch", @@ -47,7 +50,7 @@ mod test { fn get_commit_msgs(r: &Repository) -> Vec { let commits = get_commit_ids(r, 10); get_commits_info( - r.workdir().unwrap().to_str().unwrap(), + &r.workdir().unwrap().to_str().unwrap().into(), &commits, 10, ) @@ -79,7 +82,13 @@ mod test { assert_eq!(clone1.head_detached().unwrap(), false); push( - clone1_dir, "origin", "master", false, false, None, None, + &clone1_dir.into(), + "origin", + "master", + false, + false, + None, + None, ) .unwrap(); @@ -103,7 +112,13 @@ mod test { assert_eq!(clone2.head_detached().unwrap(), false); push( - clone2_dir, "origin", "master", false, false, None, None, + &clone2_dir.into(), + "origin", + "master", + false, + false, + None, + None, ) .unwrap(); @@ -122,12 +137,13 @@ mod test { assert_eq!(clone1.head_detached().unwrap(), false); //lets fetch from origin - let bytes = fetch(clone1_dir, "master", None, None).unwrap(); + let bytes = + fetch(&clone1_dir.into(), "master", None, None).unwrap(); assert!(bytes > 0); //we should be one commit behind assert_eq!( - branch_compare_upstream(clone1_dir, "master") + branch_compare_upstream(&clone1_dir.into(), "master") .unwrap() .behind, 1 @@ -137,11 +153,12 @@ mod test { assert_eq!(clone1.head_detached().unwrap(), false); - merge_upstream_rebase(clone1_dir, "master").unwrap(); + merge_upstream_rebase(&clone1_dir.into(), "master").unwrap(); - debug_cmd_print(clone1_dir, "git log"); + debug_cmd_print(&clone1_dir.into(), "git log"); - let state = crate::sync::repo_state(clone1_dir).unwrap(); + let state = + crate::sync::repo_state(&clone1_dir.into()).unwrap(); assert_eq!(state, RepoState::Clean); let commits = get_commit_msgs(&clone1); @@ -177,7 +194,13 @@ mod test { ); push( - clone1_dir, "origin", "master", false, false, None, None, + &clone1_dir.into(), + "origin", + "master", + false, + false, + None, + None, ) .unwrap(); @@ -197,7 +220,13 @@ mod test { ); push( - clone2_dir, "origin", "master", false, false, None, None, + &clone2_dir.into(), + "origin", + "master", + false, + false, + None, + None, ) .unwrap(); @@ -220,13 +249,14 @@ mod test { //lets fetch from origin - fetch(clone1_dir, "master", None, None).unwrap(); + fetch(&clone1_dir.into(), "master", None, None).unwrap(); - merge_upstream_rebase(clone1_dir, "master").unwrap(); + merge_upstream_rebase(&clone1_dir.into(), "master").unwrap(); - debug_cmd_print(clone1_dir, "git log"); + debug_cmd_print(&clone1_dir.into(), "git log"); - let state = crate::sync::repo_state(clone1_dir).unwrap(); + let state = + crate::sync::repo_state(&clone1_dir.into()).unwrap(); assert_eq!(state, RepoState::Clean); let commits = get_commit_msgs(&clone1); @@ -258,7 +288,13 @@ mod test { write_commit_file(&clone1, "test.txt", "test", "commit1"); push( - clone1_dir, "origin", "master", false, false, None, None, + &clone1_dir.into(), + "origin", + "master", + false, + false, + None, + None, ) .unwrap(); @@ -277,7 +313,13 @@ mod test { ); push( - clone2_dir, "origin", "master", false, false, None, None, + &clone2_dir.into(), + "origin", + "master", + false, + false, + None, + None, ) .unwrap(); @@ -286,20 +328,22 @@ mod test { let _commit3 = write_commit_file(&clone1, "test2.txt", "foo", "commit3"); - let bytes = fetch(clone1_dir, "master", None, None).unwrap(); + let bytes = + fetch(&clone1_dir.into(), "master", None, None).unwrap(); assert!(bytes > 0); assert_eq!( - branch_compare_upstream(clone1_dir, "master") + branch_compare_upstream(&clone1_dir.into(), "master") .unwrap() .behind, 1 ); - let res = merge_upstream_rebase(clone1_dir, "master"); + let res = merge_upstream_rebase(&clone1_dir.into(), "master"); assert!(res.is_err()); - let state = crate::sync::repo_state(clone1_dir).unwrap(); + let state = + crate::sync::repo_state(&clone1_dir.into()).unwrap(); assert_eq!(state, RepoState::Clean); diff --git a/asyncgit/src/sync/branch/mod.rs b/asyncgit/src/sync/branch/mod.rs index 9f1d62cc77..601df341a1 100644 --- a/asyncgit/src/sync/branch/mod.rs +++ b/asyncgit/src/sync/branch/mod.rs @@ -5,23 +5,24 @@ pub mod merge_ff; pub mod merge_rebase; pub mod rename; -use std::collections::HashSet; - use super::{ remotes::get_default_remote_in_repo, utils::bytes2string, + RepoPath, }; use crate::{ error::{Error, Result}, - sync::{utils, CommitId}, + sync::{repository::repo, utils::get_head_repo, CommitId}, }; use git2::{Branch, BranchType, Repository}; use scopetime::scope_time; -use utils::get_head_repo; +use std::collections::HashSet; /// returns the branch-name head is currently pointing to /// this might be expensive, see `cached::BranchName` -pub(crate) fn get_branch_name(repo_path: &str) -> Result { - let repo = utils::repo(repo_path)?; +pub(crate) fn get_branch_name( + repo_path: &RepoPath, +) -> Result { + let repo = repo(repo_path)?; get_branch_name_repo(&repo) } @@ -111,12 +112,12 @@ pub fn validate_branch_name(name: &str) -> Result { /// returns a list of `BranchInfo` with a simple summary on each branch /// `local` filters for local branches otherwise remote branches will be returned pub fn get_branches_info( - repo_path: &str, + repo_path: &RepoPath, local: bool, ) -> Result> { scope_time!("get_branches_info"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let (filter, remotes_with_tracking) = if local { (BranchType::Local, HashSet::default()) @@ -214,10 +215,10 @@ pub(crate) fn branch_set_upstream( /// returns remote of the upstream tracking branch for `branch` pub fn get_branch_remote( - repo_path: &str, + repo_path: &RepoPath, branch: &str, ) -> Result> { - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let branch = repo.find_branch(branch, BranchType::Local)?; let reference = bytes2string(branch.get().name_bytes())?; let remote_name = repo.branch_upstream_remote(&reference).ok(); @@ -229,8 +230,8 @@ pub fn get_branch_remote( } /// returns whether the pull merge strategy is set to rebase -pub fn config_is_pull_rebase(repo_path: &str) -> Result { - let repo = utils::repo(repo_path)?; +pub fn config_is_pull_rebase(repo_path: &RepoPath) -> Result { + let repo = repo(repo_path)?; let config = repo.config()?; if let Ok(rebase) = config.get_entry("pull.rebase") { @@ -244,12 +245,12 @@ pub fn config_is_pull_rebase(repo_path: &str) -> Result { /// pub fn branch_compare_upstream( - repo_path: &str, + repo_path: &RepoPath, branch: &str, ) -> Result { scope_time!("branch_compare_upstream"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let branch = repo.find_branch(branch, BranchType::Local)?; @@ -269,14 +270,14 @@ pub fn branch_compare_upstream( /// Modify HEAD to point to a branch then checkout head, does not work if there are uncommitted changes pub fn checkout_branch( - repo_path: &str, + repo_path: &RepoPath, branch_ref: &str, ) -> Result<()> { scope_time!("checkout_branch"); // This defaults to a safe checkout, so don't delete anything that // hasn't been committed or stashed, in this case it will Err - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let cur_ref = repo.head()?; let statuses = repo.statuses(Some( git2::StatusOptions::new().include_ignored(false), @@ -302,12 +303,12 @@ pub fn checkout_branch( /// pub fn checkout_remote_branch( - repo_path: &str, + repo_path: &RepoPath, branch: &BranchInfo, ) -> Result<()> { scope_time!("checkout_remote_branch"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let cur_ref = repo.head()?; if !repo @@ -345,12 +346,12 @@ pub fn checkout_remote_branch( /// The user must not be on the branch for the branch to be deleted pub fn delete_branch( - repo_path: &str, + repo_path: &RepoPath, branch_ref: &str, ) -> Result<()> { scope_time!("delete_branch"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let branch_as_ref = repo.find_reference(branch_ref)?; let mut branch = git2::Branch::wrap(branch_as_ref); if branch.is_head() { @@ -361,10 +362,13 @@ pub fn delete_branch( } /// creates a new branch pointing to current HEAD commit and updating HEAD to new branch -pub fn create_branch(repo_path: &str, name: &str) -> Result { +pub fn create_branch( + repo_path: &RepoPath, + name: &str, +) -> Result { scope_time!("create_branch"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let head_id = get_head_repo(&repo)?; let head_commit = repo.find_commit(head_id.into())?; @@ -386,7 +390,8 @@ mod tests_branch_name { fn test_smoke() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); assert_eq!( get_branch_name(repo_path).unwrap().as_str(), @@ -398,7 +403,8 @@ mod tests_branch_name { fn test_empty_repo() { let (_td, repo) = repo_init_empty().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); assert!(matches!( get_branch_name(repo_path), @@ -416,7 +422,8 @@ mod tests_create_branch { fn test_smoke() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); create_branch(repo_path, "branch1").unwrap(); @@ -436,7 +443,8 @@ mod tests_branch_compare { fn test_smoke() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); create_branch(repo_path, "test").unwrap(); @@ -462,7 +470,8 @@ mod tests_branches { fn test_smoke() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); assert_eq!( get_branches_info(repo_path, true) @@ -478,7 +487,8 @@ mod tests_branches { fn test_multiple() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); create_branch(repo_path, "test").unwrap(); @@ -497,9 +507,18 @@ mod tests_branches { let dir = dir.path().to_str().unwrap(); write_commit_file(&repo, "f1.txt", "foo", "c1"); - rename_branch(dir, "refs/heads/master", branch_name).unwrap(); - push(dir, "origin", branch_name, false, false, None, None) + rename_branch(&dir.into(), "refs/heads/master", branch_name) .unwrap(); + push( + &dir.into(), + "origin", + branch_name, + false, + false, + None, + None, + ) + .unwrap(); } #[test] @@ -516,7 +535,8 @@ mod tests_branches { clone_branch_commit_push(r2_path, "r2branch"); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); //add the remotes repo.remote("r1", r1_path).unwrap(); @@ -588,7 +608,8 @@ mod tests_branches { fn test_branch_remote_no_upstream() { let (_r, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); assert_eq!( get_branch_remote(repo_path, "master").unwrap(), @@ -600,7 +621,8 @@ mod tests_branches { fn test_branch_remote_no_branch() { let (_r, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); assert!(get_branch_remote(repo_path, "foo").is_err()); } @@ -615,7 +637,8 @@ mod tests_checkout { fn test_smoke() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); assert!( checkout_branch(repo_path, "refs/heads/master").is_ok() @@ -629,7 +652,8 @@ mod tests_checkout { fn test_multiple() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); create_branch(repo_path, "test").unwrap(); @@ -650,7 +674,8 @@ mod test_delete_branch { fn test_delete_branch() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); create_branch(repo_path, "branch1").unwrap(); create_branch(repo_path, "branch2").unwrap(); @@ -720,16 +745,30 @@ mod test_remote_branches { write_commit_file(&clone1, "test.txt", "test", "commit1"); push( - clone1_dir, "origin", "master", false, false, None, None, + &clone1_dir.into(), + "origin", + "master", + false, + false, + None, + None, ) .unwrap(); - create_branch(clone1_dir, "foo").unwrap(); + create_branch(&clone1_dir.into(), "foo").unwrap(); write_commit_file(&clone1, "test.txt", "test2", "commit2"); - push(clone1_dir, "origin", "foo", false, false, None, None) - .unwrap(); + push( + &clone1_dir.into(), + "origin", + "foo", + false, + false, + None, + None, + ) + .unwrap(); // clone2 @@ -739,11 +778,12 @@ mod test_remote_branches { let clone2_dir = clone2_dir.path().to_str().unwrap(); let local_branches = - get_branches_info(clone2_dir, true).unwrap(); + get_branches_info(&clone2_dir.into(), true).unwrap(); assert_eq!(local_branches.len(), 1); - let branches = get_branches_info(clone2_dir, false).unwrap(); + let branches = + get_branches_info(&clone2_dir.into(), false).unwrap(); assert_eq!(dbg!(&branches).len(), 3); assert_eq!(&branches[0].name, "origin/HEAD"); assert_eq!(&branches[1].name, "origin/foo"); @@ -762,13 +802,27 @@ mod test_remote_branches { write_commit_file(&clone1, "test.txt", "test", "commit1"); push( - clone1_dir, "origin", "master", false, false, None, None, + &clone1_dir.into(), + "origin", + "master", + false, + false, + None, + None, ) .unwrap(); - create_branch(clone1_dir, "foo").unwrap(); + create_branch(&clone1_dir.into(), "foo").unwrap(); write_commit_file(&clone1, "test.txt", "test2", "commit2"); - push(clone1_dir, "origin", "foo", false, false, None, None) - .unwrap(); + push( + &clone1_dir.into(), + "origin", + "foo", + false, + false, + None, + None, + ) + .unwrap(); // clone2 @@ -778,21 +832,28 @@ mod test_remote_branches { let clone2_dir = clone2_dir.path().to_str().unwrap(); let local_branches = - get_branches_info(clone2_dir, true).unwrap(); + get_branches_info(&clone2_dir.into(), true).unwrap(); assert_eq!(local_branches.len(), 1); - let branches = get_branches_info(clone2_dir, false).unwrap(); + let branches = + get_branches_info(&clone2_dir.into(), false).unwrap(); // checkout origin/foo - checkout_remote_branch(clone2_dir, &branches[1]).unwrap(); + checkout_remote_branch(&clone2_dir.into(), &branches[1]) + .unwrap(); assert_eq!( - get_branches_info(clone2_dir, true).unwrap().len(), + get_branches_info(&clone2_dir.into(), true) + .unwrap() + .len(), 2 ); - assert_eq!(&get_branch_name(clone2_dir).unwrap(), "foo"); + assert_eq!( + &get_branch_name(&clone2_dir.into()).unwrap(), + "foo" + ); } #[test] @@ -809,13 +870,19 @@ mod test_remote_branches { write_commit_file(&clone1, "test.txt", "test", "commit1"); push( - clone1_dir, "origin", "master", false, false, None, None, + &clone1_dir.into(), + "origin", + "master", + false, + false, + None, + None, ) .unwrap(); - create_branch(clone1_dir, branch_name).unwrap(); + create_branch(&clone1_dir.into(), branch_name).unwrap(); write_commit_file(&clone1, "test.txt", "test2", "commit2"); push( - clone1_dir, + &clone1_dir.into(), "origin", branch_name, false, @@ -831,12 +898,14 @@ mod test_remote_branches { repo_clone(r1_dir.path().to_str().unwrap()).unwrap(); let clone2_dir = clone2_dir.path().to_str().unwrap(); - let branches = get_branches_info(clone2_dir, false).unwrap(); + let branches = + get_branches_info(&clone2_dir.into(), false).unwrap(); - checkout_remote_branch(clone2_dir, &branches[1]).unwrap(); + checkout_remote_branch(&clone2_dir.into(), &branches[1]) + .unwrap(); assert_eq!( - &get_branch_name(clone2_dir).unwrap(), + &get_branch_name(&clone2_dir.into()).unwrap(), branch_name ); } @@ -853,16 +922,30 @@ mod test_remote_branches { write_commit_file(&clone1, "test.txt", "test", "commit1"); push( - clone1_dir, "origin", "master", false, false, None, None, + &clone1_dir.into(), + "origin", + "master", + false, + false, + None, + None, ) .unwrap(); - create_branch(clone1_dir, "foo").unwrap(); + create_branch(&clone1_dir.into(), "foo").unwrap(); write_commit_file(&clone1, "test.txt", "test2", "commit2"); - push(clone1_dir, "origin", "foo", false, false, None, None) - .unwrap(); + push( + &clone1_dir.into(), + "origin", + "foo", + false, + false, + None, + None, + ) + .unwrap(); let branches_1 = - get_branches_info(clone1_dir, false).unwrap(); + get_branches_info(&clone1_dir.into(), false).unwrap(); assert!(branches_1[0].remote_details().unwrap().has_tracking); assert!(branches_1[1].remote_details().unwrap().has_tracking); @@ -875,7 +958,7 @@ mod test_remote_branches { let clone2_dir = clone2_dir.path().to_str().unwrap(); let branches_2 = - get_branches_info(clone2_dir, false).unwrap(); + get_branches_info(&clone2_dir.into(), false).unwrap(); assert!( !branches_2[0].remote_details().unwrap().has_tracking diff --git a/asyncgit/src/sync/branch/rename.rs b/asyncgit/src/sync/branch/rename.rs index f715fd7bed..2b648dee1b 100644 --- a/asyncgit/src/sync/branch/rename.rs +++ b/asyncgit/src/sync/branch/rename.rs @@ -1,17 +1,20 @@ //! renaming of branches -use crate::{error::Result, sync::utils}; +use crate::{ + error::Result, + sync::{repository::repo, RepoPath}, +}; use scopetime::scope_time; /// Rename the branch reference pub fn rename_branch( - repo_path: &str, + repo_path: &RepoPath, branch_ref: &str, new_name: &str, ) -> Result<()> { - scope_time!("delete_branch"); + scope_time!("rename_branch"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let branch_as_ref = repo.find_reference(branch_ref)?; let mut branch = git2::Branch::wrap(branch_as_ref); branch.rename(new_name, true)?; @@ -29,7 +32,8 @@ mod test { fn test_rename_branch() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); create_branch(repo_path, "branch1").unwrap(); diff --git a/asyncgit/src/sync/commit.rs b/asyncgit/src/sync/commit.rs index 86a9b52908..25d733f10a 100644 --- a/asyncgit/src/sync/commit.rs +++ b/asyncgit/src/sync/commit.rs @@ -1,11 +1,14 @@ -use super::{utils::repo, CommitId}; -use crate::{error::Result, sync::utils::get_head_repo}; +use super::{CommitId, RepoPath}; +use crate::{ + error::Result, + sync::{repository::repo, utils::get_head_repo}, +}; use git2::{ErrorCode, ObjectType, Repository, Signature}; use scopetime::scope_time; /// pub fn amend( - repo_path: &str, + repo_path: &RepoPath, id: CommitId, msg: &str, ) -> Result { @@ -58,7 +61,7 @@ pub(crate) fn signature_allow_undefined_name( } /// this does not run any git hooks -pub fn commit(repo_path: &str, msg: &str) -> Result { +pub fn commit(repo_path: &RepoPath, msg: &str) -> Result { scope_time!("commit"); let repo = repo(repo_path)?; @@ -93,7 +96,7 @@ pub fn commit(repo_path: &str, msg: &str) -> Result { /// This function will return an `Err(…)` variant if the tag’s name is refused /// by git or if the tag already exists. pub fn tag( - repo_path: &str, + repo_path: &RepoPath, commit_id: &CommitId, tag: &str, ) -> Result { @@ -113,6 +116,7 @@ pub fn tag( mod tests { use crate::error::Result; + use crate::sync::RepoPath; use crate::sync::{ commit, get_commit_details, get_commit_files, stage_add_file, tags::get_tags, @@ -136,7 +140,8 @@ mod tests { let file_path = Path::new("foo"); let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join(file_path)) .unwrap() @@ -159,7 +164,8 @@ mod tests { let file_path = Path::new("foo"); let (_td, repo) = repo_init_empty().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); assert_eq!(get_statuses(repo_path), (0, 0)); @@ -185,7 +191,8 @@ mod tests { let file_path2 = Path::new("foo2"); let (_td, repo) = repo_init_empty()?; let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join(file_path1))?.write_all(b"test1")?; @@ -221,7 +228,8 @@ mod tests { let file_path = Path::new("foo"); let (_td, repo) = repo_init_empty().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join(file_path))? .write_all(b"test\nfoo")?; @@ -265,7 +273,8 @@ mod tests { let file_path = Path::new("foo"); let (_td, repo) = repo_init_empty().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join(file_path))? .write_all(b"test\nfoo")?; @@ -300,7 +309,8 @@ mod tests { let file_path = Path::new("foo"); let (_td, repo) = repo_init_empty().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join(file_path))? .write_all(b"test\nfoo")?; diff --git a/asyncgit/src/sync/commit_details.rs b/asyncgit/src/sync/commit_details.rs index 4ad9435f5d..a6c2cc0395 100644 --- a/asyncgit/src/sync/commit_details.rs +++ b/asyncgit/src/sync/commit_details.rs @@ -1,5 +1,5 @@ -use super::{commits_info::get_message, utils::repo, CommitId}; -use crate::error::Result; +use super::{commits_info::get_message, CommitId, RepoPath}; +use crate::{error::Result, sync::repository::repo}; use git2::Signature; use scopetime::scope_time; @@ -89,7 +89,7 @@ impl CommitDetails { /// pub fn get_commit_details( - repo_path: &str, + repo_path: &RepoPath, id: CommitId, ) -> Result { scope_time!("get_commit_details"); @@ -121,11 +121,12 @@ pub fn get_commit_details( #[cfg(test)] mod tests { - use super::{get_commit_details, CommitMessage}; - use crate::error::Result; - use crate::sync::{ - commit, stage_add_file, tests::repo_init_empty, + use crate::{ + error::Result, + sync::{ + commit, stage_add_file, tests::repo_init_empty, RepoPath, + }, }; use std::{fs::File, io::Write, path::Path}; @@ -134,7 +135,8 @@ mod tests { let file_path = Path::new("foo"); let (_td, repo) = repo_init_empty().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join(file_path))?.write_all(b"a")?; stage_add_file(repo_path, file_path).unwrap(); @@ -144,7 +146,6 @@ mod tests { let res = get_commit_details(repo_path, id).unwrap(); - dbg!(&res.message.as_ref().unwrap().subject); assert_eq!( res.message .as_ref() diff --git a/asyncgit/src/sync/commit_files.rs b/asyncgit/src/sync/commit_files.rs index b74bd8a11e..5dac5703d5 100644 --- a/asyncgit/src/sync/commit_files.rs +++ b/asyncgit/src/sync/commit_files.rs @@ -1,15 +1,15 @@ use std::cmp::Ordering; -use super::{stash::is_stash_commit, utils::repo, CommitId}; +use super::{stash::is_stash_commit, CommitId, RepoPath}; use crate::{ - error::Error, error::Result, StatusItem, StatusItemType, + error::Result, sync::repository::repo, StatusItem, StatusItemType, }; use git2::{Diff, DiffOptions, Repository}; use scopetime::scope_time; /// get all files that are part of a commit pub fn get_commit_files( - repo_path: &str, + repo_path: &RepoPath, id: CommitId, other: Option, ) -> Result> { @@ -20,7 +20,7 @@ pub fn get_commit_files( let diff = if let Some(other) = other { get_compare_commits_diff(&repo, (id, other), None)? } else { - get_commit_diff(&repo, id, None)? + get_commit_diff(repo_path, &repo, id, None)? }; let res = diff @@ -81,11 +81,12 @@ pub fn get_compare_commits_diff( } #[allow(clippy::redundant_pub_crate)] -pub(crate) fn get_commit_diff( - repo: &Repository, +pub(crate) fn get_commit_diff<'a>( + repo_path: &RepoPath, + repo: &'a Repository, id: CommitId, pathspec: Option, -) -> Result> { +) -> Result> { // scope_time!("get_commit_diff"); let commit = repo.find_commit(id.into())?; @@ -111,15 +112,10 @@ pub(crate) fn get_commit_diff( Some(&mut opts), )?; - if is_stash_commit( - repo.path().to_str().map_or_else( - || Err(Error::Generic("repo path utf8 err".to_owned())), - Ok, - )?, - &id, - )? { + if is_stash_commit(repo_path, &id)? { if let Ok(untracked_commit) = commit.parent_id(2) { let untracked_diff = get_commit_diff( + repo_path, repo, CommitId::new(untracked_commit), pathspec, @@ -140,6 +136,7 @@ mod tests { sync::{ commit, stage_add_file, stash_save, tests::{get_statuses, repo_init}, + RepoPath, }, StatusItemType, }; @@ -150,7 +147,8 @@ mod tests { let file_path = Path::new("file1.txt"); let (_td, repo) = repo_init()?; let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join(file_path))? .write_all(b"test file1 content")?; @@ -172,7 +170,8 @@ mod tests { let file_path = Path::new("file1.txt"); let (_td, repo) = repo_init()?; let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join(file_path))? .write_all(b"test file1 content")?; @@ -193,7 +192,8 @@ mod tests { let file_path2 = Path::new("file2.txt"); let (_td, repo) = repo_init()?; let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join(file_path1))?.write_all(b"test")?; stage_add_file(repo_path, file_path1)?; diff --git a/asyncgit/src/sync/commits_info.rs b/asyncgit/src/sync/commits_info.rs index c9e3a54a3a..8f9e726a0d 100644 --- a/asyncgit/src/sync/commits_info.rs +++ b/asyncgit/src/sync/commits_info.rs @@ -1,5 +1,5 @@ -use super::utils::repo; -use crate::error::Result; +use super::RepoPath; +use crate::{error::Result, sync::repository::repo}; use git2::{Commit, Error, Oid}; use scopetime::scope_time; use unicode_truncate::UnicodeTruncateStr; @@ -62,7 +62,7 @@ pub struct CommitInfo { /// pub fn get_commits_info( - repo_path: &str, + repo_path: &RepoPath, ids: &[CommitId], message_length_limit: usize, ) -> Result> { @@ -97,7 +97,7 @@ pub fn get_commits_info( /// pub fn get_commit_info( - repo_path: &str, + repo_path: &RepoPath, commit_id: &CommitId, ) -> Result { scope_time!("get_commit_info"); @@ -136,10 +136,12 @@ pub fn get_message( #[cfg(test)] mod tests { use super::get_commits_info; - use crate::error::Result; - use crate::sync::{ - commit, stage_add_file, tests::repo_init_empty, - utils::get_head_repo, + use crate::{ + error::Result, + sync::{ + commit, stage_add_file, tests::repo_init_empty, + utils::get_head_repo, RepoPath, + }, }; use std::{fs::File, io::Write, path::Path}; @@ -148,7 +150,8 @@ mod tests { let file_path = Path::new("foo"); let (_td, repo) = repo_init_empty().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join(file_path))?.write_all(b"a")?; stage_add_file(repo_path, file_path).unwrap(); @@ -173,7 +176,8 @@ mod tests { let file_path = Path::new("foo"); let (_td, repo) = repo_init_empty().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join(file_path))?.write_all(b"a")?; stage_add_file(repo_path, file_path).unwrap(); @@ -192,7 +196,8 @@ mod tests { let file_path = Path::new("foo"); let (_td, repo) = repo_init_empty().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join(file_path))?.write_all(b"a")?; stage_add_file(repo_path, file_path).unwrap(); diff --git a/asyncgit/src/sync/config.rs b/asyncgit/src/sync/config.rs index 7c66bf623e..54acea8b34 100644 --- a/asyncgit/src/sync/config.rs +++ b/asyncgit/src/sync/config.rs @@ -1,8 +1,9 @@ -use super::utils::repo; use crate::error::Result; use git2::Repository; use scopetime::scope_time; +use super::{repository::repo, RepoPath}; + // see https://git-scm.com/docs/git-config#Documentation/git-config.txt-statusshowUntrackedFiles /// represents the `status.showUntrackedFiles` git config state #[derive(Hash, Copy, Clone, PartialEq)] @@ -57,7 +58,7 @@ pub fn untracked_files_config_repo( /// pub fn untracked_files_config( - repo_path: &str, + repo_path: &RepoPath, ) -> Result { let repo = repo(repo_path)?; untracked_files_config_repo(&repo) @@ -65,7 +66,7 @@ pub fn untracked_files_config( /// get string from config pub fn get_config_string( - repo_path: &str, + repo_path: &RepoPath, key: &str, ) -> Result> { let repo = repo(repo_path)?; @@ -103,18 +104,21 @@ mod tests { #[test] fn test_get_config() { - let bad_dir_cfg = - get_config_string("oodly_noodly", "this.doesnt.exist"); + let bad_dir_cfg = get_config_string( + &"oodly_noodly".into(), + "this.doesnt.exist", + ); assert!(bad_dir_cfg.is_err()); let (_td, repo) = repo_init().unwrap(); let path = repo.path(); let rpath = path.as_os_str().to_str().unwrap(); - let bad_cfg = get_config_string(rpath, "this.doesnt.exist"); + let bad_cfg = + get_config_string(&rpath.into(), "this.doesnt.exist"); assert!(bad_cfg.is_ok()); assert!(bad_cfg.unwrap().is_none()); // repo init sets user.name - let good_cfg = get_config_string(rpath, "user.name"); + let good_cfg = get_config_string(&rpath.into(), "user.name"); assert!(good_cfg.is_ok()); assert!(good_cfg.unwrap().is_some()); } diff --git a/asyncgit/src/sync/cred.rs b/asyncgit/src/sync/cred.rs index 52e524d2aa..73161e13f5 100644 --- a/asyncgit/src/sync/cred.rs +++ b/asyncgit/src/sync/cred.rs @@ -1,10 +1,9 @@ //! credentials git helper -use super::remotes::get_default_remote_in_repo; -use crate::{ - error::{Error, Result}, - CWD, +use super::{ + remotes::get_default_remote_in_repo, repository::repo, RepoPath, }; +use crate::error::{Error, Result}; use git2::{Config, CredentialHelper}; /// basic Authentication Credentials @@ -31,8 +30,8 @@ impl BasicAuthCredential { } /// know if username and password are needed for this url -pub fn need_username_password() -> Result { - let repo = crate::sync::utils::repo(CWD)?; +pub fn need_username_password(repo_path: &RepoPath) -> Result { + let repo = repo(repo_path)?; let url = repo .find_remote(&get_default_remote_in_repo(&repo)?)? .url() @@ -43,8 +42,10 @@ pub fn need_username_password() -> Result { } /// extract username and password -pub fn extract_username_password() -> Result { - let repo = crate::sync::utils::repo(CWD)?; +pub fn extract_username_password( + repo_path: &RepoPath, +) -> Result { + let repo = repo(repo_path)?; let url = repo .find_remote(&get_default_remote_in_repo(&repo)?)? .url() @@ -88,9 +89,9 @@ mod tests { }, remotes::DEFAULT_REMOTE_NAME, tests::repo_init, + RepoPath, }; use serial_test::serial; - use std::env; #[test] fn test_credential_complete() { @@ -160,13 +161,15 @@ mod tests { fn test_need_username_password_if_https() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); - env::set_current_dir(repo_path).unwrap(); + //TODO: + // env::set_current_dir(repo_path).unwrap(); repo.remote(DEFAULT_REMOTE_NAME, "http://user@github.com") .unwrap(); - assert_eq!(need_username_password().unwrap(), true); + assert_eq!(need_username_password(repo_path).unwrap(), true); } #[test] @@ -174,13 +177,15 @@ mod tests { fn test_dont_need_username_password_if_ssh() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); - env::set_current_dir(repo_path).unwrap(); + //TODO: + // env::set_current_dir(repo_path).unwrap(); repo.remote(DEFAULT_REMOTE_NAME, "git@github.com:user/repo") .unwrap(); - assert_eq!(need_username_password().unwrap(), false); + assert_eq!(need_username_password(repo_path).unwrap(), false); } #[test] @@ -190,11 +195,13 @@ mod tests { ) { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); - env::set_current_dir(repo_path).unwrap(); + //TODO: + // env::set_current_dir(repo_path).unwrap(); - need_username_password().unwrap(); + need_username_password(repo_path).unwrap(); } #[test] @@ -202,9 +209,11 @@ mod tests { fn test_extract_username_password_from_repo() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); - env::set_current_dir(repo_path).unwrap(); + //TODO: + // env::set_current_dir(repo_path).unwrap(); repo.remote( DEFAULT_REMOTE_NAME, "http://user:pass@github.com", @@ -212,7 +221,7 @@ mod tests { .unwrap(); assert_eq!( - extract_username_password().unwrap(), + extract_username_password(repo_path).unwrap(), BasicAuthCredential::new( Some("user".to_owned()), Some("pass".to_owned()) @@ -225,14 +234,16 @@ mod tests { fn test_extract_username_from_repo() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); - env::set_current_dir(repo_path).unwrap(); + //TODO: + // env::set_current_dir(repo_path).unwrap(); repo.remote(DEFAULT_REMOTE_NAME, "http://user@github.com") .unwrap(); assert_eq!( - extract_username_password().unwrap(), + extract_username_password(repo_path).unwrap(), BasicAuthCredential::new(Some("user".to_owned()), None) ); } @@ -244,10 +255,12 @@ mod tests { ) { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); - env::set_current_dir(repo_path).unwrap(); + //TODO: not needed anymore? + // env::set_current_dir(repo_path).unwrap(); - extract_username_password().unwrap(); + extract_username_password(repo_path).unwrap(); } } diff --git a/asyncgit/src/sync/diff.rs b/asyncgit/src/sync/diff.rs index cd8b2b5766..e0f00d5a6a 100644 --- a/asyncgit/src/sync/diff.rs +++ b/asyncgit/src/sync/diff.rs @@ -2,10 +2,12 @@ use super::{ commit_files::{get_commit_diff, get_compare_commits_diff}, - utils::{self, get_head_repo, work_dir}, - CommitId, + utils::{get_head_repo, work_dir}, + CommitId, RepoPath, +}; +use crate::{ + error::Error, error::Result, hash, sync::repository::repo, }; -use crate::{error::Error, error::Result, hash}; use easy_cast::Conv; use git2::{ Delta, Diff, DiffDelta, DiffFormat, DiffHunk, Patch, Repository, @@ -192,14 +194,14 @@ pub(crate) fn get_diff_raw<'a>( /// returns diff of a specific file either in `stage` or workdir pub fn get_diff( - repo_path: &str, + repo_path: &RepoPath, p: &str, stage: bool, options: Option, ) -> Result { scope_time!("get_diff"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let work_dir = work_dir(&repo)?; let diff = get_diff_raw(&repo, p, stage, false, options)?; @@ -209,28 +211,28 @@ pub fn get_diff( /// returns diff of a specific file inside a commit /// see `get_commit_diff` pub fn get_diff_commit( - repo_path: &str, + repo_path: &RepoPath, id: CommitId, p: String, ) -> Result { scope_time!("get_diff_commit"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let work_dir = work_dir(&repo)?; - let diff = get_commit_diff(&repo, id, Some(p))?; + let diff = get_commit_diff(repo_path, &repo, id, Some(p))?; raw_diff_to_file_diff(&diff, work_dir) } /// get file changes of a diff between two commits pub fn get_diff_commits( - repo_path: &str, + repo_path: &RepoPath, ids: (CommitId, CommitId), p: String, ) -> Result { scope_time!("get_diff_commits"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let work_dir = work_dir(&repo)?; let diff = get_compare_commits_diff(&repo, (ids.0, ids.1), Some(p))?; @@ -403,11 +405,14 @@ fn new_file_content(path: &Path) -> Option> { #[cfg(test)] mod tests { use super::{get_diff, get_diff_commit}; - use crate::error::Result; - use crate::sync::{ - commit, stage_add_file, - status::{get_status, StatusType}, - tests::{get_statuses, repo_init, repo_init_empty}, + use crate::{ + error::Result, + sync::{ + commit, stage_add_file, + status::{get_status, StatusType}, + tests::{get_statuses, repo_init, repo_init_empty}, + RepoPath, + }, }; use std::{ fs::{self, File}, @@ -419,7 +424,8 @@ mod tests { fn test_untracked_subfolder() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); assert_eq!(get_statuses(repo_path), (0, 0)); @@ -443,7 +449,8 @@ mod tests { let file_path = Path::new("foo.txt"); let (_td, repo) = repo_init_empty().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); assert_eq!(get_statuses(repo_path), (0, 0)); @@ -499,7 +506,8 @@ mod tests { fn test_hunks() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); assert_eq!(get_statuses(repo_path), (0, 0)); @@ -551,7 +559,7 @@ mod tests { .unwrap(); let diff = get_diff( - sub_path.to_str().unwrap(), + &sub_path.to_str().unwrap().into(), file_path.to_str().unwrap(), false, None, @@ -566,7 +574,8 @@ mod tests { let file_path = Path::new("bar"); let (_td, repo) = repo_init_empty().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join(file_path))?.write_all(b"\x00")?; @@ -597,7 +606,8 @@ mod tests { let file_path = Path::new("bar"); let (_td, repo) = repo_init_empty().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join(file_path))? .write_all(b"\x00\xc7")?; @@ -622,7 +632,8 @@ mod tests { let file_path = Path::new("bar"); let (_td, repo) = repo_init_empty().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join(file_path))?.write_all(b"\x00")?; diff --git a/asyncgit/src/sync/hooks.rs b/asyncgit/src/sync/hooks.rs index fc076f5956..455e594abf 100644 --- a/asyncgit/src/sync/hooks.rs +++ b/asyncgit/src/sync/hooks.rs @@ -1,4 +1,4 @@ -use super::utils::{repo, work_dir}; +use super::{repository::repo, utils::work_dir, RepoPath}; use crate::error::{Error, Result}; use scopetime::scope_time; use std::{ @@ -18,7 +18,7 @@ const HOOK_COMMIT_MSG_TEMP_FILE: &str = ".git/COMMIT_EDITMSG"; /// the commit message at `.git/COMMIT_EDITMSG` and pass it's relative path as the only /// parameter to the hook script. pub fn hooks_commit_msg( - repo_path: &str, + repo_path: &RepoPath, msg: &mut String, ) -> Result { scope_time!("hooks_commit_msg"); @@ -48,7 +48,7 @@ pub fn hooks_commit_msg( /// this hook is documented here /// -pub fn hooks_pre_commit(repo_path: &str) -> Result { +pub fn hooks_pre_commit(repo_path: &RepoPath) -> Result { scope_time!("hooks_pre_commit"); let work_dir = work_dir_as_string(repo_path)?; @@ -60,7 +60,7 @@ pub fn hooks_pre_commit(repo_path: &str) -> Result { } } /// -pub fn hooks_post_commit(repo_path: &str) -> Result { +pub fn hooks_post_commit(repo_path: &RepoPath) -> Result { scope_time!("hooks_post_commit"); let work_dir = work_dir_as_string(repo_path)?; @@ -73,7 +73,7 @@ pub fn hooks_post_commit(repo_path: &str) -> Result { } } -fn work_dir_as_string(repo_path: &str) -> Result { +fn work_dir_as_string(repo_path: &RepoPath) -> Result { let repo = repo(repo_path)?; work_dir(&repo)? .to_str() @@ -163,7 +163,8 @@ mod tests { fn test_smoke() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); let mut msg = String::from("test"); let res = hooks_commit_msg(repo_path, &mut msg).unwrap(); @@ -195,7 +196,8 @@ mod tests { fn test_hooks_commit_msg_ok() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); let hook = b"#!/bin/sh exit 0 @@ -215,7 +217,8 @@ exit 0 fn test_pre_commit_sh() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); let hook = b"#!/bin/sh exit 0 @@ -230,7 +233,8 @@ exit 0 fn test_pre_commit_fail_sh() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); let hook = b"#!/bin/sh echo 'rejected' @@ -246,7 +250,8 @@ exit 1 fn test_pre_commit_py() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); // mirror how python pre-commmit sets itself up #[cfg(not(windows))] @@ -269,7 +274,8 @@ sys.exit(0) fn test_pre_commit_fail_py() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); // mirror how python pre-commmit sets itself up #[cfg(not(windows))] @@ -292,7 +298,8 @@ sys.exit(1) fn test_hooks_commit_msg_reject() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); let hook = b"#!/bin/sh echo 'msg' > $1 @@ -331,9 +338,11 @@ exit 1 fs::create_dir_all(&subfolder).unwrap(); let mut msg = String::from("test"); - let res = - hooks_commit_msg(subfolder.to_str().unwrap(), &mut msg) - .unwrap(); + let res = hooks_commit_msg( + &subfolder.to_str().unwrap().into(), + &mut msg, + ) + .unwrap(); assert_eq!( res, @@ -347,7 +356,8 @@ exit 1 fn test_commit_msg_no_block_but_alter() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); let hook = b"#!/bin/sh echo 'msg' > $1 @@ -379,7 +389,8 @@ exit 1 fs::create_dir_all(&subfolder).unwrap(); let res = - hooks_post_commit(subfolder.to_str().unwrap()).unwrap(); + hooks_post_commit(&subfolder.to_str().unwrap().into()) + .unwrap(); assert_eq!( res, diff --git a/asyncgit/src/sync/hunks.rs b/asyncgit/src/sync/hunks.rs index 333cd5007d..786c1c9079 100644 --- a/asyncgit/src/sync/hunks.rs +++ b/asyncgit/src/sync/hunks.rs @@ -1,17 +1,18 @@ use super::{ diff::{get_diff_raw, HunkHeader}, - utils::repo, + RepoPath, }; use crate::{ error::{Error, Result}, hash, + sync::repository::repo, }; use git2::{ApplyLocation, ApplyOptions, Diff}; use scopetime::scope_time; /// pub fn stage_hunk( - repo_path: &str, + repo_path: &RepoPath, file_path: &str, hunk_hash: u64, ) -> Result<()> { @@ -36,7 +37,7 @@ pub fn stage_hunk( /// this will fail for an all untracked file pub fn reset_hunk( - repo_path: &str, + repo_path: &RepoPath, file_path: &str, hunk_hash: u64, ) -> Result<()> { @@ -94,7 +95,7 @@ fn find_hunk_index(diff: &Diff, hunk_hash: u64) -> Option { /// pub fn unstage_hunk( - repo_path: &str, + repo_path: &RepoPath, file_path: &str, hunk_hash: u64, ) -> Result { @@ -162,15 +163,16 @@ mod tests { let file_path = Path::new("foo/foo.txt"); let (_td, repo) = repo_init_empty()?; let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); - + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); let sub_path = root.join("foo/"); fs::create_dir_all(&sub_path)?; File::create(&root.join(file_path))?.write_all(b"test")?; + let sub_path: &RepoPath = &sub_path.to_str().unwrap().into(); let diff = get_diff( - sub_path.to_str().unwrap(), + sub_path, file_path.to_str().unwrap(), false, None, diff --git a/asyncgit/src/sync/ignore.rs b/asyncgit/src/sync/ignore.rs index 4fee717850..ba9916a9c0 100644 --- a/asyncgit/src/sync/ignore.rs +++ b/asyncgit/src/sync/ignore.rs @@ -1,5 +1,8 @@ -use super::utils::{repo, work_dir}; -use crate::error::{Error, Result}; +use super::{utils::work_dir, RepoPath}; +use crate::{ + error::{Error, Result}, + sync::repository::repo, +}; use scopetime::scope_time; use std::{ fs::{File, OpenOptions}, @@ -11,7 +14,7 @@ static GITIGNORE: &str = ".gitignore"; /// add file or path to root ignore file pub fn add_to_ignore( - repo_path: &str, + repo_path: &RepoPath, path_to_ignore: &str, ) -> Result<()> { scope_time!("add_to_ignore"); @@ -71,7 +74,8 @@ mod tests { let file_path = Path::new("foo.txt"); let (_td, repo) = repo_init()?; let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join(file_path))?.write_all(b"test")?; @@ -98,7 +102,8 @@ mod tests { let file_path = Path::new("foo.txt"); let (_td, repo) = repo_init()?; let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join(file_path))?.write_all(b"test")?; File::create(&root.join(ignore_file_path))? @@ -119,7 +124,8 @@ mod tests { let file_path = Path::new("foo.txt"); let (_td, repo) = repo_init()?; let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join(file_path))?.write_all(b"test")?; File::create(&root.join(ignore_file_path))? @@ -139,7 +145,8 @@ mod tests { let ignore_file_path = Path::new(".gitignore"); let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); repo_write_file(&repo, ".gitignore", "#foo").unwrap(); diff --git a/asyncgit/src/sync/logwalker.rs b/asyncgit/src/sync/logwalker.rs index bbc2c2b85c..788ba74e46 100644 --- a/asyncgit/src/sync/logwalker.rs +++ b/asyncgit/src/sync/logwalker.rs @@ -108,6 +108,7 @@ impl<'a> LogWalker<'a> { mod tests { use super::*; use crate::error::Result; + use crate::sync::RepoPath; use crate::sync::{ commit, commit_files::get_commit_diff, get_commits_info, stage_add_file, tests::repo_init_empty, @@ -120,7 +121,8 @@ mod tests { let file_path = Path::new("foo"); let (_td, repo) = repo_init_empty().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join(file_path))?.write_all(b"a")?; stage_add_file(repo_path, file_path).unwrap(); @@ -144,7 +146,8 @@ mod tests { let file_path = Path::new("foo"); let (_td, repo) = repo_init_empty().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join(file_path))?.write_all(b"a")?; stage_add_file(repo_path, file_path).unwrap(); @@ -177,28 +180,31 @@ mod tests { let second_file_path = Path::new("baz"); let (_td, repo) = repo_init_empty().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: RepoPath = + root.as_os_str().to_str().unwrap().into(); File::create(&root.join(file_path))?.write_all(b"a")?; - stage_add_file(repo_path, file_path).unwrap(); + stage_add_file(&repo_path, file_path).unwrap(); - let _first_commit_id = commit(repo_path, "commit1").unwrap(); + let _first_commit_id = commit(&repo_path, "commit1").unwrap(); File::create(&root.join(second_file_path))? .write_all(b"a")?; - stage_add_file(repo_path, second_file_path).unwrap(); + stage_add_file(&repo_path, second_file_path).unwrap(); - let second_commit_id = commit(repo_path, "commit2").unwrap(); + let second_commit_id = commit(&repo_path, "commit2").unwrap(); File::create(&root.join(file_path))?.write_all(b"b")?; - stage_add_file(repo_path, file_path).unwrap(); + stage_add_file(&repo_path, file_path).unwrap(); - let _third_commit_id = commit(repo_path, "commit3").unwrap(); + let _third_commit_id = commit(&repo_path, "commit3").unwrap(); - let diff_contains_baz = |repo: &Repository, - commit_id: &CommitId| - -> Result { + let repo_path_clone = repo_path.clone(); + let diff_contains_baz = move |repo: &Repository, + commit_id: &CommitId| + -> Result { let diff = get_commit_diff( + &repo_path_clone, &repo, *commit_id, Some("baz".into()), @@ -222,10 +228,12 @@ mod tests { assert_eq!(items.len(), 0); - let diff_contains_bar = |repo: &Repository, - commit_id: &CommitId| - -> Result { + let repo_path_clone = repo_path.clone(); + let diff_contains_bar = move |repo: &Repository, + commit_id: &CommitId| + -> Result { let diff = get_commit_diff( + &repo_path_clone, &repo, *commit_id, Some("bar".into()), diff --git a/asyncgit/src/sync/merge.rs b/asyncgit/src/sync/merge.rs index dd31656592..ddcc0829f1 100644 --- a/asyncgit/src/sync/merge.rs +++ b/asyncgit/src/sync/merge.rs @@ -5,19 +5,23 @@ use crate::{ rebase::{ abort_rebase, continue_rebase, get_rebase_progress, }, - reset_stage, reset_workdir, utils, CommitId, + repository::repo, + reset_stage, reset_workdir, CommitId, }, }; use git2::{BranchType, Commit, MergeOptions, Repository}; use scopetime::scope_time; -use super::rebase::{RebaseProgress, RebaseState}; +use super::{ + rebase::{RebaseProgress, RebaseState}, + RepoPath, +}; /// -pub fn mergehead_ids(repo_path: &str) -> Result> { +pub fn mergehead_ids(repo_path: &RepoPath) -> Result> { scope_time!("mergehead_ids"); - let mut repo = utils::repo(repo_path)?; + let mut repo = repo(repo_path)?; let mut ids: Vec = Vec::new(); repo.mergehead_foreach(|id| { @@ -32,10 +36,10 @@ pub fn mergehead_ids(repo_path: &str) -> Result> { /// * reset all staged changes, /// * revert all changes in workdir /// * cleanup repo merge state -pub fn abort_merge(repo_path: &str) -> Result<()> { +pub fn abort_merge(repo_path: &RepoPath) -> Result<()> { scope_time!("cleanup_state"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; reset_stage(repo_path, "*")?; reset_workdir(repo_path, "*")?; @@ -47,13 +51,13 @@ pub fn abort_merge(repo_path: &str) -> Result<()> { /// pub fn merge_branch( - repo_path: &str, + repo_path: &RepoPath, branch: &str, branch_type: BranchType, ) -> Result<()> { scope_time!("merge_branch"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; merge_branch_repo(&repo, branch, branch_type)?; @@ -61,30 +65,32 @@ pub fn merge_branch( } /// -pub fn rebase_progress(repo_path: &str) -> Result { +pub fn rebase_progress( + repo_path: &RepoPath, +) -> Result { scope_time!("rebase_progress"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; get_rebase_progress(&repo) } /// pub fn continue_pending_rebase( - repo_path: &str, + repo_path: &RepoPath, ) -> Result { scope_time!("continue_pending_rebase"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; continue_rebase(&repo) } /// -pub fn abort_pending_rebase(repo_path: &str) -> Result<()> { +pub fn abort_pending_rebase(repo_path: &RepoPath) -> Result<()> { scope_time!("abort_pending_rebase"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; abort_rebase(&repo) } @@ -115,10 +121,10 @@ pub fn merge_branch_repo( } /// -pub fn merge_msg(repo_path: &str) -> Result { +pub fn merge_msg(repo_path: &RepoPath) -> Result { scope_time!("merge_msg"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let content = repo.message()?; Ok(content) @@ -126,13 +132,13 @@ pub fn merge_msg(repo_path: &str) -> Result { /// pub fn merge_commit( - repo_path: &str, + repo_path: &RepoPath, msg: &str, ids: &[CommitId], ) -> Result { scope_time!("merge_commit"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let mut commits: Vec = Vec::new(); @@ -151,6 +157,7 @@ mod tests { use crate::sync::{ create_branch, tests::{repo_init, write_commit_file}, + RepoPath, }; use pretty_assertions::assert_eq; @@ -158,7 +165,8 @@ mod tests { fn test_smoke() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); let c1 = write_commit_file(&repo, "test.txt", "test", "commit1"); diff --git a/asyncgit/src/sync/mod.rs b/asyncgit/src/sync/mod.rs index 6c9ca156e7..0a1809912f 100644 --- a/asyncgit/src/sync/mod.rs +++ b/asyncgit/src/sync/mod.rs @@ -20,6 +20,7 @@ mod merge; mod patches; mod rebase; pub mod remotes; +mod repository; mod reset; mod staging; mod stash; @@ -68,6 +69,8 @@ pub use remotes::{ get_default_remote, get_remotes, push::AsyncProgress, tags::PushTagsProgress, }; +pub(crate) use repository::repo; +pub use repository::{RepoPath, RepoPathRef}; pub use reset::{reset_stage, reset_workdir}; pub use staging::{discard_lines, stage_lines}; pub use stash::{ @@ -80,17 +83,19 @@ pub use tags::{ }; pub use tree::{tree_file_content, tree_files, TreeFile}; pub use utils::{ - get_head, get_head_tuple, is_bare_repo, is_repo, repo_dir, - stage_add_all, stage_add_file, stage_addremoved, Head, + get_head, get_head_tuple, is_repo, repo_dir, stage_add_all, + stage_add_file, stage_addremoved, Head, }; #[cfg(test)] mod tests { use super::{ - commit, stage_add_file, + commit, + repository::repo, + stage_add_file, status::{get_status, StatusType}, - utils::{get_head_repo, repo, repo_write_file}, - CommitId, LogWalker, + utils::{get_head_repo, repo_write_file}, + CommitId, LogWalker, RepoPath, }; use crate::error::Result; use git2::Repository; @@ -129,13 +134,16 @@ mod tests { repo_write_file(repo, file, content).unwrap(); stage_add_file( - repo.workdir().unwrap().to_str().unwrap(), + &repo.workdir().unwrap().to_str().unwrap().into(), Path::new(file), ) .unwrap(); - commit(repo.workdir().unwrap().to_str().unwrap(), commit_name) - .unwrap() + commit( + &repo.workdir().unwrap().to_str().unwrap().into(), + commit_name, + ) + .unwrap() } /// write, stage and commit a file giving the commit a specific timestamp @@ -148,7 +156,8 @@ mod tests { ) -> CommitId { repo_write_file(repo, file, content).unwrap(); - let path = repo.workdir().unwrap().to_str().unwrap(); + let path: &RepoPath = + &repo.workdir().unwrap().to_str().unwrap().into(); stage_add_file(path, Path::new(file)).unwrap(); @@ -156,7 +165,7 @@ mod tests { } fn commit_at( - repo_path: &str, + repo_path: &RepoPath, msg: &str, time: git2::Time, ) -> CommitId { @@ -258,7 +267,7 @@ mod tests { } /// helper returning amount of files with changes in the (wd,stage) - pub fn get_statuses(repo_path: &str) -> (usize, usize) { + pub fn get_statuses(repo_path: &RepoPath) -> (usize, usize) { ( get_status(repo_path, StatusType::WorkingDir, None) .unwrap() @@ -270,7 +279,7 @@ mod tests { } /// - pub fn debug_cmd_print(path: &str, cmd: &str) { + pub fn debug_cmd_print(path: &RepoPath, cmd: &str) { let cmd = debug_cmd(path, cmd); eprintln!("\n----\n{}", cmd); } @@ -289,18 +298,18 @@ mod tests { commit_ids } - fn debug_cmd(path: &str, cmd: &str) -> String { + fn debug_cmd(path: &RepoPath, cmd: &str) -> String { let output = if cfg!(target_os = "windows") { Command::new("cmd") .args(&["/C", cmd]) - .current_dir(path) + .current_dir(path.gitpath()) .output() .unwrap() } else { Command::new("sh") .arg("-c") .arg(cmd) - .current_dir(path) + .current_dir(path.gitpath()) .output() .unwrap() }; diff --git a/asyncgit/src/sync/rebase.rs b/asyncgit/src/sync/rebase.rs index fdccafda69..8fc289d03c 100644 --- a/asyncgit/src/sync/rebase.rs +++ b/asyncgit/src/sync/rebase.rs @@ -3,20 +3,20 @@ use scopetime::scope_time; use crate::{ error::{Error, Result}, - sync::utils, + sync::repository::repo, }; -use super::CommitId; +use super::{CommitId, RepoPath}; /// rebase current HEAD on `branch` pub fn rebase_branch( - repo_path: &str, + repo_path: &RepoPath, branch: &str, branch_type: BranchType, ) -> Result { scope_time!("rebase_branch"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; rebase_branch_repo(&repo, branch, branch_type) } @@ -189,8 +189,9 @@ mod test_conflict_free_rebase { checkout_branch, create_branch, rebase::{rebase_branch, RebaseState}, repo_state, + repository::repo, tests::{repo_init, write_commit_file}, - utils, CommitId, RepoState, + CommitId, RepoPath, RepoState, }; use git2::{BranchType, Repository}; @@ -209,10 +210,10 @@ mod test_conflict_free_rebase { /// fn test_rebase_branch_repo( - repo_path: &str, + repo_path: &RepoPath, branch_name: &str, ) -> CommitId { - let repo = utils::repo(repo_path).unwrap(); + let repo = repo(repo_path).unwrap(); let branch = repo.find_branch(branch_name, BranchType::Local).unwrap(); @@ -228,7 +229,8 @@ mod test_conflict_free_rebase { fn test_smoke() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); let c1 = write_commit_file(&repo, "test1.txt", "test", "commit1"); @@ -256,7 +258,8 @@ mod test_conflict_free_rebase { fn test_conflict() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); write_commit_file(&repo, "test.txt", "test1", "commit1"); @@ -289,7 +292,7 @@ mod test_rebase { }, rebase_branch, repo_state, tests::{repo_init, write_commit_file}, - RepoState, + RepoPath, RepoState, }; use git2::BranchType; @@ -297,7 +300,8 @@ mod test_rebase { fn test_conflicted_abort() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); write_commit_file(&repo, "test.txt", "test1", "commit1"); diff --git a/asyncgit/src/sync/remotes/mod.rs b/asyncgit/src/sync/remotes/mod.rs index aae4b2a1df..b0c57d262d 100644 --- a/asyncgit/src/sync/remotes/mod.rs +++ b/asyncgit/src/sync/remotes/mod.rs @@ -8,7 +8,7 @@ use crate::{ error::{Error, Result}, sync::{ cred::BasicAuthCredential, - remotes::push::ProgressNotification, utils, + remotes::push::ProgressNotification, repository::repo, utils, }, ProgressPercent, }; @@ -20,14 +20,16 @@ use utils::bytes2string; pub use callbacks::Callbacks; pub use tags::tags_missing_remote; +use super::RepoPath; + /// origin pub const DEFAULT_REMOTE_NAME: &str = "origin"; /// -pub fn get_remotes(repo_path: &str) -> Result> { +pub fn get_remotes(repo_path: &RepoPath) -> Result> { scope_time!("get_remotes"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let remotes = repo.remotes()?; let remotes: Vec = remotes.iter().flatten().map(String::from).collect(); @@ -37,8 +39,8 @@ pub fn get_remotes(repo_path: &str) -> Result> { /// 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)?; +pub fn get_default_remote(repo_path: &RepoPath) -> Result { + let repo = repo(repo_path)?; get_default_remote_in_repo(&repo) } @@ -78,12 +80,12 @@ pub(crate) fn get_default_remote_in_repo( /// fn fetch_from_remote( - repo_path: &str, + repo_path: &RepoPath, remote: &str, basic_credential: Option, progress_sender: Option>, ) -> Result<()> { - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let mut remote = repo.find_remote(remote)?; @@ -99,13 +101,13 @@ fn fetch_from_remote( /// updates/prunes all branches from all remotes pub fn fetch_all( - repo_path: &str, + repo_path: &RepoPath, basic_credential: &Option, progress_sender: &Option>, ) -> Result<()> { scope_time!("fetch_all"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let remotes = repo .remotes()? .iter() @@ -133,14 +135,14 @@ pub fn fetch_all( /// fetches from upstream/remote for local `branch` pub(crate) fn fetch( - repo_path: &str, + repo_path: &RepoPath, branch: &str, basic_credential: Option, progress_sender: Option>, ) -> Result { scope_time!("fetch"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let branch_ref = repo .find_branch(branch, BranchType::Local)? .into_reference(); @@ -171,7 +173,12 @@ mod tests { let (remote_dir, _remote) = repo_init().unwrap(); let remote_path = remote_dir.path().to_str().unwrap(); let (repo_dir, _repo) = repo_clone(remote_path).unwrap(); - let repo_path = repo_dir.path().as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = &repo_dir + .into_path() + .as_os_str() + .to_str() + .unwrap() + .into(); let remotes = get_remotes(repo_path).unwrap(); @@ -185,7 +192,12 @@ mod tests { let (remote_dir, _remote) = repo_init().unwrap(); let remote_path = remote_dir.path().to_str().unwrap(); let (repo_dir, _repo) = repo_clone(remote_path).unwrap(); - let repo_path = repo_dir.path().as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = &repo_dir + .into_path() + .as_os_str() + .to_str() + .unwrap() + .into(); debug_cmd_print( repo_path, @@ -199,10 +211,9 @@ mod tests { vec![String::from("origin"), String::from("second")] ); - let first = get_default_remote_in_repo( - &utils::repo(repo_path).unwrap(), - ) - .unwrap(); + let first = + get_default_remote_in_repo(&repo(repo_path).unwrap()) + .unwrap(); assert_eq!(first, String::from("origin")); } @@ -211,7 +222,12 @@ mod tests { let (remote_dir, _remote) = repo_init().unwrap(); let remote_path = remote_dir.path().to_str().unwrap(); let (repo_dir, _repo) = repo_clone(remote_path).unwrap(); - let repo_path = repo_dir.path().as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = &repo_dir + .into_path() + .as_os_str() + .to_str() + .unwrap() + .into(); debug_cmd_print( repo_path, @@ -231,10 +247,9 @@ mod tests { vec![String::from("alternate"), String::from("origin")] ); - let first = get_default_remote_in_repo( - &utils::repo(repo_path).unwrap(), - ) - .unwrap(); + let first = + get_default_remote_in_repo(&repo(repo_path).unwrap()) + .unwrap(); assert_eq!(first, String::from("origin")); } @@ -243,7 +258,12 @@ mod tests { let (remote_dir, _remote) = repo_init().unwrap(); let remote_path = remote_dir.path().to_str().unwrap(); let (repo_dir, _repo) = repo_clone(remote_path).unwrap(); - let repo_path = repo_dir.path().as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = &repo_dir + .into_path() + .as_os_str() + .to_str() + .unwrap() + .into(); debug_cmd_print( repo_path, @@ -264,9 +284,8 @@ mod tests { ] ); - let res = get_default_remote_in_repo( - &utils::repo(repo_path).unwrap(), - ); + let res = + get_default_remote_in_repo(&repo(repo_path).unwrap()); assert_eq!(res.is_err(), true); assert!(matches!(res, Err(Error::NoDefaultRemoteFound))); } diff --git a/asyncgit/src/sync/remotes/push.rs b/asyncgit/src/sync/remotes/push.rs index cb661a0309..94589c0c85 100644 --- a/asyncgit/src/sync/remotes/push.rs +++ b/asyncgit/src/sync/remotes/push.rs @@ -1,10 +1,9 @@ -use super::utils; use crate::{ error::{Error, Result}, progress::ProgressPercent, sync::{ branch::branch_set_upstream, cred::BasicAuthCredential, - remotes::Callbacks, CommitId, + remotes::Callbacks, repository::repo, CommitId, RepoPath, }, }; use crossbeam_channel::Sender; @@ -91,7 +90,7 @@ impl AsyncProgress for ProgressNotification { #[allow(clippy::redundant_pub_crate)] pub(crate) fn push( - repo_path: &str, + repo_path: &RepoPath, remote: &str, branch: &str, force: bool, @@ -101,7 +100,7 @@ pub(crate) fn push( ) -> Result<()> { scope_time!("push"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let mut remote = repo.find_remote(remote)?; let mut options = PushOptions::new(); @@ -178,13 +177,13 @@ mod tests { writeln!(tmp_repo_file, "TempSomething").unwrap(); sync::commit( - tmp_repo_dir.path().to_str().unwrap(), + &tmp_repo_dir.path().to_str().unwrap().into(), "repo_1_commit", ) .unwrap(); push( - tmp_repo_dir.path().to_str().unwrap(), + &tmp_repo_dir.path().to_str().unwrap().into(), "origin", "master", false, @@ -201,7 +200,7 @@ mod tests { writeln!(tmp_other_repo_file, "TempElse").unwrap(); sync::commit( - tmp_other_repo_dir.path().to_str().unwrap(), + &tmp_other_repo_dir.path().to_str().unwrap().into(), "repo_2_commit", ) .unwrap(); @@ -210,7 +209,7 @@ mod tests { // should fail as branches diverged assert_eq!( push( - tmp_other_repo_dir.path().to_str().unwrap(), + &tmp_other_repo_dir.path().to_str().unwrap().into(), "origin", "master", false, @@ -226,7 +225,7 @@ mod tests { // should work as it forces the push through assert_eq!( push( - tmp_other_repo_dir.path().to_str().unwrap(), + &tmp_other_repo_dir.path().to_str().unwrap().into(), "origin", "master", true, @@ -269,13 +268,13 @@ mod tests { writeln!(tmp_repo_file, "TempSomething").unwrap(); sync::stage_add_file( - tmp_repo_dir.path().to_str().unwrap(), + &tmp_repo_dir.path().to_str().unwrap().into(), Path::new("temp_file.txt"), ) .unwrap(); let repo_1_commit = sync::commit( - tmp_repo_dir.path().to_str().unwrap(), + &tmp_repo_dir.path().to_str().unwrap().into(), "repo_1_commit", ) .unwrap(); @@ -283,7 +282,7 @@ mod tests { //NOTE: make sure the commit actually contains that file assert_eq!( sync::get_commit_files( - tmp_repo_dir.path().to_str().unwrap(), + &tmp_repo_dir.path().to_str().unwrap().into(), repo_1_commit, None ) @@ -296,7 +295,7 @@ mod tests { assert!(commits.contains(&repo_1_commit)); push( - tmp_repo_dir.path().to_str().unwrap(), + &tmp_repo_dir.path().to_str().unwrap().into(), "origin", "master", false, @@ -313,13 +312,13 @@ mod tests { writeln!(tmp_other_repo_file, "TempElse").unwrap(); sync::stage_add_file( - tmp_other_repo_dir.path().to_str().unwrap(), + &tmp_other_repo_dir.path().to_str().unwrap().into(), Path::new("temp_file.txt"), ) .unwrap(); let repo_2_commit = sync::commit( - tmp_other_repo_dir.path().to_str().unwrap(), + &tmp_other_repo_dir.path().to_str().unwrap().into(), "repo_2_commit", ) .unwrap(); @@ -339,7 +338,7 @@ mod tests { // should fail as branches diverged assert_eq!( push( - tmp_other_repo_dir.path().to_str().unwrap(), + &tmp_other_repo_dir.path().to_str().unwrap().into(), "origin", "master", false, @@ -360,7 +359,7 @@ mod tests { // should work as it forces the push through push( - tmp_other_repo_dir.path().to_str().unwrap(), + &tmp_other_repo_dir.path().to_str().unwrap().into(), "origin", "master", true, @@ -407,7 +406,7 @@ mod tests { assert!(commits.contains(&commit_1)); push( - tmp_repo_dir.path().to_str().unwrap(), + &tmp_repo_dir.path().to_str().unwrap().into(), "origin", "master", false, @@ -419,14 +418,14 @@ mod tests { // Create the local branch sync::create_branch( - tmp_repo_dir.path().to_str().unwrap(), + &tmp_repo_dir.path().to_str().unwrap().into(), "test_branch", ) .unwrap(); // Push the local branch push( - tmp_repo_dir.path().to_str().unwrap(), + &tmp_repo_dir.path().to_str().unwrap().into(), "origin", "test_branch", false, @@ -452,7 +451,7 @@ mod tests { // Delete the remote branch assert_eq!( push( - tmp_repo_dir.path().to_str().unwrap(), + &tmp_repo_dir.path().to_str().unwrap().into(), "origin", "test_branch", false, diff --git a/asyncgit/src/sync/remotes/tags.rs b/asyncgit/src/sync/remotes/tags.rs index 6cae198e76..0c7a045f35 100644 --- a/asyncgit/src/sync/remotes/tags.rs +++ b/asyncgit/src/sync/remotes/tags.rs @@ -1,10 +1,13 @@ //! -use super::{push::AsyncProgress, utils}; +use super::push::AsyncProgress; use crate::{ error::Result, progress::ProgressPercent, - sync::{cred::BasicAuthCredential, remotes::Callbacks}, + sync::{ + cred::BasicAuthCredential, remotes::Callbacks, + repository::repo, RepoPath, + }, }; use crossbeam_channel::Sender; use git2::{Direction, PushOptions}; @@ -44,13 +47,13 @@ impl AsyncProgress for PushTagsProgress { /// lists the remotes tags fn remote_tag_refs( - repo_path: &str, + repo_path: &RepoPath, remote: &str, basic_credential: Option, ) -> Result> { scope_time!("remote_tags"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let mut remote = repo.find_remote(remote)?; let callbacks = Callbacks::new(None, basic_credential); let conn = remote.connect_auth( @@ -73,13 +76,13 @@ fn remote_tag_refs( /// lists the remotes tags missing pub fn tags_missing_remote( - repo_path: &str, + repo_path: &RepoPath, remote: &str, basic_credential: Option, ) -> Result> { scope_time!("tags_missing_remote"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let tags = repo.tag_names(None)?; let mut local_tags = tags @@ -98,7 +101,7 @@ pub fn tags_missing_remote( /// pub fn push_tags( - repo_path: &str, + repo_path: &RepoPath, remote: &str, basic_credential: Option, progress_sender: Option>, @@ -115,7 +118,7 @@ pub fn push_tags( basic_credential.clone(), )?; - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let mut remote = repo.find_remote(remote)?; let total = tags_missing.len(); @@ -165,11 +168,13 @@ mod tests { let (clone1_dir, clone1) = repo_clone(r1_dir).unwrap(); - let clone1_dir = clone1_dir.path().to_str().unwrap(); + let clone1_dir: &RepoPath = + &clone1_dir.path().to_str().unwrap().into(); let (clone2_dir, clone2) = repo_clone(r1_dir).unwrap(); - let clone2_dir = clone2_dir.path().to_str().unwrap(); + let clone2_dir: &RepoPath = + &clone2_dir.path().to_str().unwrap().into(); // clone1 @@ -211,11 +216,13 @@ mod tests { let (clone1_dir, clone1) = repo_clone(r1_dir).unwrap(); - let clone1_dir = clone1_dir.path().to_str().unwrap(); + let clone1_dir: &RepoPath = + &clone1_dir.path().to_str().unwrap().into(); let (clone2_dir, _clone2) = repo_clone(r1_dir).unwrap(); - let clone2_dir = clone2_dir.path().to_str().unwrap(); + let clone2_dir: &RepoPath = + &clone2_dir.path().to_str().unwrap().into(); // clone1 @@ -248,7 +255,8 @@ mod tests { let (clone1_dir, clone1) = repo_clone(r1_dir).unwrap(); - let clone1_dir = clone1_dir.path().to_str().unwrap(); + let clone1_dir: &RepoPath = + &clone1_dir.path().to_str().unwrap().into(); // clone1 @@ -281,7 +289,8 @@ mod tests { let r1_dir = r1_dir.path().to_str().unwrap(); let (clone1_dir, clone1) = repo_clone(r1_dir).unwrap(); - let clone1_dir = clone1_dir.path().to_str().unwrap(); + let clone1_dir: &RepoPath = + &clone1_dir.path().to_str().unwrap().into(); let commit1 = write_commit_file(&clone1, "test.txt", "test", "commit1"); @@ -291,7 +300,8 @@ mod tests { .unwrap(); let (clone2_dir, _clone2) = repo_clone(r1_dir).unwrap(); - let clone2_dir = clone2_dir.path().to_str().unwrap(); + let clone2_dir: &RepoPath = + &clone2_dir.path().to_str().unwrap().into(); // clone1 - creates tag @@ -319,7 +329,8 @@ mod tests { let r1_dir = r1_dir.path().to_str().unwrap(); let (clone1_dir, clone1) = repo_clone(r1_dir).unwrap(); - let clone1_dir = clone1_dir.path().to_str().unwrap(); + let clone1_dir: &RepoPath = + &clone1_dir.path().to_str().unwrap().into(); let commit1 = write_commit_file(&clone1, "test.txt", "test", "commit1"); @@ -329,7 +340,8 @@ mod tests { .unwrap(); let (clone2_dir, _clone2) = repo_clone(r1_dir).unwrap(); - let clone2_dir = clone2_dir.path().to_str().unwrap(); + let clone2_dir: &RepoPath = + &clone2_dir.path().to_str().unwrap().into(); // clone1 - creates tag diff --git a/asyncgit/src/sync/repository.rs b/asyncgit/src/sync/repository.rs new file mode 100644 index 0000000000..1fad120617 --- /dev/null +++ b/asyncgit/src/sync/repository.rs @@ -0,0 +1,63 @@ +use std::{ + cell::RefCell, + path::{Path, PathBuf}, +}; + +use git2::{Repository, RepositoryOpenFlags}; + +use crate::error::Result; + +/// +pub type RepoPathRef = RefCell; + +/// +#[derive(Clone)] +pub enum RepoPath { + /// + Path(PathBuf), + /// + Workdir { + /// + gitdir: PathBuf, + /// + workdir: PathBuf, + }, +} + +impl RepoPath { + /// + pub fn gitpath(&self) -> &Path { + match self { + Self::Path(p) => p.as_path(), + Self::Workdir { gitdir, .. } => gitdir.as_path(), + } + } + + /// + pub fn workdir(&self) -> Option<&Path> { + match self { + Self::Path(_) => None, + Self::Workdir { workdir, .. } => Some(workdir.as_path()), + } + } +} + +impl From<&str> for RepoPath { + fn from(p: &str) -> Self { + Self::Path(PathBuf::from(p)) + } +} + +pub fn repo(repo_path: &RepoPath) -> Result { + let repo = Repository::open_ext( + repo_path.gitpath(), + RepositoryOpenFlags::empty(), + Vec::<&Path>::new(), + )?; + + if let Some(workdir) = repo_path.workdir() { + repo.set_workdir(workdir, false)?; + } + + Ok(repo) +} diff --git a/asyncgit/src/sync/reset.rs b/asyncgit/src/sync/reset.rs index 147737b8d9..f057f231c4 100644 --- a/asyncgit/src/sync/reset.rs +++ b/asyncgit/src/sync/reset.rs @@ -1,10 +1,10 @@ -use super::utils::{get_head_repo, repo}; -use crate::error::Result; +use super::{utils::get_head_repo, RepoPath}; +use crate::{error::Result, sync::repository::repo}; use git2::{build::CheckoutBuilder, ObjectType}; use scopetime::scope_time; /// -pub fn reset_stage(repo_path: &str, path: &str) -> Result<()> { +pub fn reset_stage(repo_path: &RepoPath, path: &str) -> Result<()> { scope_time!("reset_stage"); let repo = repo(repo_path)?; @@ -22,7 +22,7 @@ pub fn reset_stage(repo_path: &str, path: &str) -> Result<()> { } /// -pub fn reset_workdir(repo_path: &str, path: &str) -> Result<()> { +pub fn reset_workdir(repo_path: &RepoPath, path: &str) -> Result<()> { scope_time!("reset_workdir"); let repo = repo(repo_path)?; @@ -49,6 +49,7 @@ mod tests { debug_cmd_print, get_statuses, repo_init, repo_init_empty, }, utils::{stage_add_all, stage_add_file}, + RepoPath, }; use std::{ fs::{self, File}, @@ -86,7 +87,8 @@ mod tests { fn test_reset_only_unstaged() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); let res = get_status(repo_path, StatusType::WorkingDir, None) .unwrap(); @@ -130,7 +132,8 @@ mod tests { fn test_reset_untracked_in_subdir() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); { fs::create_dir(&root.join("foo")).unwrap(); @@ -155,7 +158,8 @@ mod tests { fn test_reset_folder() -> Result<()> { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); { fs::create_dir(&root.join("foo"))?; @@ -200,7 +204,8 @@ mod tests { fn test_reset_untracked_in_subdir_and_index() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); let file = "foo/bar.txt"; { @@ -240,7 +245,8 @@ mod tests { let file_path = Path::new("foo.txt"); let (_td, repo) = repo_init_empty().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join(file_path)) .unwrap() @@ -262,7 +268,8 @@ mod tests { fn test_reset_untracked_in_subdir_with_cwd_in_subdir() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); { fs::create_dir(&root.join("foo")).unwrap(); @@ -277,7 +284,7 @@ mod tests { assert_eq!(get_statuses(repo_path), (1, 0)); reset_workdir( - &root.join("foo").as_os_str().to_str().unwrap(), + &root.join("foo").as_os_str().to_str().unwrap().into(), "foo/bar.txt", ) .unwrap(); @@ -291,7 +298,8 @@ mod tests { fn test_reset_untracked_subdir() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); { fs::create_dir_all(&root.join("foo/bar")).unwrap(); diff --git a/asyncgit/src/sync/staging/discard_tracked.rs b/asyncgit/src/sync/staging/discard_tracked.rs index bc10bfd1e5..022aab99b5 100644 --- a/asyncgit/src/sync/staging/discard_tracked.rs +++ b/asyncgit/src/sync/staging/discard_tracked.rs @@ -1,15 +1,17 @@ use super::{apply_selection, load_file}; -use crate::error::Result; -use crate::sync::{ - diff::DiffLinePosition, - patches::get_file_diff_patch_and_hunklines, - utils::{repo, repo_write_file}, +use crate::{ + error::Result, + sync::{ + diff::DiffLinePosition, + patches::get_file_diff_patch_and_hunklines, repository::repo, + utils::repo_write_file, RepoPath, + }, }; use scopetime::scope_time; /// discards specific lines in an unstaged hunk of a diff pub fn discard_lines( - repo_path: &str, + repo_path: &RepoPath, file_path: &str, lines: &[DiffLinePosition], ) -> Result<()> { @@ -69,7 +71,7 @@ mod test { "; let (path, repo) = repo_init().unwrap(); - let path = path.path().to_str().unwrap(); + let path: &RepoPath = &path.path().to_str().unwrap().into(); write_commit_file(&repo, "test.txt", FILE_1, "c1"); @@ -114,7 +116,7 @@ end "; let (path, repo) = repo_init().unwrap(); - let path = path.path().to_str().unwrap(); + let path: &RepoPath = &path.path().to_str().unwrap().into(); write_commit_file(&repo, "test.txt", FILE_1, "c1"); @@ -153,7 +155,7 @@ end "; let (path, repo) = repo_init().unwrap(); - let path = path.path().to_str().unwrap(); + let path: &RepoPath = &path.path().to_str().unwrap().into(); write_commit_file(&repo, "test.txt", FILE_1, "c1"); @@ -200,7 +202,7 @@ end "; let (path, repo) = repo_init().unwrap(); - let path = path.path().to_str().unwrap(); + let path: &RepoPath = &path.path().to_str().unwrap().into(); write_commit_file(&repo, "test.txt", FILE_1, "c1"); @@ -243,7 +245,7 @@ end "; let (path, repo) = repo_init().unwrap(); - let path = path.path().to_str().unwrap(); + let path: &RepoPath = &path.path().to_str().unwrap().into(); write_commit_file(&repo, "test.txt", FILE_1, "c1"); @@ -288,7 +290,7 @@ end "; let (path, repo) = repo_init().unwrap(); - let path = path.path().to_str().unwrap(); + let path: &RepoPath = &path.path().to_str().unwrap().into(); write_commit_file(&repo, "test.txt", FILE_1, "c1"); @@ -321,7 +323,7 @@ end "; let (path, repo) = repo_init().unwrap(); - let path = path.path().to_str().unwrap(); + let path: &RepoPath = &path.path().to_str().unwrap().into(); write_commit_file(&repo, "test.txt", FILE_1, "c1"); diff --git a/asyncgit/src/sync/staging/stage_tracked.rs b/asyncgit/src/sync/staging/stage_tracked.rs index 99c6fa54b1..5f9861a131 100644 --- a/asyncgit/src/sync/staging/stage_tracked.rs +++ b/asyncgit/src/sync/staging/stage_tracked.rs @@ -3,7 +3,8 @@ use crate::{ error::{Error, Result}, sync::{ diff::DiffLinePosition, - patches::get_file_diff_patch_and_hunklines, utils::repo, + patches::get_file_diff_patch_and_hunklines, repository::repo, + RepoPath, }, }; use easy_cast::Conv; @@ -12,7 +13,7 @@ use std::path::Path; /// pub fn stage_lines( - repo_path: &str, + repo_path: &RepoPath, file_path: &str, is_stage: bool, lines: &[DiffLinePosition], @@ -80,7 +81,7 @@ mod test { "; let (path, repo) = repo_init().unwrap(); - let path = path.path().to_str().unwrap(); + let path: &RepoPath = &path.path().to_str().unwrap().into(); write_commit_file(&repo, "test.txt", FILE_1, "c1"); @@ -113,7 +114,7 @@ b = 3 c = 4"; let (path, repo) = repo_init().unwrap(); - let path = path.path().to_str().unwrap(); + let path: &RepoPath = &path.path().to_str().unwrap().into(); write_commit_file(&repo, "test.txt", FILE_1, "c1"); @@ -154,7 +155,7 @@ c = 4"; "; let (path, repo) = repo_init().unwrap(); - let path = path.path().to_str().unwrap(); + let path: &RepoPath = &path.path().to_str().unwrap().into(); write_commit_file(&repo, "test.txt", FILE_1, "c1"); diff --git a/asyncgit/src/sync/stash.rs b/asyncgit/src/sync/stash.rs index 7c8ca43bfe..9a269db0f0 100644 --- a/asyncgit/src/sync/stash.rs +++ b/asyncgit/src/sync/stash.rs @@ -1,5 +1,8 @@ -use super::{utils::repo, CommitId}; -use crate::error::{Error, Result}; +use super::{CommitId, RepoPath}; +use crate::{ + error::{Error, Result}, + sync::repository::repo, +}; use git2::{ build::CheckoutBuilder, Oid, Repository, StashApplyOptions, StashFlags, @@ -7,7 +10,7 @@ use git2::{ use scopetime::scope_time; /// -pub fn get_stashes(repo_path: &str) -> Result> { +pub fn get_stashes(repo_path: &RepoPath) -> Result> { scope_time!("get_stashes"); let mut repo = repo(repo_path)?; @@ -24,7 +27,7 @@ pub fn get_stashes(repo_path: &str) -> Result> { /// checks whether a given commit is a stash commit. pub fn is_stash_commit( - repo_path: &str, + repo_path: &RepoPath, id: &CommitId, ) -> Result { let stashes = get_stashes(repo_path)?; @@ -32,7 +35,10 @@ pub fn is_stash_commit( } /// -pub fn stash_drop(repo_path: &str, stash_id: CommitId) -> Result<()> { +pub fn stash_drop( + repo_path: &RepoPath, + stash_id: CommitId, +) -> Result<()> { scope_time!("stash_drop"); let mut repo = repo(repo_path)?; @@ -45,7 +51,10 @@ pub fn stash_drop(repo_path: &str, stash_id: CommitId) -> Result<()> { } /// -pub fn stash_pop(repo_path: &str, stash_id: CommitId) -> Result<()> { +pub fn stash_pop( + repo_path: &RepoPath, + stash_id: CommitId, +) -> Result<()> { scope_time!("stash_pop"); let mut repo = repo(repo_path)?; @@ -59,7 +68,7 @@ pub fn stash_pop(repo_path: &str, stash_id: CommitId) -> Result<()> { /// pub fn stash_apply( - repo_path: &str, + repo_path: &RepoPath, stash_id: CommitId, allow_conflicts: bool, ) -> Result<()> { @@ -101,7 +110,7 @@ fn get_stash_index( /// pub fn stash_save( - repo_path: &str, + repo_path: &RepoPath, message: Option<&str>, include_untracked: bool, keep_index: bool, @@ -143,7 +152,8 @@ mod tests { fn test_smoke() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); assert_eq!( stash_save(repo_path, None, true, false).is_ok(), @@ -157,7 +167,8 @@ mod tests { fn test_stashing() -> Result<()> { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join("foo.txt"))? .write_all(b"test\nfoo")?; @@ -175,7 +186,8 @@ mod tests { fn test_stashes() -> Result<()> { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join("foo.txt"))? .write_all(b"test\nfoo")?; @@ -198,7 +210,8 @@ mod tests { fn test_stash_nothing_untracked() -> Result<()> { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join("foo.txt"))? .write_all(b"test\nfoo")?; @@ -215,7 +228,8 @@ mod tests { let file_path1 = Path::new("file1.txt"); let (_td, repo) = repo_init()?; let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join(file_path1))?.write_all(b"test")?; stage_add_file(repo_path, file_path1)?; @@ -242,7 +256,8 @@ mod tests { fn test_stash_apply_conflict() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); repo_write_file(&repo, "test.txt", "test").unwrap(); @@ -260,7 +275,8 @@ mod tests { fn test_stash_apply_conflict2() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); write_commit_file(&repo, "test.txt", "test", "c1"); @@ -280,7 +296,8 @@ mod tests { fn test_stash_apply_creating_conflict() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); write_commit_file(&repo, "test.txt", "test", "c1"); @@ -304,7 +321,8 @@ mod tests { fn test_stash_pop_no_conflict() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); write_commit_file(&repo, "test.txt", "test", "c1"); @@ -326,7 +344,8 @@ mod tests { fn test_stash_pop_conflict() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); repo_write_file(&repo, "test.txt", "test").unwrap(); @@ -348,7 +367,8 @@ mod tests { fn test_stash_pop_conflict_after_commit() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); write_commit_file(&repo, "test.txt", "test", "c1"); diff --git a/asyncgit/src/sync/state.rs b/asyncgit/src/sync/state.rs index 11f0e1b4fa..4eac2dee5c 100644 --- a/asyncgit/src/sync/state.rs +++ b/asyncgit/src/sync/state.rs @@ -1,4 +1,5 @@ -use crate::{error::Result, sync::utils}; +use super::RepoPath; +use crate::{error::Result, sync::repository::repo}; use git2::RepositoryState; use scopetime::scope_time; @@ -22,7 +23,7 @@ impl From for RepoState { RepositoryState::Merge => Self::Merge, RepositoryState::RebaseMerge => Self::Rebase, _ => { - log::debug!("state not supported yet: {:?}", state); + log::warn!("state not supported yet: {:?}", state); Self::Other } } @@ -30,10 +31,10 @@ impl From for RepoState { } /// -pub fn repo_state(repo_path: &str) -> Result { +pub fn repo_state(repo_path: &RepoPath) -> Result { scope_time!("repo_state"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let state = repo.state(); diff --git a/asyncgit/src/sync/status.rs b/asyncgit/src/sync/status.rs index 5196e6f74b..6613b85754 100644 --- a/asyncgit/src/sync/status.rs +++ b/asyncgit/src/sync/status.rs @@ -3,13 +3,13 @@ use crate::{ error::Error, error::Result, - sync::{config::untracked_files_config_repo, utils}, + sync::{config::untracked_files_config_repo, repository::repo}, }; use git2::{Delta, Status, StatusOptions, StatusShow}; use scopetime::scope_time; use std::path::Path; -use super::ShowUntrackedFilesConfig; +use super::{RepoPath, ShowUntrackedFilesConfig}; /// #[derive(Copy, Clone, Hash, PartialEq, Debug)] @@ -96,13 +96,13 @@ impl From for StatusShow { /// gurantees sorting pub fn get_status( - repo_path: &str, + repo_path: &RepoPath, status_type: StatusType, show_untracked: Option, ) -> Result> { scope_time!("get_status"); - let repo = utils::repo(repo_path)?; + let repo = repo(repo_path)?; let show_untracked = if let Some(config) = show_untracked { config diff --git a/asyncgit/src/sync/tags.rs b/asyncgit/src/sync/tags.rs index 98034fabea..2d2753beec 100644 --- a/asyncgit/src/sync/tags.rs +++ b/asyncgit/src/sync/tags.rs @@ -1,5 +1,5 @@ -use super::{get_commits_info, utils::repo, CommitId}; -use crate::error::Result; +use super::{get_commits_info, CommitId, RepoPath}; +use crate::{error::Result, sync::repository::repo}; use scopetime::scope_time; use std::collections::{BTreeMap, HashMap, HashSet}; @@ -25,7 +25,7 @@ pub struct TagWithMetadata { static MAX_MESSAGE_WIDTH: usize = 100; /// returns `Tags` type filled with all tags found in repo -pub fn get_tags(repo_path: &str) -> Result { +pub fn get_tags(repo_path: &RepoPath) -> Result { scope_time!("get_tags"); let mut res = Tags::new(); @@ -67,7 +67,7 @@ pub fn get_tags(repo_path: &str) -> Result { /// pub fn get_tags_with_metadata( - repo_path: &str, + repo_path: &RepoPath, ) -> Result> { scope_time!("get_tags_with_metadata"); @@ -119,7 +119,10 @@ pub fn get_tags_with_metadata( } /// -pub fn delete_tag(repo_path: &str, tag_name: &str) -> Result<()> { +pub fn delete_tag( + repo_path: &RepoPath, + tag_name: &str, +) -> Result<()> { scope_time!("delete_tag"); let repo = repo(repo_path)?; @@ -138,7 +141,8 @@ mod tests { fn test_smoke() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); assert_eq!(get_tags(repo_path).unwrap().is_empty(), true); } @@ -147,7 +151,8 @@ mod tests { fn test_multitags() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); let sig = repo.signature().unwrap(); let head_id = repo.head().unwrap().target().unwrap(); diff --git a/asyncgit/src/sync/tree.rs b/asyncgit/src/sync/tree.rs index 5f4a408183..d13d70649b 100644 --- a/asyncgit/src/sync/tree.rs +++ b/asyncgit/src/sync/tree.rs @@ -1,7 +1,7 @@ -use super::CommitId; +use super::{CommitId, RepoPath}; use crate::{ error::{Error, Result}, - sync::utils::repo, + sync::repository::repo, }; use git2::{Oid, Repository, Tree}; use scopetime::scope_time; @@ -23,7 +23,7 @@ pub struct TreeFile { /// guarantees sorting the result pub fn tree_files( - repo_path: &str, + repo_path: &RepoPath, commit: CommitId, ) -> Result> { scope_time!("tree_files"); @@ -73,7 +73,7 @@ fn path_cmp(a: &Path, b: &Path) -> Ordering { /// will only work on utf8 content pub fn tree_file_content( - repo_path: &str, + repo_path: &RepoPath, file: &TreeFile, ) -> Result { scope_time!("tree_file_content"); @@ -130,7 +130,8 @@ mod tests { fn test_smoke() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); let c1 = write_commit_file(&repo, "test.txt", "content", "c1"); diff --git a/asyncgit/src/sync/utils.rs b/asyncgit/src/sync/utils.rs index f0aa16fa02..349e98a4ae 100644 --- a/asyncgit/src/sync/utils.rs +++ b/asyncgit/src/sync/utils.rs @@ -1,6 +1,8 @@ //! sync git api (various methods) -use super::{CommitId, ShowUntrackedFilesConfig}; +use super::{ + repository::repo, CommitId, RepoPath, ShowUntrackedFilesConfig, +}; use crate::{ error::{Error, Result}, sync::config::untracked_files_config_repo, @@ -23,54 +25,28 @@ pub struct Head { } /// -pub fn is_repo(repo_path: &str) -> bool { +pub fn is_repo(repo_path: &RepoPath) -> bool { Repository::open_ext( - repo_path, + repo_path.gitpath(), RepositoryOpenFlags::empty(), Vec::<&Path>::new(), ) .is_ok() } -/// checks if the git repo at path `repo_path` is a bare repo -pub fn is_bare_repo(repo_path: &str) -> Result { - let repo = Repository::open_ext( - repo_path, - RepositoryOpenFlags::empty(), - Vec::<&Path>::new(), - )?; - - Ok(repo.is_bare()) -} - -/// -pub(crate) fn repo(repo_path: &str) -> Result { - let repo = Repository::open_ext( - repo_path, - RepositoryOpenFlags::empty(), - Vec::<&Path>::new(), - )?; - - if repo.is_bare() { - return Err(Error::Generic("bare repo".to_string())); - } - - Ok(repo) -} - /// pub(crate) fn work_dir(repo: &Repository) -> Result<&Path> { repo.workdir().ok_or(Error::NoWorkDir) } /// path to .git folder -pub fn repo_dir(repo_path: &str) -> Result { +pub fn repo_dir(repo_path: &RepoPath) -> Result { let repo = repo(repo_path)?; Ok(repo.path().to_owned()) } /// -pub fn repo_work_dir(repo_path: &str) -> Result { +pub fn repo_work_dir(repo_path: &RepoPath) -> Result { let repo = repo(repo_path)?; work_dir(&repo)?.to_str().map_or_else( || Err(Error::Generic("invalid workdir".to_string())), @@ -79,13 +55,13 @@ pub fn repo_work_dir(repo_path: &str) -> Result { } /// -pub fn get_head(repo_path: &str) -> Result { +pub fn get_head(repo_path: &RepoPath) -> Result { let repo = repo(repo_path)?; get_head_repo(&repo) } /// -pub fn get_head_tuple(repo_path: &str) -> Result { +pub fn get_head_tuple(repo_path: &RepoPath) -> Result { let repo = repo(repo_path)?; let id = get_head_repo(&repo)?; let name = get_head_refname(&repo)?; @@ -111,7 +87,10 @@ pub fn get_head_repo(repo: &Repository) -> Result { } /// add a file diff from workingdir to stage (will not add removed files see `stage_addremoved`) -pub fn stage_add_file(repo_path: &str, path: &Path) -> Result<()> { +pub fn stage_add_file( + repo_path: &RepoPath, + path: &Path, +) -> Result<()> { scope_time!("stage_add_file"); let repo = repo(repo_path)?; @@ -126,7 +105,7 @@ pub fn stage_add_file(repo_path: &str, path: &Path) -> Result<()> { /// like `stage_add_file` but uses a pattern to match/glob multiple files/folders pub fn stage_add_all( - repo_path: &str, + repo_path: &RepoPath, pattern: &str, stage_untracked: Option, ) -> Result<()> { @@ -158,7 +137,7 @@ pub fn stage_add_all( } /// Undo last commit in repo -pub fn undo_last_commit(repo_path: &str) -> Result<()> { +pub fn undo_last_commit(repo_path: &RepoPath) -> Result<()> { let repo = repo(repo_path)?; let previous_commit = repo.revparse_single("HEAD~")?; @@ -173,7 +152,10 @@ pub fn undo_last_commit(repo_path: &str) -> Result<()> { } /// stage a removed file -pub fn stage_addremoved(repo_path: &str, path: &Path) -> Result<()> { +pub fn stage_addremoved( + repo_path: &RepoPath, + path: &Path, +) -> Result<()> { scope_time!("stage_addremoved"); let repo = repo(repo_path)?; @@ -250,7 +232,7 @@ mod tests { let repo_path = root.as_os_str().to_str().unwrap(); assert_eq!( - stage_add_file(repo_path, file_path).is_ok(), + stage_add_file(&repo_path.into(), file_path).is_ok(), false ); } @@ -260,7 +242,8 @@ mod tests { let file_path = Path::new("file1.txt"); let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); File::create(&root.join(file_path)) .unwrap() @@ -283,7 +266,8 @@ mod tests { fn test_staging_folder() -> Result<()> { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); let status_count = |s: StatusType| -> usize { get_status(repo_path, s, None).unwrap().len() @@ -311,7 +295,8 @@ mod tests { fn test_undo_commit_empty_repo() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); // expect to fail assert!(undo_last_commit(repo_path).is_err()); @@ -321,7 +306,8 @@ mod tests { fn test_undo_commit() { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); // write commit file test.txt let c1 = @@ -346,7 +332,8 @@ mod tests { fn test_not_staging_untracked_folder() -> Result<()> { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); fs::create_dir_all(&root.join("a/d"))?; File::create(&root.join(Path::new("a/d/f1.txt")))? @@ -374,7 +361,8 @@ mod tests { let file_path = Path::new("file1.txt"); let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); let status_count = |s: StatusType| -> usize { get_status(repo_path, s, None).unwrap().len() @@ -408,7 +396,8 @@ mod tests { fn test_staging_sub_git_folder() -> Result<()> { let (_td, repo) = repo_init().unwrap(); let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); let status_count = |s: StatusType| -> usize { get_status(repo_path, s, None).unwrap().len() @@ -418,7 +407,10 @@ mod tests { fs::create_dir_all(sub)?; - debug_cmd_print(sub.to_str().unwrap(), "git init subgit"); + debug_cmd_print( + &sub.to_str().unwrap().into(), + "git init subgit", + ); File::create(sub.join("subgit/foo.txt")) .unwrap() @@ -437,7 +429,8 @@ mod tests { fn test_head_empty() -> Result<()> { let (_td, repo) = repo_init_empty()?; let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); assert_eq!(get_head(repo_path).is_ok(), false); @@ -448,7 +441,8 @@ mod tests { fn test_head() -> Result<()> { let (_td, repo) = repo_init()?; let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + let repo_path: &RepoPath = + &root.as_os_str().to_str().unwrap().into(); assert_eq!(get_head(repo_path).is_ok(), true); diff --git a/asyncgit/src/tags.rs b/asyncgit/src/tags.rs index 544e9f3a35..0a7ad01377 100644 --- a/asyncgit/src/tags.rs +++ b/asyncgit/src/tags.rs @@ -1,8 +1,8 @@ use crate::{ error::Result, hash, - sync::{self}, - AsyncGitNotification, CWD, + sync::{self, RepoPath}, + AsyncGitNotification, }; use crossbeam_channel::Sender; use std::{ @@ -26,12 +26,17 @@ pub struct AsyncTags { last: Arc>>, sender: Sender, pending: Arc, + repo: RepoPath, } impl AsyncTags { /// - pub fn new(sender: &Sender) -> Self { + pub fn new( + repo: RepoPath, + sender: &Sender, + ) -> Self { Self { + repo, last: Arc::new(Mutex::new(None)), sender: sender.clone(), pending: Arc::new(AtomicUsize::new(0)), @@ -81,9 +86,10 @@ impl AsyncTags { let arc_pending = Arc::clone(&self.pending); self.pending.fetch_add(1, Ordering::Relaxed); + let repo = self.repo.clone(); rayon_core::spawn(move || { - let notify = Self::getter(&arc_last, outdated) + let notify = Self::getter(&repo, &arc_last, outdated) .expect("error getting tags"); arc_pending.fetch_sub(1, Ordering::Relaxed); @@ -101,10 +107,11 @@ impl AsyncTags { } fn getter( + repo: &RepoPath, arc_last: &Arc>>, outdated: bool, ) -> Result { - let tags = sync::get_tags(CWD)?; + let tags = sync::get_tags(repo)?; let hash = hash(&tags); diff --git a/src/app.rs b/src/app.rs index 74a5b7d936..6c4854129b 100644 --- a/src/app.rs +++ b/src/app.rs @@ -23,7 +23,10 @@ use crate::{ AsyncAppNotification, AsyncNotification, }; use anyhow::{bail, Result}; -use asyncgit::{sync, AsyncGitNotification, CWD}; +use asyncgit::{ + sync::{self, RepoPathRef}, + AsyncGitNotification, +}; use crossbeam_channel::Sender; use crossterm::event::{Event, KeyEvent}; use std::{ @@ -41,6 +44,7 @@ use tui::{ /// the main app type pub struct App { + repo: RepoPathRef, do_quit: bool, help: HelpComponent, msg: MsgComponent, @@ -85,6 +89,7 @@ impl App { /// #[allow(clippy::too_many_lines)] pub fn new( + repo: RepoPathRef, sender: &Sender, sender_app: &Sender, input: Input, @@ -104,11 +109,13 @@ impl App { key_config.clone(), ), commit: CommitComponent::new( + repo.clone(), queue.clone(), theme.clone(), key_config.clone(), ), blame_file_popup: BlameFileComponent::new( + &repo, &queue, sender, &strings::blame_title(&key_config), @@ -116,23 +123,27 @@ impl App { key_config.clone(), ), revision_files_popup: RevisionFilesPopup::new( + repo.clone(), &queue, sender_app, theme.clone(), key_config.clone(), ), stashmsg_popup: StashMsgComponent::new( + repo.clone(), queue.clone(), theme.clone(), key_config.clone(), ), inspect_commit_popup: InspectCommitComponent::new( + &repo, &queue, sender, theme.clone(), key_config.clone(), ), compare_commits_popup: CompareCommitsComponent::new( + &repo, &queue, sender, theme.clone(), @@ -143,50 +154,59 @@ impl App { key_config.clone(), ), push_popup: PushComponent::new( + &repo, &queue, sender, theme.clone(), key_config.clone(), ), push_tags_popup: PushTagsComponent::new( + &repo, &queue, sender, theme.clone(), key_config.clone(), ), pull_popup: PullComponent::new( + &repo, &queue, sender, theme.clone(), key_config.clone(), ), fetch_popup: FetchComponent::new( + repo.clone(), &queue, sender, theme.clone(), key_config.clone(), ), tag_commit_popup: TagCommitComponent::new( + repo.clone(), queue.clone(), theme.clone(), key_config.clone(), ), create_branch_popup: CreateBranchComponent::new( + repo.clone(), queue.clone(), theme.clone(), key_config.clone(), ), rename_branch_popup: RenameBranchComponent::new( + repo.clone(), queue.clone(), theme.clone(), key_config.clone(), ), select_branch_popup: BranchListComponent::new( + repo.clone(), queue.clone(), theme.clone(), key_config.clone(), ), tags_popup: TagListComponent::new( + repo.clone(), &queue, sender, theme.clone(), @@ -215,12 +235,14 @@ impl App { msg: MsgComponent::new(theme.clone(), key_config.clone()), tab: 0, revlog: Revlog::new( + &repo, &queue, sender, theme.clone(), key_config.clone(), ), status_tab: Status::new( + repo.clone(), &queue, sender, theme.clone(), @@ -228,17 +250,20 @@ impl App { options, ), stashing_tab: Stashing::new( + &repo, sender, &queue, theme.clone(), key_config.clone(), ), stashlist_tab: StashList::new( + repo.clone(), &queue, theme.clone(), key_config.clone(), ), files_tab: FilesTab::new( + repo.clone(), sender_app, &queue, theme.clone(), @@ -249,6 +274,7 @@ impl App { key_config, requires_redraw: Cell::new(false), file_to_open: None, + repo, } } @@ -342,6 +368,7 @@ impl App { let result = match self.file_to_open.take() { Some(path) => { ExternalEditorComponent::open_file_in_editor( + &self.repo.borrow(), Path::new(&path), ) } @@ -775,7 +802,10 @@ impl App { } } Action::StashDrop(_) | Action::StashPop(_) => { - if let Err(e) = StashList::action_confirmed(&action) { + if let Err(e) = StashList::action_confirmed( + &self.repo.borrow(), + &action, + ) { self.queue.push(InternalEvent::ShowErrorMsg( e.to_string(), )); @@ -784,16 +814,22 @@ impl App { flags.insert(NeedsUpdate::ALL); } Action::ResetHunk(path, hash) => { - sync::reset_hunk(CWD, &path, hash)?; + sync::reset_hunk(&self.repo.borrow(), &path, hash)?; flags.insert(NeedsUpdate::ALL); } Action::ResetLines(path, lines) => { - sync::discard_lines(CWD, &path, &lines)?; + sync::discard_lines( + &self.repo.borrow(), + &path, + &lines, + )?; flags.insert(NeedsUpdate::ALL); } Action::DeleteLocalBranch(branch_ref) => { - if let Err(e) = sync::delete_branch(CWD, &branch_ref) - { + if let Err(e) = sync::delete_branch( + &self.repo.borrow(), + &branch_ref, + ) { self.queue.push(InternalEvent::ShowErrorMsg( e.to_string(), )); @@ -824,7 +860,9 @@ impl App { self.select_branch_popup.update_branches()?; } Action::DeleteTag(tag_name) => { - if let Err(error) = sync::delete_tag(CWD, &tag_name) { + if let Err(error) = + sync::delete_tag(&self.repo.borrow(), &tag_name) + { self.queue.push(InternalEvent::ShowErrorMsg( error.to_string(), )); diff --git a/src/args.rs b/src/args.rs index 67b2e29449..6d2df0d86e 100644 --- a/src/args.rs +++ b/src/args.rs @@ -1,5 +1,6 @@ use crate::bug_report; use anyhow::{anyhow, Result}; +use asyncgit::sync::RepoPath; use clap::{ crate_authors, crate_description, crate_name, crate_version, App as ClapApp, Arg, @@ -13,6 +14,7 @@ use std::{ pub struct CliArgs { pub theme: PathBuf, + pub repo_path: RepoPath, } pub fn process_cmdline() -> Result { @@ -41,10 +43,17 @@ pub fn process_cmdline() -> Result { ) .arg( Arg::with_name("directory") - .help("Set the working directory") + .help("Set the git directory") .short("d") .long("directory") .takes_value(true), + ) + .arg( + Arg::with_name("workdir") + .help("Set the working directory") + .short("w") + .long("workdir") + .takes_value(true), ); let arg_matches = app.get_matches(); @@ -55,20 +64,31 @@ pub fn process_cmdline() -> Result { if arg_matches.is_present("logging") { setup_logging()?; } - if arg_matches.is_present("directory") { - let directory = - arg_matches.value_of("directory").unwrap_or("."); - env::set_current_dir(directory)?; - } + + let workdir = arg_matches.value_of("workdir").map(PathBuf::from); + let gitdir = arg_matches + .value_of("directory") + .map_or_else(|| PathBuf::from("."), PathBuf::from); + + #[allow(clippy::option_if_let_else)] + let repo_path = if let Some(w) = workdir { + RepoPath::Workdir { gitdir, workdir: w } + } else { + RepoPath::Path(gitdir) + }; + let arg_theme = arg_matches.value_of("theme").unwrap_or("theme.ron"); + if get_app_config_path()?.join(arg_theme).is_file() { Ok(CliArgs { theme: get_app_config_path()?.join(arg_theme), + repo_path, }) } else { Ok(CliArgs { theme: get_app_config_path()?.join("theme.ron"), + repo_path, }) } } diff --git a/src/components/blame_file.rs b/src/components/blame_file.rs index 3d7fc4513f..4c5bf4fe98 100644 --- a/src/components/blame_file.rs +++ b/src/components/blame_file.rs @@ -11,7 +11,7 @@ use crate::{ }; use anyhow::Result; use asyncgit::{ - sync::{BlameHunk, CommitId, FileBlame}, + sync::{BlameHunk, CommitId, FileBlame, RepoPathRef}, AsyncBlame, AsyncGitNotification, BlameParams, }; use crossbeam_channel::Sender; @@ -244,6 +244,7 @@ impl Component for BlameFileComponent { impl BlameFileComponent { /// pub fn new( + repo: &RepoPathRef, queue: &Queue, sender: &Sender, title: &str, @@ -253,7 +254,10 @@ impl BlameFileComponent { Self { title: String::from(title), theme, - async_blame: AsyncBlame::new(sender), + async_blame: AsyncBlame::new( + repo.borrow().clone(), + sender, + ), queue: queue.clone(), visible: false, file_path: None, diff --git a/src/components/branchlist.rs b/src/components/branchlist.rs index 548c1f0065..4da9231a3f 100644 --- a/src/components/branchlist.rs +++ b/src/components/branchlist.rs @@ -19,9 +19,9 @@ use asyncgit::{ RemoteBranch, }, checkout_branch, get_branches_info, BranchInfo, BranchType, - CommitId, RepoState, + CommitId, RepoPathRef, RepoState, }, - AsyncGitNotification, CWD, + AsyncGitNotification, }; use crossterm::event::Event; use std::{cell::Cell, convert::TryInto}; @@ -39,6 +39,7 @@ use unicode_truncate::UnicodeTruncateStr; /// pub struct BranchListComponent { + repo: RepoPathRef, branches: Vec, local: bool, visible: bool, @@ -324,6 +325,7 @@ impl Component for BranchListComponent { impl BranchListComponent { pub fn new( + repo: RepoPathRef, queue: Queue, theme: SharedTheme, key_config: SharedKeyConfig, @@ -338,6 +340,7 @@ impl BranchListComponent { theme, key_config, current_height: Cell::new(0), + repo, } } @@ -352,7 +355,8 @@ impl BranchListComponent { /// fetch list of branches pub fn update_branches(&mut self) -> Result<()> { if self.is_visible() { - self.branches = get_branches_info(CWD, self.local)?; + self.branches = + get_branches_info(&self.repo.borrow(), self.local)?; //remove remote branch called `HEAD` if !self.local { self.branches @@ -386,7 +390,7 @@ impl BranchListComponent { self.branches.get(usize::from(self.selection)) { sync::merge_branch( - CWD, + &self.repo.borrow(), &branch.name, self.get_branch_type(), )?; @@ -402,7 +406,7 @@ impl BranchListComponent { self.branches.get(usize::from(self.selection)) { sync::rebase_branch( - CWD, + &self.repo.borrow(), &branch.name, self.get_branch_type(), )?; @@ -425,7 +429,8 @@ impl BranchListComponent { self.hide(); self.queue.push(InternalEvent::Update(NeedsUpdate::ALL)); - if sync::repo_state(CWD)? != RepoState::Clean { + if sync::repo_state(&self.repo.borrow())? != RepoState::Clean + { self.queue.push(InternalEvent::TabSwitch); } @@ -614,13 +619,13 @@ impl BranchListComponent { if self.local { checkout_branch( - asyncgit::CWD, + &self.repo.borrow(), &self.branches[self.selection as usize].reference, )?; self.hide(); } else { checkout_remote_branch( - CWD, + &self.repo.borrow(), &self.branches[self.selection as usize], )?; self.local = true; diff --git a/src/components/changes.rs b/src/components/changes.rs index 8434fe1eef..1f2ec9cd13 100644 --- a/src/components/changes.rs +++ b/src/components/changes.rs @@ -11,13 +11,17 @@ use crate::{ ui::style::SharedTheme, }; use anyhow::Result; -use asyncgit::{sync, StatusItem, StatusItemType, CWD}; +use asyncgit::{ + sync::{self, RepoPathRef}, + StatusItem, StatusItemType, +}; use crossterm::event::Event; use std::path::Path; use tui::{backend::Backend, layout::Rect, Frame}; /// pub struct ChangesComponent { + repo: RepoPathRef, files: StatusTreeComponent, is_working_dir: bool, queue: Queue, @@ -27,7 +31,10 @@ pub struct ChangesComponent { impl ChangesComponent { /// + //TODO: fix + #[allow(clippy::too_many_arguments)] pub fn new( + repo: RepoPathRef, title: &str, focus: bool, is_working_dir: bool, @@ -48,6 +55,7 @@ impl ChangesComponent { queue, key_config, options, + repo, } } @@ -85,9 +93,15 @@ impl ChangesComponent { let path = Path::new(i.path.as_str()); match i.status { StatusItemType::Deleted => { - sync::stage_addremoved(CWD, path)?; + sync::stage_addremoved( + &self.repo.borrow(), + path, + )?; } - _ => sync::stage_add_file(CWD, path)?, + _ => sync::stage_add_file( + &self.repo.borrow(), + path, + )?, }; if self.is_empty() { @@ -103,7 +117,7 @@ impl ChangesComponent { //TODO: check if we can handle the one file case with it aswell sync::stage_add_all( - CWD, + &self.repo.borrow(), tree_item.info.full_path.as_str(), config, )?; @@ -112,7 +126,7 @@ impl ChangesComponent { } let path = tree_item.info.full_path.as_str(); - sync::reset_stage(CWD, path)?; + sync::reset_stage(&self.repo.borrow(), path)?; return Ok(true); } @@ -122,7 +136,7 @@ impl ChangesComponent { fn index_add_all(&mut self) -> Result<()> { let config = self.options.borrow().status_show_untracked; - sync::stage_add_all(CWD, "*", config)?; + sync::stage_add_all(&self.repo.borrow(), "*", config)?; self.queue.push(InternalEvent::Update(NeedsUpdate::ALL)); @@ -130,7 +144,7 @@ impl ChangesComponent { } fn stage_remove_all(&mut self) -> Result<()> { - sync::reset_stage(CWD, "*")?; + sync::reset_stage(&self.repo.borrow(), "*")?; self.queue.push(InternalEvent::Update(NeedsUpdate::ALL)); @@ -155,9 +169,10 @@ impl ChangesComponent { fn add_to_ignore(&mut self) -> bool { if let Some(tree_item) = self.selection() { - if let Err(e) = - sync::add_to_ignore(CWD, &tree_item.info.full_path) - { + if let Err(e) = sync::add_to_ignore( + &self.repo.borrow(), + &tree_item.info.full_path, + ) { self.queue.push(InternalEvent::ShowErrorMsg( format!( "ignore error:\n{}\nfile:\n{:?}", diff --git a/src/components/commit.rs b/src/components/commit.rs index 8c85378905..670c52b059 100644 --- a/src/components/commit.rs +++ b/src/components/commit.rs @@ -13,9 +13,9 @@ use anyhow::Result; use asyncgit::{ cached, message_prettify, sync::{ - self, get_config_string, CommitId, HookResult, RepoState, + self, get_config_string, CommitId, HookResult, RepoPathRef, + RepoState, }, - CWD, }; use crossterm::event::Event; use easy_cast::Cast; @@ -37,6 +37,7 @@ enum Mode { } pub struct CommitComponent { + repo: RepoPathRef, input: TextInputComponent, mode: Mode, queue: Queue, @@ -51,6 +52,7 @@ const FIRST_LINE_LIMIT: usize = 50; impl CommitComponent { /// pub fn new( + repo: RepoPathRef, queue: Queue, theme: SharedTheme, key_config: SharedKeyConfig, @@ -58,7 +60,6 @@ impl CommitComponent { Self { queue, mode: Mode::Normal, - input: TextInputComponent::new( theme.clone(), key_config.clone(), @@ -67,9 +68,10 @@ impl CommitComponent { true, ), key_config, - git_branch_name: cached::BranchName::new(CWD), + git_branch_name: cached::BranchName::new(repo.clone()), commit_template: None, theme, + repo, } } @@ -126,7 +128,8 @@ impl CommitComponent { } pub fn show_editor(&mut self) -> Result<()> { - let file_path = sync::repo_dir(CWD)?.join("COMMIT_EDITMSG"); + let file_path = sync::repo_dir(&self.repo.borrow())? + .join("COMMIT_EDITMSG"); { let mut file = File::create(&file_path)?; @@ -140,7 +143,10 @@ impl CommitComponent { )?; } - ExternalEditorComponent::open_file_in_editor(&file_path)?; + ExternalEditorComponent::open_file_in_editor( + &self.repo.borrow(), + &file_path, + )?; let mut message = String::new(); @@ -157,11 +163,12 @@ impl CommitComponent { } fn commit(&mut self) -> Result<()> { - let gpgsign = get_config_string(CWD, "commit.gpgsign") - .ok() - .flatten() - .and_then(|path| path.parse::().ok()) - .unwrap_or_default(); + let gpgsign = + get_config_string(&self.repo.borrow(), "commit.gpgsign") + .ok() + .flatten() + .and_then(|path| path.parse::().ok()) + .unwrap_or_default(); if gpgsign { anyhow::bail!("config commit.gpgsign=true detected.\ngpg signing not supported.\ndeactivate in your repo/gitconfig to be able to commit without signing."); @@ -173,7 +180,9 @@ impl CommitComponent { } fn commit_with_msg(&mut self, msg: String) -> Result<()> { - if let HookResult::NotOk(e) = sync::hooks_pre_commit(CWD)? { + if let HookResult::NotOk(e) = + sync::hooks_pre_commit(&self.repo.borrow())? + { log::error!("pre-commit hook error: {}", e); self.queue.push(InternalEvent::ShowErrorMsg(format!( "pre-commit hook error:\n{}", @@ -183,7 +192,7 @@ impl CommitComponent { } let mut msg = message_prettify(msg, Some(b'#'))?; if let HookResult::NotOk(e) = - sync::hooks_commit_msg(CWD, &mut msg)? + sync::hooks_commit_msg(&self.repo.borrow(), &mut msg)? { log::error!("commit-msg hook error: {}", e); self.queue.push(InternalEvent::ShowErrorMsg(format!( @@ -194,9 +203,13 @@ impl CommitComponent { } let res = match &self.mode { - Mode::Normal => sync::commit(CWD, &msg), - Mode::Amend(amend) => sync::amend(CWD, *amend, &msg), - Mode::Merge(ids) => sync::merge_commit(CWD, &msg, ids), + Mode::Normal => sync::commit(&self.repo.borrow(), &msg), + Mode::Amend(amend) => { + sync::amend(&self.repo.borrow(), *amend, &msg) + } + Mode::Merge(ids) => { + sync::merge_commit(&self.repo.borrow(), &msg, ids) + } }; if let Err(e) = res { @@ -208,7 +221,9 @@ impl CommitComponent { return Ok(()); } - if let HookResult::NotOk(e) = sync::hooks_post_commit(CWD)? { + if let HookResult::NotOk(e) = + sync::hooks_post_commit(&self.repo.borrow())? + { log::error!("post-commit hook error: {}", e); self.queue.push(InternalEvent::ShowErrorMsg(format!( "post-commit hook error:\n{}", @@ -229,7 +244,7 @@ impl CommitComponent { fn can_amend(&self) -> bool { matches!(self.mode, Mode::Normal) - && sync::get_head(CWD).is_ok() + && sync::get_head(&self.repo.borrow()).is_ok() && (self.is_empty() || !self.is_changed()) } @@ -244,10 +259,11 @@ impl CommitComponent { fn amend(&mut self) -> Result<()> { if self.can_amend() { - let id = sync::get_head(CWD)?; + let id = sync::get_head(&self.repo.borrow())?; self.mode = Mode::Amend(id); - let details = sync::get_commit_details(CWD, id)?; + let details = + sync::get_commit_details(&self.repo.borrow(), id)?; self.input.set_title(strings::commit_title_amend()); @@ -360,17 +376,22 @@ impl Component for CommitComponent { self.mode = Mode::Normal; - self.mode = if sync::repo_state(CWD)? == RepoState::Merge { - let ids = sync::mergehead_ids(CWD)?; + self.mode = if sync::repo_state(&self.repo.borrow())? + == RepoState::Merge + { + let ids = sync::mergehead_ids(&self.repo.borrow())?; self.input.set_title(strings::commit_title_merge()); - self.input.set_text(sync::merge_msg(CWD)?); + self.input + .set_text(sync::merge_msg(&self.repo.borrow())?); Mode::Merge(ids) } else { - self.commit_template = - get_config_string(CWD, "commit.template") - .ok() - .flatten() - .and_then(|path| read_to_string(path).ok()); + self.commit_template = get_config_string( + &self.repo.borrow(), + "commit.template", + ) + .ok() + .flatten() + .and_then(|path| read_to_string(path).ok()); if self.is_empty() { if let Some(s) = &self.commit_template { diff --git a/src/components/commit_details/compare_details.rs b/src/components/commit_details/compare_details.rs index 1b42766e97..1e045e9bb1 100644 --- a/src/components/commit_details/compare_details.rs +++ b/src/components/commit_details/compare_details.rs @@ -12,10 +12,7 @@ use crate::{ ui::style::SharedTheme, }; use anyhow::Result; -use asyncgit::{ - sync::{self, CommitDetails, CommitId}, - CWD, -}; +use asyncgit::sync::{self, CommitDetails, CommitId, RepoPathRef}; use crossterm::event::Event; use tui::{ backend::Backend, @@ -25,6 +22,7 @@ use tui::{ }; pub struct CompareDetailsComponent { + repo: RepoPathRef, data: Option<(CommitDetails, CommitDetails)>, theme: SharedTheme, focused: bool, @@ -32,18 +30,27 @@ pub struct CompareDetailsComponent { impl CompareDetailsComponent { /// - pub const fn new(theme: SharedTheme, focused: bool) -> Self { + pub const fn new( + repo: RepoPathRef, + theme: SharedTheme, + focused: bool, + ) -> Self { Self { data: None, theme, focused, + repo, } } pub fn set_commits(&mut self, ids: Option<(CommitId, CommitId)>) { self.data = ids.and_then(|ids| { - let c1 = sync::get_commit_details(CWD, ids.0).ok(); - let c2 = sync::get_commit_details(CWD, ids.1).ok(); + let c1 = + sync::get_commit_details(&self.repo.borrow(), ids.0) + .ok(); + let c2 = + sync::get_commit_details(&self.repo.borrow(), ids.1) + .ok(); c1.and_then(|c1| { c2.map(|c2| { diff --git a/src/components/commit_details/details.rs b/src/components/commit_details/details.rs index af9c005cf6..cf219b5996 100644 --- a/src/components/commit_details/details.rs +++ b/src/components/commit_details/details.rs @@ -11,9 +11,8 @@ use crate::{ ui::style::SharedTheme, }; use anyhow::Result; -use asyncgit::{ - sync::{self, CommitDetails, CommitId, CommitMessage}, - CWD, +use asyncgit::sync::{ + self, CommitDetails, CommitId, CommitMessage, RepoPathRef, }; use crossterm::event::Event; use std::clone::Clone; @@ -30,6 +29,7 @@ use tui::{ use super::style::Detail; pub struct DetailsComponent { + repo: RepoPathRef, data: Option, tags: Vec, theme: SharedTheme, @@ -46,11 +46,13 @@ type WrappedCommitMessage<'a> = impl DetailsComponent { /// pub const fn new( + repo: RepoPathRef, theme: SharedTheme, key_config: SharedKeyConfig, focused: bool, ) -> Self { Self { + repo, data: None, tags: Vec::new(), theme, @@ -69,8 +71,9 @@ impl DetailsComponent { ) { self.tags.clear(); - self.data = - id.and_then(|id| sync::get_commit_details(CWD, id).ok()); + self.data = id.and_then(|id| { + sync::get_commit_details(&self.repo.borrow(), id).ok() + }); self.scroll.reset(); diff --git a/src/components/commit_details/mod.rs b/src/components/commit_details/mod.rs index 9f8f2d3b42..61aa5a44a3 100644 --- a/src/components/commit_details/mod.rs +++ b/src/components/commit_details/mod.rs @@ -12,8 +12,8 @@ use crate::{ }; use anyhow::Result; use asyncgit::{ - sync::CommitTags, AsyncCommitFiles, AsyncGitNotification, - CommitFilesParams, + sync::{CommitTags, RepoPathRef}, + AsyncCommitFiles, AsyncGitNotification, CommitFilesParams, }; use compare_details::CompareDetailsComponent; use crossbeam_channel::Sender; @@ -40,6 +40,7 @@ impl CommitDetailsComponent { /// pub fn new( + repo: &RepoPathRef, queue: &Queue, sender: &Sender, theme: SharedTheme, @@ -47,15 +48,20 @@ impl CommitDetailsComponent { ) -> Self { Self { single_details: DetailsComponent::new( + repo.clone(), theme.clone(), key_config.clone(), false, ), compare_details: CompareDetailsComponent::new( + repo.clone(), theme.clone(), false, ), - git_commit_files: AsyncCommitFiles::new(sender), + git_commit_files: AsyncCommitFiles::new( + repo.borrow().clone(), + sender, + ), file_tree: StatusTreeComponent::new( "", false, diff --git a/src/components/compare_commits.rs b/src/components/compare_commits.rs index d410f41167..ac46c28f5e 100644 --- a/src/components/compare_commits.rs +++ b/src/components/compare_commits.rs @@ -9,9 +9,9 @@ use crate::{ }; use anyhow::Result; use asyncgit::{ - sync::{self, diff::DiffOptions, CommitId}, + sync::{self, diff::DiffOptions, CommitId, RepoPathRef}, AsyncDiff, AsyncGitNotification, CommitFilesParams, DiffParams, - DiffType, CWD, + DiffType, }; use crossbeam_channel::Sender; use crossterm::event::Event; @@ -23,6 +23,7 @@ use tui::{ }; pub struct CompareCommitsComponent { + repo: RepoPathRef, commit_ids: Option<(CommitId, CommitId)>, diff: DiffComponent, details: CommitDetailsComponent, @@ -156,26 +157,30 @@ impl CompareCommitsComponent { /// pub fn new( + repo: &RepoPathRef, queue: &Queue, sender: &Sender, theme: SharedTheme, key_config: SharedKeyConfig, ) -> Self { Self { + repo: repo.clone(), details: CommitDetailsComponent::new( + repo, queue, sender, theme.clone(), key_config.clone(), ), diff: DiffComponent::new( + repo.clone(), queue.clone(), theme, key_config.clone(), true, ), commit_ids: None, - git_diff: AsyncDiff::new(sender), + git_diff: AsyncDiff::new(repo.borrow().clone(), sender), visible: false, key_config, } @@ -190,7 +195,7 @@ impl CompareCommitsComponent { let other = if let Some(other) = other { other } else { - sync::get_head_tuple(CWD)?.id + sync::get_head_tuple(&self.repo.borrow())?.id }; self.commit_ids = Some((id, other)); self.show()?; diff --git a/src/components/create_branch.rs b/src/components/create_branch.rs index b0cb86bd7b..265be31a52 100644 --- a/src/components/create_branch.rs +++ b/src/components/create_branch.rs @@ -10,7 +10,7 @@ use crate::{ ui::style::SharedTheme, }; use anyhow::Result; -use asyncgit::{sync, CWD}; +use asyncgit::sync::{self, RepoPathRef}; use crossterm::event::Event; use easy_cast::Cast; use tui::{ @@ -18,6 +18,7 @@ use tui::{ }; pub struct CreateBranchComponent { + repo: RepoPathRef, input: TextInputComponent, queue: Queue, key_config: SharedKeyConfig, @@ -95,6 +96,7 @@ impl Component for CreateBranchComponent { impl CreateBranchComponent { /// pub fn new( + repo: RepoPathRef, queue: Queue, theme: SharedTheme, key_config: SharedKeyConfig, @@ -110,6 +112,7 @@ impl CreateBranchComponent { ), theme, key_config, + repo, } } @@ -122,7 +125,10 @@ impl CreateBranchComponent { /// pub fn create_branch(&mut self) { - let res = sync::create_branch(CWD, self.input.get_text()); + let res = sync::create_branch( + &self.repo.borrow(), + self.input.get_text(), + ); self.input.clear(); self.hide(); diff --git a/src/components/diff.rs b/src/components/diff.rs index a982687118..273d8c96b2 100644 --- a/src/components/diff.rs +++ b/src/components/diff.rs @@ -13,8 +13,8 @@ use crate::{ use anyhow::Result; use asyncgit::{ hash, - sync::{self, diff::DiffLinePosition}, - DiffLine, DiffLineType, FileDiff, CWD, + sync::{self, diff::DiffLinePosition, RepoPathRef}, + DiffLine, DiffLineType, FileDiff, }; use bytesize::ByteSize; use crossterm::event::Event; @@ -100,6 +100,7 @@ impl Selection { /// pub struct DiffComponent { + repo: RepoPathRef, diff: Option, pending: bool, selection: Selection, @@ -117,6 +118,7 @@ pub struct DiffComponent { impl DiffComponent { /// pub fn new( + repo: RepoPathRef, queue: Queue, theme: SharedTheme, key_config: SharedKeyConfig, @@ -135,6 +137,7 @@ impl DiffComponent { theme, key_config, is_immutable, + repo, } } /// @@ -458,7 +461,11 @@ impl DiffComponent { if let Some(diff) = &self.diff { if let Some(hunk) = self.selected_hunk { let hash = diff.hunks[hunk].header_hash; - sync::unstage_hunk(CWD, &self.current.path, hash)?; + sync::unstage_hunk( + &self.repo.borrow(), + &self.current.path, + hash, + )?; self.queue_update(); } } @@ -471,12 +478,16 @@ impl DiffComponent { if let Some(hunk) = self.selected_hunk { if diff.untracked { sync::stage_add_file( - CWD, + &self.repo.borrow(), Path::new(&self.current.path), )?; } else { let hash = diff.hunks[hunk].header_hash; - sync::stage_hunk(CWD, &self.current.path, hash)?; + sync::stage_hunk( + &self.repo.borrow(), + &self.current.path, + hash, + )?; } self.queue_update(); @@ -524,7 +535,7 @@ impl DiffComponent { self, "(un)stage lines:", sync::stage_lines( - CWD, + &self.repo.borrow(), &self.current.path, self.is_stage(), &selected_lines, diff --git a/src/components/externaleditor.rs b/src/components/externaleditor.rs index 0e67949a09..eee93d15be 100644 --- a/src/components/externaleditor.rs +++ b/src/components/externaleditor.rs @@ -8,9 +8,8 @@ use crate::{ ui::{self, style::SharedTheme}, }; use anyhow::{anyhow, bail, Result}; -use asyncgit::{ - sync::{get_config_string, utils::repo_work_dir}, - CWD, +use asyncgit::sync::{ + get_config_string, utils::repo_work_dir, RepoPath, }; use crossterm::{ event::Event, @@ -49,8 +48,11 @@ impl ExternalEditorComponent { } /// opens file at given `path` in an available editor - pub fn open_file_in_editor(path: &Path) -> Result<()> { - let work_dir = repo_work_dir(CWD)?; + pub fn open_file_in_editor( + repo: &RepoPath, + path: &Path, + ) -> Result<()> { + let work_dir = repo_work_dir(repo)?; let path = if path.is_relative() { Path::new(&work_dir).join(path) @@ -71,7 +73,9 @@ impl ExternalEditorComponent { let editor = env::var(environment_options[0]) .ok() - .or_else(|| get_config_string(CWD, "core.editor").ok()?) + .or_else(|| { + get_config_string(repo, "core.editor").ok()? + }) .or_else(|| env::var(environment_options[1]).ok()) .or_else(|| env::var(environment_options[2]).ok()) .unwrap_or_else(|| String::from("vi")); diff --git a/src/components/fetch.rs b/src/components/fetch.rs index 1d24d898e9..bedca015e3 100644 --- a/src/components/fetch.rs +++ b/src/components/fetch.rs @@ -11,9 +11,12 @@ use crate::{ use anyhow::Result; use asyncgit::{ asyncjob::AsyncSingleJob, - sync::cred::{ - extract_username_password, need_username_password, - BasicAuthCredential, + sync::{ + cred::{ + extract_username_password, need_username_password, + BasicAuthCredential, + }, + RepoPathRef, }, AsyncFetchJob, AsyncGitNotification, ProgressPercent, }; @@ -29,6 +32,7 @@ use tui::{ /// pub struct FetchComponent { + repo: RepoPathRef, visible: bool, async_fetch: AsyncSingleJob, progress: Option, @@ -42,6 +46,7 @@ pub struct FetchComponent { impl FetchComponent { /// pub fn new( + repo: RepoPathRef, queue: &Queue, sender: &Sender, theme: SharedTheme, @@ -59,15 +64,16 @@ impl FetchComponent { ), theme, key_config, + repo, } } /// pub fn fetch(&mut self) -> Result<()> { self.show()?; - if need_username_password()? { - let cred = - extract_username_password().unwrap_or_else(|_| { + if need_username_password(&self.repo.borrow())? { + let cred = extract_username_password(&self.repo.borrow()) + .unwrap_or_else(|_| { BasicAuthCredential::new(None, None) }); if cred.is_complete() { @@ -87,7 +93,10 @@ impl FetchComponent { self.pending = true; self.progress = None; self.progress = Some(ProgressPercent::empty()); - self.async_fetch.spawn(AsyncFetchJob::new(cred)); + self.async_fetch.spawn(AsyncFetchJob::new( + self.repo.borrow().clone(), + cred, + )); } /// diff --git a/src/components/inspect_commit.rs b/src/components/inspect_commit.rs index 5ab5de2554..2cfbe46f4a 100644 --- a/src/components/inspect_commit.rs +++ b/src/components/inspect_commit.rs @@ -12,7 +12,7 @@ use crate::{ }; use anyhow::Result; use asyncgit::{ - sync::{diff::DiffOptions, CommitId, CommitTags}, + sync::{diff::DiffOptions, CommitId, CommitTags, RepoPathRef}, AsyncDiff, AsyncGitNotification, CommitFilesParams, DiffParams, DiffType, }; @@ -176,6 +176,7 @@ impl InspectCommitComponent { /// pub fn new( + repo: &RepoPathRef, queue: &Queue, sender: &Sender, theme: SharedTheme, @@ -184,12 +185,14 @@ impl InspectCommitComponent { Self { queue: queue.clone(), details: CommitDetailsComponent::new( + repo, queue, sender, theme.clone(), key_config.clone(), ), diff: DiffComponent::new( + repo.clone(), queue.clone(), theme, key_config.clone(), @@ -197,7 +200,7 @@ impl InspectCommitComponent { ), commit_id: None, tags: None, - git_diff: AsyncDiff::new(sender), + git_diff: AsyncDiff::new(repo.borrow().clone(), sender), visible: false, key_config, } diff --git a/src/components/pull.rs b/src/components/pull.rs index a45bb110cf..38ab554396 100644 --- a/src/components/pull.rs +++ b/src/components/pull.rs @@ -17,10 +17,9 @@ use asyncgit::{ extract_username_password, need_username_password, BasicAuthCredential, }, - get_default_remote, + get_default_remote, RepoPathRef, }, AsyncGitNotification, AsyncPull, FetchRequest, RemoteProgress, - CWD, }; use crossbeam_channel::Sender; use crossterm::event::Event; @@ -34,6 +33,7 @@ use tui::{ /// pub struct PullComponent { + repo: RepoPathRef, visible: bool, git_fetch: AsyncPull, progress: Option, @@ -48,17 +48,19 @@ pub struct PullComponent { impl PullComponent { /// pub fn new( + repo: &RepoPathRef, queue: &Queue, sender: &Sender, theme: SharedTheme, key_config: SharedKeyConfig, ) -> Self { Self { + repo: repo.clone(), queue: queue.clone(), pending: false, visible: false, branch: String::new(), - git_fetch: AsyncPull::new(sender), + git_fetch: AsyncPull::new(repo.borrow().clone(), sender), progress: None, input_cred: CredComponent::new( theme.clone(), @@ -73,9 +75,9 @@ impl PullComponent { pub fn fetch(&mut self, branch: String) -> Result<()> { self.branch = branch; self.show()?; - if need_username_password()? { - let cred = - extract_username_password().unwrap_or_else(|_| { + if need_username_password(&self.repo.borrow())? { + let cred = extract_username_password(&self.repo.borrow()) + .unwrap_or_else(|_| { BasicAuthCredential::new(None, None) }); if cred.is_complete() { @@ -96,7 +98,7 @@ impl PullComponent { self.pending = true; self.progress = None; self.git_fetch.request(FetchRequest { - remote: get_default_remote(CWD)?, + remote: get_default_remote(&self.repo.borrow())?, branch: self.branch.clone(), basic_credential: cred, })?; @@ -144,11 +146,13 @@ impl PullComponent { // check if something is incoming and try a ff merge then fn try_ff_merge(&mut self) -> Result<()> { - let branch_compare = - sync::branch_compare_upstream(CWD, &self.branch)?; + let branch_compare = sync::branch_compare_upstream( + &self.repo.borrow(), + &self.branch, + )?; if branch_compare.behind > 0 { let ff_res = sync::branch_merge_upstream_fastforward( - CWD, + &self.repo.borrow(), &self.branch, ); if let Err(err) = ff_res { @@ -167,13 +171,19 @@ impl PullComponent { try_or_popup!( self, "rebase failed:", - sync::merge_upstream_rebase(CWD, &self.branch) + sync::merge_upstream_rebase( + &self.repo.borrow(), + &self.branch + ) ); } else { try_or_popup!( self, "merge failed:", - sync::merge_upstream_commit(CWD, &self.branch) + sync::merge_upstream_commit( + &self.repo.borrow(), + &self.branch + ) ); } } @@ -182,8 +192,10 @@ impl PullComponent { self.queue.push(InternalEvent::ConfirmAction( Action::PullMerge { incoming, - rebase: sync::config_is_pull_rebase(CWD) - .unwrap_or_default(), + rebase: sync::config_is_pull_rebase( + &self.repo.borrow(), + ) + .unwrap_or_default(), }, )); self.hide(); diff --git a/src/components/push.rs b/src/components/push.rs index 916acd9e40..6123362b54 100644 --- a/src/components/push.rs +++ b/src/components/push.rs @@ -15,10 +15,10 @@ use asyncgit::{ extract_username_password, need_username_password, BasicAuthCredential, }, - get_branch_remote, get_default_remote, + get_branch_remote, get_default_remote, RepoPathRef, }, AsyncGitNotification, AsyncPush, PushRequest, RemoteProgress, - RemoteProgressState, CWD, + RemoteProgressState, }; use crossbeam_channel::Sender; use crossterm::event::Event; @@ -50,6 +50,7 @@ impl PushComponentModifier { /// pub struct PushComponent { + repo: RepoPathRef, modifier: PushComponentModifier, visible: bool, git_push: AsyncPush, @@ -65,18 +66,20 @@ pub struct PushComponent { impl PushComponent { /// pub fn new( + repo: &RepoPathRef, queue: &Queue, sender: &Sender, theme: SharedTheme, key_config: SharedKeyConfig, ) -> Self { Self { + repo: repo.clone(), queue: queue.clone(), modifier: PushComponentModifier::None, pending: false, visible: false, branch: String::new(), - git_push: AsyncPush::new(sender), + git_push: AsyncPush::new(repo.borrow().clone(), sender), progress: None, input_cred: CredComponent::new( theme.clone(), @@ -104,9 +107,9 @@ impl PushComponent { self.show()?; - if need_username_password()? { - let cred = - extract_username_password().unwrap_or_else(|_| { + if need_username_password(&self.repo.borrow())? { + let cred = extract_username_password(&self.repo.borrow()) + .unwrap_or_else(|_| { BasicAuthCredential::new(None, None) }); if cred.is_complete() { @@ -126,13 +129,13 @@ impl PushComponent { force: bool, ) -> Result<()> { let remote = if let Ok(Some(remote)) = - get_branch_remote(CWD, &self.branch) + get_branch_remote(&self.repo.borrow(), &self.branch) { log::info!("push: branch '{}' has upstream for remote '{}' - using that",self.branch,remote); remote } else { log::info!("push: branch '{}' has no upstream - looking up default remote",self.branch); - let remote = get_default_remote(CWD)?; + let remote = get_default_remote(&self.repo.borrow())?; log::info!( "push: branch '{}' to remote '{}'", self.branch, diff --git a/src/components/push_tags.rs b/src/components/push_tags.rs index 93be795c89..7735d70f7d 100644 --- a/src/components/push_tags.rs +++ b/src/components/push_tags.rs @@ -16,8 +16,9 @@ use asyncgit::{ BasicAuthCredential, }, get_default_remote, AsyncProgress, PushTagsProgress, + RepoPathRef, }, - AsyncGitNotification, AsyncPushTags, PushTagsRequest, CWD, + AsyncGitNotification, AsyncPushTags, PushTagsRequest, }; use crossbeam_channel::Sender; use crossterm::event::Event; @@ -31,6 +32,7 @@ use tui::{ /// pub struct PushTagsComponent { + repo: RepoPathRef, visible: bool, git_push: AsyncPushTags, progress: Option, @@ -44,16 +46,21 @@ pub struct PushTagsComponent { impl PushTagsComponent { /// pub fn new( + repo: &RepoPathRef, queue: &Queue, sender: &Sender, theme: SharedTheme, key_config: SharedKeyConfig, ) -> Self { Self { + repo: repo.clone(), queue: queue.clone(), pending: false, visible: false, - git_push: AsyncPushTags::new(sender), + git_push: AsyncPushTags::new( + repo.borrow().clone(), + sender, + ), progress: None, input_cred: CredComponent::new( theme.clone(), @@ -67,9 +74,9 @@ impl PushTagsComponent { /// pub fn push_tags(&mut self) -> Result<()> { self.show()?; - if need_username_password()? { - let cred = - extract_username_password().unwrap_or_else(|_| { + if need_username_password(&self.repo.borrow())? { + let cred = extract_username_password(&self.repo.borrow()) + .unwrap_or_else(|_| { BasicAuthCredential::new(None, None) }); if cred.is_complete() { @@ -90,7 +97,7 @@ impl PushTagsComponent { self.pending = true; self.progress = None; self.git_push.request(PushTagsRequest { - remote: get_default_remote(CWD)?, + remote: get_default_remote(&self.repo.borrow())?, basic_credential: cred, })?; Ok(()) diff --git a/src/components/rename_branch.rs b/src/components/rename_branch.rs index 247817aa78..757f86bb17 100644 --- a/src/components/rename_branch.rs +++ b/src/components/rename_branch.rs @@ -10,14 +10,12 @@ use crate::{ ui::style::SharedTheme, }; use anyhow::Result; -use asyncgit::{ - sync::{self}, - CWD, -}; +use asyncgit::sync::{self, RepoPathRef}; use crossterm::event::Event; use tui::{backend::Backend, layout::Rect, Frame}; pub struct RenameBranchComponent { + repo: RepoPathRef, input: TextInputComponent, branch_ref: Option, queue: Queue, @@ -92,11 +90,13 @@ impl Component for RenameBranchComponent { impl RenameBranchComponent { /// pub fn new( + repo: RepoPathRef, queue: Queue, theme: SharedTheme, key_config: SharedKeyConfig, ) -> Self { Self { + repo, queue, input: TextInputComponent::new( theme, @@ -127,8 +127,11 @@ impl RenameBranchComponent { /// pub fn rename_branch(&mut self) { if let Some(br) = &self.branch_ref { - let res = - sync::rename_branch(CWD, br, self.input.get_text()); + let res = sync::rename_branch( + &self.repo.borrow(), + br, + self.input.get_text(), + ); match res { Ok(_) => { diff --git a/src/components/revision_files.rs b/src/components/revision_files.rs index 5f9116b7c5..12d9d47af3 100644 --- a/src/components/revision_files.rs +++ b/src/components/revision_files.rs @@ -11,10 +11,7 @@ use crate::{ AsyncAppNotification, AsyncNotification, }; use anyhow::Result; -use asyncgit::{ - sync::{self, CommitId, TreeFile}, - CWD, -}; +use asyncgit::sync::{self, CommitId, RepoPathRef, TreeFile}; use crossbeam_channel::Sender; use crossterm::event::Event; use filetreelist::{FileTree, FileTreeItem}; @@ -37,6 +34,7 @@ enum Focus { } pub struct RevisionFilesComponent { + repo: RepoPathRef, queue: Queue, theme: SharedTheme, //TODO: store TreeFiles in `tree` @@ -52,6 +50,7 @@ pub struct RevisionFilesComponent { impl RevisionFilesComponent { /// pub fn new( + repo: RepoPathRef, queue: &Queue, sender: &Sender, theme: SharedTheme, @@ -62,6 +61,7 @@ impl RevisionFilesComponent { tree: FileTree::default(), scroll: VerticalScroll::new(), current_file: SyntaxTextComponent::new( + repo.clone(), sender, key_config.clone(), theme.clone(), @@ -71,6 +71,7 @@ impl RevisionFilesComponent { revision: None, focus: Focus::Tree, key_config, + repo, } } @@ -79,7 +80,8 @@ impl RevisionFilesComponent { let same_id = self.revision.map(|c| c == commit).unwrap_or_default(); if !same_id { - self.files = sync::tree_files(CWD, commit)?; + self.files = + sync::tree_files(&self.repo.borrow(), commit)?; let filenames: Vec<&Path> = self.files.iter().map(|f| f.path.as_path()).collect(); self.tree = FileTree::new(&filenames, &BTreeSet::new())?; diff --git a/src/components/revision_files_popup.rs b/src/components/revision_files_popup.rs index 6b5f64f6d4..6b5123a1b7 100644 --- a/src/components/revision_files_popup.rs +++ b/src/components/revision_files_popup.rs @@ -13,7 +13,7 @@ use crate::{ AsyncAppNotification, AsyncNotification, }; use anyhow::Result; -use asyncgit::sync::CommitId; +use asyncgit::sync::{CommitId, RepoPathRef}; use crossbeam_channel::Sender; use crossterm::event::Event; use tui::{backend::Backend, layout::Rect, widgets::Clear, Frame}; @@ -27,6 +27,7 @@ pub struct RevisionFilesPopup { impl RevisionFilesPopup { /// pub fn new( + repo: RepoPathRef, queue: &Queue, sender: &Sender, theme: SharedTheme, @@ -34,6 +35,7 @@ impl RevisionFilesPopup { ) -> Self { Self { files: RevisionFilesComponent::new( + repo, queue, sender, theme, diff --git a/src/components/stashmsg.rs b/src/components/stashmsg.rs index 5e00370d09..5ebeac6b78 100644 --- a/src/components/stashmsg.rs +++ b/src/components/stashmsg.rs @@ -11,11 +11,12 @@ use crate::{ ui::style::SharedTheme, }; use anyhow::Result; -use asyncgit::{sync, CWD}; +use asyncgit::sync::{self, RepoPathRef}; use crossterm::event::Event; use tui::{backend::Backend, layout::Rect, Frame}; pub struct StashMsgComponent { + repo: RepoPathRef, options: StashingOptions, input: TextInputComponent, queue: Queue, @@ -63,8 +64,8 @@ impl Component for StashMsgComponent { if let Event::Key(e) = ev { if e == self.key_config.keys.enter { - match sync::stash_save( - CWD, + let result = sync::stash_save( + &self.repo.borrow(), if self.input.get_text().is_empty() { None } else { @@ -72,7 +73,8 @@ impl Component for StashMsgComponent { }, self.options.stash_untracked, self.options.keep_index, - ) { + ); + match result { Ok(_) => { self.input.clear(); self.hide(); @@ -123,6 +125,7 @@ impl Component for StashMsgComponent { impl StashMsgComponent { /// pub fn new( + repo: RepoPathRef, queue: Queue, theme: SharedTheme, key_config: SharedKeyConfig, @@ -138,6 +141,7 @@ impl StashMsgComponent { true, ), key_config, + repo, } } diff --git a/src/components/syntax_text.rs b/src/components/syntax_text.rs index 9df85a4995..f1f4a24b05 100644 --- a/src/components/syntax_text.rs +++ b/src/components/syntax_text.rs @@ -15,8 +15,8 @@ use crate::{ use anyhow::Result; use asyncgit::{ asyncjob::AsyncSingleJob, - sync::{self, TreeFile}, - ProgressPercent, CWD, + sync::{self, RepoPathRef, TreeFile}, + ProgressPercent, }; use crossbeam_channel::Sender; use crossterm::event::Event; @@ -32,6 +32,7 @@ use tui::{ }; pub struct SyntaxTextComponent { + repo: RepoPathRef, current_file: Option<(String, Either)>, async_highlighting: AsyncSingleJob, syntax_progress: Option, @@ -44,6 +45,7 @@ pub struct SyntaxTextComponent { impl SyntaxTextComponent { /// pub fn new( + repo: RepoPathRef, sender: &Sender, key_config: SharedKeyConfig, theme: SharedTheme, @@ -56,6 +58,7 @@ impl SyntaxTextComponent { focused: false, key_config, theme, + repo, } } @@ -110,7 +113,7 @@ impl SyntaxTextComponent { if !already_loaded { //TODO: fetch file content async aswell - match sync::tree_file_content(CWD, item) { + match sync::tree_file_content(&self.repo.borrow(), item) { Ok(content) => { let content = tabs_to_spaces(content); self.syntax_progress = diff --git a/src/components/tag_commit.rs b/src/components/tag_commit.rs index 3077b69d31..5d478105e3 100644 --- a/src/components/tag_commit.rs +++ b/src/components/tag_commit.rs @@ -10,14 +10,12 @@ use crate::{ ui::style::SharedTheme, }; use anyhow::Result; -use asyncgit::{ - sync::{self, CommitId}, - CWD, -}; +use asyncgit::sync::{self, CommitId, RepoPathRef}; use crossterm::event::Event; use tui::{backend::Backend, layout::Rect, Frame}; pub struct TagCommitComponent { + repo: RepoPathRef, input: TextInputComponent, commit_id: Option, queue: Queue, @@ -92,6 +90,7 @@ impl Component for TagCommitComponent { impl TagCommitComponent { /// pub fn new( + repo: RepoPathRef, queue: Queue, theme: SharedTheme, key_config: SharedKeyConfig, @@ -107,6 +106,7 @@ impl TagCommitComponent { ), commit_id: None, key_config, + repo, } } @@ -121,7 +121,12 @@ impl TagCommitComponent { /// pub fn tag(&mut self) { if let Some(commit_id) = self.commit_id { - match sync::tag(CWD, &commit_id, self.input.get_text()) { + let result = sync::tag( + &self.repo.borrow(), + &commit_id, + self.input.get_text(), + ); + match result { Ok(_) => { self.input.clear(); self.hide(); diff --git a/src/components/taglist.rs b/src/components/taglist.rs index d55bf42ce5..db02bcffd4 100644 --- a/src/components/taglist.rs +++ b/src/components/taglist.rs @@ -18,8 +18,8 @@ use asyncgit::{ extract_username_password, need_username_password, BasicAuthCredential, }, - sync::{get_tags_with_metadata, TagWithMetadata}, - AsyncGitNotification, CWD, + sync::{get_tags_with_metadata, RepoPathRef, TagWithMetadata}, + AsyncGitNotification, }; use crossbeam_channel::Sender; use crossterm::event::Event; @@ -38,6 +38,7 @@ use ui::style::SharedTheme; /// pub struct TagListComponent { + repo: RepoPathRef, theme: SharedTheme, queue: Queue, tags: Option>, @@ -249,6 +250,7 @@ impl Component for TagListComponent { impl TagListComponent { pub fn new( + repo: RepoPathRef, queue: &Queue, sender: &Sender, theme: SharedTheme, @@ -265,6 +267,7 @@ impl TagListComponent { missing_remote_tags: None, async_remote_tags: AsyncSingleJob::new(sender.clone()), key_config, + repo, } } @@ -273,17 +276,19 @@ impl TagListComponent { self.table_state.get_mut().select(Some(0)); self.show()?; - let basic_credential = if need_username_password()? { - let credential = extract_username_password()?; + let basic_credential = + if need_username_password(&self.repo.borrow())? { + let credential = + extract_username_password(&self.repo.borrow())?; - if credential.is_complete() { - Some(credential) + if credential.is_complete() { + Some(credential) + } else { + None + } } else { None - } - } else { - None - }; + }; self.basic_credential = basic_credential; @@ -320,7 +325,7 @@ impl TagListComponent { /// fetch list of tags pub fn update_tags(&mut self) -> Result<()> { - let tags = get_tags_with_metadata(CWD)?; + let tags = get_tags_with_metadata(&self.repo.borrow())?; self.tags = Some(tags); @@ -329,6 +334,7 @@ impl TagListComponent { pub fn update_missing_remote_tags(&mut self) { self.async_remote_tags.spawn(AsyncRemoteTagsJob::new( + self.repo.borrow().clone(), self.basic_credential.clone(), )); } diff --git a/src/main.rs b/src/main.rs index 4b2a9d9050..e36ef64561 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,7 +38,7 @@ mod version; use crate::{app::App, args::process_cmdline}; use anyhow::{bail, Result}; -use asyncgit::AsyncGitNotification; +use asyncgit::{sync::RepoPath, AsyncGitNotification}; use backtrace::Backtrace; use crossbeam_channel::{tick, unbounded, Receiver, Select}; use crossterm::{ @@ -55,6 +55,7 @@ use scopeguard::defer; use scopetime::scope_time; use spinner::Spinner; use std::{ + cell::RefCell, io::{self, Write}, panic, process, time::{Duration, Instant}, @@ -104,7 +105,7 @@ fn main() -> Result<()> { asyncgit::register_tracing_logging(); - if !valid_path()? { + if !valid_path(&cliargs.repo_path) { eprintln!("invalid path\nplease run gitui inside of a non-bare git repository"); return Ok(()); } @@ -134,8 +135,14 @@ fn main() -> Result<()> { let ticker = tick(TICK_INTERVAL); let spinner_ticker = tick(SPINNER_INTERVAL); - let mut app = - App::new(&tx_git, &tx_app, input, theme, key_config); + let mut app = App::new( + RefCell::new(cliargs.repo_path), + &tx_git, + &tx_app, + input, + theme, + key_config, + ); let mut spinner = Spinner::default(); let mut first_update = true; @@ -238,9 +245,8 @@ fn draw( Ok(()) } -fn valid_path() -> Result { - Ok(asyncgit::sync::is_repo(asyncgit::CWD) - && !asyncgit::sync::is_bare_repo(asyncgit::CWD)?) +fn valid_path(repo_path: &RepoPath) -> bool { + asyncgit::sync::is_repo(repo_path) } fn select_event( diff --git a/src/tabs/files.rs b/src/tabs/files.rs index 4838c76700..76a6f5df27 100644 --- a/src/tabs/files.rs +++ b/src/tabs/files.rs @@ -17,10 +17,11 @@ use crate::{ AsyncAppNotification, AsyncNotification, }; use anyhow::Result; -use asyncgit::{sync, CWD}; +use asyncgit::sync::{self, RepoPathRef}; use crossbeam_channel::Sender; pub struct FilesTab { + repo: RepoPathRef, visible: bool, theme: SharedTheme, key_config: SharedKeyConfig, @@ -30,6 +31,7 @@ pub struct FilesTab { impl FilesTab { /// pub fn new( + repo: RepoPathRef, sender: &Sender, queue: &Queue, theme: SharedTheme, @@ -38,6 +40,7 @@ impl FilesTab { Self { visible: false, files: RevisionFilesComponent::new( + repo.clone(), queue, sender, theme.clone(), @@ -45,13 +48,14 @@ impl FilesTab { ), theme, key_config, + repo, } } /// pub fn update(&mut self) -> Result<()> { if self.is_visible() { - if let Ok(head) = sync::get_head(CWD) { + if let Ok(head) = sync::get_head(&self.repo.borrow()) { self.files.set_commit(head)?; } } diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 30cfa61ec0..1204b216b6 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -12,9 +12,9 @@ use crate::{ use anyhow::Result; use asyncgit::{ cached, - sync::{self, CommitId}, + sync::{self, CommitId, RepoPathRef}, AsyncGitNotification, AsyncLog, AsyncTags, CommitFilesParams, - FetchStatus, CWD, + FetchStatus, }; use crossbeam_channel::Sender; use crossterm::event::Event; @@ -30,6 +30,7 @@ const SLICE_SIZE: usize = 1200; /// pub struct Revlog { + repo: RepoPathRef, commit_details: CommitDetailsComponent, list: CommitList, git_log: AsyncLog, @@ -43,14 +44,17 @@ pub struct Revlog { impl Revlog { /// pub fn new( + repo: &RepoPathRef, queue: &Queue, sender: &Sender, theme: SharedTheme, key_config: SharedKeyConfig, ) -> Self { Self { + repo: repo.clone(), queue: queue.clone(), commit_details: CommitDetailsComponent::new( + repo, queue, sender, theme.clone(), @@ -61,10 +65,14 @@ impl Revlog { theme, key_config.clone(), ), - git_log: AsyncLog::new(sender, None), - git_tags: AsyncTags::new(sender), + git_log: AsyncLog::new( + repo.borrow().clone(), + sender, + None, + ), + git_tags: AsyncTags::new(repo.borrow().clone(), sender), visible: false, - branch_name: cached::BranchName::new(CWD), + branch_name: cached::BranchName::new(repo.clone()), key_config, } } @@ -139,7 +147,7 @@ impl Revlog { self.list.selection().saturating_sub(SLICE_SIZE / 2); let commits = sync::get_commits_info( - CWD, + &self.repo.borrow(), &self.git_log.get_slice(want_min, SLICE_SIZE)?, self.list.current_size().0.into(), ); diff --git a/src/tabs/stashing.rs b/src/tabs/stashing.rs index 13d10a4a4b..d0e9a165bc 100644 --- a/src/tabs/stashing.rs +++ b/src/tabs/stashing.rs @@ -12,8 +12,8 @@ use crate::{ }; use anyhow::Result; use asyncgit::{ - sync::{self, status::StatusType}, - AsyncGitNotification, AsyncStatus, StatusParams, CWD, + sync::{self, status::StatusType, RepoPathRef}, + AsyncGitNotification, AsyncStatus, StatusParams, }; use crossbeam_channel::Sender; use crossterm::event::Event; @@ -31,6 +31,7 @@ pub struct StashingOptions { } pub struct Stashing { + repo: RepoPathRef, index: StatusTreeComponent, visible: bool, options: StashingOptions, @@ -45,12 +46,14 @@ impl Stashing { /// pub fn new( + repo: &RepoPathRef, sender: &Sender, queue: &Queue, theme: SharedTheme, key_config: SharedKeyConfig, ) -> Self { Self { + repo: repo.clone(), index: StatusTreeComponent::new( &strings::stashing_files_title(&key_config), true, @@ -64,7 +67,10 @@ impl Stashing { stash_untracked: true, }, theme, - git_status: AsyncStatus::new(sender.clone()), + git_status: AsyncStatus::new( + repo.borrow().clone(), + sender.clone(), + ), queue: queue.clone(), key_config, } @@ -258,7 +264,7 @@ impl Component for Stashing { fn show(&mut self) -> Result<()> { let config_untracked_files = - sync::untracked_files_config(CWD)?; + sync::untracked_files_config(&self.repo.borrow())?; self.options.stash_untracked = !config_untracked_files.include_none(); diff --git a/src/tabs/stashlist.rs b/src/tabs/stashlist.rs index 721e265a6c..5136493555 100644 --- a/src/tabs/stashlist.rs +++ b/src/tabs/stashlist.rs @@ -9,13 +9,11 @@ use crate::{ ui::style::SharedTheme, }; use anyhow::Result; -use asyncgit::{ - sync::{self, CommitId}, - CWD, -}; +use asyncgit::sync::{self, CommitId, RepoPath, RepoPathRef}; use crossterm::event::Event; pub struct StashList { + repo: RepoPathRef, list: CommitList, visible: bool, queue: Queue, @@ -25,6 +23,7 @@ pub struct StashList { impl StashList { /// pub fn new( + repo: RepoPathRef, queue: &Queue, theme: SharedTheme, key_config: SharedKeyConfig, @@ -38,15 +37,19 @@ impl StashList { ), queue: queue.clone(), key_config, + repo, } } /// pub fn update(&mut self) -> Result<()> { if self.is_visible() { - let stashes = sync::get_stashes(CWD)?; - let commits = - sync::get_commits_info(CWD, stashes.as_slice(), 100)?; + let stashes = sync::get_stashes(&self.repo.borrow())?; + let commits = sync::get_commits_info( + &self.repo.borrow(), + stashes.as_slice(), + 100, + )?; self.list.set_count_total(commits.len()); self.list.items().set_items(0, commits); @@ -57,7 +60,8 @@ impl StashList { fn apply_stash(&mut self) { if let Some(e) = self.list.selected_entry() { - match sync::stash_apply(CWD, e.id, false) { + match sync::stash_apply(&self.repo.borrow(), e.id, false) + { Ok(_) => { self.queue.push(InternalEvent::TabSwitch); } @@ -97,26 +101,29 @@ impl StashList { } /// Called when a pending stash action has been confirmed - pub fn action_confirmed(action: &Action) -> Result<()> { + pub fn action_confirmed( + repo: &RepoPath, + action: &Action, + ) -> Result<()> { match action { - Action::StashDrop(ids) => Self::drop(ids)?, - Action::StashPop(id) => Self::pop(*id)?, + Action::StashDrop(ids) => Self::drop(repo, ids)?, + Action::StashPop(id) => Self::pop(repo, *id)?, _ => (), }; Ok(()) } - fn drop(ids: &[CommitId]) -> Result<()> { + fn drop(repo: &RepoPath, ids: &[CommitId]) -> Result<()> { for id in ids { - sync::stash_drop(CWD, *id)?; + sync::stash_drop(repo, *id)?; } Ok(()) } - fn pop(id: CommitId) -> Result<()> { - sync::stash_pop(CWD, id)?; + fn pop(repo: &RepoPath, id: CommitId) -> Result<()> { + sync::stash_pop(repo, id)?; Ok(()) } } diff --git a/src/tabs/status.rs b/src/tabs/status.rs index 6fa2d10970..65dcd84a18 100644 --- a/src/tabs/status.rs +++ b/src/tabs/status.rs @@ -14,10 +14,12 @@ use crate::{ use anyhow::Result; use asyncgit::{ cached, - sync::{self, status::StatusType, RepoState}, + sync::{ + self, status::StatusType, RepoPath, RepoPathRef, RepoState, + }, sync::{BranchCompare, CommitId}, AsyncDiff, AsyncGitNotification, AsyncStatus, DiffParams, - DiffType, StatusParams, CWD, + DiffType, StatusParams, }; use crossbeam_channel::Sender; use crossterm::event::Event; @@ -56,6 +58,7 @@ enum DiffTarget { } pub struct Status { + repo: RepoPathRef, visible: bool, focus: Focus, diff_target: DiffTarget, @@ -79,7 +82,7 @@ impl DrawableComponent for Status { f: &mut tui::Frame, rect: tui::layout::Rect, ) -> Result<()> { - let repo_unclean = Self::repo_state_unclean(); + let repo_unclean = self.repo_state_unclean(); let rects = if repo_unclean { Layout::default() .direction(Direction::Vertical) @@ -134,7 +137,7 @@ impl DrawableComponent for Status { self.draw_branch_state(f, &left_chunks); if repo_unclean { - Self::draw_repo_state(f, rects[1]); + self.draw_repo_state(f, rects[1]); } Ok(()) @@ -146,18 +149,21 @@ impl Status { /// pub fn new( + repo: RepoPathRef, queue: &Queue, sender: &Sender, theme: SharedTheme, key_config: SharedKeyConfig, options: SharedOptions, ) -> Self { + let repo_clone = repo.borrow().clone(); Self { queue: queue.clone(), visible: true, focus: Focus::WorkDir, diff_target: DiffTarget::WorkingDir, index_wd: ChangesComponent::new( + repo.clone(), &strings::title_status(&key_config), true, true, @@ -167,6 +173,7 @@ impl Status { options.clone(), ), index: ChangesComponent::new( + repo.clone(), &strings::title_index(&key_config), false, false, @@ -176,19 +183,27 @@ impl Status { options.clone(), ), diff: DiffComponent::new( + repo.clone(), queue.clone(), theme, key_config.clone(), false, ), - git_diff: AsyncDiff::new(sender), - git_status_workdir: AsyncStatus::new(sender.clone()), - git_status_stage: AsyncStatus::new(sender.clone()), + git_diff: AsyncDiff::new(repo_clone.clone(), sender), + git_status_workdir: AsyncStatus::new( + repo_clone.clone(), + sender.clone(), + ), + git_status_stage: AsyncStatus::new( + repo_clone, + sender.clone(), + ), git_action_executed: false, git_branch_state: None, - git_branch_name: cached::BranchName::new(CWD), + git_branch_name: cached::BranchName::new(repo.clone()), key_config, options, + repo, } } @@ -232,11 +247,11 @@ impl Status { } } - fn repo_state_text(state: &RepoState) -> String { + fn repo_state_text(repo: &RepoPath, state: &RepoState) -> String { match state { RepoState::Merge => { let ids = - sync::mergehead_ids(CWD).unwrap_or_default(); + sync::mergehead_ids(repo).unwrap_or_default(); format!( "Commits: {}", @@ -246,7 +261,7 @@ impl Status { ) } RepoState::Rebase => { - if let Ok(p) = sync::rebase_progress(CWD) { + if let Ok(p) = sync::rebase_progress(repo) { format!( "Step: {}/{} Current Commit: {}", p.current + 1, @@ -265,12 +280,16 @@ impl Status { } fn draw_repo_state( + &self, f: &mut tui::Frame, r: tui::layout::Rect, ) { - if let Ok(state) = sync::repo_state(CWD) { + if let Ok(state) = sync::repo_state(&self.repo.borrow()) { if state != RepoState::Clean { - let txt = Self::repo_state_text(&state); + let txt = Self::repo_state_text( + &self.repo.borrow(), + &state, + ); let w = Paragraph::new(txt) .block( @@ -290,8 +309,8 @@ impl Status { } } - fn repo_state_unclean() -> bool { - if let Ok(state) = sync::repo_state(CWD) { + fn repo_state_unclean(&self) -> bool { + if let Ok(state) = sync::repo_state(&self.repo.borrow()) { if state != RepoState::Clean { return true; } @@ -497,7 +516,10 @@ impl Status { /// called after confirmation pub fn reset(&mut self, item: &ResetItem) -> bool { - if let Err(e) = sync::reset_workdir(CWD, item.path.as_str()) { + if let Err(e) = sync::reset_workdir( + &self.repo.borrow(), + item.path.as_str(), + ) { self.queue.push(InternalEvent::ShowErrorMsg(format!( "reset failed:\n{}", e @@ -542,15 +564,18 @@ impl Status { try_or_popup!( self, "undo commit failed:", - sync::utils::undo_last_commit(CWD) + sync::utils::undo_last_commit(&self.repo.borrow()) ); } fn branch_compare(&mut self) { self.git_branch_state = self.git_branch_name.last().and_then(|branch| { - sync::branch_compare_upstream(CWD, branch.as_str()) - .ok() + sync::branch_compare_upstream( + &self.repo.borrow(), + branch.as_str(), + ) + .ok() }); } @@ -560,25 +585,31 @@ impl Status { .map_or(true, |state| state.ahead > 0) } - fn can_abort_merge() -> bool { - sync::repo_state(CWD).unwrap_or(RepoState::Clean) + fn can_abort_merge(&self) -> bool { + sync::repo_state(&self.repo.borrow()) + .unwrap_or(RepoState::Clean) == RepoState::Merge } - fn pending_rebase() -> bool { - sync::repo_state(CWD).unwrap_or(RepoState::Clean) + fn pending_rebase(&self) -> bool { + sync::repo_state(&self.repo.borrow()) + .unwrap_or(RepoState::Clean) == RepoState::Rebase } pub fn abort_merge(&self) { - try_or_popup!(self, "abort merge", sync::abort_merge(CWD)); + try_or_popup!( + self, + "abort merge", + sync::abort_merge(&self.repo.borrow()) + ); } pub fn abort_rebase(&self) { try_or_popup!( self, "abort rebase", - sync::abort_pending_rebase(CWD) + sync::abort_pending_rebase(&self.repo.borrow()) ); } @@ -586,7 +617,7 @@ impl Status { try_or_popup!( self, "continue rebase", - sync::continue_pending_rebase(CWD) + sync::continue_pending_rebase(&self.repo.borrow()) ); } @@ -637,7 +668,7 @@ impl Status { fn can_commit(&self) -> bool { self.index.focused() && !self.index.is_empty() - && !Self::pending_rebase() + && !self.pending_rebase() } } @@ -694,25 +725,25 @@ impl Component for Status { out.push(CommandInfo::new( strings::commands::undo_commit(&self.key_config), true, - (!Self::pending_rebase() && !focus_on_diff) + (!self.pending_rebase() && !focus_on_diff) || force_all, )); out.push(CommandInfo::new( strings::commands::abort_merge(&self.key_config), true, - Self::can_abort_merge() || force_all, + self.can_abort_merge() || force_all, )); out.push(CommandInfo::new( strings::commands::continue_rebase(&self.key_config), true, - Self::pending_rebase() || force_all, + self.pending_rebase() || force_all, )); out.push(CommandInfo::new( strings::commands::abort_rebase(&self.key_config), true, - Self::pending_rebase() || force_all, + self.pending_rebase() || force_all, )); } @@ -819,7 +850,7 @@ impl Component for Status { )); Ok(EventState::Consumed) } else if k == self.key_config.keys.abort_merge - && Self::can_abort_merge() + && self.can_abort_merge() { self.queue.push(InternalEvent::ConfirmAction( Action::AbortMerge, @@ -827,7 +858,7 @@ impl Component for Status { Ok(EventState::Consumed) } else if k == self.key_config.keys.abort_merge - && Self::pending_rebase() + && self.pending_rebase() { self.queue.push(InternalEvent::ConfirmAction( Action::AbortRebase, @@ -835,7 +866,7 @@ impl Component for Status { Ok(EventState::Consumed) } else if k == self.key_config.keys.rebase_branch - && Self::pending_rebase() + && self.pending_rebase() { self.continue_rebase(); self.queue.push(InternalEvent::Update(