forked from GitoxideLabs/gitoxide
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request GitoxideLabs#1453 from cruessler/gix-blame
Explore gix APIs, experiment with gix-blame API
- Loading branch information
Showing
19 changed files
with
3,178 additions
and
28 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,71 @@ | ||
use gix::bstr::ByteSlice; | ||
use gix::config::tree; | ||
use std::ffi::OsStr; | ||
|
||
pub fn blame_file( | ||
mut repo: gix::Repository, | ||
file: &OsStr, | ||
out: impl std::io::Write, | ||
err: Option<&mut dyn std::io::Write>, | ||
) -> anyhow::Result<()> { | ||
{ | ||
let mut config = repo.config_snapshot_mut(); | ||
if config.string(&tree::Core::DELTA_BASE_CACHE_LIMIT).is_none() { | ||
config.set_value(&tree::Core::DELTA_BASE_CACHE_LIMIT, "100m")?; | ||
} | ||
} | ||
let index = repo.index_or_empty()?; | ||
repo.object_cache_size_if_unset(repo.compute_object_cache_size_for_tree_diffs(&index)); | ||
|
||
let file = gix::path::os_str_into_bstr(file)?; | ||
let specs = repo.pathspec( | ||
false, | ||
[file], | ||
true, | ||
&index, | ||
gix::worktree::stack::state::attributes::Source::WorktreeThenIdMapping.adjust_for_bare(repo.is_bare()), | ||
)?; | ||
// TODO: there should be a way to normalize paths without going through patterns, at least in this case maybe? | ||
// `Search` actually sorts patterns by excluding or not, all that can lead to strange results. | ||
let file = specs | ||
.search() | ||
.patterns() | ||
.map(|p| p.path().to_owned()) | ||
.next() | ||
.expect("exactly one pattern"); | ||
|
||
let suspect = repo.head()?.peel_to_commit_in_place()?; | ||
let traverse = | ||
gix::traverse::commit::topo::Builder::from_iters(&repo.objects, [suspect.id], None::<Vec<gix::ObjectId>>) | ||
.with_commit_graph(repo.commit_graph_if_enabled()?) | ||
.build()?; | ||
let mut resource_cache = repo.diff_resource_cache_for_tree_diff()?; | ||
let outcome = gix::blame::file(&repo.objects, traverse, &mut resource_cache, file.as_bstr())?; | ||
let statistics = outcome.statistics; | ||
write_blame_entries(out, outcome)?; | ||
|
||
if let Some(err) = err { | ||
writeln!(err, "{statistics:#?}")?; | ||
} | ||
Ok(()) | ||
} | ||
|
||
fn write_blame_entries(mut out: impl std::io::Write, outcome: gix::blame::Outcome) -> Result<(), std::io::Error> { | ||
for (entry, lines_in_hunk) in outcome.entries_with_lines() { | ||
for ((actual_lno, source_lno), line) in entry | ||
.range_in_blamed_file() | ||
.zip(entry.range_in_source_file()) | ||
.zip(lines_in_hunk) | ||
{ | ||
write!( | ||
out, | ||
"{short_id} {line_no} {src_line_no} {line}", | ||
line_no = actual_lno + 1, | ||
src_line_no = source_lno + 1, | ||
short_id = entry.commit_id.to_hex_with_len(8), | ||
)?; | ||
} | ||
} | ||
|
||
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
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 |
---|---|---|
|
@@ -5,7 +5,7 @@ name = "gix-blame" | |
version = "0.0.0" | ||
repository = "https://github.com/GitoxideLabs/gitoxide" | ||
license = "MIT OR Apache-2.0" | ||
description = "A crate of the gitoxide project dedicated implementing a 'blame' algorithm" | ||
description = "A crate of the gitoxide project dedicated to implementing a 'blame' algorithm" | ||
authors = ["Christoph Rüßler <[email protected]>", "Sebastian Thiel <[email protected]>"] | ||
edition = "2021" | ||
rust-version = "1.65" | ||
|
@@ -14,6 +14,19 @@ rust-version = "1.65" | |
doctest = false | ||
|
||
[dependencies] | ||
gix-trace = { version = "^0.1.11", path = "../gix-trace" } | ||
gix-diff = { version = "^0.49.0", path = "../gix-diff", default-features = false, features = ["blob"] } | ||
gix-object = { version = "^0.46.0", path = "../gix-object" } | ||
gix-hash = { version = "^0.15.0", path = "../gix-hash" } | ||
gix-worktree = { version = "^0.38.0", path = "../gix-worktree", default-features = false, features = ["attributes"] } | ||
gix-traverse = { version = "^0.43.0", path = "../gix-traverse" } | ||
|
||
thiserror = "2.0.0" | ||
|
||
[dev-dependencies] | ||
gix-ref = { version = "^0.49.0", path = "../gix-ref" } | ||
gix-filter = { version = "^0.16.0", path = "../gix-filter" } | ||
gix-fs = { version = "^0.12.0", path = "../gix-fs" } | ||
gix-index = { version = "^0.37.0", path = "../gix-index" } | ||
gix-odb = { version = "^0.66.0", path = "../gix-odb" } | ||
gix-testtools = { path = "../tests/tools" } |
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,30 @@ | ||
use gix_object::bstr::BString; | ||
|
||
/// The error returned by [file()](crate::file()). | ||
#[derive(Debug, thiserror::Error)] | ||
#[allow(missing_docs)] | ||
pub enum Error { | ||
#[error("No commit was given")] | ||
EmptyTraversal, | ||
#[error(transparent)] | ||
BlobDiffSetResource(#[from] gix_diff::blob::platform::set_resource::Error), | ||
#[error(transparent)] | ||
BlobDiffPrepare(#[from] gix_diff::blob::platform::prepare_diff::Error), | ||
#[error("The file to blame at '{file_path}' wasn't found in the first commit at {commit_id}")] | ||
FileMissing { | ||
/// The file-path to the object to blame. | ||
file_path: BString, | ||
/// The commit whose tree didn't contain `file_path`. | ||
commit_id: gix_hash::ObjectId, | ||
}, | ||
#[error("Couldn't find commit or tree in the object database")] | ||
FindObject(#[from] gix_object::find::Error), | ||
#[error("Could not find existing blob or commit")] | ||
FindExistingObject(#[from] gix_object::find::existing_object::Error), | ||
#[error("Could not find existing iterator over a tree")] | ||
FindExistingIter(#[from] gix_object::find::existing_iter::Error), | ||
#[error("Failed to obtain the next commit in the commit-graph traversal")] | ||
Traverse(#[source] Box<dyn std::error::Error + Send + Sync>), | ||
#[error(transparent)] | ||
DiffTree(#[from] gix_diff::tree::Error), | ||
} |
Oops, something went wrong.