-
-
Notifications
You must be signed in to change notification settings - Fork 575
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Stephan Dilly
authored
May 5, 2020
1 parent
4df7704
commit 1db1f00
Showing
15 changed files
with
817 additions
and
147 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
use crate::{sync, AsyncNotification, CWD}; | ||
use crossbeam_channel::Sender; | ||
use git2::Oid; | ||
use scopetime::scope_time; | ||
use std::{ | ||
iter::FromIterator, | ||
sync::{ | ||
atomic::{AtomicBool, Ordering}, | ||
Arc, Mutex, | ||
}, | ||
}; | ||
use sync::{utils::repo, LogWalker}; | ||
|
||
/// | ||
pub struct AsyncLog { | ||
current: Arc<Mutex<Vec<Oid>>>, | ||
sender: Sender<AsyncNotification>, | ||
pending: Arc<AtomicBool>, | ||
} | ||
|
||
static LIMIT_COUNT: usize = 1000; | ||
|
||
impl AsyncLog { | ||
/// | ||
pub fn new(sender: Sender<AsyncNotification>) -> Self { | ||
Self { | ||
current: Arc::new(Mutex::new(Vec::new())), | ||
sender, | ||
pending: Arc::new(AtomicBool::new(false)), | ||
} | ||
} | ||
|
||
/// | ||
pub fn count(&mut self) -> usize { | ||
self.current.lock().unwrap().len() | ||
} | ||
|
||
/// | ||
pub fn get_slice( | ||
&self, | ||
start_index: usize, | ||
amount: usize, | ||
) -> Vec<Oid> { | ||
let list = self.current.lock().unwrap(); | ||
let list_len = list.len(); | ||
let min = start_index.min(list_len); | ||
let max = min + amount; | ||
let max = max.min(list_len); | ||
Vec::from_iter(list[min..max].iter().cloned()) | ||
} | ||
|
||
/// | ||
pub fn is_pending(&self) -> bool { | ||
self.pending.load(Ordering::Relaxed) | ||
} | ||
|
||
/// | ||
pub fn fetch(&mut self) { | ||
if !self.is_pending() { | ||
self.clear(); | ||
|
||
let arc_current = Arc::clone(&self.current); | ||
let sender = self.sender.clone(); | ||
let arc_pending = Arc::clone(&self.pending); | ||
rayon_core::spawn(move || { | ||
arc_pending.store(true, Ordering::Relaxed); | ||
|
||
scope_time!("async::revlog"); | ||
|
||
let mut entries = Vec::with_capacity(LIMIT_COUNT); | ||
let r = repo(CWD); | ||
let mut walker = LogWalker::new(&r); | ||
loop { | ||
entries.clear(); | ||
let res_is_err = walker | ||
.read(&mut entries, LIMIT_COUNT) | ||
.is_err(); | ||
|
||
if !res_is_err { | ||
let mut current = arc_current.lock().unwrap(); | ||
current.extend(entries.iter()); | ||
} | ||
|
||
if res_is_err || entries.len() <= 1 { | ||
break; | ||
} else { | ||
Self::notify(&sender); | ||
} | ||
} | ||
|
||
arc_pending.store(false, Ordering::Relaxed); | ||
|
||
Self::notify(&sender); | ||
}); | ||
} | ||
} | ||
|
||
fn clear(&mut self) { | ||
self.current.lock().unwrap().clear(); | ||
} | ||
|
||
fn notify(sender: &Sender<AsyncNotification>) { | ||
sender.send(AsyncNotification::Log).expect("error sending"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
use super::utils::repo; | ||
use git2::{Commit, Error, Oid}; | ||
use scopetime::scope_time; | ||
|
||
/// | ||
#[derive(Debug)] | ||
pub struct CommitInfo { | ||
/// | ||
pub message: String, | ||
/// | ||
pub time: i64, | ||
/// | ||
pub author: String, | ||
/// | ||
pub hash: String, | ||
} | ||
|
||
/// | ||
pub fn get_commits_info( | ||
repo_path: &str, | ||
ids: &[Oid], | ||
) -> Result<Vec<CommitInfo>, Error> { | ||
scope_time!("get_commits_info"); | ||
|
||
let repo = repo(repo_path); | ||
|
||
let commits = ids.iter().map(|id| repo.find_commit(*id).unwrap()); | ||
|
||
let res = commits | ||
.map(|c: Commit| { | ||
let message = get_message(&c); | ||
let author = if let Some(name) = c.author().name() { | ||
String::from(name) | ||
} else { | ||
String::from("<unknown>") | ||
}; | ||
CommitInfo { | ||
message, | ||
author, | ||
time: c.time().seconds(), | ||
hash: c.id().to_string(), | ||
} | ||
}) | ||
.collect::<Vec<_>>(); | ||
|
||
Ok(res) | ||
} | ||
|
||
fn get_message(c: &Commit) -> String { | ||
if let Some(msg) = c.message() { | ||
limit_str(msg, 50) | ||
} else { | ||
String::from("<unknown>") | ||
} | ||
} | ||
|
||
fn limit_str(s: &str, limit: usize) -> String { | ||
if let Some(first) = s.lines().next() { | ||
first.chars().take(limit).collect::<String>() | ||
} else { | ||
String::new() | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
|
||
use super::get_commits_info; | ||
use crate::sync::{ | ||
commit, stage_add_file, tests::repo_init_empty, | ||
}; | ||
use std::{ | ||
fs::File, | ||
io::{Error, Write}, | ||
path::Path, | ||
}; | ||
|
||
#[test] | ||
fn test_log() -> Result<(), Error> { | ||
let file_path = Path::new("foo"); | ||
let (_td, repo) = repo_init_empty(); | ||
let root = repo.path().parent().unwrap(); | ||
let repo_path = root.as_os_str().to_str().unwrap(); | ||
|
||
File::create(&root.join(file_path))?.write_all(b"a")?; | ||
stage_add_file(repo_path, file_path); | ||
let c1 = commit(repo_path, "commit1"); | ||
File::create(&root.join(file_path))?.write_all(b"a")?; | ||
stage_add_file(repo_path, file_path); | ||
let c2 = commit(repo_path, "commit2"); | ||
|
||
let res = get_commits_info(repo_path, &vec![c2, c1]).unwrap(); | ||
|
||
assert_eq!(res.len(), 2); | ||
assert_eq!(res[0].message.as_str(), "commit2"); | ||
assert_eq!(res[0].author.as_str(), "name"); | ||
assert_eq!(res[1].message.as_str(), "commit1"); | ||
|
||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
use git2::{Error, Oid, Repository, Revwalk}; | ||
|
||
/// | ||
pub struct LogWalker<'a> { | ||
repo: &'a Repository, | ||
revwalk: Option<Revwalk<'a>>, | ||
} | ||
|
||
impl<'a> LogWalker<'a> { | ||
/// | ||
pub fn new(repo: &'a Repository) -> Self { | ||
Self { | ||
repo, | ||
revwalk: None, | ||
} | ||
} | ||
|
||
/// | ||
pub fn read( | ||
&mut self, | ||
out: &mut Vec<Oid>, | ||
limit: usize, | ||
) -> Result<usize, Error> { | ||
let mut count = 0_usize; | ||
|
||
if self.revwalk.is_none() { | ||
let mut walk = self.repo.revwalk()?; | ||
walk.push_head()?; | ||
self.revwalk = Some(walk); | ||
} | ||
|
||
if let Some(ref mut walk) = self.revwalk { | ||
for id in walk { | ||
if let Ok(id) = id { | ||
out.push(id); | ||
count += 1; | ||
|
||
if count == limit { | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
|
||
Ok(count) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use crate::sync::{ | ||
commit, get_commits_info, stage_add_file, | ||
tests::repo_init_empty, | ||
}; | ||
use std::{ | ||
fs::File, | ||
io::{Error, Write}, | ||
path::Path, | ||
}; | ||
|
||
#[test] | ||
fn test_limit() -> Result<(), Error> { | ||
let file_path = Path::new("foo"); | ||
let (_td, repo) = repo_init_empty(); | ||
let root = repo.path().parent().unwrap(); | ||
let repo_path = root.as_os_str().to_str().unwrap(); | ||
|
||
File::create(&root.join(file_path))?.write_all(b"a")?; | ||
stage_add_file(repo_path, file_path); | ||
commit(repo_path, "commit1"); | ||
File::create(&root.join(file_path))?.write_all(b"a")?; | ||
stage_add_file(repo_path, file_path); | ||
let oid2 = commit(repo_path, "commit2"); | ||
|
||
let mut items = Vec::new(); | ||
let mut walk = LogWalker::new(&repo); | ||
walk.read(&mut items, 1).unwrap(); | ||
|
||
assert_eq!(items.len(), 1); | ||
assert_eq!(items[0], oid2); | ||
|
||
Ok(()) | ||
} | ||
|
||
#[test] | ||
fn test_logwalker() -> Result<(), Error> { | ||
let file_path = Path::new("foo"); | ||
let (_td, repo) = repo_init_empty(); | ||
let root = repo.path().parent().unwrap(); | ||
let repo_path = root.as_os_str().to_str().unwrap(); | ||
|
||
File::create(&root.join(file_path))?.write_all(b"a")?; | ||
stage_add_file(repo_path, file_path); | ||
commit(repo_path, "commit1"); | ||
File::create(&root.join(file_path))?.write_all(b"a")?; | ||
stage_add_file(repo_path, file_path); | ||
let oid2 = commit(repo_path, "commit2"); | ||
|
||
let mut items = Vec::new(); | ||
let mut walk = LogWalker::new(&repo); | ||
walk.read(&mut items, 100).unwrap(); | ||
|
||
let info = get_commits_info(repo_path, &items).unwrap(); | ||
dbg!(&info); | ||
|
||
assert_eq!(items.len(), 2); | ||
assert_eq!(items[0], oid2); | ||
|
||
let mut items = Vec::new(); | ||
walk.read(&mut items, 100).unwrap(); | ||
|
||
assert_eq!(items.len(), 0); | ||
|
||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.