History

feat: `revision::walk::Platform::selected(filter)` to selectively prune parts of the commit graph. (#801)

Sebastian Thiel committed 3 years ago

Commit ec93f751 parent a70085e2 files · +67 −21Browse files

Unified · Split

2 files
  1. gix/src/revision/walk.rs +36 −21
  2. gix/tests/id/mod.rs +31 −0
gix/src/revision/walk.rs+36−21
@@ -50,13 +50,14 @@ impl<'repo> Platform<'repo> { · 49 unmodified lines
5050
5151 /// Produce the iterator
5252 impl<'repo> Platform<'repo> {
53− /// Return an iterator to traverse all commits reachable as configured by the [Platform].
54− ///
55− /// # Performance
53+ /// For each commit, let `filter` return `true` if it and its parents should be included in the traversal, or `false`
54+ /// if the traversal should exclude it and its ancestry entirely.
5655 ///
57− /// It's highly recommended to set an [`object cache`][Repository::object_cache_size()] on the parent repo
58− /// to greatly speed up performance if the returned id is supposed to be looked up right after.
59− pub fn all(self) -> Result<revision::Walk<'repo>, Error> {
56+ /// If `filter` is None, no pruning of the graph will be performed which is the default.
57+ pub fn selected(
58+ self,
59+ mut filter: impl FnMut(&gix_hash::oid) -> bool + 'repo,
60+ ) -> Result<revision::Walk<'repo>, Error> {
6061 let Platform {
6162 repo,
6263 tips,
@@ -74,22 +75,27 @@ impl<'repo> Platform<'repo> { · 11 unmodified lines
7475 let shallow_commits = repo.shallow_commits()?;
7576 let mut grafted_parents_to_skip = Vec::new();
7677 let mut buf = Vec::new();
77− move |id| match shallow_commits.as_ref() {
78− Some(commits) => {
79− let id = id.to_owned();
80− if let Ok(idx) = grafted_parents_to_skip.binary_search(&id) {
81− grafted_parents_to_skip.remove(idx);
82− return false;
83− };
84− if commits.binary_search(&id).is_ok() {
85− if let Ok(commit) = repo.objects.find_commit_iter(id, &mut buf) {
86− grafted_parents_to_skip.extend(commit.parent_ids());
87− grafted_parents_to_skip.sort();
88− }
89− };
90− true
78+ move |id| {
79+ if !filter(id) {
80+ return false;
81+ }
82+ match shallow_commits.as_ref() {
83+ Some(commits) => {
84+ let id = id.to_owned();
85+ if let Ok(idx) = grafted_parents_to_skip.binary_search(&id) {
86+ grafted_parents_to_skip.remove(idx);
87+ return false;
88+ };
89+ if commits.binary_search(&id).is_ok() {
90+ if let Ok(commit) = repo.objects.find_commit_iter(id, &mut buf) {
91+ grafted_parents_to_skip.extend(commit.parent_ids());
92+ grafted_parents_to_skip.sort();
93+ }
94+ };
95+ true
96+ }
97+ None => true,
9198 }
92− None => true,
9399 }
94100 },
95101 )
@@ -98,6 +104,15 @@ impl<'repo> Platform<'repo> { · 2 unmodified lines
98104 ),
99105 })
100106 }
107+ /// Return an iterator to traverse all commits reachable as configured by the [Platform].
108+ ///
109+ /// # Performance
110+ ///
111+ /// It's highly recommended to set an [`object cache`][Repository::object_cache_size()] on the parent repo
112+ /// to greatly speed up performance if the returned id is supposed to be looked up right after.
113+ pub fn all(self) -> Result<revision::Walk<'repo>, Error> {
114+ self.selected(|_| true)
115+ }
101116 }
102117
103118 pub(crate) mod iter {
gix/tests/id/mod.rs+31−0
@@ -67,6 +67,7 @@ fn display_and_debug() -> crate::Result { · 66 unmodified lines
6767 }
6868
6969 mod ancestors {
70+ use crate::id::hex_to_id;
7071 use gix_traverse::commit;
7172
7273 #[test]
@@ -98,4 +99,34 @@ mod ancestors { · 25 unmodified lines
9899 );
99100 Ok(())
100101 }
102+
103+ #[test]
104+ fn filtered() -> crate::Result {
105+ let repo = crate::repo("make_repo_with_fork_and_dates.sh")?.to_thread_local();
106+ let head = repo.head()?.into_fully_peeled_id().expect("born")?;
107+
108+ for sorting in [
109+ commit::Sorting::Topological,
110+ commit::Sorting::ByCommitTimeNewestFirst,
111+ commit::Sorting::ByCommitTimeNewestFirstCutoffOlderThan {
112+ time_in_seconds_since_epoch: 0,
113+ },
114+ ] {
115+ let commits_graph_order = head
116+ .ancestors()
117+ .sorting(sorting)
118+ .selected(|id| {
119+ let _assert_lifetime_works = &repo; // assure we can use repo here.
120+ id != hex_to_id("9902e3c3e8f0c569b4ab295ddf473e6de763e1e7")
121+ && id != hex_to_id("bcb05040a6925f2ff5e10d3ae1f9264f2e8c43ac")
122+ })?
123+ .collect::<Result<Vec<_>, _>>()?;
124+ assert_eq!(
125+ commits_graph_order,
126+ &[hex_to_id("288e509293165cb5630d08f4185bdf2445bf6170")],
127+ "we ignore all but the first"
128+ );
129+ }
130+ Ok(())
131+ }
101132 }