Skip to content

Commit

Permalink
Show symbol if tag is not yet pushed
Browse files Browse the repository at this point in the history
This partly addresses #742.
  • Loading branch information
cruessler committed Jun 9, 2021
1 parent 3bdb1d3 commit f7c1aad
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 2 deletions.
5 changes: 5 additions & 0 deletions asyncgit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -85,6 +87,9 @@ pub enum AsyncGitNotification {
///
//TODO: this does not belong here
SyntaxHighlighting,
///
//TODO: this does not belong here
RemoteTags,
}

/// current working directory `./`
Expand Down
72 changes: 72 additions & 0 deletions asyncgit/src/remotes.rs
Original file line number Diff line number Diff line change
@@ -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)
}
});
}
}
}
2 changes: 2 additions & 0 deletions asyncgit/src/sync/remotes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down
2 changes: 1 addition & 1 deletion asyncgit/src/sync/remotes/tags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down
3 changes: 3 additions & 0 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ impl App {
),
tags_popup: TagListComponent::new(
&queue,
sender,
theme.clone(),
key_config.clone(),
),
Expand Down Expand Up @@ -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?
Expand All @@ -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()
}

///
Expand Down
71 changes: 70 additions & 1 deletion src/components/taglist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand All @@ -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,
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -230,6 +239,7 @@ impl Component for TagListComponent {
impl TagListComponent {
pub fn new(
queue: &Queue,
sender: &Sender<AsyncGitNotification>,
theme: SharedTheme,
key_config: SharedKeyConfig,
) -> Self {
Expand All @@ -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,
}
}
Expand All @@ -254,12 +269,46 @@ impl TagListComponent {
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)?;

self.tags = Some(tags);

if self.missing_remote_tags.is_none() {
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(())
}

Expand Down Expand Up @@ -307,7 +356,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))
Expand Down

0 comments on commit f7c1aad

Please sign in to comment.