mirror of
https://github.com/extrawurst/gitui.git
synced 2024-12-28 19:44:14 +03:00
Add filter to LogWalker
This is the first step towards adding a file history view. The filter itself is not related to files specifically, though. It could also be used for different purposes.
This commit is contained in:
parent
947c4a1a5e
commit
f132722272
@ -28,11 +28,16 @@ impl<'a> Ord for TimeOrderedCommit<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LogWalkerFilter =
|
||||||
|
Box<dyn Fn(&Repository, &CommitId) -> Result<bool>>;
|
||||||
|
|
||||||
///
|
///
|
||||||
pub struct LogWalker<'a> {
|
pub struct LogWalker<'a> {
|
||||||
commits: BinaryHeap<TimeOrderedCommit<'a>>,
|
commits: BinaryHeap<TimeOrderedCommit<'a>>,
|
||||||
visited: HashSet<Oid>,
|
visited: HashSet<Oid>,
|
||||||
limit: usize,
|
limit: usize,
|
||||||
|
repo: &'a Repository,
|
||||||
|
filter: Option<LogWalkerFilter>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> LogWalker<'a> {
|
impl<'a> LogWalker<'a> {
|
||||||
@ -47,9 +52,19 @@ impl<'a> LogWalker<'a> {
|
|||||||
commits,
|
commits,
|
||||||
limit,
|
limit,
|
||||||
visited: HashSet::with_capacity(1000),
|
visited: HashSet::with_capacity(1000),
|
||||||
|
repo,
|
||||||
|
filter: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
pub fn filter(self, filter: LogWalkerFilter) -> Self {
|
||||||
|
Self {
|
||||||
|
filter: Some(filter),
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pub fn read(&mut self, out: &mut Vec<CommitId>) -> Result<usize> {
|
pub fn read(&mut self, out: &mut Vec<CommitId>) -> Result<usize> {
|
||||||
let mut count = 0_usize;
|
let mut count = 0_usize;
|
||||||
@ -59,7 +74,17 @@ impl<'a> LogWalker<'a> {
|
|||||||
self.visit(p);
|
self.visit(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
out.push(c.0.id().into());
|
let id: CommitId = c.0.id().into();
|
||||||
|
let commit_should_be_included =
|
||||||
|
if let Some(ref filter) = self.filter {
|
||||||
|
filter(self.repo, &id)?
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
};
|
||||||
|
|
||||||
|
if commit_should_be_included {
|
||||||
|
out.push(id);
|
||||||
|
}
|
||||||
|
|
||||||
count += 1;
|
count += 1;
|
||||||
if count == self.limit {
|
if count == self.limit {
|
||||||
@ -82,9 +107,10 @@ impl<'a> LogWalker<'a> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::error::Result;
|
||||||
use crate::sync::{
|
use crate::sync::{
|
||||||
commit, get_commits_info, stage_add_file,
|
commit, commit_files::get_commit_diff, get_commits_info,
|
||||||
tests::repo_init_empty,
|
stage_add_file, tests::repo_init_empty,
|
||||||
};
|
};
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use std::{fs::File, io::Write, path::Path};
|
use std::{fs::File, io::Write, path::Path};
|
||||||
@ -144,4 +170,79 @@ mod tests {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_logwalker_with_filter() -> Result<()> {
|
||||||
|
let file_path = Path::new("foo");
|
||||||
|
let second_file_path = Path::new("baz");
|
||||||
|
let (_td, repo) = repo_init_empty().unwrap();
|
||||||
|
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).unwrap();
|
||||||
|
|
||||||
|
let _first_commit_id = commit(repo_path, "commit1").unwrap();
|
||||||
|
|
||||||
|
File::create(&root.join(second_file_path))?
|
||||||
|
.write_all(b"a")?;
|
||||||
|
stage_add_file(repo_path, second_file_path).unwrap();
|
||||||
|
|
||||||
|
let second_commit_id = commit(repo_path, "commit2").unwrap();
|
||||||
|
|
||||||
|
File::create(&root.join(file_path))?.write_all(b"b")?;
|
||||||
|
stage_add_file(repo_path, file_path).unwrap();
|
||||||
|
|
||||||
|
let _third_commit_id = commit(repo_path, "commit3").unwrap();
|
||||||
|
|
||||||
|
let diff_contains_baz = |repo: &Repository,
|
||||||
|
commit_id: &CommitId|
|
||||||
|
-> Result<bool> {
|
||||||
|
let diff = get_commit_diff(
|
||||||
|
&repo,
|
||||||
|
*commit_id,
|
||||||
|
Some("baz".into()),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let contains_file = diff.deltas().len() > 0;
|
||||||
|
|
||||||
|
Ok(contains_file)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut items = Vec::new();
|
||||||
|
let mut walker = LogWalker::new(&repo, 100)?
|
||||||
|
.filter(Box::new(diff_contains_baz));
|
||||||
|
walker.read(&mut items).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(items.len(), 1);
|
||||||
|
assert_eq!(items[0], second_commit_id.into());
|
||||||
|
|
||||||
|
let mut items = Vec::new();
|
||||||
|
walker.read(&mut items).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(items.len(), 0);
|
||||||
|
|
||||||
|
let diff_contains_bar = |repo: &Repository,
|
||||||
|
commit_id: &CommitId|
|
||||||
|
-> Result<bool> {
|
||||||
|
let diff = get_commit_diff(
|
||||||
|
&repo,
|
||||||
|
*commit_id,
|
||||||
|
Some("bar".into()),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let contains_file = diff.deltas().len() > 0;
|
||||||
|
|
||||||
|
Ok(contains_file)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut items = Vec::new();
|
||||||
|
let mut walker = LogWalker::new(&repo, 100)?
|
||||||
|
.filter(Box::new(diff_contains_bar));
|
||||||
|
walker.read(&mut items).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(items.len(), 0);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user