Skip to content

Commit a654965

Browse files
author
Stephan Dilly
committed
make tag fetching async (#170)
1 parent a84ae09 commit a654965

File tree

10 files changed

+148
-26
lines changed

10 files changed

+148
-26
lines changed

Diff for: asyncgit/src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ mod error;
1313
mod revlog;
1414
mod status;
1515
pub mod sync;
16+
mod tags;
1617

1718
pub use crate::{
1819
commit_files::AsyncCommitFiles,
@@ -23,6 +24,7 @@ pub use crate::{
2324
diff::{DiffLine, DiffLineType, FileDiff},
2425
status::{StatusItem, StatusItemType},
2526
},
27+
tags::{AsyncTags, TagsResult},
2628
};
2729
use std::{
2830
collections::hash_map::DefaultHasher,
@@ -40,6 +42,8 @@ pub enum AsyncNotification {
4042
Log,
4143
///
4244
CommitFiles,
45+
///
46+
Tags,
4347
}
4448

4549
/// current working director `./`

Diff for: asyncgit/src/sync/commits_info.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use git2::{Commit, Error, Oid};
44
use scopetime::scope_time;
55

66
/// identifies a single commit
7-
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
7+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
88
pub struct CommitId(Oid);
99

1010
impl CommitId {

Diff for: asyncgit/src/sync/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ mod tags;
1717
pub mod utils;
1818

1919
pub(crate) use branch::get_branch_name;
20+
2021
pub use commit::{amend, commit};
2122
pub use commit_details::{get_commit_details, CommitDetails};
2223
pub use commit_files::get_commit_files;

Diff for: asyncgit/src/sync/tags.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use super::{utils::repo, CommitId};
22
use crate::error::Result;
33
use scopetime::scope_time;
4-
use std::collections::HashMap;
4+
use std::collections::BTreeMap;
55

66
/// hashmap of tag target commit hash to tag names
7-
pub type Tags = HashMap<CommitId, Vec<String>>;
7+
pub type Tags = BTreeMap<CommitId, Vec<String>>;
88

99
/// returns `Tags` type filled with all tags found in repo
1010
pub fn get_tags(repo_path: &str) -> Result<Tags> {

Diff for: asyncgit/src/tags.rs

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
use crate::{
2+
error::Result,
3+
hash,
4+
sync::{self},
5+
AsyncNotification, CWD,
6+
};
7+
use crossbeam_channel::Sender;
8+
use std::sync::{
9+
atomic::{AtomicUsize, Ordering},
10+
Arc, Mutex,
11+
};
12+
use sync::Tags;
13+
14+
///
15+
#[derive(Default, Clone)]
16+
pub struct TagsResult {
17+
///
18+
pub hash: u64,
19+
///
20+
pub tags: Tags,
21+
}
22+
23+
///
24+
pub struct AsyncTags {
25+
last: Arc<Mutex<Option<TagsResult>>>,
26+
sender: Sender<AsyncNotification>,
27+
pending: Arc<AtomicUsize>,
28+
}
29+
30+
impl AsyncTags {
31+
///
32+
pub fn new(sender: &Sender<AsyncNotification>) -> Self {
33+
Self {
34+
last: Arc::new(Mutex::new(None)),
35+
sender: sender.clone(),
36+
pending: Arc::new(AtomicUsize::new(0)),
37+
}
38+
}
39+
40+
///
41+
pub fn last(&mut self) -> Result<Option<TagsResult>> {
42+
let last = self.last.lock()?;
43+
44+
Ok(last.clone())
45+
}
46+
47+
///
48+
fn last_hash(
49+
last: Arc<Mutex<Option<TagsResult>>>,
50+
) -> Option<u64> {
51+
if let Ok(last) = last.lock() {
52+
last.as_ref().map(|last| last.hash)
53+
} else {
54+
None
55+
}
56+
}
57+
58+
///
59+
pub fn is_pending(&self) -> bool {
60+
self.pending.load(Ordering::Relaxed) > 0
61+
}
62+
63+
///
64+
pub fn request(&mut self) -> Result<()> {
65+
log::trace!("request");
66+
67+
if self.is_pending() {
68+
return Ok(());
69+
}
70+
71+
let arc_last = Arc::clone(&self.last);
72+
let sender = self.sender.clone();
73+
let arc_pending = Arc::clone(&self.pending);
74+
rayon_core::spawn(move || {
75+
arc_pending.fetch_add(1, Ordering::Relaxed);
76+
77+
let notify = AsyncTags::getter(arc_last)
78+
.expect("error getting tags");
79+
80+
arc_pending.fetch_sub(1, Ordering::Relaxed);
81+
82+
if notify {
83+
log::trace!("NOTIFY TAGS");
84+
85+
sender
86+
.send(AsyncNotification::Tags)
87+
.expect("error sending notify");
88+
}
89+
});
90+
91+
Ok(())
92+
}
93+
94+
fn getter(
95+
arc_last: Arc<Mutex<Option<TagsResult>>>,
96+
) -> Result<bool> {
97+
let tags = sync::get_tags(CWD)?;
98+
99+
let hash = hash(&tags);
100+
101+
if Self::last_hash(arc_last.clone())
102+
.map(|last| last == hash)
103+
.unwrap_or_default()
104+
{
105+
return Ok(false);
106+
}
107+
108+
{
109+
let mut last = arc_last.lock()?;
110+
*last = Some(TagsResult { tags, hash });
111+
}
112+
113+
Ok(true)
114+
}
115+
}

Diff for: src/components/commit_details/details.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ impl DetailsComponent {
4040
pub fn set_commit(
4141
&mut self,
4242
id: Option<CommitId>,
43-
tags: &Tags,
43+
tags: Option<&Tags>,
4444
) -> Result<()> {
4545
self.tags.clear();
4646

@@ -51,8 +51,10 @@ impl DetailsComponent {
5151
};
5252

5353
if let Some(id) = id {
54-
if let Some(tags) = tags.get(&id) {
55-
self.tags.extend(tags.clone());
54+
if let Some(tags) = tags {
55+
if let Some(tags) = tags.get(&id) {
56+
self.tags.extend(tags.clone());
57+
}
5658
}
5759
}
5860

Diff for: src/components/commit_details/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ impl CommitDetailsComponent {
6868
pub fn set_commit(
6969
&mut self,
7070
id: Option<CommitId>,
71-
tags: &Tags,
71+
tags: Option<&Tags>,
7272
) -> Result<()> {
7373
self.details.set_commit(id, tags)?;
7474

Diff for: src/components/commitlist.rs

+5-11
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::{
1010
ui::style::{SharedTheme, Theme},
1111
};
1212
use anyhow::Result;
13-
use asyncgit::sync::Tags;
13+
use asyncgit::TagsResult;
1414
use crossterm::event::Event;
1515
use std::{
1616
borrow::Cow, cell::Cell, cmp, convert::TryFrom, time::Instant,
@@ -33,7 +33,7 @@ pub struct CommitList {
3333
count_total: usize,
3434
items: ItemBatch,
3535
scroll_state: (Instant, f32),
36-
tags: Option<Tags>,
36+
tags: Option<TagsResult>,
3737
current_size: Cell<(u16, u16)>,
3838
scroll_top: Cell<usize>,
3939
theme: SharedTheme,
@@ -88,23 +88,17 @@ impl CommitList {
8888
}
8989

9090
///
91-
pub fn tags(&self) -> Option<&Tags> {
91+
pub fn tags(&self) -> Option<&TagsResult> {
9292
self.tags.as_ref()
9393
}
9494

95-
///
96-
pub fn has_tags(&self) -> bool {
97-
self.tags.is_some()
98-
}
99-
10095
///
10196
pub fn clear(&mut self) {
102-
self.tags = None;
10397
self.items.clear();
10498
}
10599

106100
///
107-
pub fn set_tags(&mut self, tags: Tags) {
101+
pub fn set_tags(&mut self, tags: TagsResult) {
108102
self.tags = Some(tags);
109103
}
110104

@@ -251,7 +245,7 @@ impl CommitList {
251245
.enumerate()
252246
{
253247
let tags = if let Some(tags) =
254-
self.tags.as_ref().and_then(|t| t.get(&e.id))
248+
self.tags.as_ref().and_then(|t| t.tags.get(&e.id))
255249
{
256250
Some(tags.join(" "))
257251
} else {

Diff for: src/components/inspect_commit.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use crate::{
99
};
1010
use anyhow::Result;
1111
use asyncgit::{
12-
sync::{CommitId, Tags},
13-
AsyncDiff, AsyncNotification, DiffParams, DiffType,
12+
sync::CommitId, AsyncDiff, AsyncNotification, DiffParams,
13+
DiffType,
1414
};
1515
use crossbeam_channel::Sender;
1616
use crossterm::event::Event;
@@ -225,7 +225,7 @@ impl InspectCommitComponent {
225225
}
226226

227227
fn update(&mut self) -> Result<()> {
228-
self.details.set_commit(self.commit_id, &Tags::new())?;
228+
self.details.set_commit(self.commit_id, None)?;
229229
self.update_diff()?;
230230

231231
Ok(())

Diff for: src/tabs/revlog.rs

+11-5
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use anyhow::Result;
1313
use asyncgit::{
1414
cached,
1515
sync::{self, CommitId},
16-
AsyncLog, AsyncNotification, FetchStatus, CWD,
16+
AsyncLog, AsyncNotification, AsyncTags, FetchStatus, CWD,
1717
};
1818
use crossbeam_channel::Sender;
1919
use crossterm::event::Event;
@@ -30,6 +30,7 @@ pub struct Revlog {
3030
commit_details: CommitDetailsComponent,
3131
list: CommitList,
3232
git_log: AsyncLog,
33+
git_tags: AsyncTags,
3334
queue: Queue,
3435
visible: bool,
3536
branch_name: cached::BranchName,
@@ -51,6 +52,7 @@ impl Revlog {
5152
),
5253
list: CommitList::new(strings::LOG_TITLE, theme),
5354
git_log: AsyncLog::new(sender),
55+
git_tags: AsyncTags::new(sender),
5456
visible: false,
5557
branch_name: cached::BranchName::new(CWD),
5658
}
@@ -78,9 +80,7 @@ impl Revlog {
7880
self.fetch_commits()?;
7981
}
8082

81-
if !self.list.has_tags() || log_changed {
82-
self.list.set_tags(sync::get_tags(CWD)?);
83-
}
83+
self.git_tags.request()?;
8484

8585
self.list.set_branch(
8686
self.branch_name.lookup().map(Some).unwrap_or(None),
@@ -89,7 +89,7 @@ impl Revlog {
8989
if self.commit_details.is_visible() {
9090
self.commit_details.set_commit(
9191
self.selected_commit(),
92-
self.list.tags().expect("tags"),
92+
self.list.tags().map(|tags| &tags.tags),
9393
)?;
9494
}
9595
}
@@ -106,6 +106,12 @@ impl Revlog {
106106
match ev {
107107
AsyncNotification::CommitFiles
108108
| AsyncNotification::Log => self.update()?,
109+
AsyncNotification::Tags => {
110+
if let Some(tags) = self.git_tags.last()? {
111+
self.list.set_tags(tags);
112+
self.update()?;
113+
}
114+
}
109115
_ => (),
110116
}
111117
}

0 commit comments

Comments
 (0)