mirror of
https://github.com/gitui-org/gitui
synced 2026-05-23 17:08:21 +00:00
parent
14ce5a7c58
commit
0fa3e0f5a8
6 changed files with 151 additions and 2 deletions
|
|
@ -33,6 +33,8 @@ mod progress;
|
|||
mod push;
|
||||
mod push_tags;
|
||||
pub mod remote_progress;
|
||||
///
|
||||
pub mod remotes;
|
||||
mod revlog;
|
||||
mod status;
|
||||
pub mod sync;
|
||||
|
|
@ -85,6 +87,9 @@ pub enum AsyncGitNotification {
|
|||
///
|
||||
//TODO: this does not belong here
|
||||
SyntaxHighlighting,
|
||||
///
|
||||
//TODO: this does not belong here
|
||||
RemoteTags,
|
||||
}
|
||||
|
||||
/// current working directory `./`
|
||||
|
|
|
|||
72
asyncgit/src/remotes.rs
Normal file
72
asyncgit/src/remotes.rs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
use crate::{
|
||||
asyncjob::AsyncJob,
|
||||
error::Result,
|
||||
sync::cred::BasicAuthCredential,
|
||||
sync::remotes::{get_default_remote, tags_missing_remote},
|
||||
CWD,
|
||||
};
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
enum JobState {
|
||||
Request(Option<BasicAuthCredential>),
|
||||
Response(Result<Vec<String>>),
|
||||
}
|
||||
|
||||
///
|
||||
#[derive(Clone, Default)]
|
||||
pub struct AsyncRemoteTagsJob {
|
||||
state: Arc<Mutex<Option<JobState>>>,
|
||||
}
|
||||
|
||||
///
|
||||
impl AsyncRemoteTagsJob {
|
||||
///
|
||||
pub fn new(
|
||||
basic_credential: Option<BasicAuthCredential>,
|
||||
) -> Self {
|
||||
Self {
|
||||
state: Arc::new(Mutex::new(Some(JobState::Request(
|
||||
basic_credential,
|
||||
)))),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
pub fn result(&self) -> Option<Result<Vec<String>>> {
|
||||
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 AsyncRemoteTagsJob {
|
||||
fn run(&mut self) {
|
||||
if let Ok(mut state) = self.state.lock() {
|
||||
*state = state.take().map(|state| match state {
|
||||
JobState::Request(basic_credential) => {
|
||||
let result =
|
||||
get_default_remote(CWD).and_then(|remote| {
|
||||
tags_missing_remote(
|
||||
CWD,
|
||||
&remote,
|
||||
basic_credential,
|
||||
)
|
||||
});
|
||||
|
||||
JobState::Response(result)
|
||||
}
|
||||
JobState::Response(result) => {
|
||||
JobState::Response(result)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,6 +16,8 @@ use push::remote_callbacks;
|
|||
use scopetime::scope_time;
|
||||
use utils::bytes2string;
|
||||
|
||||
pub use tags::tags_missing_remote;
|
||||
|
||||
/// origin
|
||||
pub const DEFAULT_REMOTE_NAME: &str = "origin";
|
||||
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ fn remote_tag_refs(
|
|||
}
|
||||
|
||||
/// lists the remotes tags missing
|
||||
fn tags_missing_remote(
|
||||
pub fn tags_missing_remote(
|
||||
repo_path: &str,
|
||||
remote: &str,
|
||||
basic_credential: Option<BasicAuthCredential>,
|
||||
|
|
|
|||
|
|
@ -167,6 +167,7 @@ impl App {
|
|||
),
|
||||
tags_popup: TagListComponent::new(
|
||||
&queue,
|
||||
sender,
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
|
|
@ -357,6 +358,7 @@ impl App {
|
|||
self.push_tags_popup.update_git(ev)?;
|
||||
self.pull_popup.update_git(ev)?;
|
||||
self.revision_files_popup.update(ev);
|
||||
self.tags_popup.update(ev);
|
||||
|
||||
//TODO: better system for this
|
||||
// can we simply process the queue here and everyone just uses the queue to schedule a cmd update?
|
||||
|
|
@ -383,6 +385,7 @@ impl App {
|
|||
|| self.push_tags_popup.any_work_pending()
|
||||
|| self.pull_popup.any_work_pending()
|
||||
|| self.revision_files_popup.any_work_pending()
|
||||
|| self.tags_popup.any_work_pending()
|
||||
}
|
||||
|
||||
///
|
||||
|
|
|
|||
|
|
@ -11,9 +11,13 @@ use crate::{
|
|||
};
|
||||
use anyhow::Result;
|
||||
use asyncgit::{
|
||||
asyncjob::AsyncSingleJob,
|
||||
remotes::AsyncRemoteTagsJob,
|
||||
sync::cred::{extract_username_password, need_username_password},
|
||||
sync::{get_tags_with_metadata, TagWithMetadata},
|
||||
CWD,
|
||||
AsyncGitNotification, CWD,
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
use crossterm::event::Event;
|
||||
use std::convert::TryInto;
|
||||
use tui::{
|
||||
|
|
@ -36,6 +40,9 @@ pub struct TagListComponent {
|
|||
visible: bool,
|
||||
table_state: std::cell::Cell<TableState>,
|
||||
current_height: std::cell::Cell<usize>,
|
||||
missing_remote_tags: Option<Vec<String>>,
|
||||
async_remote_tags:
|
||||
AsyncSingleJob<AsyncRemoteTagsJob, AsyncGitNotification>,
|
||||
key_config: SharedKeyConfig,
|
||||
}
|
||||
|
||||
|
|
@ -65,6 +72,8 @@ impl DrawableComponent for TagListComponent {
|
|||
});
|
||||
|
||||
let constraints = [
|
||||
// symbol if tag is not yet on remote and can be pushed
|
||||
Constraint::Length(1),
|
||||
// tag name
|
||||
Constraint::Length(tag_name_width.try_into()?),
|
||||
// commit date
|
||||
|
|
@ -230,6 +239,7 @@ impl Component for TagListComponent {
|
|||
impl TagListComponent {
|
||||
pub fn new(
|
||||
queue: &Queue,
|
||||
sender: &Sender<AsyncGitNotification>,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
) -> Self {
|
||||
|
|
@ -240,6 +250,11 @@ impl TagListComponent {
|
|||
visible: false,
|
||||
table_state: std::cell::Cell::new(TableState::default()),
|
||||
current_height: std::cell::Cell::new(0),
|
||||
missing_remote_tags: None,
|
||||
async_remote_tags: AsyncSingleJob::new(
|
||||
sender.clone(),
|
||||
AsyncGitNotification::RemoteTags,
|
||||
),
|
||||
key_config,
|
||||
}
|
||||
}
|
||||
|
|
@ -251,9 +266,41 @@ impl TagListComponent {
|
|||
|
||||
self.update_tags()?;
|
||||
|
||||
let basic_credential = if need_username_password()? {
|
||||
let credential = extract_username_password()?;
|
||||
|
||||
if credential.is_complete() {
|
||||
Some(credential)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
self.async_remote_tags
|
||||
.spawn(AsyncRemoteTagsJob::new(basic_credential));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
pub fn update(&mut self, event: AsyncGitNotification) {
|
||||
if event == AsyncGitNotification::RemoteTags {
|
||||
if let Some(job) = self.async_remote_tags.take_last() {
|
||||
if let Some(Ok(missing_remote_tags)) = job.result() {
|
||||
self.missing_remote_tags =
|
||||
Some(missing_remote_tags);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
pub fn any_work_pending(&self) -> bool {
|
||||
self.async_remote_tags.is_pending()
|
||||
}
|
||||
|
||||
/// fetch list of tags
|
||||
pub fn update_tags(&mut self) -> Result<()> {
|
||||
let tags = get_tags_with_metadata(CWD)?;
|
||||
|
|
@ -307,7 +354,27 @@ impl TagListComponent {
|
|||
|
||||
///
|
||||
fn get_row(&self, tag: &TagWithMetadata) -> Row {
|
||||
const UPSTREAM_SYMBOL: &str = "\u{2191}";
|
||||
const EMPTY_SYMBOL: &str = " ";
|
||||
|
||||
let is_tag_missing_on_remote = self
|
||||
.missing_remote_tags
|
||||
.as_ref()
|
||||
.map_or(false, |missing_remote_tags| {
|
||||
let remote_tag = format!("refs/tags/{}", tag.name);
|
||||
|
||||
missing_remote_tags.contains(&remote_tag)
|
||||
});
|
||||
|
||||
let has_remote_str = if is_tag_missing_on_remote {
|
||||
UPSTREAM_SYMBOL
|
||||
} else {
|
||||
EMPTY_SYMBOL
|
||||
};
|
||||
|
||||
let cells: Vec<Cell> = vec![
|
||||
Cell::from(has_remote_str)
|
||||
.style(self.theme.commit_author(false)),
|
||||
Cell::from(tag.name.clone())
|
||||
.style(self.theme.text(true, false)),
|
||||
Cell::from(utils::time_to_string(tag.time, true))
|
||||
|
|
|
|||
Loading…
Reference in a new issue