From dad8e8d43de79a3c39a37f118e529dc88fab5495 Mon Sep 17 00:00:00 2001 From: Stephan Dilly Date: Tue, 17 Aug 2021 14:24:25 +0200 Subject: cargo fmt: use hardtabs since it does not support hard-whitespaces its the only way to make whitespaces consisitent and checked --- .vscode/settings.json | 1 - asyncgit/src/asyncjob/mod.rs | 368 ++--- asyncgit/src/blame.rs | 312 ++--- asyncgit/src/cached/branchname.rs | 66 +- asyncgit/src/commit_files.rs | 180 +-- asyncgit/src/diff.rs | 334 ++--- asyncgit/src/error.rs | 64 +- asyncgit/src/fetch.rs | 276 ++-- asyncgit/src/lib.rs | 92 +- asyncgit/src/progress.rs | 66 +- asyncgit/src/push.rs | 290 ++-- asyncgit/src/push_tags.rs | 264 ++-- asyncgit/src/remote_progress.rs | 240 ++-- asyncgit/src/remote_tags.rs | 100 +- asyncgit/src/revlog.rs | 356 ++--- asyncgit/src/status.rs | 280 ++-- asyncgit/src/sync/blame.rs | 376 +++--- asyncgit/src/sync/branch/merge_commit.rs | 466 +++---- asyncgit/src/sync/branch/merge_ff.rs | 236 ++-- asyncgit/src/sync/branch/merge_rebase.rs | 576 ++++---- asyncgit/src/sync/branch/mod.rs | 1162 ++++++++-------- asyncgit/src/sync/branch/rename.rs | 92 +- asyncgit/src/sync/commit.rs | 460 +++---- asyncgit/src/sync/commit_details.rs | 236 ++-- asyncgit/src/sync/commit_files.rs | 270 ++-- asyncgit/src/sync/commits_info.rs | 328 ++--- asyncgit/src/sync/config.rs | 152 +-- asyncgit/src/sync/cred.rs | 446 +++--- asyncgit/src/sync/diff.rs | 849 ++++++------ asyncgit/src/sync/hooks.rs | 498 +++---- asyncgit/src/sync/hunks.rs | 296 ++-- asyncgit/src/sync/ignore.rs | 248 ++-- asyncgit/src/sync/logwalker.rs | 412 +++--- asyncgit/src/sync/merge.rs | 144 +- asyncgit/src/sync/mod.rs | 504 +++---- asyncgit/src/sync/patches.rs | 84 +- asyncgit/src/sync/remotes/callbacks.rs | 404 +++--- asyncgit/src/sync/remotes/mod.rs | 338 ++--- asyncgit/src/sync/remotes/push.rs | 904 ++++++------- asyncgit/src/sync/remotes/tags.rs | 380 +++--- asyncgit/src/sync/reset.rs | 412 +++--- asyncgit/src/sync/staging/discard_tracked.rs | 442 +++--- asyncgit/src/sync/staging/mod.rs | 308 ++--- asyncgit/src/sync/staging/stage_tracked.rs | 270 ++-- asyncgit/src/sync/stash.rs | 474 +++---- asyncgit/src/sync/state.rs | 32 +- asyncgit/src/sync/status.rs | 230 ++-- asyncgit/src/sync/tags.rs | 284 ++-- asyncgit/src/sync/tree.rs | 402 +++--- asyncgit/src/sync/utils.rs | 608 ++++----- asyncgit/src/tags.rs | 234 ++-- filetreelist/src/error.rs | 8 +- filetreelist/src/filetree.rs | 918 ++++++------- filetreelist/src/filetreeitems.rs | 1586 +++++++++++----------- filetreelist/src/item.rs | 368 ++--- filetreelist/src/lib.rs | 16 +- filetreelist/src/tree_iter.rs | 44 +- filetreelist/src/treeitems_iter.rs | 84 +- invalidstring/src/lib.rs | 8 +- rustfmt.toml | 2 +- scopetime/src/lib.rs | 80 +- src/app.rs | 1614 +++++++++++----------- src/args.rs | 164 +-- src/bug_report.rs | 36 +- src/clipboard.rs | 86 +- src/cmdbar.rs | 368 ++--- src/components/blame_file.rs | 978 +++++++------- src/components/branchlist.rs | 1109 ++++++++------- src/components/changes.rs | 556 ++++---- src/components/command.rs | 134 +- src/components/commit.rs | 736 +++++----- src/components/commit_details/details.rs | 952 ++++++------- src/components/commit_details/mod.rs | 368 ++--- src/components/commitlist.rs | 871 ++++++------ src/components/create_branch.rs | 308 ++--- src/components/cred.rs | 278 ++-- src/components/diff.rs | 1528 ++++++++++----------- src/components/externaleditor.rs | 330 ++--- src/components/filetree.rs | 1050 +++++++-------- src/components/help.rs | 446 +++--- src/components/inspect_commit.rs | 516 +++---- src/components/mod.rs | 234 ++-- src/components/msg.rs | 220 +-- src/components/pull.rs | 490 +++---- src/components/push.rs | 558 ++++---- src/components/push_tags.rs | 440 +++--- src/components/rename_branch.rs | 280 ++-- src/components/reset.rs | 240 ++-- src/components/revision_files.rs | 548 ++++---- src/components/revision_files_popup.rs | 222 +-- src/components/stashmsg.rs | 246 ++-- src/components/syntax_text.rs | 444 +++--- src/components/tag_commit.rs | 244 ++-- src/components/taglist.rs | 818 +++++------ src/components/textinput.rs | 1022 +++++++------- src/components/utils/filetree.rs | 740 +++++----- src/components/utils/logitems.rs | 144 +- src/components/utils/mod.rs | 64 +- src/components/utils/scroll_vertical.rs | 236 ++-- src/components/utils/statustree.rs | 1742 ++++++++++++------------ src/input.rs | 196 +-- src/keys.rs | 400 +++--- src/main.rs | 422 +++--- src/notify_mutex.rs | 58 +- src/profiler.rs | 52 +- src/queue.rs | 164 +-- src/spinner.rs | 80 +- src/strings.rs | 1872 +++++++++++++------------- src/tabs/files.rs | 182 +-- src/tabs/revlog.rs | 664 ++++----- src/tabs/stashing.rs | 438 +++--- src/tabs/stashlist.rs | 388 +++--- src/tabs/status.rs | 1396 ++++++++++--------- src/ui/mod.rs | 174 +-- src/ui/reflow.rs | 1217 +++++++++-------- src/ui/scrollbar.rs | 110 +- src/ui/scrolllist.rs | 112 +- src/ui/stateful_paragraph.rs | 346 ++--- src/ui/style.rs | 556 ++++---- src/ui/syntax_text.rs | 302 ++--- src/version.rs | 46 +- 121 files changed, 25246 insertions(+), 25249 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index a9c40cf5..bf7d5340 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,4 @@ { "editor.formatOnSave": true, "workbench.settings.enableNaturalLanguageSearch": false, - "telemetry.enableTelemetry": false, } \ No newline at end of file diff --git a/asyncgit/src/asyncjob/mod.rs b/asyncgit/src/asyncjob/mod.rs index 3b48787c..161df802 100644 --- a/asyncgit/src/asyncjob/mod.rs +++ b/asyncgit/src/asyncjob/mod.rs @@ -8,202 +8,202 @@ use std::sync::{Arc, Mutex}; /// trait that defines an async task we can run on a threadpool pub trait AsyncJob: Send + Sync + Clone { - /// can run a synchronous time intensive task - fn run(&mut self); + /// can run a synchronous time intensive task + fn run(&mut self); } /// Abstraction for a FIFO task queue that will only queue up **one** `next` job. /// It keeps overwriting the next job until it is actually taken to be processed #[derive(Debug, Clone)] pub struct AsyncSingleJob { - next: Arc>>, - last: Arc>>, - sender: Sender, - pending: Arc>, - notification: T, + next: Arc>>, + last: Arc>>, + sender: Sender, + pending: Arc>, + notification: T, } impl - AsyncSingleJob + AsyncSingleJob { - /// - pub fn new(sender: Sender, value: T) -> Self { - Self { - next: Arc::new(Mutex::new(None)), - last: Arc::new(Mutex::new(None)), - pending: Arc::new(Mutex::new(())), - notification: value, - sender, - } - } - - /// - pub fn is_pending(&self) -> bool { - self.pending.try_lock().is_err() - } - - /// makes sure `next` is cleared and returns `true` if it actually canceled something - pub fn cancel(&mut self) -> bool { - if let Ok(mut next) = self.next.lock() { - if next.is_some() { - *next = None; - return true; - } - } - - false - } - - /// take out last finished job - pub fn take_last(&self) -> Option { - if let Ok(mut last) = self.last.lock() { - last.take() - } else { - None - } - } - - /// spawns `task` if nothing is running currently, otherwise schedules as `next` overwriting if `next` was set before - pub fn spawn(&mut self, task: J) -> bool { - self.schedule_next(task); - self.check_for_job() - } - - fn check_for_job(&self) -> bool { - if self.is_pending() { - return false; - } - - if let Some(task) = self.take_next() { - let self_arc = self.clone(); - - rayon_core::spawn(move || { - if let Err(e) = self_arc.run_job(task) { - log::error!("async job error: {}", e); - } - }); - - return true; - } - - false - } - - fn run_job(&self, mut task: J) -> Result<()> { - //limit the pending scope - { - let _pending = self.pending.lock()?; - - task.run(); - - if let Ok(mut last) = self.last.lock() { - *last = Some(task); - } - - self.sender.send(self.notification)?; - } - - self.check_for_job(); - - Ok(()) - } - - fn schedule_next(&mut self, task: J) { - if let Ok(mut next) = self.next.lock() { - *next = Some(task); - } - } - - fn take_next(&self) -> Option { - if let Ok(mut next) = self.next.lock() { - next.take() - } else { - None - } - } + /// + pub fn new(sender: Sender, value: T) -> Self { + Self { + next: Arc::new(Mutex::new(None)), + last: Arc::new(Mutex::new(None)), + pending: Arc::new(Mutex::new(())), + notification: value, + sender, + } + } + + /// + pub fn is_pending(&self) -> bool { + self.pending.try_lock().is_err() + } + + /// makes sure `next` is cleared and returns `true` if it actually canceled something + pub fn cancel(&mut self) -> bool { + if let Ok(mut next) = self.next.lock() { + if next.is_some() { + *next = None; + return true; + } + } + + false + } + + /// take out last finished job + pub fn take_last(&self) -> Option { + if let Ok(mut last) = self.last.lock() { + last.take() + } else { + None + } + } + + /// spawns `task` if nothing is running currently, otherwise schedules as `next` overwriting if `next` was set before + pub fn spawn(&mut self, task: J) -> bool { + self.schedule_next(task); + self.check_for_job() + } + + fn check_for_job(&self) -> bool { + if self.is_pending() { + return false; + } + + if let Some(task) = self.take_next() { + let self_arc = self.clone(); + + rayon_core::spawn(move || { + if let Err(e) = self_arc.run_job(task) { + log::error!("async job error: {}", e); + } + }); + + return true; + } + + false + } + + fn run_job(&self, mut task: J) -> Result<()> { + //limit the pending scope + { + let _pending = self.pending.lock()?; + + task.run(); + + if let Ok(mut last) = self.last.lock() { + *last = Some(task); + } + + self.sender.send(self.notification)?; + } + + self.check_for_job(); + + Ok(()) + } + + fn schedule_next(&mut self, task: J) { + if let Ok(mut next) = self.next.lock() { + *next = Some(task); + } + } + + fn take_next(&self) -> Option { + if let Ok(mut next) = self.next.lock() { + next.take() + } else { + None + } + } } #[cfg(test)] mod test { - use super::*; - use crossbeam_channel::unbounded; - use pretty_assertions::assert_eq; - use std::{ - sync::atomic::AtomicU32, thread::sleep, time::Duration, - }; - - #[derive(Clone)] - struct TestJob { - v: Arc, - value_to_add: u32, - } - - impl AsyncJob for TestJob { - fn run(&mut self) { - sleep(Duration::from_millis(100)); - - self.v.fetch_add( - self.value_to_add, - std::sync::atomic::Ordering::Relaxed, - ); - } - } - - type Notificaton = (); - - #[test] - fn test_overwrite() { - let (sender, receiver) = unbounded(); - - let mut job: AsyncSingleJob = - AsyncSingleJob::new(sender, ()); - - let task = TestJob { - v: Arc::new(AtomicU32::new(1)), - value_to_add: 1, - }; - - assert!(job.spawn(task.clone())); - sleep(Duration::from_millis(1)); - for _ in 0..5 { - assert!(!job.spawn(task.clone())); - } - - let _foo = receiver.recv().unwrap(); - let _foo = receiver.recv().unwrap(); - assert!(receiver.is_empty()); - - assert_eq!( - task.v.load(std::sync::atomic::Ordering::Relaxed), - 3 - ); - } - - #[test] - fn test_cancel() { - let (sender, receiver) = unbounded(); - - let mut job: AsyncSingleJob = - AsyncSingleJob::new(sender, ()); - - let task = TestJob { - v: Arc::new(AtomicU32::new(1)), - value_to_add: 1, - }; - - assert!(job.spawn(task.clone())); - sleep(Duration::from_millis(1)); - - for _ in 0..5 { - assert!(!job.spawn(task.clone())); - } - assert!(job.cancel()); - - let _foo = receiver.recv().unwrap(); - - assert_eq!( - task.v.load(std::sync::atomic::Ordering::Relaxed), - 2 - ); - } + use super::*; + use crossbeam_channel::unbounded; + use pretty_assertions::assert_eq; + use std::{ + sync::atomic::AtomicU32, thread::sleep, time::Duration, + }; + + #[derive(Clone)] + struct TestJob { + v: Arc, + value_to_add: u32, + } + + impl AsyncJob for TestJob { + fn run(&mut self) { + sleep(Duration::from_millis(100)); + + self.v.fetch_add( + self.value_to_add, + std::sync::atomic::Ordering::Relaxed, + ); + } + } + + type Notificaton = (); + + #[test] + fn test_overwrite() { + let (sender, receiver) = unbounded(); + + let mut job: AsyncSingleJob = + AsyncSingleJob::new(sender, ()); + + let task = TestJob { + v: Arc::new(AtomicU32::new(1)), + value_to_add: 1, + }; + + assert!(job.spawn(task.clone())); + sleep(Duration::from_millis(1)); + for _ in 0..5 { + assert!(!job.spawn(task.clone())); + } + + let _foo = receiver.recv().unwrap(); + let _foo = receiver.recv().unwrap(); + assert!(receiver.is_empty()); + + assert_eq!( + task.v.load(std::sync::atomic::Ordering::Relaxed), + 3 + ); + } + + #[test] + fn test_cancel() { + let (sender, receiver) = unbounded(); + + let mut job: AsyncSingleJob = + AsyncSingleJob::new(sender, ()); + + let task = TestJob { + v: Arc::new(AtomicU32::new(1)), + value_to_add: 1, + }; + + assert!(job.spawn(task.clone())); + sleep(Duration::from_millis(1)); + + for _ in 0..5 { + assert!(!job.spawn(task.clone())); + } + assert!(job.cancel()); + + let _foo = receiver.recv().unwrap(); + + assert_eq!( + task.v.load(std::sync::atomic::Ordering::Relaxed), + 2 + ); + } } diff --git a/asyncgit/src/blame.rs b/asyncgit/src/blame.rs index 9bacfab8..9a2d562f 100644 --- a/asyncgit/src/blame.rs +++ b/asyncgit/src/blame.rs @@ -1,179 +1,179 @@ use crate::{ - error::Result, - hash, - sync::{self, FileBlame}, - AsyncGitNotification, CWD, + error::Result, + hash, + sync::{self, FileBlame}, + AsyncGitNotification, CWD, }; use crossbeam_channel::Sender; use std::{ - hash::Hash, - sync::{ - atomic::{AtomicUsize, Ordering}, - Arc, Mutex, - }, + hash::Hash, + sync::{ + atomic::{AtomicUsize, Ordering}, + Arc, Mutex, + }, }; /// #[derive(Hash, Clone, PartialEq)] pub struct BlameParams { - /// path to the file to blame - pub file_path: String, + /// path to the file to blame + pub file_path: String, } struct Request(R, Option); #[derive(Default, Clone)] struct LastResult { - params: P, - hash: u64, - result: R, + params: P, + hash: u64, + result: R, } /// pub struct AsyncBlame { - current: Arc>>, - last: Arc>>>, - sender: Sender, - pending: Arc, + current: Arc>>, + last: Arc>>>, + sender: Sender, + pending: Arc, } impl AsyncBlame { - /// - pub fn new(sender: &Sender) -> Self { - Self { - current: Arc::new(Mutex::new(Request(0, None))), - last: Arc::new(Mutex::new(None)), - sender: sender.clone(), - pending: Arc::new(AtomicUsize::new(0)), - } - } - - /// - pub fn last( - &mut self, - ) -> Result> { - let last = self.last.lock()?; - - Ok(last.clone().map(|last_result| { - (last_result.params, last_result.result) - })) - } - - /// - pub fn refresh(&mut self) -> Result<()> { - if let Ok(Some(param)) = self.get_last_param() { - self.clear_current()?; - self.request(param)?; - } - Ok(()) - } - - /// - pub fn is_pending(&self) -> bool { - self.pending.load(Ordering::Relaxed) > 0 - } - - /// - pub fn request( - &mut self, - params: BlameParams, - ) -> Result> { - log::trace!("request"); - - let hash = hash(¶ms); - - { - let mut current = self.current.lock()?; - - if current.0 == hash { - return Ok(current.1.clone()); - } - - current.0 = hash; - current.1 = None; - } - - let arc_current = Arc::clone(&self.current); - let arc_last = Arc::clone(&self.last); - let sender = self.sender.clone(); - let arc_pending = Arc::clone(&self.pending); - - self.pending.fetch_add(1, Ordering::Relaxed); - - rayon_core::spawn(move || { - let notify = Self::get_blame_helper( - params, - &arc_last, - &arc_current, - hash, - ); - - let notify = match notify { - Err(err) => { - log::error!("get_blame_helper error: {}", err); - true - } - Ok(notify) => notify, - }; - - arc_pending.fetch_sub(1, Ordering::Relaxed); - - sender - .send(if notify { - AsyncGitNotification::Blame - } else { - AsyncGitNotification::FinishUnchanged - }) - .expect("error sending blame"); - }); - - Ok(None) - } - - fn get_blame_helper( - params: BlameParams, - arc_last: &Arc< - Mutex>>, - >, - arc_current: &Arc>>, - hash: u64, - ) -> Result { - let file_blame = - sync::blame::blame_file(CWD, ¶ms.file_path)?; - - let mut notify = false; - { - let mut current = arc_current.lock()?; - if current.0 == hash { - current.1 = Some(file_blame.clone()); - notify = true; - } - } - - { - let mut last = arc_last.lock()?; - *last = Some(LastResult { - result: file_blame, - hash, - params, - }); - } - - Ok(notify) - } - - fn get_last_param(&self) -> Result> { - Ok(self - .last - .lock()? - .clone() - .map(|last_result| last_result.params)) - } - - fn clear_current(&mut self) -> Result<()> { - let mut current = self.current.lock()?; - current.0 = 0; - current.1 = None; - Ok(()) - } + /// + pub fn new(sender: &Sender) -> Self { + Self { + current: Arc::new(Mutex::new(Request(0, None))), + last: Arc::new(Mutex::new(None)), + sender: sender.clone(), + pending: Arc::new(AtomicUsize::new(0)), + } + } + + /// + pub fn last( + &mut self, + ) -> Result> { + let last = self.last.lock()?; + + Ok(last.clone().map(|last_result| { + (last_result.params, last_result.result) + })) + } + + /// + pub fn refresh(&mut self) -> Result<()> { + if let Ok(Some(param)) = self.get_last_param() { + self.clear_current()?; + self.request(param)?; + } + Ok(()) + } + + /// + pub fn is_pending(&self) -> bool { + self.pending.load(Ordering::Relaxed) > 0 + } + + /// + pub fn request( + &mut self, + params: BlameParams, + ) -> Result> { + log::trace!("request"); + + let hash = hash(¶ms); + + { + let mut current = self.current.lock()?; + + if current.0 == hash { + return Ok(current.1.clone()); + } + + current.0 = hash; + current.1 = None; + } + + let arc_current = Arc::clone(&self.current); + let arc_last = Arc::clone(&self.last); + let sender = self.sender.clone(); + let arc_pending = Arc::clone(&self.pending); + + self.pending.fetch_add(1, Ordering::Relaxed); + + rayon_core::spawn(move || { + let notify = Self::get_blame_helper( + params, + &arc_last, + &arc_current, + hash, + ); + + let notify = match notify { + Err(err) => { + log::error!("get_blame_helper error: {}", err); + true + } + Ok(notify) => notify, + }; + + arc_pending.fetch_sub(1, Ordering::Relaxed); + + sender + .send(if notify { + AsyncGitNotification::Blame + } else { + AsyncGitNotification::FinishUnchanged + }) + .expect("error sending blame"); + }); + + Ok(None) + } + + fn get_blame_helper( + params: BlameParams, + arc_last: &Arc< + Mutex>>, + >, + arc_current: &Arc>>, + hash: u64, + ) -> Result { + let file_blame = + sync::blame::blame_file(CWD, ¶ms.file_path)?; + + let mut notify = false; + { + let mut current = arc_current.lock()?; + if current.0 == hash { + current.1 = Some(file_blame.clone()); + notify = true; + } + } + + { + let mut last = arc_last.lock()?; + *last = Some(LastResult { + result: file_blame, + hash, + params, + }); + } + + Ok(notify) + } + + fn get_last_param(&self) -> Result> { + Ok(self + .last + .lock()? + .clone() + .map(|last_result| last_result.params)) + } + + fn clear_current(&mut self) -> Result<()> { + let mut current = self.current.lock()?; + current.0 = 0; + current.1 = None; + Ok(()) + } } diff --git a/asyncgit/src/cached/branchname.rs b/asyncgit/src/cached/branchname.rs index 50ec7975..d5c53546 100644 --- a/asyncgit/src/cached/branchname.rs +++ b/asyncgit/src/cached/branchname.rs @@ -1,48 +1,48 @@ use crate::{ - error::Result, - sync::{self, branch::get_branch_name}, + error::Result, + sync::{self, branch::get_branch_name}, }; use sync::Head; /// pub struct BranchName { - last_result: Option<(Head, String)>, - repo_path: String, + last_result: Option<(Head, String)>, + repo_path: String, } impl BranchName { - /// - pub fn new(path: &str) -> Self { - Self { - repo_path: path.to_string(), - last_result: None, - } - } + /// + pub fn new(path: &str) -> Self { + Self { + repo_path: path.to_string(), + last_result: None, + } + } - /// - pub fn lookup(&mut self) -> Result { - let current_head = - sync::get_head_tuple(self.repo_path.as_str())?; + /// + pub fn lookup(&mut self) -> Result { + let current_head = + sync::get_head_tuple(self.repo_path.as_str())?; - if let Some((last_head, branch_name)) = - self.last_result.as_ref() - { - if *last_head == current_head { - return Ok(branch_name.clone()); - } - } + if let Some((last_head, branch_name)) = + self.last_result.as_ref() + { + if *last_head == current_head { + return Ok(branch_name.clone()); + } + } - self.fetch(current_head) - } + self.fetch(current_head) + } - /// - pub fn last(&self) -> Option { - self.last_result.as_ref().map(|last| last.1.clone()) - } + /// + pub fn last(&self) -> Option { + self.last_result.as_ref().map(|last| last.1.clone()) + } - fn fetch(&mut self, head: Head) -> Result { - let name = get_branch_name(self.repo_path.as_str())?; - self.last_result = Some((head, name.clone())); - Ok(name) - } + fn fetch(&mut self, head: Head) -> Result { + let name = get_branch_name(self.repo_path.as_str())?; + self.last_result = Some((head, name.clone())); + Ok(name) + } } diff --git a/asyncgit/src/commit_files.rs b/asyncgit/src/commit_files.rs index a0948312..1bc61725 100644 --- a/asyncgit/src/commit_files.rs +++ b/asyncgit/src/commit_files.rs @@ -1,12 +1,12 @@ use crate::{ - error::Result, - sync::{self, CommitId}, - AsyncGitNotification, StatusItem, CWD, + error::Result, + sync::{self, CommitId}, + AsyncGitNotification, StatusItem, CWD, }; use crossbeam_channel::Sender; use std::sync::{ - atomic::{AtomicUsize, Ordering}, - Arc, Mutex, + atomic::{AtomicUsize, Ordering}, + Arc, Mutex, }; type ResultType = Vec; @@ -14,92 +14,92 @@ struct Request(R, A); /// pub struct AsyncCommitFiles { - current: Arc>>>, - sender: Sender, - pending: Arc, + current: Arc>>>, + sender: Sender, + pending: Arc, } impl AsyncCommitFiles { - /// - pub fn new(sender: &Sender) -> Self { - Self { - current: Arc::new(Mutex::new(None)), - sender: sender.clone(), - pending: Arc::new(AtomicUsize::new(0)), - } - } - - /// - pub fn current( - &mut self, - ) -> Result> { - let c = self.current.lock()?; - - c.as_ref() - .map_or(Ok(None), |c| Ok(Some((c.0, c.1.clone())))) - } - - /// - pub fn is_pending(&self) -> bool { - self.pending.load(Ordering::Relaxed) > 0 - } - - /// - pub fn fetch(&mut self, id: CommitId) -> Result<()> { - if self.is_pending() { - return Ok(()); - } - - log::trace!("request: {}", id.to_string()); - - { - let current = self.current.lock()?; - if let Some(c) = &*current { - if c.0 == id { - return Ok(()); - } - } - } - - let arc_current = Arc::clone(&self.current); - let sender = self.sender.clone(); - let arc_pending = Arc::clone(&self.pending); - - self.pending.fetch_add(1, Ordering::Relaxed); - - rayon_core::spawn(move || { - Self::fetch_helper(id, &arc_current) - .expect("failed to fetch"); - - arc_pending.fetch_sub(1, Ordering::Relaxed); - - sender - .send(AsyncGitNotification::CommitFiles) - .expect("error sending"); - }); - - Ok(()) - } - - fn fetch_helper( - id: CommitId, - arc_current: &Arc< - Mutex>>, - >, - ) -> Result<()> { - let res = sync::get_commit_files(CWD, id)?; - - log::trace!( - "get_commit_files: {} ({})", - id.to_string(), - res.len() - ); - - { - let mut current = arc_current.lock()?; - *current = Some(Request(id, res)); - } - - Ok(()) - } + /// + pub fn new(sender: &Sender) -> Self { + Self { + current: Arc::new(Mutex::new(None)), + sender: sender.clone(), + pending: Arc::new(AtomicUsize::new(0)), + } + } + + /// + pub fn current( + &mut self, + ) -> Result> { + let c = self.current.lock()?; + + c.as_ref() + .map_or(Ok(None), |c| Ok(Some((c.0, c.1.clone())))) + } + + /// + pub fn is_pending(&self) -> bool { + self.pending.load(Ordering::Relaxed) > 0 + } + + /// + pub fn fetch(&mut self, id: CommitId) -> Result<()> { + if self.is_pending() { + return Ok(()); + } + + log::trace!("request: {}", id.to_string()); + + { + let current = self.current.lock()?; + if let Some(c) = &*current { + if c.0 == id { + return Ok(()); + } + } + } + + let arc_current = Arc::clone(&self.current); + let sender = self.sender.clone(); + let arc_pending = Arc::clone(&self.pending); + + self.pending.fetch_add(1, Ordering::Relaxed); + + rayon_core::spawn(move || { + Self::fetch_helper(id, &arc_current) + .expect("failed to fetch"); + + arc_pending.fetch_sub(1, Ordering::Relaxed); + + sender + .send(AsyncGitNotification::CommitFiles) + .expect("error sending"); + }); + + Ok(()) + } + + fn fetch_helper( + id: CommitId, + arc_current: &Arc< + Mutex>>, + >, + ) -> Result<()> { + let res = sync::get_commit_files(CWD, id)?; + + log::trace!( + "get_commit_files: {} ({})", + id.to_string(), + res.len() + ); + + { + let mut current = arc_current.lock()?; + *current = Some(Request(id, res)); + } + + Ok(()) + } } diff --git a/asyncgit/src/diff.rs b/asyncgit/src/diff.rs index 9214c50b..06c5e38f 100644 --- a/asyncgit/src/diff.rs +++ b/asyncgit/src/diff.rs @@ -1,195 +1,195 @@ use crate::{ - error::Result, - hash, - sync::{self, CommitId}, - AsyncGitNotification, FileDiff, CWD, + error::Result, + hash, + sync::{self, CommitId}, + AsyncGitNotification, FileDiff, CWD, }; use crossbeam_channel::Sender; use std::{ - hash::Hash, - sync::{ - atomic::{AtomicUsize, Ordering}, - Arc, Mutex, - }, + hash::Hash, + sync::{ + atomic::{AtomicUsize, Ordering}, + Arc, Mutex, + }, }; /// #[derive(Hash, Clone, PartialEq)] pub enum DiffType { - /// diff in a given commit - Commit(CommitId), - /// diff against staged file - Stage, - /// diff against file in workdir - WorkDir, + /// diff in a given commit + Commit(CommitId), + /// diff against staged file + Stage, + /// diff against file in workdir + WorkDir, } /// #[derive(Hash, Clone, PartialEq)] pub struct DiffParams { - /// path to the file to diff - pub path: String, - /// what kind of diff - pub diff_type: DiffType, + /// path to the file to diff + pub path: String, + /// what kind of diff + pub diff_type: DiffType, } struct Request(R, Option); #[derive(Default, Clone)] struct LastResult { - params: P, - hash: u64, - result: R, + params: P, + hash: u64, + result: R, } /// pub struct AsyncDiff { - current: Arc>>, - last: Arc>>>, - sender: Sender, - pending: Arc, + current: Arc>>, + last: Arc>>>, + sender: Sender, + pending: Arc, } impl AsyncDiff { - /// - pub fn new(sender: &Sender) -> Self { - Self { - current: Arc::new(Mutex::new(Request(0, None))), - last: Arc::new(Mutex::new(None)), - sender: sender.clone(), - pending: Arc::new(AtomicUsize::new(0)), - } - } - - /// - pub fn last(&mut self) -> Result> { - let last = self.last.lock()?; - - Ok(last.clone().map(|res| (res.params, res.result))) - } - - /// - pub fn refresh(&mut self) -> Result<()> { - if let Ok(Some(param)) = self.get_last_param() { - self.clear_current()?; - self.request(param)?; - } - Ok(()) - } - - /// - pub fn is_pending(&self) -> bool { - self.pending.load(Ordering::Relaxed) > 0 - } - - /// - pub fn request( - &mut self, - params: DiffParams, - ) -> Result> { - log::trace!("request"); - - let hash = hash(¶ms); - - { - let mut current = self.current.lock()?; - - if current.0 == hash { - return Ok(current.1.clone()); - } - - current.0 = hash; - current.1 = None; - } - - let arc_current = Arc::clone(&self.current); - let arc_last = Arc::clone(&self.last); - let sender = self.sender.clone(); - let arc_pending = Arc::clone(&self.pending); - - self.pending.fetch_add(1, Ordering::Relaxed); - - rayon_core::spawn(move || { - let notify = Self::get_diff_helper( - params, - &arc_last, - &arc_current, - hash, - ); - - let notify = match notify { - Err(err) => { - log::error!("get_diff_helper error: {}", err); - true - } - Ok(notify) => notify, - }; - - arc_pending.fetch_sub(1, Ordering::Relaxed); - - sender - .send(if notify { - AsyncGitNotification::Diff - } else { - AsyncGitNotification::FinishUnchanged - }) - .expect("error sending diff"); - }); - - Ok(None) - } - - fn get_diff_helper( - params: DiffParams, - arc_last: &Arc< - Mutex>>, - >, - arc_current: &Arc>>, - hash: u64, - ) -> Result { - let res = match params.diff_type { - DiffType::Stage => { - sync::diff::get_diff(CWD, ¶ms.path, true)? - } - DiffType::WorkDir => { - sync::diff::get_diff(CWD, ¶ms.path, false)? - } - DiffType::Commit(id) => sync::diff::get_diff_commit( - CWD, - id, - params.path.clone(), - )?, - }; - - let mut notify = false; - { - let mut current = arc_current.lock()?; - if current.0 == hash { - current.1 = Some(res.clone()); - notify = true; - } - } - - { - let mut last = arc_last.lock()?; - *last = Some(LastResult { - result: res, - hash, - params, - }); - } - - Ok(notify) - } - - fn get_last_param(&self) -> Result> { - Ok(self.last.lock()?.clone().map(|e| e.params)) - } - - fn clear_current(&mut self) -> Result<()> { - let mut current = self.current.lock()?; - current.0 = 0; - current.1 = None; - Ok(()) - } + /// + pub fn new(sender: &Sender) -> Self { + Self { + current: Arc::new(Mutex::new(Request(0, None))), + last: Arc::new(Mutex::new(None)), + sender: sender.clone(), + pending: Arc::new(AtomicUsize::new(0)), + } + } + + /// + pub fn last(&mut self) -> Result> { + let last = self.last.lock()?; + + Ok(last.clone().map(|res| (res.params, res.result))) + } + + /// + pub fn refresh(&mut self) -> Result<()> { + if let Ok(Some(param)) = self.get_last_param() { + self.clear_current()?; + self.request(param)?; + } + Ok(()) + } + + /// + pub fn is_pending(&self) -> bool { + self.pending.load(Ordering::Relaxed) > 0 + } + + /// + pub fn request( + &mut self, + params: DiffParams, + ) -> Result> { + log::trace!("request"); + + let hash = hash(¶ms); + + { + let mut current = self.current.lock()?; + + if current.0 == hash { + return Ok(current.1.clone()); + } + + current.0 = hash; + current.1 = None; + } + + let arc_current = Arc::clone(&self.current); + let arc_last = Arc::clone(&self.last); + let sender = self.sender.clone(); + let arc_pending = Arc::clone(&self.pending); + + self.pending.fetch_add(1, Ordering::Relaxed); + + rayon_core::spawn(move || { + let notify = Self::get_diff_helper( + params, + &arc_last, + &arc_current, + hash, + ); + + let notify = match notify { + Err(err) => { + log::error!("get_diff_helper error: {}", err); + true + } + Ok(notify) => notify, + }; + + arc_pending.fetch_sub(1, Ordering::Relaxed); + + sender + .send(if notify { + AsyncGitNotification::Diff + } else { + AsyncGitNotification::FinishUnchanged + }) + .expect("error sending diff"); + }); + + Ok(None) + } + + fn get_diff_helper( + params: DiffParams, + arc_last: &Arc< + Mutex>>, + >, + arc_current: &Arc>>, + hash: u64, + ) -> Result { + let res = match params.diff_type { + DiffType::Stage => { + sync::diff::get_diff(CWD, ¶ms.path, true)? + } + DiffType::WorkDir => { + sync::diff::get_diff(CWD, ¶ms.path, false)? + } + DiffType::Commit(id) => sync::diff::get_diff_commit( + CWD, + id, + params.path.clone(), + )?, + }; + + let mut notify = false; + { + let mut current = arc_current.lock()?; + if current.0 == hash { + current.1 = Some(res.clone()); + notify = true; + } + } + + { + let mut last = arc_last.lock()?; + *last = Some(LastResult { + result: res, + hash, + params, + }); + } + + Ok(notify) + } + + fn get_last_param(&self) -> Result> { + Ok(self.last.lock()?.clone().map(|e| e.params)) + } + + fn clear_current(&mut self) -> Result<()> { + let mut current = self.current.lock()?; + current.0 = 0; + current.1 = None; + Ok(()) + } } diff --git a/asyncgit/src/error.rs b/asyncgit/src/error.rs index 80c490fe..d6e00d76 100644 --- a/asyncgit/src/error.rs +++ b/asyncgit/src/error.rs @@ -5,56 +5,56 @@ use thiserror::Error; #[derive(Error, Debug)] pub enum Error { - #[error("`{0}`")] - Generic(String), + #[error("`{0}`")] + Generic(String), - #[error("git: no head found")] - NoHead, + #[error("git: no head found")] + NoHead, - #[error("git: remote url not found")] - UnknownRemote, + #[error("git: remote url not found")] + UnknownRemote, - #[error("git: inconclusive remotes")] - NoDefaultRemoteFound, + #[error("git: inconclusive remotes")] + NoDefaultRemoteFound, - #[error("git: work dir error")] - NoWorkDir, + #[error("git: work dir error")] + NoWorkDir, - #[error("git: uncommitted changes")] - UncommittedChanges, + #[error("git: uncommitted changes")] + UncommittedChanges, - #[error("git: can\u{2019}t run blame on a binary file")] - NoBlameOnBinaryFile, + #[error("git: can\u{2019}t run blame on a binary file")] + NoBlameOnBinaryFile, - #[error("binary file")] - BinaryFile, + #[error("binary file")] + BinaryFile, - #[error("io error:{0}")] - Io(#[from] std::io::Error), + #[error("io error:{0}")] + Io(#[from] std::io::Error), - #[error("git error:{0}")] - Git(#[from] git2::Error), + #[error("git error:{0}")] + Git(#[from] git2::Error), - #[error("utf8 error:{0}")] - Utf8Conversion(#[from] FromUtf8Error), + #[error("utf8 error:{0}")] + Utf8Conversion(#[from] FromUtf8Error), - #[error("TryFromInt error:{0}")] - IntConversion(#[from] TryFromIntError), + #[error("TryFromInt error:{0}")] + IntConversion(#[from] TryFromIntError), - #[error("EasyCast error:{0}")] - EasyCast(#[from] easy_cast::Error), + #[error("EasyCast error:{0}")] + EasyCast(#[from] easy_cast::Error), } pub type Result = std::result::Result; impl From> for Error { - fn from(error: std::sync::PoisonError) -> Self { - Self::Generic(format!("poison error: {}", error)) - } + fn from(error: std::sync::PoisonError) -> Self { + Self::Generic(format!("poison error: {}", error)) + } } impl From> for Error { - fn from(error: crossbeam_channel::SendError) -> Self { - Self::Generic(format!("send error: {}", error)) - } + fn from(error: crossbeam_channel::SendError) -> Self { + Self::Generic(format!("send error: {}", error)) + } } diff --git a/asyncgit/src/fetch.rs b/asyncgit/src/fetch.rs index a0063e67..ed8caa6c 100644 --- a/asyncgit/src/fetch.rs +++ b/asyncgit/src/fetch.rs @@ -1,159 +1,159 @@ use crate::{ - error::{Error, Result}, - sync::{ - cred::BasicAuthCredential, - remotes::{fetch, push::ProgressNotification}, - }, - AsyncGitNotification, RemoteProgress, CWD, + error::{Error, Result}, + sync::{ + cred::BasicAuthCredential, + remotes::{fetch, push::ProgressNotification}, + }, + AsyncGitNotification, RemoteProgress, CWD, }; use crossbeam_channel::{unbounded, Sender}; use std::{ - sync::{Arc, Mutex}, - thread, + sync::{Arc, Mutex}, + thread, }; /// #[derive(Default, Clone, Debug)] pub struct FetchRequest { - /// - pub remote: String, - /// - pub branch: String, - /// - pub basic_credential: Option, + /// + pub remote: String, + /// + pub branch: String, + /// + pub basic_credential: Option, } #[derive(Default, Clone, Debug)] struct FetchState { - request: FetchRequest, + request: FetchRequest, } /// pub struct AsyncFetch { - state: Arc>>, - last_result: Arc>>, - progress: Arc>>, - sender: Sender, + state: Arc>>, + last_result: Arc>>, + progress: Arc>>, + sender: Sender, } impl AsyncFetch { - /// - pub fn new(sender: &Sender) -> Self { - Self { - state: Arc::new(Mutex::new(None)), - last_result: Arc::new(Mutex::new(None)), - progress: Arc::new(Mutex::new(None)), - sender: sender.clone(), - } - } - - /// - pub fn is_pending(&self) -> Result { - let state = self.state.lock()?; - Ok(state.is_some()) - } - - /// - pub fn last_result(&self) -> Result> { - let res = self.last_result.lock()?; - Ok(res.clone()) - } - - /// - pub fn progress(&self) -> Result> { - let res = self.progress.lock()?; - Ok(res.as_ref().map(|progress| progress.clone().into())) - } - - /// - pub fn request(&mut self, params: FetchRequest) -> Result<()> { - log::trace!("request"); - - if self.is_pending()? { - return Ok(()); - } - - self.set_request(¶ms)?; - RemoteProgress::set_progress(&self.progress, None)?; - - let arc_state = Arc::clone(&self.state); - let arc_res = Arc::clone(&self.last_result); - let arc_progress = Arc::clone(&self.progress); - let sender = self.sender.clone(); - - thread::spawn(move || { - let (progress_sender, receiver) = unbounded(); - - let handle = RemoteProgress::spawn_receiver_thread( - AsyncGitNotification::Fetch, - sender.clone(), - receiver, - arc_progress, - ); - - let res = fetch( - CWD, - ¶ms.branch, - params.basic_credential, - Some(progress_sender.clone()), - ); - - progress_sender - .send(ProgressNotification::Done) - .expect("closing send failed"); - - handle.join().expect("joining thread failed"); - - Self::set_result(&arc_res, res).expect("result error"); - - Self::clear_request(&arc_state).expect("clear error"); - - sender - .send(AsyncGitNotification::Fetch) - .expect("AsyncNotification error"); - }); - - Ok(()) - } - - fn set_request(&self, params: &FetchRequest) -> Result<()> { - let mut state = self.state.lock()?; - - if state.is_some() { - return Err(Error::Generic("pending request".into())); - } - - *state = Some(FetchState { - request: params.clone(), - }); - - Ok(()) - } - - fn clear_request( - state: &Arc>>, - ) -> Result<()> { - let mut state = state.lock()?; - - *state = None; - - Ok(()) - } - - fn set_result( - arc_result: &Arc>>, - res: Result, - ) -> Result<()> { - let mut last_res = arc_result.lock()?; - - *last_res = match res { - Ok(bytes) => Some((bytes, String::new())), - Err(e) => { - log::error!("fetch error: {}", e); - Some((0, e.to_string())) - } - }; - - Ok(()) - } + /// + pub fn new(sender: &Sender) -> Self { + Self { + state: Arc::new(Mutex::new(None)), + last_result: Arc::new(Mutex::new(None)), + progress: Arc::new(Mutex::new(None)), + sender: sender.clone(), + } + } + + /// + pub fn is_pending(&self) -> Result { + let state = self.state.lock()?; + Ok(state.is_some()) + } + + /// + pub fn last_result(&self) -> Result> { + let res = self.last_result.lock()?; + Ok(res.clone()) + } + + /// + pub fn progress(&self) -> Result> { + let res = self.progress.lock()?; + Ok(res.as_ref().map(|progress| progress.clone().into())) + } + + /// + pub fn request(&mut self, params: FetchRequest) -> Result<()> { + log::trace!("request"); + + if self.is_pending()? { + return Ok(()); + } + + self.set_request(¶ms)?; + RemoteProgress::set_progress(&self.progress, None)?; + + let arc_state = Arc::clone(&self.state); + let arc_res = Arc::clone(&self.last_result); + let arc_progress = Arc::clone(&self.progress); + let sender = self.sender.clone(); + + thread::spawn(move || { + let (progress_sender, receiver) = unbounded(); + + let handle = RemoteProgress::spawn_receiver_thread( + AsyncGitNotification::Fetch, + sender.clone(), + receiver, + arc_progress, + ); + + let res = fetch( + CWD, + ¶ms.branch, + params.basic_credential, + Some(progress_sender.clone()), + ); + + progress_sender + .send(ProgressNotification::Done) + .expect("closing send failed"); + + handle.join().expect("joining thread failed"); + + Self::set_result(&arc_res, res).expect("result error"); + + Self::clear_request(&arc_state).expect("clear error"); + + sender + .send(AsyncGitNotification::Fetch) + .expect("AsyncNotification error"); + }); + + Ok(()) + } + + fn set_request(&self, params: &FetchRequest) -> Result<()> { + let mut state = self.state.lock()?; + + if state.is_some() { + return Err(Error::Generic("pending request".into())); + } + + *state = Some(FetchState { + request: params.clone(), + }); + + Ok(()) + } + + fn clear_request( + state: &Arc>>, + ) -> Result<()> { + let mut state = state.lock()?; + + *state = None; + + Ok(()) + } + + fn set_result( + arc_result: &Arc>>, + res: Result, + ) -> Result<()> { + let mut last_res = arc_result.lock()?; + + *last_res = match res { + Ok(bytes) => Some((bytes, String::new())), + Err(e) => { + log::error!("fetch error: {}", e); + Some((0, e.to_string())) + } + }; + + Ok(()) + } } diff --git a/asyncgit/src/lib.rs b/asyncgit/src/lib.rs index 64b92778..c77e9548 100644 --- a/asyncgit/src/lib.rs +++ b/asyncgit/src/lib.rs @@ -2,11 +2,11 @@ #![forbid(missing_docs)] #![deny( - unused_imports, - unused_must_use, - dead_code, - unstable_name_collisions, - unused_assignments + unused_imports, + unused_must_use, + dead_code, + unstable_name_collisions, + unused_assignments )] #![deny(unstable_name_collisions)] #![deny(clippy::all, clippy::perf, clippy::nursery, clippy::pedantic)] @@ -40,49 +40,49 @@ pub mod sync; mod tags; pub use crate::{ - blame::{AsyncBlame, BlameParams}, - commit_files::AsyncCommitFiles, - diff::{AsyncDiff, DiffParams, DiffType}, - fetch::{AsyncFetch, FetchRequest}, - push::{AsyncPush, PushRequest}, - push_tags::{AsyncPushTags, PushTagsRequest}, - remote_progress::{RemoteProgress, RemoteProgressState}, - revlog::{AsyncLog, FetchStatus}, - status::{AsyncStatus, StatusParams}, - sync::{ - diff::{DiffLine, DiffLineType, FileDiff}, - status::{StatusItem, StatusItemType}, - }, - tags::AsyncTags, + blame::{AsyncBlame, BlameParams}, + commit_files::AsyncCommitFiles, + diff::{AsyncDiff, DiffParams, DiffType}, + fetch::{AsyncFetch, FetchRequest}, + push::{AsyncPush, PushRequest}, + push_tags::{AsyncPushTags, PushTagsRequest}, + remote_progress::{RemoteProgress, RemoteProgressState}, + revlog::{AsyncLog, FetchStatus}, + status::{AsyncStatus, StatusParams}, + sync::{ + diff::{DiffLine, DiffLineType, FileDiff}, + status::{StatusItem, StatusItemType}, + }, + tags::AsyncTags, }; use std::{ - collections::hash_map::DefaultHasher, - hash::{Hash, Hasher}, + collections::hash_map::DefaultHasher, + hash::{Hash, Hasher}, }; /// this type is used to communicate events back through the channel #[derive(Copy, Clone, Debug, PartialEq)] pub enum AsyncGitNotification { - /// this indicates that no new state was fetched but that a async process finished - FinishUnchanged, - /// - Status, - /// - Diff, - /// - Log, - /// - CommitFiles, - /// - Tags, - /// - Push, - /// - PushTags, - /// - Fetch, - /// - Blame, + /// this indicates that no new state was fetched but that a async process finished + FinishUnchanged, + /// + Status, + /// + Diff, + /// + Log, + /// + CommitFiles, + /// + Tags, + /// + Push, + /// + PushTags, + /// + Fetch, + /// + Blame, } /// current working directory `./` @@ -90,16 +90,16 @@ 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(); - v.hash(&mut hasher); - hasher.finish() + let mut hasher = DefaultHasher::new(); + v.hash(&mut hasher); + hasher.finish() } /// pub fn register_tracing_logging() -> bool { - git2::trace_set(git2::TraceLevel::Trace, git_trace) + git2::trace_set(git2::TraceLevel::Trace, git_trace) } fn git_trace(level: git2::TraceLevel, msg: &str) { - log::info!("[{:?}]: {}", level, msg); + log::info!("[{:?}]: {}", level, msg); } diff --git a/asyncgit/src/progress.rs b/asyncgit/src/progress.rs index 55ae92c0..3c58918c 100644 --- a/asyncgit/src/progress.rs +++ b/asyncgit/src/progress.rs @@ -6,49 +6,49 @@ use std::cmp; /// #[derive(Clone, Debug)] pub struct ProgressPercent { - /// percent 0..100 - pub progress: u8, + /// percent 0..100 + pub progress: u8, } impl ProgressPercent { - /// - pub fn new(current: usize, total: usize) -> Self { - let total = f64::conv(cmp::max(current, total)); - let progress = f64::conv(current) / total * 100.0; - let progress = u8::try_conv_nearest(progress).unwrap_or(100); - Self { progress } - } - /// - pub const fn empty() -> Self { - Self { progress: 0 } - } - /// - pub const fn full() -> Self { - Self { progress: 100 } - } + /// + pub fn new(current: usize, total: usize) -> Self { + let total = f64::conv(cmp::max(current, total)); + let progress = f64::conv(current) / total * 100.0; + let progress = u8::try_conv_nearest(progress).unwrap_or(100); + Self { progress } + } + /// + pub const fn empty() -> Self { + Self { progress: 0 } + } + /// + pub const fn full() -> Self { + Self { progress: 100 } + } } #[cfg(test)] mod tests { - use super::*; + use super::*; - #[test] - fn test_progress_zero_total() { - let prog = ProgressPercent::new(1, 0); + #[test] + fn test_progress_zero_total() { + let prog = ProgressPercent::new(1, 0); - assert_eq!(prog.progress, 100); - } + assert_eq!(prog.progress, 100); + } - #[test] - fn test_progress_zero_all() { - let prog = ProgressPercent::new(0, 0); - assert_eq!(prog.progress, 100); - } + #[test] + fn test_progress_zero_all() { + let prog = ProgressPercent::new(0, 0); + assert_eq!(prog.progress, 100); + } - #[test] - fn test_progress_rounding() { - let prog = ProgressPercent::new(2, 10); + #[test] + fn test_progress_rounding() { + let prog = ProgressPercent::new(2, 10); - assert_eq!(prog.progress, 20); - } + assert_eq!(prog.progress, 20); + } } diff --git a/asyncgit/src/push.rs b/asyncgit/src/push.rs index 9bcfcd43..9c4f14cb 100644 --- a/asyncgit/src/push.rs +++ b/asyncgit/src/push.rs @@ -1,166 +1,166 @@ use crate::{ - error::{Error, Result}, - sync::{ - cred::BasicAuthCredential, remotes::push::push, - remotes::push::ProgressNotification, - }, - AsyncGitNotification, RemoteProgress, CWD, + error::{Error, Result}, + sync::{ + cred::BasicAuthCredential, remotes::push::push, + remotes::push::ProgressNotification, + }, + AsyncGitNotification, RemoteProgress, CWD, }; use crossbeam_channel::{unbounded, Sender}; use std::{ - sync::{Arc, Mutex}, - thread, + sync::{Arc, Mutex}, + thread, }; /// #[derive(Default, Clone, Debug)] pub struct PushRequest { - /// - pub remote: String, - /// - pub branch: String, - /// - pub force: bool, - /// - pub delete: bool, - /// - pub basic_credential: Option, + /// + pub remote: String, + /// + pub branch: String, + /// + pub force: bool, + /// + pub delete: bool, + /// + pub basic_credential: Option, } #[derive(Default, Clone, Debug)] struct PushState { - request: PushRequest, + request: PushRequest, } /// pub struct AsyncPush { - state: Arc>>, - last_result: Arc>>, - progress: Arc>>, - sender: Sender, + state: Arc>>, + last_result: Arc>>, + progress: Arc>>, + sender: Sender, } impl AsyncPush { - /// - pub fn new(sender: &Sender) -> Self { - Self { - state: Arc::new(Mutex::new(None)), - last_result: Arc::new(Mutex::new(None)), - progress: Arc::new(Mutex::new(None)), - sender: sender.clone(), - } - } - - /// - pub fn is_pending(&self) -> Result { - let state = self.state.lock()?; - Ok(state.is_some()) - } - - /// - pub fn last_result(&self) -> Result> { - let res = self.last_result.lock()?; - Ok(res.clone()) - } - - /// - pub fn progress(&self) -> Result> { - let res = self.progress.lock()?; - Ok(res.as_ref().map(|progress| progress.clone().into())) - } - - /// - pub fn request(&mut self, params: PushRequest) -> Result<()> { - log::trace!("request"); - - if self.is_pending()? { - return Ok(()); - } - - self.set_request(¶ms)?; - RemoteProgress::set_progress(&self.progress, None)?; - - let arc_state = Arc::clone(&self.state); - let arc_res = Arc::clone(&self.last_result); - let arc_progress = Arc::clone(&self.progress); - let sender = self.sender.clone(); - - thread::spawn(move || { - let (progress_sender, receiver) = unbounded(); - - let handle = RemoteProgress::spawn_receiver_thread( - AsyncGitNotification::Push, - sender.clone(), - receiver, - arc_progress, - ); - - let res = push( - CWD, - params.remote.as_str(), - params.branch.as_str(), - params.force, - params.delete, - params.basic_credential.clone(), - Some(progress_sender.clone()), - ); - - progress_sender - .send(ProgressNotification::Done) - .expect("closing send failed"); - - handle.join().expect("joining thread failed"); - - Self::set_result(&arc_res, res).expect("result error"); - - Self::clear_request(&arc_state).expect("clear error"); - - sender - .send(AsyncGitNotification::Push) - .expect("error sending push"); - }); - - Ok(()) - } - - fn set_request(&self, params: &PushRequest) -> Result<()> { - let mut state = self.state.lock()?; - - if state.is_some() { - return Err(Error::Generic("pending request".into())); - } - - *state = Some(PushState { - request: params.clone(), - }); - - Ok(()) - } - - fn clear_request( - state: &Arc>>, - ) -> Result<()> { - let mut state = state.lock()?; - - *state = None; - - Ok(()) - } - - fn set_result( - arc_result: &Arc>>, - res: Result<()>, - ) -> Result<()> { - let mut last_res = arc_result.lock()?; - - *last_res = match res { - Ok(_) => None, - Err(e) => { - log::error!("push error: {}", e); - Some(e.to_string()) - } - }; - - Ok(()) - } + /// + pub fn new(sender: &Sender) -> Self { + Self { + state: Arc::new(Mutex::new(None)), + last_result: Arc::new(Mutex::new(None)), + progress: Arc::new(Mutex::new(None)), + sender: sender.clone(), + } + } + + /// + pub fn is_pending(&self) -> Result { + let state = self.state.lock()?; + Ok(state.is_some()) + } + + /// + pub fn last_result(&self) -> Result> { + let res = self.last_result.lock()?; + Ok(res.clone()) + } + + /// + pub fn progress(&self) -> Result> { + let res = self.progress.lock()?; + Ok(res.as_ref().map(|progress| progress.clone().into())) + } + + /// + pub fn request(&mut self, params: PushRequest) -> Result<()> { + log::trace!("request"); + + if self.is_pending()? { + return Ok(()); + } + + self.set_request(¶ms)?; + RemoteProgress::set_progress(&self.progress, None)?; + + let arc_state = Arc::clone(&self.state); + let arc_res = Arc::clone(&self.last_result); + let arc_progress = Arc::clone(&self.progress); + let sender = self.sender.clone(); + + thread::spawn(move || { + let (progress_sender, receiver) = unbounded(); + + let handle = RemoteProgress::spawn_receiver_thread( + AsyncGitNotification::Push, + sender.clone(), + receiver, + arc_progress, + ); + + let res = push( + CWD, + params.remote.as_str(), + params.branch.as_str(), + params.force, + params.delete, + params.basic_credential.clone(), + Some(progress_sender.clone()), + ); + + progress_sender + .send(ProgressNotification::Done) + .expect("closing send failed"); + + handle.join().expect("joining thread failed"); + + Self::set_result(&arc_res, res).expect("result error"); + + Self::clear_request(&arc_state).expect("clear error"); + + sender + .send(AsyncGitNotification::Push) + .expect("error sending push"); + }); + + Ok(()) + } + + fn set_request(&self, params: &PushRequest) -> Result<()> { + let mut state = self.state.lock()?; + + if state.is_some() { + return Err(Error::Generic("pending request".into())); + } + + *state = Some(PushState { + request: params.clone(), + }); + + Ok(()) + } + + fn clear_request( + state: &Arc>>, + ) -> Result<()> { + let mut state = state.lock()?; + + *state = None; + + Ok(()) + } + + fn set_result( + arc_result: &Arc>>, + res: Result<()>, + ) -> Result<()> { + let mut last_res = arc_result.lock()?; + + *last_res = match res { + Ok(_) => None, + Err(e) => { + log::error!("push error: {}", e); + Some(e.to_string()) + } + }; + + Ok(()) + } } diff --git a/asyncgit/src/push_tags.rs b/asyncgit/src/push_tags.rs index 4661917b..01fc1cff 100644 --- a/asyncgit/src/push_tags.rs +++ b/asyncgit/src/push_tags.rs @@ -1,153 +1,153 @@ use crate::{ - error::{Error, Result}, - sync::{ - cred::BasicAuthCredential, - remotes::tags::{push_tags, PushTagsProgress}, - }, - AsyncGitNotification, RemoteProgress, CWD, + error::{Error, Result}, + sync::{ + cred::BasicAuthCredential, + remotes::tags::{push_tags, PushTagsProgress}, + }, + AsyncGitNotification, RemoteProgress, CWD, }; use crossbeam_channel::{unbounded, Sender}; use std::{ - sync::{Arc, Mutex}, - thread, + sync::{Arc, Mutex}, + thread, }; /// #[derive(Default, Clone, Debug)] pub struct PushTagsRequest { - /// - pub remote: String, - /// - pub basic_credential: Option, + /// + pub remote: String, + /// + pub basic_credential: Option, } #[derive(Default, Clone, Debug)] struct PushState { - request: PushTagsRequest, + request: PushTagsRequest, } /// pub struct AsyncPushTags { - state: Arc>>, - last_result: Arc>>, - progress: Arc>>, - sender: Sender, + state: Arc>>, + last_result: Arc>>, + progress: Arc>>, + sender: Sender, } impl AsyncPushTags { - /// - pub fn new(sender: &Sender) -> Self { - Self { - state: Arc::new(Mutex::new(None)), - last_result: Arc::new(Mutex::new(None)), - progress: Arc::new(Mutex::new(None)), - sender: sender.clone(), - } - } - - /// - pub fn is_pending(&self) -> Result { - let state = self.state.lock()?; - Ok(state.is_some()) - } - - /// - pub fn last_result(&self) -> Result> { - let res = self.last_result.lock()?; - Ok(res.clone()) - } - - /// - pub fn progress(&self) -> Result> { - let res = self.progress.lock()?; - Ok(*res) - }