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
50 50
51/// Produce the iterator51/// Produce the iterator
52impl<'repo> Platform<'repo> {52impl<'repo> Platform<'repo> {
53 /// Return an iterator to traverse all commits reachable as configured by the [Platform].53 /// For each commit, let `filter` return `true` if it and its parents should be included in the traversal, or `false`
54 ///54 /// if the traversal should exclude it and its ancestry entirely.
55 /// # Performance
56 ///55 ///
57 /// It's highly recommended to set an [`object cache`][Repository::object_cache_size()] on the parent repo56 /// If `filter` is None, no pruning of the graph will be performed which is the default.
58 /// to greatly speed up performance if the returned id is supposed to be looked up right after.57 pub fn selected(
59 pub fn all(self) -> Result<revision::Walk<'repo>, Error> {58 self,
59 mut filter: impl FnMut(&gix_hash::oid) -> bool + 'repo,
60 ) -> Result<revision::Walk<'repo>, Error> {
60 let Platform {61 let Platform {
61 repo,62 repo,
62 tips,63 tips,
@@ -74,22 +75,27 @@ impl<'repo> Platform<'repo> { · 11 unmodified lines
74 let shallow_commits = repo.shallow_commits()?;75 let shallow_commits = repo.shallow_commits()?;
75 let mut grafted_parents_to_skip = Vec::new();76 let mut grafted_parents_to_skip = Vec::new();
76 let mut buf = Vec::new();77 let mut buf = Vec::new();
77 move |id| match shallow_commits.as_ref() {78 move |id| {
78 Some(commits) => {79 if !filter(id) {
79 let id = id.to_owned();80 return false;
80 if let Ok(idx) = grafted_parents_to_skip.binary_search(&id) {81 }
81 grafted_parents_to_skip.remove(idx);82 match shallow_commits.as_ref() {
82 return false;83 Some(commits) => {
83 };84 let id = id.to_owned();
84 if commits.binary_search(&id).is_ok() {85 if let Ok(idx) = grafted_parents_to_skip.binary_search(&id) {
85 if let Ok(commit) = repo.objects.find_commit_iter(id, &mut buf) {86 grafted_parents_to_skip.remove(idx);
86 grafted_parents_to_skip.extend(commit.parent_ids());87 return false;
87 grafted_parents_to_skip.sort();88 };
88 }89 if commits.binary_search(&id).is_ok() {
89 };90 if let Ok(commit) = repo.objects.find_commit_iter(id, &mut buf) {
90 true91 grafted_parents_to_skip.extend(commit.parent_ids());
92 grafted_parents_to_skip.sort();
93 }
94 };
95 true
96 }
97 None => true,
91 }98 }
92 None => true,
93 }99 }
94 },100 },
95 )101 )
@@ -98,6 +104,15 @@ impl<'repo> Platform<'repo> { · 2 unmodified lines
98 ),104 ),
99 })105 })
100 }106 }
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 }
101}116}
102 117
103pub(crate) mod iter {118pub(crate) mod iter {
gix/tests/id/mod.rs+31−0
@@ -67,6 +67,7 @@ fn display_and_debug() -> crate::Result { · 66 unmodified lines
67}67}
68 68
69mod ancestors {69mod ancestors {
70 use crate::id::hex_to_id;
70 use gix_traverse::commit;71 use gix_traverse::commit;
71 72
72 #[test]73 #[test]
@@ -98,4 +99,34 @@ mod ancestors { · 25 unmodified lines
98 );99 );
99 Ok(())100 Ok(())
100 }101 }
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 }
101}132}