From 08b89f04a54fd0fd9a614941580789041105a604 Mon Sep 17 00:00:00 2001 From: Stephan Dilly Date: Sun, 21 Nov 2021 00:46:45 +0100 Subject: [PATCH 1/8] wip poc for fetching all branches --- Cargo.lock | 4 ---- asyncgit/Cargo.toml | 4 ++-- asyncgit/src/fetch.rs | 10 +++++++++- asyncgit/src/sync/remotes/mod.rs | 29 ++++++++++++++++++++++++++++- 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 26dcc474a2..337f5b751c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -483,8 +483,6 @@ dependencies = [ [[package]] name = "git2" version = "0.13.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "845e007a28f1fcac035715988a234e8ec5458fd825b20a20c7dec74237ef341f" dependencies = [ "bitflags", "libc", @@ -646,8 +644,6 @@ checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219" [[package]] name = "libgit2-sys" version = "0.12.25+1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68169ef08d6519b2fe133ecc637408d933c0174b23b80bb2f79828966fbaab" dependencies = [ "cc", "libc", diff --git a/asyncgit/Cargo.toml b/asyncgit/Cargo.toml index 5574ba222d..2a450f71f9 100644 --- a/asyncgit/Cargo.toml +++ b/asyncgit/Cargo.toml @@ -13,8 +13,8 @@ keywords = ["git"] [dependencies] scopetime = { path = "../scopetime", version = "0.1" } -git2 = "0.13" -# git2 = { path = "../../extern/git2-rs", features = ["vendored-openssl"]} +# git2 = "0.13" +git2 = { path = "../../extern/git2-rs", features = ["vendored-openssl"]} # git2 = { git="https://github.com/extrawurst/git2-rs.git", rev="fc13dcc", features = ["vendored-openssl"]} # pinning to vendored openssl, using the git2 feature this gets lost with new resolver openssl-sys = { version = '0.9', features= ["vendored"] } diff --git a/asyncgit/src/fetch.rs b/asyncgit/src/fetch.rs index d7fb4506fc..ed14de7530 100644 --- a/asyncgit/src/fetch.rs +++ b/asyncgit/src/fetch.rs @@ -2,7 +2,7 @@ use crate::{ error::{Error, Result}, sync::{ cred::BasicAuthCredential, - remotes::{fetch, push::ProgressNotification}, + remotes::{fetch, fetch_all, push::ProgressNotification}, }, AsyncGitNotification, RemoteProgress, CWD, }; @@ -90,6 +90,14 @@ impl AsyncFetch { arc_progress, ); + fetch_all( + CWD, + "origin", + params.basic_credential.clone(), + Some(progress_sender.clone()), + ) + .expect(""); + let res = fetch( CWD, ¶ms.branch, diff --git a/asyncgit/src/sync/remotes/mod.rs b/asyncgit/src/sync/remotes/mod.rs index 133c761c3d..440938c7ff 100644 --- a/asyncgit/src/sync/remotes/mod.rs +++ b/asyncgit/src/sync/remotes/mod.rs @@ -75,6 +75,31 @@ pub(crate) fn get_default_remote_in_repo( Err(Error::NoDefaultRemoteFound) } +/// +pub fn fetch_all( + repo_path: &str, + remote: &str, + basic_credential: Option, + progress_sender: Option>, +) -> Result<()> { + scope_time!("fetch_all"); + + let repo = utils::repo(repo_path)?; + + let mut remote = repo.find_remote(remote)?; + + let mut options = FetchOptions::new(); + let callbacks = Callbacks::new( + progress_sender.clone(), + basic_credential.clone(), + ); + options.prune(git2::FetchPrune::On); + options.remote_callbacks(callbacks.callbacks()); + remote.fetch_all(Some(&mut options), None)?; + + Ok(()) +} + /// fetches from upstream/remote for `branch` pub(crate) fn fetch( repo_path: &str, @@ -82,7 +107,7 @@ pub(crate) fn fetch( basic_credential: Option, progress_sender: Option>, ) -> Result { - scope_time!("fetch_origin"); + scope_time!("fetch"); let repo = utils::repo(repo_path)?; let branch_ref = repo @@ -97,6 +122,8 @@ pub(crate) fn fetch( let callbacks = Callbacks::new(progress_sender, basic_credential); options.remote_callbacks(callbacks.callbacks()); + log::debug!("fetch: {}", branch); + remote.fetch(&[branch], Some(&mut options), None)?; Ok(remote.stats().received_bytes()) From 4ad36bde2bcfd0404dedffbad515d8ba66e0e7c5 Mon Sep 17 00:00:00 2001 From: Stephan Dilly Date: Mon, 22 Nov 2021 21:45:41 +0100 Subject: [PATCH 2/8] simplify --- Cargo.lock | 4 ++++ asyncgit/Cargo.toml | 4 ++-- asyncgit/src/sync/remotes/mod.rs | 7 ++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 337f5b751c..26dcc474a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -483,6 +483,8 @@ dependencies = [ [[package]] name = "git2" version = "0.13.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "845e007a28f1fcac035715988a234e8ec5458fd825b20a20c7dec74237ef341f" dependencies = [ "bitflags", "libc", @@ -644,6 +646,8 @@ checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219" [[package]] name = "libgit2-sys" version = "0.12.25+1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f68169ef08d6519b2fe133ecc637408d933c0174b23b80bb2f79828966fbaab" dependencies = [ "cc", "libc", diff --git a/asyncgit/Cargo.toml b/asyncgit/Cargo.toml index 2a450f71f9..5574ba222d 100644 --- a/asyncgit/Cargo.toml +++ b/asyncgit/Cargo.toml @@ -13,8 +13,8 @@ keywords = ["git"] [dependencies] scopetime = { path = "../scopetime", version = "0.1" } -# git2 = "0.13" -git2 = { path = "../../extern/git2-rs", features = ["vendored-openssl"]} +git2 = "0.13" +# git2 = { path = "../../extern/git2-rs", features = ["vendored-openssl"]} # git2 = { git="https://github.com/extrawurst/git2-rs.git", rev="fc13dcc", features = ["vendored-openssl"]} # pinning to vendored openssl, using the git2 feature this gets lost with new resolver openssl-sys = { version = '0.9', features= ["vendored"] } diff --git a/asyncgit/src/sync/remotes/mod.rs b/asyncgit/src/sync/remotes/mod.rs index 440938c7ff..cf71353d43 100644 --- a/asyncgit/src/sync/remotes/mod.rs +++ b/asyncgit/src/sync/remotes/mod.rs @@ -89,13 +89,10 @@ pub fn fetch_all( let mut remote = repo.find_remote(remote)?; let mut options = FetchOptions::new(); - let callbacks = Callbacks::new( - progress_sender.clone(), - basic_credential.clone(), - ); + let callbacks = Callbacks::new(progress_sender, basic_credential); options.prune(git2::FetchPrune::On); options.remote_callbacks(callbacks.callbacks()); - remote.fetch_all(Some(&mut options), None)?; + remote.fetch(&[] as &[&str], Some(&mut options), None)?; Ok(()) } From 5fca56686c20e75016fcf7caa7bb81fd632bb2b0 Mon Sep 17 00:00:00 2001 From: Stephan Dilly Date: Mon, 22 Nov 2021 22:45:17 +0100 Subject: [PATCH 3/8] support fetching all branches on all remotes --- asyncgit/src/fetch.rs | 9 ++------- asyncgit/src/sync/remotes/mod.rs | 33 ++++++++++++++++++++++++++++---- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/asyncgit/src/fetch.rs b/asyncgit/src/fetch.rs index ed14de7530..c57cff90cc 100644 --- a/asyncgit/src/fetch.rs +++ b/asyncgit/src/fetch.rs @@ -90,13 +90,8 @@ impl AsyncFetch { arc_progress, ); - fetch_all( - CWD, - "origin", - params.basic_credential.clone(), - Some(progress_sender.clone()), - ) - .expect(""); + fetch_all(CWD, params.basic_credential.clone()) + .expect(""); let res = fetch( CWD, diff --git a/asyncgit/src/sync/remotes/mod.rs b/asyncgit/src/sync/remotes/mod.rs index cf71353d43..3fb1492e56 100644 --- a/asyncgit/src/sync/remotes/mod.rs +++ b/asyncgit/src/sync/remotes/mod.rs @@ -76,14 +76,12 @@ pub(crate) fn get_default_remote_in_repo( } /// -pub fn fetch_all( +fn fetch_from_remote( repo_path: &str, remote: &str, basic_credential: Option, progress_sender: Option>, ) -> Result<()> { - scope_time!("fetch_all"); - let repo = utils::repo(repo_path)?; let mut remote = repo.find_remote(remote)?; @@ -97,7 +95,34 @@ pub fn fetch_all( Ok(()) } -/// fetches from upstream/remote for `branch` +/// updates/prunes all branches from all remotes +pub fn fetch_all( + repo_path: &str, + basic_credential: Option, +) -> Result<()> { + scope_time!("fetch_all"); + + let repo = utils::repo(repo_path)?; + let remotes = repo + .remotes()? + .iter() + .filter_map(|r| r) + .map(String::from) + .collect::>(); + + for remote in remotes { + fetch_from_remote( + repo_path, + &remote, + basic_credential.clone(), + None, + )?; + } + + Ok(()) +} + +/// fetches from upstream/remote for local `branch` pub(crate) fn fetch( repo_path: &str, branch: &str, From 63397ab21799ede3066e243a8e183e4850d02f66 Mon Sep 17 00:00:00 2001 From: Stephan Dilly Date: Tue, 23 Nov 2021 17:13:23 +0100 Subject: [PATCH 4/8] fetch job --- asyncgit/src/fetch.rs | 15 +-- asyncgit/src/fetch_job.rs | 79 +++++++++++ asyncgit/src/lib.rs | 8 +- asyncgit/src/sync/remotes/mod.rs | 14 +- src/app.rs | 30 ++++- src/components/branchlist.rs | 8 ++ src/components/fetch.rs | 221 +++++++++++++++++++++++++++++++ src/components/mod.rs | 2 + src/components/pull.rs | 8 +- src/keys/key_list_file.rs | 1 - src/queue.rs | 2 + src/strings.rs | 14 ++ src/tabs/status.rs | 2 +- 13 files changed, 380 insertions(+), 24 deletions(-) create mode 100644 asyncgit/src/fetch_job.rs create mode 100644 src/components/fetch.rs diff --git a/asyncgit/src/fetch.rs b/asyncgit/src/fetch.rs index c57cff90cc..fd8cfe395a 100644 --- a/asyncgit/src/fetch.rs +++ b/asyncgit/src/fetch.rs @@ -1,8 +1,10 @@ +//TODO: rename mod to pull + use crate::{ error::{Error, Result}, sync::{ cred::BasicAuthCredential, - remotes::{fetch, fetch_all, push::ProgressNotification}, + remotes::{fetch, push::ProgressNotification}, }, AsyncGitNotification, RemoteProgress, CWD, }; @@ -28,14 +30,14 @@ pub struct FetchRequest { struct FetchState {} /// -pub struct AsyncFetch { +pub struct AsyncPull { state: Arc>>, last_result: Arc>>, progress: Arc>>, sender: Sender, } -impl AsyncFetch { +impl AsyncPull { /// pub fn new(sender: &Sender) -> Self { Self { @@ -84,15 +86,12 @@ impl AsyncFetch { let (progress_sender, receiver) = unbounded(); let handle = RemoteProgress::spawn_receiver_thread( - AsyncGitNotification::Fetch, + AsyncGitNotification::Pull, sender.clone(), receiver, arc_progress, ); - fetch_all(CWD, params.basic_credential.clone()) - .expect(""); - let res = fetch( CWD, ¶ms.branch, @@ -111,7 +110,7 @@ impl AsyncFetch { Self::clear_request(&arc_state).expect("clear error"); sender - .send(AsyncGitNotification::Fetch) + .send(AsyncGitNotification::Pull) .expect("AsyncNotification error"); }); diff --git a/asyncgit/src/fetch_job.rs b/asyncgit/src/fetch_job.rs new file mode 100644 index 0000000000..9cd03c33cb --- /dev/null +++ b/asyncgit/src/fetch_job.rs @@ -0,0 +1,79 @@ +//! + +//TODO: +#![allow(dead_code)] + +use crate::{ + asyncjob::{AsyncJob, RunParams}, + error::Result, + sync::cred::BasicAuthCredential, + sync::remotes::fetch_all, + AsyncGitNotification, ProgressPercent, CWD, +}; + +use std::sync::{Arc, Mutex}; + +enum JobState { + Request(Option), + Response(Result<()>), +} + +/// +#[derive(Clone, Default)] +pub struct AsyncFetchJob { + state: Arc>>, +} + +/// +impl AsyncFetchJob { + /// + pub fn new( + basic_credential: Option, + ) -> Self { + Self { + state: Arc::new(Mutex::new(Some(JobState::Request( + basic_credential, + )))), + } + } + + /// + 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 AsyncFetchJob { + type Notification = AsyncGitNotification; + type Progress = ProgressPercent; + + fn run( + &mut self, + _params: RunParams, + ) -> Result { + if let Ok(mut state) = self.state.lock() { + *state = state.take().map(|state| match state { + JobState::Request(basic_credentials) => { + let result = + fetch_all(CWD, &basic_credentials, &None); + + JobState::Response(result) + } + JobState::Response(result) => { + JobState::Response(result) + } + }); + } + + Ok(AsyncGitNotification::Fetch) + } +} diff --git a/asyncgit/src/lib.rs b/asyncgit/src/lib.rs index 2f3c674ff6..0a3b821d7f 100644 --- a/asyncgit/src/lib.rs +++ b/asyncgit/src/lib.rs @@ -29,6 +29,7 @@ mod commit_files; mod diff; mod error; mod fetch; +mod fetch_job; mod progress; mod push; mod push_tags; @@ -44,7 +45,8 @@ pub use crate::{ commit_files::{AsyncCommitFiles, CommitFilesParams}, diff::{AsyncDiff, DiffParams, DiffType}, error::{Error, Result}, - fetch::{AsyncFetch, FetchRequest}, + fetch::{AsyncPull, FetchRequest}, + fetch_job::AsyncFetchJob, progress::ProgressPercent, push::{AsyncPush, PushRequest}, push_tags::{AsyncPushTags, PushTagsRequest}, @@ -83,11 +85,13 @@ pub enum AsyncGitNotification { /// PushTags, /// - Fetch, + Pull, /// Blame, /// RemoteTags, + /// + Fetch, } /// current working directory `./` diff --git a/asyncgit/src/sync/remotes/mod.rs b/asyncgit/src/sync/remotes/mod.rs index 3fb1492e56..f97636b80c 100644 --- a/asyncgit/src/sync/remotes/mod.rs +++ b/asyncgit/src/sync/remotes/mod.rs @@ -10,6 +10,7 @@ use crate::{ cred::BasicAuthCredential, remotes::push::ProgressNotification, utils, }, + ProgressPercent, }; use crossbeam_channel::Sender; use git2::{BranchType, FetchOptions, Repository}; @@ -98,7 +99,8 @@ fn fetch_from_remote( /// updates/prunes all branches from all remotes pub fn fetch_all( repo_path: &str, - basic_credential: Option, + basic_credential: &Option, + progress_sender: &Option>, ) -> Result<()> { scope_time!("fetch_all"); @@ -106,17 +108,23 @@ pub fn fetch_all( let remotes = repo .remotes()? .iter() - .filter_map(|r| r) + .flatten() .map(String::from) .collect::>(); + let remotes_count = remotes.len(); - for remote in remotes { + for (idx, remote) in remotes.into_iter().enumerate() { fetch_from_remote( repo_path, &remote, basic_credential.clone(), None, )?; + + if let Some(sender) = progress_sender { + let progress = ProgressPercent::new(idx, remotes_count); + sender.send(progress)?; + } } Ok(()) diff --git a/src/app.rs b/src/app.rs index 91e02e3049..74a5b7d936 100644 --- a/src/app.rs +++ b/src/app.rs @@ -6,11 +6,12 @@ use crate::{ BranchListComponent, CommandBlocking, CommandInfo, CommitComponent, CompareCommitsComponent, Component, ConfirmComponent, CreateBranchComponent, DrawableComponent, - ExternalEditorComponent, FileFindPopup, HelpComponent, - InspectCommitComponent, MsgComponent, OptionsPopupComponent, - PullComponent, PushComponent, PushTagsComponent, - RenameBranchComponent, RevisionFilesPopup, SharedOptions, - StashMsgComponent, TagCommitComponent, TagListComponent, + ExternalEditorComponent, FetchComponent, FileFindPopup, + HelpComponent, InspectCommitComponent, MsgComponent, + OptionsPopupComponent, PullComponent, PushComponent, + PushTagsComponent, RenameBranchComponent, RevisionFilesPopup, + SharedOptions, StashMsgComponent, TagCommitComponent, + TagListComponent, }, input::{Input, InputEvent, InputState}, keys::{KeyConfig, SharedKeyConfig}, @@ -55,6 +56,7 @@ pub struct App { push_popup: PushComponent, push_tags_popup: PushTagsComponent, pull_popup: PullComponent, + fetch_popup: FetchComponent, tag_commit_popup: TagCommitComponent, create_branch_popup: CreateBranchComponent, rename_branch_popup: RenameBranchComponent, @@ -158,6 +160,12 @@ impl App { theme.clone(), key_config.clone(), ), + fetch_popup: FetchComponent::new( + &queue, + sender, + theme.clone(), + key_config.clone(), + ), tag_commit_popup: TagCommitComponent::new( queue.clone(), theme.clone(), @@ -389,6 +397,7 @@ impl App { self.push_popup.update_git(ev)?; self.push_tags_popup.update_git(ev)?; self.pull_popup.update_git(ev); + self.fetch_popup.update_git(ev); self.select_branch_popup.update_git(ev)?; } @@ -421,6 +430,7 @@ impl App { || self.push_popup.any_work_pending() || self.push_tags_popup.any_work_pending() || self.pull_popup.any_work_pending() + || self.fetch_popup.any_work_pending() || self.revision_files_popup.any_work_pending() || self.tags_popup.any_work_pending() } @@ -453,6 +463,7 @@ impl App { push_popup, push_tags_popup, pull_popup, + fetch_popup, tag_commit_popup, create_branch_popup, rename_branch_popup, @@ -489,6 +500,7 @@ impl App { push_popup, push_tags_popup, pull_popup, + fetch_popup, options_popup, reset, msg @@ -696,6 +708,14 @@ impl App { } flags.insert(NeedsUpdate::ALL); } + InternalEvent::FetchRemotes => { + if let Err(error) = self.fetch_popup.fetch() { + self.queue.push(InternalEvent::ShowErrorMsg( + error.to_string(), + )); + } + flags.insert(NeedsUpdate::ALL); + } InternalEvent::PushTags => { self.push_tags_popup.push_tags()?; flags.insert(NeedsUpdate::ALL); diff --git a/src/components/branchlist.rs b/src/components/branchlist.rs index 64bccd1336..548c1f0065 100644 --- a/src/components/branchlist.rs +++ b/src/components/branchlist.rs @@ -196,6 +196,12 @@ impl Component for BranchListComponent { true, self.local, )); + + out.push(CommandInfo::new( + strings::commands::fetch_remotes(&self.key_config), + true, + !self.local, + )); } visibility_blocking(self) } @@ -290,6 +296,8 @@ impl Component for BranchListComponent { self.queue .push(InternalEvent::CompareCommits(b, None)); } + } else if e == self.key_config.keys.pull && !self.local { + self.queue.push(InternalEvent::FetchRemotes); } else if e == self.key_config.keys.cmd_bar_toggle { //do not consume if its the more key return Ok(EventState::NotConsumed); diff --git a/src/components/fetch.rs b/src/components/fetch.rs new file mode 100644 index 0000000000..78d115cee8 --- /dev/null +++ b/src/components/fetch.rs @@ -0,0 +1,221 @@ +use crate::{ + components::{ + cred::CredComponent, visibility_blocking, CommandBlocking, + CommandInfo, Component, DrawableComponent, EventState, + }, + keys::SharedKeyConfig, + queue::{InternalEvent, NeedsUpdate, Queue}, + strings, + ui::{self, style::SharedTheme}, +}; +use anyhow::Result; +use asyncgit::{ + asyncjob::AsyncSingleJob, + sync::cred::{ + extract_username_password, need_username_password, + BasicAuthCredential, + }, + AsyncFetchJob, AsyncGitNotification, ProgressPercent, +}; +use crossbeam_channel::Sender; +use crossterm::event::Event; +use tui::{ + backend::Backend, + layout::Rect, + text::Span, + widgets::{Block, BorderType, Borders, Clear, Gauge}, + Frame, +}; + +/// +pub struct FetchComponent { + visible: bool, + async_fetch: AsyncSingleJob, + progress: Option, + pending: bool, + queue: Queue, + theme: SharedTheme, + key_config: SharedKeyConfig, + input_cred: CredComponent, +} + +impl FetchComponent { + /// + pub fn new( + queue: &Queue, + sender: &Sender, + theme: SharedTheme, + key_config: SharedKeyConfig, + ) -> Self { + Self { + queue: queue.clone(), + pending: false, + visible: false, + async_fetch: AsyncSingleJob::new(sender.clone()), + progress: None, + input_cred: CredComponent::new( + theme.clone(), + key_config.clone(), + ), + theme, + key_config, + } + } + + /// + pub fn fetch(&mut self) -> Result<()> { + self.show()?; + if need_username_password()? { + let cred = + extract_username_password().unwrap_or_else(|_| { + BasicAuthCredential::new(None, None) + }); + if cred.is_complete() { + self.fetch_all(Some(cred)); + } else { + self.input_cred.set_cred(cred); + self.input_cred.show()?; + } + } else { + self.fetch_all(None); + } + + Ok(()) + } + + fn fetch_all(&mut self, cred: Option) { + self.pending = true; + self.progress = None; + self.progress = Some(ProgressPercent::empty()); + self.async_fetch.spawn(AsyncFetchJob::new(cred)); + } + + /// + pub const fn any_work_pending(&self) -> bool { + self.pending + } + + /// + pub fn update_git(&mut self, ev: AsyncGitNotification) { + if self.is_visible() && ev == AsyncGitNotification::Fetch { + if let Err(error) = self.update() { + self.pending = false; + self.hide(); + self.queue.push(InternalEvent::ShowErrorMsg( + format!("fetch failed:\n{}", error), + )); + } + } + } + + /// + #[allow(clippy::unnecessary_wraps)] + fn update(&mut self) -> Result<()> { + self.pending = self.async_fetch.is_pending(); + self.progress = self.async_fetch.progress(); + + if !self.pending { + self.hide(); + self.queue + .push(InternalEvent::Update(NeedsUpdate::BRANCHES)); + } + + Ok(()) + } +} + +impl DrawableComponent for FetchComponent { + fn draw( + &self, + f: &mut Frame, + rect: Rect, + ) -> Result<()> { + if self.visible { + let progress = self.progress.unwrap_or_default().progress; + + let area = ui::centered_rect_absolute(30, 3, f.size()); + + f.render_widget(Clear, area); + f.render_widget( + Gauge::default() + // .label(state.as_str()) + .block( + Block::default() + .title(Span::styled( + strings::FETCH_POPUP_MSG, + self.theme.title(true), + )) + .borders(Borders::ALL) + .border_type(BorderType::Thick) + .border_style(self.theme.block(true)), + ) + .gauge_style(self.theme.push_gauge()) + .percent(u16::from(progress)), + area, + ); + self.input_cred.draw(f, rect)?; + } + + Ok(()) + } +} + +impl Component for FetchComponent { + fn commands( + &self, + out: &mut Vec, + force_all: bool, + ) -> CommandBlocking { + if self.is_visible() || force_all { + if !force_all { + out.clear(); + } + + if self.input_cred.is_visible() { + return self.input_cred.commands(out, force_all); + } + out.push(CommandInfo::new( + strings::commands::close_msg(&self.key_config), + !self.pending, + self.visible, + )); + } + + visibility_blocking(self) + } + + fn event(&mut self, ev: Event) -> Result { + if self.visible { + if let Event::Key(_) = ev { + if self.input_cred.is_visible() { + self.input_cred.event(ev)?; + + if self.input_cred.get_cred().is_complete() + || !self.input_cred.is_visible() + { + self.fetch_all(Some( + self.input_cred.get_cred().clone(), + )); + self.input_cred.hide(); + } + } + } + return Ok(EventState::Consumed); + } + Ok(EventState::NotConsumed) + } + + fn is_visible(&self) -> bool { + self.visible + } + + fn hide(&mut self) { + self.visible = false; + } + + fn show(&mut self) -> Result<()> { + self.visible = true; + + Ok(()) + } +} diff --git a/src/components/mod.rs b/src/components/mod.rs index 3dcf25c55d..6e040276a1 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -10,6 +10,7 @@ mod create_branch; mod cred; mod diff; mod externaleditor; +mod fetch; mod file_find_popup; mod filetree; mod help; @@ -42,6 +43,7 @@ pub use compare_commits::CompareCommitsComponent; pub use create_branch::CreateBranchComponent; pub use diff::DiffComponent; pub use externaleditor::ExternalEditorComponent; +pub use fetch::FetchComponent; pub use file_find_popup::FileFindPopup; pub use help::HelpComponent; pub use inspect_commit::InspectCommitComponent; diff --git a/src/components/pull.rs b/src/components/pull.rs index 7e807e013a..a45bb110cf 100644 --- a/src/components/pull.rs +++ b/src/components/pull.rs @@ -19,7 +19,7 @@ use asyncgit::{ }, get_default_remote, }, - AsyncFetch, AsyncGitNotification, FetchRequest, RemoteProgress, + AsyncGitNotification, AsyncPull, FetchRequest, RemoteProgress, CWD, }; use crossbeam_channel::Sender; @@ -35,7 +35,7 @@ use tui::{ /// pub struct PullComponent { visible: bool, - git_fetch: AsyncFetch, + git_fetch: AsyncPull, progress: Option, pending: bool, branch: String, @@ -58,7 +58,7 @@ impl PullComponent { pending: false, visible: false, branch: String::new(), - git_fetch: AsyncFetch::new(sender), + git_fetch: AsyncPull::new(sender), progress: None, input_cred: CredComponent::new( theme.clone(), @@ -111,7 +111,7 @@ impl PullComponent { /// pub fn update_git(&mut self, ev: AsyncGitNotification) { - if self.is_visible() && ev == AsyncGitNotification::Fetch { + if self.is_visible() && ev == AsyncGitNotification::Pull { if let Err(error) = self.update() { self.pending = false; self.hide(); diff --git a/src/keys/key_list_file.rs b/src/keys/key_list_file.rs index 7290d510a9..451c8c82ac 100644 --- a/src/keys/key_list_file.rs +++ b/src/keys/key_list_file.rs @@ -81,7 +81,6 @@ pub struct KeysListFile { } impl KeysListFile { - #[allow(dead_code)] pub fn read_file(config_file: PathBuf) -> Result { let mut f = File::open(config_file)?; let mut buffer = Vec::new(); diff --git a/src/queue.rs b/src/queue.rs index 1160730e9e..63c8a9ee41 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -97,6 +97,8 @@ pub enum InternalEvent { OpenFileFinder(Vec), /// FileFinderChanged(Option), + /// + FetchRemotes, } /// single threaded simple queue for components to communicate with each other diff --git a/src/strings.rs b/src/strings.rs index a4931444aa..f056097408 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -10,6 +10,7 @@ pub mod order { pub static PUSH_POPUP_MSG: &str = "Push"; pub static FORCE_PUSH_POPUP_MSG: &str = "Force Push"; pub static PULL_POPUP_MSG: &str = "Pull"; +pub static FETCH_POPUP_MSG: &str = "Fetch"; pub static PUSH_POPUP_PROGRESS_NONE: &str = "preparing..."; pub static PUSH_POPUP_STATES_ADDING: &str = "adding objects (1/3)"; pub static PUSH_POPUP_STATES_DELTAS: &str = "deltas (2/3)"; @@ -1266,4 +1267,17 @@ pub mod commands { CMD_GROUP_GENERAL, ) } + + pub fn fetch_remotes( + key_config: &SharedKeyConfig, + ) -> CommandText { + CommandText::new( + format!( + "Fetch [{}]", + key_config.get_hint(key_config.keys.pull), + ), + "fetch/prune", + CMD_GROUP_BRANCHES, + ) + } } diff --git a/src/tabs/status.rs b/src/tabs/status.rs index e5c1434b0f..6fa2d10970 100644 --- a/src/tabs/status.rs +++ b/src/tabs/status.rs @@ -401,7 +401,7 @@ impl Status { AsyncGitNotification::Diff => self.update_diff()?, AsyncGitNotification::Status => self.update_status()?, AsyncGitNotification::Push - | AsyncGitNotification::Fetch + | AsyncGitNotification::Pull | AsyncGitNotification::CommitFiles => { self.branch_compare(); } From 53f0babf8424b73d66bbd4bddcb265dd88a91eaf Mon Sep 17 00:00:00 2001 From: Stephan Dilly Date: Tue, 23 Nov 2021 17:53:44 +0100 Subject: [PATCH 5/8] rename --- asyncgit/src/lib.rs | 4 ++-- asyncgit/src/{fetch.rs => pull.rs} | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) rename asyncgit/src/{fetch.rs => pull.rs} (99%) diff --git a/asyncgit/src/lib.rs b/asyncgit/src/lib.rs index 0a3b821d7f..2df5bdc9a5 100644 --- a/asyncgit/src/lib.rs +++ b/asyncgit/src/lib.rs @@ -28,9 +28,9 @@ pub mod cached; mod commit_files; mod diff; mod error; -mod fetch; mod fetch_job; mod progress; +mod pull; mod push; mod push_tags; pub mod remote_progress; @@ -45,9 +45,9 @@ pub use crate::{ commit_files::{AsyncCommitFiles, CommitFilesParams}, diff::{AsyncDiff, DiffParams, DiffType}, error::{Error, Result}, - fetch::{AsyncPull, FetchRequest}, fetch_job::AsyncFetchJob, progress::ProgressPercent, + pull::{AsyncPull, FetchRequest}, push::{AsyncPush, PushRequest}, push_tags::{AsyncPushTags, PushTagsRequest}, remote_progress::{RemoteProgress, RemoteProgressState}, diff --git a/asyncgit/src/fetch.rs b/asyncgit/src/pull.rs similarity index 99% rename from asyncgit/src/fetch.rs rename to asyncgit/src/pull.rs index fd8cfe395a..30562835f5 100644 --- a/asyncgit/src/fetch.rs +++ b/asyncgit/src/pull.rs @@ -1,5 +1,3 @@ -//TODO: rename mod to pull - use crate::{ error::{Error, Result}, sync::{ From b3e08e63eef840d5c5d00f0e49e49d8c4b7d96b1 Mon Sep 17 00:00:00 2001 From: Stephan Dilly Date: Tue, 23 Nov 2021 21:56:39 +0100 Subject: [PATCH 6/8] cleanup --- asyncgit/src/fetch_job.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/asyncgit/src/fetch_job.rs b/asyncgit/src/fetch_job.rs index 9cd03c33cb..01ec3eff9f 100644 --- a/asyncgit/src/fetch_job.rs +++ b/asyncgit/src/fetch_job.rs @@ -1,8 +1,5 @@ //! -//TODO: -#![allow(dead_code)] - use crate::{ asyncjob::{AsyncJob, RunParams}, error::Result, From bef593cea4dfe0a377678b6204e6ae32b19f00bf Mon Sep 17 00:00:00 2001 From: Stephan Dilly Date: Tue, 23 Nov 2021 21:57:41 +0100 Subject: [PATCH 7/8] todo --- asyncgit/src/fetch_job.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/asyncgit/src/fetch_job.rs b/asyncgit/src/fetch_job.rs index 01ec3eff9f..0daf667e44 100644 --- a/asyncgit/src/fetch_job.rs +++ b/asyncgit/src/fetch_job.rs @@ -60,6 +60,7 @@ impl AsyncJob for AsyncFetchJob { if let Ok(mut state) = self.state.lock() { *state = state.take().map(|state| match state { JobState::Request(basic_credentials) => { + //TODO: support progress let result = fetch_all(CWD, &basic_credentials, &None); From 9a1a476917441ce080b1de9336446db6f532fe93 Mon Sep 17 00:00:00 2001 From: Stephan Dilly Date: Tue, 23 Nov 2021 22:03:07 +0100 Subject: [PATCH 8/8] cleanup --- asyncgit/src/sync/remotes/mod.rs | 2 -- src/components/fetch.rs | 14 ++------------ 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/asyncgit/src/sync/remotes/mod.rs b/asyncgit/src/sync/remotes/mod.rs index f97636b80c..f4419f8039 100644 --- a/asyncgit/src/sync/remotes/mod.rs +++ b/asyncgit/src/sync/remotes/mod.rs @@ -152,8 +152,6 @@ pub(crate) fn fetch( let callbacks = Callbacks::new(progress_sender, basic_credential); options.remote_callbacks(callbacks.callbacks()); - log::debug!("fetch: {}", branch); - remote.fetch(&[branch], Some(&mut options), None)?; Ok(remote.stats().received_bytes()) diff --git a/src/components/fetch.rs b/src/components/fetch.rs index 78d115cee8..1d24d898e9 100644 --- a/src/components/fetch.rs +++ b/src/components/fetch.rs @@ -98,19 +98,12 @@ impl FetchComponent { /// pub fn update_git(&mut self, ev: AsyncGitNotification) { if self.is_visible() && ev == AsyncGitNotification::Fetch { - if let Err(error) = self.update() { - self.pending = false; - self.hide(); - self.queue.push(InternalEvent::ShowErrorMsg( - format!("fetch failed:\n{}", error), - )); - } + self.update(); } } /// - #[allow(clippy::unnecessary_wraps)] - fn update(&mut self) -> Result<()> { + fn update(&mut self) { self.pending = self.async_fetch.is_pending(); self.progress = self.async_fetch.progress(); @@ -119,8 +112,6 @@ impl FetchComponent { self.queue .push(InternalEvent::Update(NeedsUpdate::BRANCHES)); } - - Ok(()) } } @@ -138,7 +129,6 @@ impl DrawableComponent for FetchComponent { f.render_widget(Clear, area); f.render_widget( Gauge::default() - // .label(state.as_str()) .block( Block::default() .title(Span::styled(