Skip to content

Commit a585b60

Browse files
committed
Lazily consume topo
1 parent 7af598e commit a585b60

File tree

1 file changed

+62
-68
lines changed
  • gitoxide-core/src/repository

1 file changed

+62
-68
lines changed

gitoxide-core/src/repository/log.rs

Lines changed: 62 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -6,98 +6,92 @@ pub fn log(mut repo: gix::Repository, out: &mut dyn std::io::Write, pathspec: BS
66
repo.object_cache_size_if_unset(repo.compute_object_cache_size_for_tree_diffs(&**repo.index_or_empty()?));
77

88
let head = repo.head()?.peel_to_commit_in_place()?;
9-
let infos: Vec<_> =
9+
let mut topo =
1010
gix::traverse::commit::topo::Builder::from_iters(&repo.objects, [head.id], None::<Vec<gix::ObjectId>>)
11-
.build()?
12-
.collect();
11+
.build()?;
1312

14-
let infos: Vec<_> = infos
15-
.into_iter()
16-
.filter(|info| {
17-
let commit = repo.find_commit(info.as_ref().unwrap().id).unwrap();
13+
while let Some(info) = topo.next() {
14+
let info = info?;
15+
let commit = repo.find_commit(info.id).unwrap();
1816

19-
let mut buffer = Vec::new();
20-
let tree = repo.objects.find_tree(&commit.tree_id().unwrap(), &mut buffer).unwrap();
17+
let mut buffer = Vec::new();
18+
let tree = repo.objects.find_tree(&commit.tree_id().unwrap(), &mut buffer).unwrap();
2119

22-
let Some(entry) = tree.bisect_entry(pathspec.as_ref(), false) else {
23-
return false;
24-
};
20+
let Some(entry) = tree.bisect_entry(pathspec.as_ref(), false) else {
21+
continue;
22+
};
2523

26-
let parent_ids: Vec<_> = commit.parent_ids().collect();
24+
let parent_ids: Vec<_> = commit.parent_ids().collect();
2725

28-
if parent_ids.is_empty() {
29-
// We confirmed above that the file is in `commit`'s tree. If `parent_ids` is
30-
// empty, the file was added in `commit`.
26+
if parent_ids.is_empty() {
27+
// We confirmed above that the file is in `commit`'s tree. If `parent_ids` is
28+
// empty, the file was added in `commit`.
3129

32-
return true;
33-
}
30+
write_info(&repo, out, &info)?;
3431

35-
let parent_ids_with_changes: Vec<_> = parent_ids
36-
.clone()
37-
.into_iter()
38-
.filter(|parent_id| {
39-
let mut buffer = Vec::new();
40-
let parent_commit = repo.find_commit(*parent_id).unwrap();
41-
let parent_tree = repo
42-
.objects
43-
.find_tree(&parent_commit.tree_id().unwrap(), &mut buffer)
44-
.unwrap();
45-
46-
if let Some(parent_entry) = parent_tree.bisect_entry(pathspec.as_ref(), false) {
47-
if entry.oid == parent_entry.oid {
48-
// The blobs storing the file in `entry` and `parent_entry` are
49-
// identical which means the file was not changed in `commit`.
50-
51-
return false;
52-
}
53-
}
32+
break;
33+
}
5434

55-
true
56-
})
57-
.collect();
35+
let parent_ids_with_changes: Vec<_> = parent_ids
36+
.clone()
37+
.into_iter()
38+
.filter(|parent_id| {
39+
let mut buffer = Vec::new();
40+
let parent_commit = repo.find_commit(*parent_id).unwrap();
41+
let parent_tree = repo
42+
.objects
43+
.find_tree(&parent_commit.tree_id().unwrap(), &mut buffer)
44+
.unwrap();
5845

59-
if parent_ids.len() != parent_ids_with_changes.len() {
60-
// At least one parent had an identical version of the file which means it was not
61-
// changed in `commit`.
46+
if let Some(parent_entry) = parent_tree.bisect_entry(pathspec.as_ref(), false) {
47+
if entry.oid == parent_entry.oid {
48+
// The blobs storing the file in `entry` and `parent_entry` are
49+
// identical which means the file was not changed in `commit`.
6250

63-
return false;
64-
}
51+
return false;
52+
}
53+
}
54+
55+
true
56+
})
57+
.collect();
6558

66-
for parent_id in parent_ids_with_changes {
67-
let modifications =
68-
get_modifications_for_file_path(&repo.objects, pathspec.as_ref(), commit.id, parent_id.into());
59+
if parent_ids.len() != parent_ids_with_changes.len() {
60+
// At least one parent had an identical version of the file which means it was not
61+
// changed in `commit`.
6962

70-
return !modifications.is_empty();
71-
}
63+
continue;
64+
}
7265

73-
return false;
74-
})
75-
.collect();
66+
for parent_id in parent_ids_with_changes {
67+
let modifications =
68+
get_modifications_for_file_path(&repo.objects, pathspec.as_ref(), commit.id, parent_id.into());
7669

77-
write_infos(&repo, out, infos)?;
70+
if !modifications.is_empty() {
71+
write_info(&repo, &mut *out, &info)?;
72+
}
73+
}
74+
}
7875

7976
Ok(())
8077
}
8178

82-
fn write_infos(
79+
fn write_info(
8380
repo: &gix::Repository,
8481
mut out: impl std::io::Write,
85-
infos: Vec<Result<gix::traverse::commit::Info, gix::traverse::commit::topo::Error>>,
82+
info: &gix::traverse::commit::Info,
8683
) -> Result<(), std::io::Error> {
87-
for info in infos {
88-
let info = info.unwrap();
89-
let commit = repo.find_commit(info.id).unwrap();
84+
let commit = repo.find_commit(info.id).unwrap();
9085

91-
let message = commit.message_raw_sloppy();
92-
let title = message.lines().next();
86+
let message = commit.message_raw_sloppy();
87+
let title = message.lines().next();
9388

94-
writeln!(
95-
out,
96-
"{} {}",
97-
info.id.to_hex_with_len(8),
98-
title.map(BString::from).unwrap_or_else(|| "<no message>".into())
99-
)?;
100-
}
89+
writeln!(
90+
out,
91+
"{} {}",
92+
info.id.to_hex_with_len(8),
93+
title.map(BString::from).unwrap_or_else(|| "<no message>".into())
94+
)?;
10195

10296
Ok(())
10397
}

0 commit comments

Comments
 (0)