mirror of
https://github.com/extrawurst/gitui.git
synced 2024-12-03 15:23:09 +03:00
Test push progress (#272)
This commit is contained in:
parent
56959e6596
commit
17de5a900c
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -407,8 +407,7 @@ checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "git2"
|
name = "git2"
|
||||||
version = "0.13.10"
|
version = "0.13.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/rust-lang/git2-rs.git?rev=5fddf7e04dc76e70873569ca9f1de3287ec3edda#5fddf7e04dc76e70873569ca9f1de3287ec3edda"
|
||||||
checksum = "86d97249f21e9542caeee9f8e1d150905cd875bf723f5ff771bdb4852eb83a24"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"libc",
|
"libc",
|
||||||
@ -549,8 +548,7 @@ checksum = "a9f8082297d534141b30c8d39e9b1773713ab50fdbe4ff30f750d063b3bfd701"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "libgit2-sys"
|
name = "libgit2-sys"
|
||||||
version = "0.12.12+1.0.1"
|
version = "0.12.12+1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/rust-lang/git2-rs.git?rev=5fddf7e04dc76e70873569ca9f1de3287ec3edda#5fddf7e04dc76e70873569ca9f1de3287ec3edda"
|
||||||
checksum = "0100ae90655025134424939f1f60e27e879460d451dff6afedde4f8226cbebfc"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -13,7 +13,8 @@ keywords = ["git"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
scopetime = { path = "../scopetime", version = "0.1" }
|
scopetime = { path = "../scopetime", version = "0.1" }
|
||||||
git2 = { version = "0.13", features = ["vendored-openssl"] }
|
# git2 = { version = "0.13", features = ["vendored-openssl"] }
|
||||||
|
git2 = { git="https://github.com/rust-lang/git2-rs.git", rev="5fddf7e04dc76e70873569ca9f1de3287ec3edda", features = ["vendored-openssl"] }
|
||||||
rayon-core = "1.8"
|
rayon-core = "1.8"
|
||||||
crossbeam-channel = "0.4"
|
crossbeam-channel = "0.4"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
@ -52,11 +52,11 @@ pub struct AsyncDiff {
|
|||||||
|
|
||||||
impl AsyncDiff {
|
impl AsyncDiff {
|
||||||
///
|
///
|
||||||
pub fn new(sender: Sender<AsyncNotification>) -> Self {
|
pub fn new(sender: &Sender<AsyncNotification>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
current: Arc::new(Mutex::new(Request(0, None))),
|
current: Arc::new(Mutex::new(Request(0, None))),
|
||||||
last: Arc::new(Mutex::new(None)),
|
last: Arc::new(Mutex::new(None)),
|
||||||
sender,
|
sender: sender.clone(),
|
||||||
pending: Arc::new(AtomicUsize::new(0)),
|
pending: Arc::new(AtomicUsize::new(0)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ pub mod cached;
|
|||||||
mod commit_files;
|
mod commit_files;
|
||||||
mod diff;
|
mod diff;
|
||||||
mod error;
|
mod error;
|
||||||
|
mod push;
|
||||||
mod revlog;
|
mod revlog;
|
||||||
mod status;
|
mod status;
|
||||||
pub mod sync;
|
pub mod sync;
|
||||||
@ -19,6 +20,7 @@ mod tags;
|
|||||||
pub use crate::{
|
pub use crate::{
|
||||||
commit_files::AsyncCommitFiles,
|
commit_files::AsyncCommitFiles,
|
||||||
diff::{AsyncDiff, DiffParams, DiffType},
|
diff::{AsyncDiff, DiffParams, DiffType},
|
||||||
|
push::{AsyncPush, PushRequest},
|
||||||
revlog::{AsyncLog, FetchStatus},
|
revlog::{AsyncLog, FetchStatus},
|
||||||
status::{AsyncStatus, StatusParams},
|
status::{AsyncStatus, StatusParams},
|
||||||
sync::{
|
sync::{
|
||||||
@ -47,6 +49,8 @@ pub enum AsyncNotification {
|
|||||||
CommitFiles,
|
CommitFiles,
|
||||||
///
|
///
|
||||||
Tags,
|
Tags,
|
||||||
|
///
|
||||||
|
Push,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// current working director `./`
|
/// current working director `./`
|
||||||
|
140
asyncgit/src/push.rs
Normal file
140
asyncgit/src/push.rs
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
use crate::{
|
||||||
|
error::{Error, Result},
|
||||||
|
sync, AsyncNotification, CWD,
|
||||||
|
};
|
||||||
|
use crossbeam_channel::Sender;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
enum PushStates {
|
||||||
|
None,
|
||||||
|
// Packing,
|
||||||
|
// Pushing(usize, usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PushStates {
|
||||||
|
fn default() -> Self {
|
||||||
|
PushStates::None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
#[derive(Default, Clone, Debug)]
|
||||||
|
pub struct PushRequest {
|
||||||
|
///
|
||||||
|
pub remote: String,
|
||||||
|
///
|
||||||
|
pub branch: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Clone, Debug)]
|
||||||
|
struct PushState {
|
||||||
|
request: PushRequest,
|
||||||
|
state: PushStates,
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
pub struct AsyncPush {
|
||||||
|
state: Arc<Mutex<Option<PushState>>>,
|
||||||
|
last_result: Arc<Mutex<Option<String>>>,
|
||||||
|
sender: Sender<AsyncNotification>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsyncPush {
|
||||||
|
///
|
||||||
|
pub fn new(sender: &Sender<AsyncNotification>) -> Self {
|
||||||
|
Self {
|
||||||
|
state: Arc::new(Mutex::new(None)),
|
||||||
|
last_result: Arc::new(Mutex::new(None)),
|
||||||
|
sender: sender.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
pub fn is_pending(&self) -> Result<bool> {
|
||||||
|
let state = self.state.lock()?;
|
||||||
|
Ok(state.is_some())
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
pub fn last_result(&self) -> Result<Option<String>> {
|
||||||
|
let res = self.last_result.lock()?;
|
||||||
|
Ok(res.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
pub fn request(&mut self, params: PushRequest) -> Result<()> {
|
||||||
|
log::trace!("request");
|
||||||
|
|
||||||
|
if self.is_pending()? {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.set_request(¶ms)?;
|
||||||
|
|
||||||
|
let arc_state = Arc::clone(&self.state);
|
||||||
|
let arc_res = Arc::clone(&self.last_result);
|
||||||
|
let sender = self.sender.clone();
|
||||||
|
|
||||||
|
rayon_core::spawn(move || {
|
||||||
|
//TODO: use channels to communicate progress
|
||||||
|
let res = sync::push_origin(
|
||||||
|
CWD,
|
||||||
|
params.remote.as_str(),
|
||||||
|
params.branch.as_str(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Self::set_result(arc_res, res).expect("result error");
|
||||||
|
|
||||||
|
Self::clear_request(arc_state).expect("clear error");
|
||||||
|
|
||||||
|
sender
|
||||||
|
.send(AsyncNotification::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(),
|
||||||
|
..PushState::default()
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_request(
|
||||||
|
state: Arc<Mutex<Option<PushState>>>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let mut state = state.lock()?;
|
||||||
|
|
||||||
|
*state = None;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_result(
|
||||||
|
arc_result: Arc<Mutex<Option<String>>>,
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
}
|
@ -30,9 +30,7 @@ pub use hooks::{hooks_commit_msg, hooks_post_commit, HookResult};
|
|||||||
pub use hunks::{reset_hunk, stage_hunk, unstage_hunk};
|
pub use hunks::{reset_hunk, stage_hunk, unstage_hunk};
|
||||||
pub use ignore::add_to_ignore;
|
pub use ignore::add_to_ignore;
|
||||||
pub use logwalker::LogWalker;
|
pub use logwalker::LogWalker;
|
||||||
pub use remotes::{
|
pub use remotes::{fetch_origin, get_remotes, push_origin};
|
||||||
fetch_origin, get_remotes, push_origin, remote_push_master,
|
|
||||||
};
|
|
||||||
pub use reset::{reset_stage, reset_workdir};
|
pub use reset::{reset_stage, reset_workdir};
|
||||||
pub use stash::{get_stashes, stash_apply, stash_drop, stash_save};
|
pub use stash::{get_stashes, stash_apply, stash_drop, stash_save};
|
||||||
pub use tags::{get_tags, CommitTags, Tags};
|
pub use tags::{get_tags, CommitTags, Tags};
|
||||||
|
@ -16,18 +16,6 @@ pub fn get_remotes(repo_path: &str) -> Result<Vec<String>> {
|
|||||||
Ok(remotes)
|
Ok(remotes)
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
pub fn remote_push_master(repo_path: &str) -> Result<()> {
|
|
||||||
scope_time!("remote_push_master");
|
|
||||||
|
|
||||||
let repo = utils::repo(repo_path)?;
|
|
||||||
let mut remote = repo.find_remote("origin")?;
|
|
||||||
|
|
||||||
remote.push(&["refs/heads/master"], None)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
///
|
||||||
pub fn fetch_origin(repo_path: &str, branch: &str) -> Result<usize> {
|
pub fn fetch_origin(repo_path: &str, branch: &str) -> Result<usize> {
|
||||||
scope_time!("remote_fetch_master");
|
scope_time!("remote_fetch_master");
|
||||||
@ -44,14 +32,19 @@ pub fn fetch_origin(repo_path: &str, branch: &str) -> Result<usize> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pub fn push_origin(repo_path: &str, branch: &str) -> Result<()> {
|
pub fn push_origin(
|
||||||
|
repo_path: &str,
|
||||||
|
remote: &str,
|
||||||
|
branch: &str,
|
||||||
|
) -> Result<()> {
|
||||||
scope_time!("push_origin");
|
scope_time!("push_origin");
|
||||||
|
|
||||||
let repo = utils::repo(repo_path)?;
|
let repo = utils::repo(repo_path)?;
|
||||||
let mut remote = repo.find_remote("origin")?;
|
let mut remote = repo.find_remote(remote)?;
|
||||||
|
|
||||||
let mut options = PushOptions::new();
|
let mut options = PushOptions::new();
|
||||||
options.remote_callbacks(remote_callbacks());
|
options.remote_callbacks(remote_callbacks());
|
||||||
|
options.packbuilder_parallelism(0);
|
||||||
|
|
||||||
remote.push(&[branch], Some(&mut options))?;
|
remote.push(&[branch], Some(&mut options))?;
|
||||||
|
|
||||||
@ -60,6 +53,17 @@ pub fn push_origin(repo_path: &str, branch: &str) -> Result<()> {
|
|||||||
|
|
||||||
fn remote_callbacks<'a>() -> RemoteCallbacks<'a> {
|
fn remote_callbacks<'a>() -> RemoteCallbacks<'a> {
|
||||||
let mut callbacks = RemoteCallbacks::new();
|
let mut callbacks = RemoteCallbacks::new();
|
||||||
|
callbacks.push_transfer_progress(|progress, total, bytes| {
|
||||||
|
log::debug!(
|
||||||
|
"progress: {}/{} ({} B)",
|
||||||
|
progress,
|
||||||
|
total,
|
||||||
|
bytes,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
callbacks.pack_progress(|stage, current, total| {
|
||||||
|
log::debug!("packing: {:?} - {}/{}", stage, current, total);
|
||||||
|
});
|
||||||
callbacks.credentials(|url, username_from_url, allowed_types| {
|
callbacks.credentials(|url, username_from_url, allowed_types| {
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"creds: '{}' {:?} ({:?})",
|
"creds: '{}' {:?} ({:?})",
|
||||||
|
66
src/app.rs
66
src/app.rs
@ -5,8 +5,8 @@ use crate::{
|
|||||||
event_pump, CommandBlocking, CommandInfo, CommitComponent,
|
event_pump, CommandBlocking, CommandInfo, CommitComponent,
|
||||||
Component, CreateBranchComponent, DrawableComponent,
|
Component, CreateBranchComponent, DrawableComponent,
|
||||||
ExternalEditorComponent, HelpComponent,
|
ExternalEditorComponent, HelpComponent,
|
||||||
InspectCommitComponent, MsgComponent, ResetComponent,
|
InspectCommitComponent, MsgComponent, PushComponent,
|
||||||
StashMsgComponent, TagCommitComponent,
|
ResetComponent, StashMsgComponent, TagCommitComponent,
|
||||||
},
|
},
|
||||||
input::{Input, InputEvent, InputState},
|
input::{Input, InputEvent, InputState},
|
||||||
keys::{KeyConfig, SharedKeyConfig},
|
keys::{KeyConfig, SharedKeyConfig},
|
||||||
@ -41,6 +41,7 @@ pub struct App {
|
|||||||
stashmsg_popup: StashMsgComponent,
|
stashmsg_popup: StashMsgComponent,
|
||||||
inspect_commit_popup: InspectCommitComponent,
|
inspect_commit_popup: InspectCommitComponent,
|
||||||
external_editor_popup: ExternalEditorComponent,
|
external_editor_popup: ExternalEditorComponent,
|
||||||
|
push_popup: PushComponent,
|
||||||
tag_commit_popup: TagCommitComponent,
|
tag_commit_popup: TagCommitComponent,
|
||||||
create_branch_popup: CreateBranchComponent,
|
create_branch_popup: CreateBranchComponent,
|
||||||
cmdbar: RefCell<CommandBar>,
|
cmdbar: RefCell<CommandBar>,
|
||||||
@ -98,6 +99,12 @@ impl App {
|
|||||||
theme.clone(),
|
theme.clone(),
|
||||||
key_config.clone(),
|
key_config.clone(),
|
||||||
),
|
),
|
||||||
|
push_popup: PushComponent::new(
|
||||||
|
&queue,
|
||||||
|
sender,
|
||||||
|
theme.clone(),
|
||||||
|
key_config.clone(),
|
||||||
|
),
|
||||||
tag_commit_popup: TagCommitComponent::new(
|
tag_commit_popup: TagCommitComponent::new(
|
||||||
queue.clone(),
|
queue.clone(),
|
||||||
theme.clone(),
|
theme.clone(),
|
||||||
@ -225,21 +232,7 @@ impl App {
|
|||||||
flags.insert(new_flags);
|
flags.insert(new_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_flags = self.process_queue()?;
|
self.process_queue(flags)?;
|
||||||
flags.insert(new_flags);
|
|
||||||
|
|
||||||
if flags.contains(NeedsUpdate::ALL) {
|
|
||||||
self.update()?;
|
|
||||||
}
|
|
||||||
//TODO: make this a queue event?
|
|
||||||
//NOTE: set when any tree component changed selection
|
|
||||||
if flags.contains(NeedsUpdate::DIFF) {
|
|
||||||
self.status_tab.update_diff()?;
|
|
||||||
self.inspect_commit_popup.update_diff()?;
|
|
||||||
}
|
|
||||||
if flags.contains(NeedsUpdate::COMMANDS) {
|
|
||||||
self.update_commands();
|
|
||||||
}
|
|
||||||
} else if let InputEvent::State(polling_state) = ev {
|
} else if let InputEvent::State(polling_state) = ev {
|
||||||
self.external_editor_popup.hide();
|
self.external_editor_popup.hide();
|
||||||
if let InputState::Paused = polling_state {
|
if let InputState::Paused = polling_state {
|
||||||
@ -293,10 +286,11 @@ impl App {
|
|||||||
self.stashing_tab.update_git(ev)?;
|
self.stashing_tab.update_git(ev)?;
|
||||||
self.revlog.update_git(ev)?;
|
self.revlog.update_git(ev)?;
|
||||||
self.inspect_commit_popup.update_git(ev)?;
|
self.inspect_commit_popup.update_git(ev)?;
|
||||||
|
self.push_popup.update_git(ev)?;
|
||||||
|
|
||||||
//TODO: better system for this
|
//TODO: better system for this
|
||||||
// can we simply process the queue here and everyone just uses the queue to schedule a cmd update?
|
// can we simply process the queue here and everyone just uses the queue to schedule a cmd update?
|
||||||
self.update_commands();
|
self.process_queue(NeedsUpdate::COMMANDS)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -337,6 +331,7 @@ impl App {
|
|||||||
stashmsg_popup,
|
stashmsg_popup,
|
||||||
inspect_commit_popup,
|
inspect_commit_popup,
|
||||||
external_editor_popup,
|
external_editor_popup,
|
||||||
|
push_popup,
|
||||||
tag_commit_popup,
|
tag_commit_popup,
|
||||||
create_branch_popup,
|
create_branch_popup,
|
||||||
help,
|
help,
|
||||||
@ -411,7 +406,28 @@ impl App {
|
|||||||
self.cmdbar.borrow_mut().set_cmds(self.commands(false));
|
self.cmdbar.borrow_mut().set_cmds(self.commands(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_queue(&mut self) -> Result<NeedsUpdate> {
|
fn process_queue(&mut self, flags: NeedsUpdate) -> Result<()> {
|
||||||
|
let mut flags = flags;
|
||||||
|
let new_flags = self.process_internal_events()?;
|
||||||
|
flags.insert(new_flags);
|
||||||
|
|
||||||
|
if flags.contains(NeedsUpdate::ALL) {
|
||||||
|
self.update()?;
|
||||||
|
}
|
||||||
|
//TODO: make this a queue event?
|
||||||
|
//NOTE: set when any tree component changed selection
|
||||||
|
if flags.contains(NeedsUpdate::DIFF) {
|
||||||
|
self.status_tab.update_diff()?;
|
||||||
|
self.inspect_commit_popup.update_diff()?;
|
||||||
|
}
|
||||||
|
if flags.contains(NeedsUpdate::COMMANDS) {
|
||||||
|
self.update_commands();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_internal_events(&mut self) -> Result<NeedsUpdate> {
|
||||||
let mut flags = NeedsUpdate::empty();
|
let mut flags = NeedsUpdate::empty();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@ -458,11 +474,6 @@ impl App {
|
|||||||
flags
|
flags
|
||||||
.insert(NeedsUpdate::ALL | NeedsUpdate::COMMANDS);
|
.insert(NeedsUpdate::ALL | NeedsUpdate::COMMANDS);
|
||||||
}
|
}
|
||||||
InternalEvent::ShowInfoMsg(msg) => {
|
|
||||||
self.msg.show_info(msg.as_str())?;
|
|
||||||
flags
|
|
||||||
.insert(NeedsUpdate::ALL | NeedsUpdate::COMMANDS);
|
|
||||||
}
|
|
||||||
InternalEvent::Update(u) => flags.insert(u),
|
InternalEvent::Update(u) => flags.insert(u),
|
||||||
InternalEvent::OpenCommit => self.commit.show()?,
|
InternalEvent::OpenCommit => self.commit.show()?,
|
||||||
InternalEvent::PopupStashing(opts) => {
|
InternalEvent::PopupStashing(opts) => {
|
||||||
@ -486,6 +497,10 @@ impl App {
|
|||||||
self.file_to_open = path;
|
self.file_to_open = path;
|
||||||
flags.insert(NeedsUpdate::COMMANDS)
|
flags.insert(NeedsUpdate::COMMANDS)
|
||||||
}
|
}
|
||||||
|
InternalEvent::Push(branch) => {
|
||||||
|
self.push_popup.push(branch)?;
|
||||||
|
flags.insert(NeedsUpdate::ALL)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(flags)
|
Ok(flags)
|
||||||
@ -534,6 +549,7 @@ impl App {
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: make this automatic, i keep forgetting to add popups here
|
||||||
fn any_popup_visible(&self) -> bool {
|
fn any_popup_visible(&self) -> bool {
|
||||||
self.commit.is_visible()
|
self.commit.is_visible()
|
||||||
|| self.help.is_visible()
|
|| self.help.is_visible()
|
||||||
@ -544,6 +560,7 @@ impl App {
|
|||||||
|| self.external_editor_popup.is_visible()
|
|| self.external_editor_popup.is_visible()
|
||||||
|| self.tag_commit_popup.is_visible()
|
|| self.tag_commit_popup.is_visible()
|
||||||
|| self.create_branch_popup.is_visible()
|
|| self.create_branch_popup.is_visible()
|
||||||
|
|| self.push_popup.is_visible()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_popups<B: Backend>(
|
fn draw_popups<B: Backend>(
|
||||||
@ -570,6 +587,7 @@ impl App {
|
|||||||
self.external_editor_popup.draw(f, size)?;
|
self.external_editor_popup.draw(f, size)?;
|
||||||
self.tag_commit_popup.draw(f, size)?;
|
self.tag_commit_popup.draw(f, size)?;
|
||||||
self.create_branch_popup.draw(f, size)?;
|
self.create_branch_popup.draw(f, size)?;
|
||||||
|
self.push_popup.draw(f, size)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -173,7 +173,7 @@ impl InspectCommitComponent {
|
|||||||
),
|
),
|
||||||
commit_id: None,
|
commit_id: None,
|
||||||
tags: None,
|
tags: None,
|
||||||
git_diff: AsyncDiff::new(sender.clone()),
|
git_diff: AsyncDiff::new(sender),
|
||||||
visible: false,
|
visible: false,
|
||||||
key_config,
|
key_config,
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ mod filetree;
|
|||||||
mod help;
|
mod help;
|
||||||
mod inspect_commit;
|
mod inspect_commit;
|
||||||
mod msg;
|
mod msg;
|
||||||
|
mod push;
|
||||||
mod reset;
|
mod reset;
|
||||||
mod stashmsg;
|
mod stashmsg;
|
||||||
mod tag_commit;
|
mod tag_commit;
|
||||||
@ -31,6 +32,7 @@ pub use filetree::FileTreeComponent;
|
|||||||
pub use help::HelpComponent;
|
pub use help::HelpComponent;
|
||||||
pub use inspect_commit::InspectCommitComponent;
|
pub use inspect_commit::InspectCommitComponent;
|
||||||
pub use msg::MsgComponent;
|
pub use msg::MsgComponent;
|
||||||
|
pub use push::PushComponent;
|
||||||
pub use reset::ResetComponent;
|
pub use reset::ResetComponent;
|
||||||
pub use stashmsg::StashMsgComponent;
|
pub use stashmsg::StashMsgComponent;
|
||||||
pub use tag_commit::TagCommitComponent;
|
pub use tag_commit::TagCommitComponent;
|
||||||
|
@ -119,13 +119,4 @@ impl MsgComponent {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
pub fn show_info(&mut self, msg: &str) -> Result<()> {
|
|
||||||
self.title = strings::msg_title_info(&self.key_config);
|
|
||||||
self.msg = msg.to_string();
|
|
||||||
self.show()?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
169
src/components/push.rs
Normal file
169
src/components/push.rs
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
use crate::{
|
||||||
|
components::{
|
||||||
|
visibility_blocking, CommandBlocking, CommandInfo, Component,
|
||||||
|
DrawableComponent,
|
||||||
|
},
|
||||||
|
keys::SharedKeyConfig,
|
||||||
|
queue::{InternalEvent, Queue},
|
||||||
|
strings,
|
||||||
|
ui::{self, style::SharedTheme},
|
||||||
|
};
|
||||||
|
use anyhow::Result;
|
||||||
|
use asyncgit::{AsyncNotification, AsyncPush, PushRequest};
|
||||||
|
use crossbeam_channel::Sender;
|
||||||
|
use crossterm::event::Event;
|
||||||
|
use tui::{
|
||||||
|
backend::Backend,
|
||||||
|
layout::Rect,
|
||||||
|
widgets::{Block, BorderType, Borders, Clear, Paragraph, Text},
|
||||||
|
Frame,
|
||||||
|
};
|
||||||
|
|
||||||
|
///
|
||||||
|
pub struct PushComponent {
|
||||||
|
visible: bool,
|
||||||
|
git_push: AsyncPush,
|
||||||
|
pending: bool,
|
||||||
|
queue: Queue,
|
||||||
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PushComponent {
|
||||||
|
///
|
||||||
|
pub fn new(
|
||||||
|
queue: &Queue,
|
||||||
|
sender: &Sender<AsyncNotification>,
|
||||||
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
queue: queue.clone(),
|
||||||
|
pending: false,
|
||||||
|
visible: false,
|
||||||
|
git_push: AsyncPush::new(sender),
|
||||||
|
theme,
|
||||||
|
key_config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
pub fn push(&mut self, branch: String) -> Result<()> {
|
||||||
|
self.pending = true;
|
||||||
|
self.git_push.request(PushRequest {
|
||||||
|
remote: String::from("origin"),
|
||||||
|
branch,
|
||||||
|
})?;
|
||||||
|
self.show()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
pub fn update_git(
|
||||||
|
&mut self,
|
||||||
|
ev: AsyncNotification,
|
||||||
|
) -> Result<()> {
|
||||||
|
if self.is_visible() {
|
||||||
|
if let AsyncNotification::Push = ev {
|
||||||
|
self.update()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
fn update(&mut self) -> Result<()> {
|
||||||
|
self.pending = self.git_push.is_pending()?;
|
||||||
|
|
||||||
|
if !self.pending {
|
||||||
|
if let Some(err) = self.git_push.last_result()? {
|
||||||
|
self.queue.borrow_mut().push_back(
|
||||||
|
InternalEvent::ShowErrorMsg(format!(
|
||||||
|
"push failed:\n{}",
|
||||||
|
err
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DrawableComponent for PushComponent {
|
||||||
|
fn draw<B: Backend>(
|
||||||
|
&self,
|
||||||
|
f: &mut Frame<B>,
|
||||||
|
_rect: Rect,
|
||||||
|
) -> Result<()> {
|
||||||
|
if self.visible {
|
||||||
|
let txt = vec![Text::Raw(strings::PUSH_POPUP_MSG.into())];
|
||||||
|
|
||||||
|
let area = ui::centered_rect_absolute(25, 3, f.size());
|
||||||
|
f.render_widget(Clear, area);
|
||||||
|
f.render_widget(
|
||||||
|
Paragraph::new(txt.iter())
|
||||||
|
.block(
|
||||||
|
Block::default()
|
||||||
|
.borders(Borders::ALL)
|
||||||
|
.border_type(BorderType::Thick)
|
||||||
|
.title_style(self.theme.title(true))
|
||||||
|
.border_style(self.theme.block(true)),
|
||||||
|
)
|
||||||
|
.style(self.theme.text_danger()),
|
||||||
|
area,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for PushComponent {
|
||||||
|
fn commands(
|
||||||
|
&self,
|
||||||
|
out: &mut Vec<CommandInfo>,
|
||||||
|
_force_all: bool,
|
||||||
|
) -> CommandBlocking {
|
||||||
|
if self.is_visible() {
|
||||||
|
out.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
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<bool> {
|
||||||
|
if self.visible {
|
||||||
|
if let Event::Key(e) = ev {
|
||||||
|
if e == self.key_config.enter {
|
||||||
|
self.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_visible(&self) -> bool {
|
||||||
|
self.visible
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hide(&mut self) {
|
||||||
|
self.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show(&mut self) -> Result<()> {
|
||||||
|
self.visible = true;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@ -39,8 +39,6 @@ pub enum InternalEvent {
|
|||||||
///
|
///
|
||||||
ShowErrorMsg(String),
|
ShowErrorMsg(String),
|
||||||
///
|
///
|
||||||
ShowInfoMsg(String),
|
|
||||||
///
|
|
||||||
Update(NeedsUpdate),
|
Update(NeedsUpdate),
|
||||||
/// open commit msg input
|
/// open commit msg input
|
||||||
OpenCommit,
|
OpenCommit,
|
||||||
@ -56,6 +54,8 @@ pub enum InternalEvent {
|
|||||||
CreateBranch,
|
CreateBranch,
|
||||||
///
|
///
|
||||||
OpenExternalEditor(Option<String>),
|
OpenExternalEditor(Option<String>),
|
||||||
|
///
|
||||||
|
Push(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -4,6 +4,8 @@ pub mod order {
|
|||||||
pub static NAV: i8 = 1;
|
pub static NAV: i8 = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub static PUSH_POPUP_MSG: &str = "pushing...";
|
||||||
|
|
||||||
pub fn title_status(key_config: &SharedKeyConfig) -> String {
|
pub fn title_status(key_config: &SharedKeyConfig) -> String {
|
||||||
format!(
|
format!(
|
||||||
"Unstaged Changes [{}]",
|
"Unstaged Changes [{}]",
|
||||||
@ -40,9 +42,6 @@ pub fn msg_opening_editor(_key_config: &SharedKeyConfig) -> String {
|
|||||||
pub fn msg_title_error(_key_config: &SharedKeyConfig) -> String {
|
pub fn msg_title_error(_key_config: &SharedKeyConfig) -> String {
|
||||||
"Error".to_string()
|
"Error".to_string()
|
||||||
}
|
}
|
||||||
pub fn msg_title_info(_key_config: &SharedKeyConfig) -> String {
|
|
||||||
"Info".to_string()
|
|
||||||
}
|
|
||||||
pub fn commit_title(_key_config: &SharedKeyConfig) -> String {
|
pub fn commit_title(_key_config: &SharedKeyConfig) -> String {
|
||||||
"Commit".to_string()
|
"Commit".to_string()
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,7 @@ impl Status {
|
|||||||
key_config.clone(),
|
key_config.clone(),
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
git_diff: AsyncDiff::new(sender.clone()),
|
git_diff: AsyncDiff::new(sender),
|
||||||
git_status_workdir: AsyncStatus::new(sender.clone()),
|
git_status_workdir: AsyncStatus::new(sender.clone()),
|
||||||
git_status_stage: AsyncStatus::new(sender.clone()),
|
git_status_stage: AsyncStatus::new(sender.clone()),
|
||||||
git_action_executed: false,
|
git_action_executed: false,
|
||||||
@ -327,18 +327,10 @@ impl Status {
|
|||||||
fn push(&self) {
|
fn push(&self) {
|
||||||
if let Some(branch) = self.index_wd.branch_name() {
|
if let Some(branch) = self.index_wd.branch_name() {
|
||||||
let branch = format!("refs/heads/{}", branch);
|
let branch = format!("refs/heads/{}", branch);
|
||||||
if let Err(e) = sync::push_origin(CWD, branch.as_str()) {
|
|
||||||
self.queue.borrow_mut().push_back(
|
self.queue
|
||||||
InternalEvent::ShowErrorMsg(format!(
|
.borrow_mut()
|
||||||
"push failed:\n{}",
|
.push_back(InternalEvent::Push(branch));
|
||||||
e
|
|
||||||
)),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
self.queue.borrow_mut().push_back(
|
|
||||||
InternalEvent::ShowInfoMsg("pushed".to_string()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user