From 92f63d107c1dca1f10139668ff5b3ca752261b0f Mon Sep 17 00:00:00 2001 From: extrawurst Date: Mon, 21 Nov 2022 16:32:17 +0100 Subject: [PATCH] support fetching branch_infos async --- asyncgit/src/branches.rs | 77 ++++++++++++++++++++++++++++++++++++ asyncgit/src/lib.rs | 4 ++ src/components/branchlist.rs | 2 +- src/tabs/revlog.rs | 36 +++++++++++++---- src/tabs/status.rs | 27 +++++++++---- 5 files changed, 129 insertions(+), 17 deletions(-) create mode 100644 asyncgit/src/branches.rs diff --git a/asyncgit/src/branches.rs b/asyncgit/src/branches.rs new file mode 100644 index 0000000000..6885b54b01 --- /dev/null +++ b/asyncgit/src/branches.rs @@ -0,0 +1,77 @@ +use crate::{ + asyncjob::{AsyncJob, RunParams}, + error::Result, + sync::{branch::get_branches_info, BranchInfo, RepoPath}, + AsyncGitNotification, +}; +use std::sync::{Arc, Mutex}; + +enum JobState { + Request { + local_branches: bool, + repo: RepoPath, + }, + Response(Result>), +} + +/// +#[derive(Clone, Default)] +pub struct AsyncBranchesJob { + state: Arc>>, +} + +/// +impl AsyncBranchesJob { + /// + pub fn new(repo: RepoPath, local_branches: bool) -> Self { + Self { + state: Arc::new(Mutex::new(Some(JobState::Request { + repo, + local_branches, + }))), + } + } + + /// + pub fn result(&self) -> Option>> { + if let Ok(mut state) = self.state.lock() { + if let Some(state) = state.take() { + return match state { + JobState::Request { .. } => None, + JobState::Response(result) => Some(result), + }; + } + } + + None + } +} + +impl AsyncJob for AsyncBranchesJob { + type Notification = AsyncGitNotification; + type Progress = (); + + fn run( + &mut self, + _params: RunParams, + ) -> Result { + if let Ok(mut state) = self.state.lock() { + *state = state.take().map(|state| match state { + JobState::Request { + local_branches, + repo, + } => { + let branches = + get_branches_info(&repo, local_branches); + + JobState::Response(branches) + } + JobState::Response(result) => { + JobState::Response(result) + } + }); + } + + Ok(AsyncGitNotification::Branches) + } +} diff --git a/asyncgit/src/lib.rs b/asyncgit/src/lib.rs index d399995922..f94e649601 100644 --- a/asyncgit/src/lib.rs +++ b/asyncgit/src/lib.rs @@ -24,6 +24,7 @@ pub mod asyncjob; mod blame; +mod branches; pub mod cached; mod commit_files; mod diff; @@ -42,6 +43,7 @@ mod tags; pub use crate::{ blame::{AsyncBlame, BlameParams}, + branches::AsyncBranchesJob, commit_files::{AsyncCommitFiles, CommitFilesParams}, diff::{AsyncDiff, DiffParams, DiffType}, error::{Error, Result}, @@ -95,6 +97,8 @@ pub enum AsyncGitNotification { RemoteTags, /// Fetch, + /// + Branches, } /// helper function to calculate the hash of an arbitrary type that implements the `Hash` trait diff --git a/src/components/branchlist.rs b/src/components/branchlist.rs index 64c8fc8e31..b27600a850 100644 --- a/src/components/branchlist.rs +++ b/src/components/branchlist.rs @@ -364,7 +364,7 @@ impl BranchListComponent { } fn check_remotes(&mut self) { - if !self.local { + if !self.local && self.visible { self.has_remotes = get_branches_info(&self.repo.borrow(), false) .map(|branches| !branches.is_empty()) diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 1e14659262..02f6d7a8cf 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -12,9 +12,10 @@ use crate::{ }; use anyhow::Result; use asyncgit::{ - sync::{self, get_branches_info, CommitId, RepoPathRef}, - AsyncGitNotification, AsyncLog, AsyncTags, CommitFilesParams, - FetchStatus, + asyncjob::AsyncSingleJob, + sync::{self, CommitId, RepoPathRef}, + AsyncBranchesJob, AsyncGitNotification, AsyncLog, AsyncTags, + CommitFilesParams, FetchStatus, }; use crossbeam_channel::Sender; use crossterm::event::Event; @@ -35,6 +36,7 @@ pub struct Revlog { list: CommitList, git_log: AsyncLog, git_tags: AsyncTags, + git_branches: AsyncSingleJob, queue: Queue, visible: bool, key_config: SharedKeyConfig, @@ -71,6 +73,7 @@ impl Revlog { None, ), git_tags: AsyncTags::new(repo.borrow().clone(), sender), + git_branches: AsyncSingleJob::new(sender.clone()), visible: false, key_config, } @@ -80,6 +83,7 @@ impl Revlog { pub fn any_work_pending(&self) -> bool { self.git_log.is_pending() || self.git_tags.is_pending() + || self.git_branches.is_pending() || self.commit_details.any_work_pending() } @@ -101,11 +105,6 @@ impl Revlog { self.git_tags.request(Duration::from_secs(3), false)?; - self.list.set_branches(get_branches_info( - &self.repo.borrow(), - true, - )?); - if self.commit_details.is_visible() { let commit = self.selected_commit(); let tags = self.selected_commit_tags(&commit); @@ -135,6 +134,21 @@ impl Revlog { self.update()?; } } + AsyncGitNotification::Branches => { + if let Some(branches) = + self.git_branches.take_last() + { + if let Some(Ok(branches)) = branches.result() + { + log::info!( + "branches: {}", + branches.len() + ); + self.list.set_branches(branches); + self.update()?; + } + } + } _ => (), } } @@ -447,6 +461,12 @@ impl Component for Revlog { fn show(&mut self) -> Result<()> { self.visible = true; self.list.clear(); + + self.git_branches.spawn(AsyncBranchesJob::new( + self.repo.borrow().clone(), + true, + )); + self.update()?; Ok(()) diff --git a/src/tabs/status.rs b/src/tabs/status.rs index 544986df2b..e17ce38481 100644 --- a/src/tabs/status.rs +++ b/src/tabs/status.rs @@ -14,13 +14,14 @@ use crate::{ }; use anyhow::Result; use asyncgit::{ + asyncjob::AsyncSingleJob, cached, sync::{ self, status::StatusType, RepoPath, RepoPathRef, RepoState, }, sync::{BranchCompare, CommitId}, - AsyncDiff, AsyncGitNotification, AsyncStatus, DiffParams, - DiffType, PushType, StatusParams, + AsyncBranchesJob, AsyncDiff, AsyncGitNotification, AsyncStatus, + DiffParams, DiffType, PushType, StatusParams, }; use crossbeam_channel::Sender; use crossterm::event::Event; @@ -73,6 +74,7 @@ pub struct Status { git_status_stage: AsyncStatus, git_branch_state: Option, git_branch_name: cached::BranchName, + git_branches: AsyncSingleJob, queue: Queue, git_action_executed: bool, options: SharedOptions, @@ -203,6 +205,7 @@ impl Status { repo_clone, sender.clone(), ), + git_branches: AsyncSingleJob::new(sender.clone()), git_action_executed: false, git_branch_state: None, git_branch_name: cached::BranchName::new(repo.clone()), @@ -424,14 +427,22 @@ impl Status { self.git_diff.is_pending() || self.git_status_stage.is_pending() || self.git_status_workdir.is_pending() + || self.git_branches.is_pending() } fn check_remotes(&mut self) { - //TODO: make get_branches_info async - self.has_remotes = - sync::get_branches_info(&self.repo.borrow(), false) - .map(|branches| !branches.is_empty()) - .unwrap_or(false); + self.has_remotes = false; + + if let Some(result) = self.git_branches.take_last() { + if let Some(Ok(branches)) = result.result() { + self.has_remotes = !branches.is_empty(); + } + } else { + self.git_branches.spawn(AsyncBranchesJob::new( + self.repo.borrow().clone(), + false, + )); + } } /// @@ -442,6 +453,7 @@ impl Status { match ev { AsyncGitNotification::Diff => self.update_diff()?, AsyncGitNotification::Status => self.update_status()?, + AsyncGitNotification::Branches => self.check_remotes(), AsyncGitNotification::Push | AsyncGitNotification::Pull | AsyncGitNotification::CommitFiles => { @@ -461,7 +473,6 @@ impl Status { self.index_wd.set_items(&workdir_status.items)?; self.update_diff()?; - self.check_remotes(); if self.git_action_executed { self.git_action_executed = false;