From 6cda77675fa0e1d9cc8493a343168a5f9a8124a1 Mon Sep 17 00:00:00 2001 From: Adi Thakral Date: Fri, 29 Jul 2022 16:02:03 -0700 Subject: [PATCH 1/2] Initial implementation for git_blame_buffer --- LibGit2Sharp/BlameHunkCollection.cs | 45 ++++++++++++++++++++++------- LibGit2Sharp/Core/NativeMethods.cs | 7 +++++ LibGit2Sharp/Core/Proxy.cs | 21 ++++++++++++++ 3 files changed, 63 insertions(+), 10 deletions(-) diff --git a/LibGit2Sharp/BlameHunkCollection.cs b/LibGit2Sharp/BlameHunkCollection.cs index 869daf527..8783a44d7 100644 --- a/LibGit2Sharp/BlameHunkCollection.cs +++ b/LibGit2Sharp/BlameHunkCollection.cs @@ -11,10 +11,12 @@ namespace LibGit2Sharp /// /// The result of a blame operation. /// - public class BlameHunkCollection : IEnumerable + public class BlameHunkCollection : IEnumerable, IDisposable { private readonly IRepository repo; private readonly List hunks = new List(); + private readonly RepositoryHandle repoHandle; + private readonly BlameHandle blameHandle; /// /// For easy mocking @@ -49,15 +51,23 @@ internal unsafe BlameHunkCollection(Repository repo, RepositoryHandle repoHandle } } - using (var blameHandle = Proxy.git_blame_file(repoHandle, path, rawopts)) - { - var numHunks = NativeMethods.git_blame_get_hunk_count(blameHandle); - for (uint i = 0; i < numHunks; ++i) - { - var rawHunk = Proxy.git_blame_get_hunk_byindex(blameHandle, i); - hunks.Add(new BlameHunk(this.repo, rawHunk)); - } - } + blameHandle = Proxy.git_blame_file(repoHandle, path, rawopts); + + this.PopulateHunks(); + } + + private unsafe BlameHunkCollection(IRepository repo, RepositoryHandle repoHandle, BlameHandle reference, byte[] buffer) + { + this.repo = repo; + this.repoHandle = repoHandle; + this.blameHandle = Proxy.git_blame_buffer(repoHandle, reference, buffer); + + this.PopulateHunks(); + } + + public BlameHunkCollection FromBuffer(byte[] buffer) + { + return new BlameHunkCollection(repo, repoHandle, this.blameHandle, buffer); } /// @@ -100,5 +110,20 @@ IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + + private unsafe void PopulateHunks() + { + var numHunks = NativeMethods.git_blame_get_hunk_count(blameHandle); + for (uint i = 0; i < numHunks; ++i) + { + var rawHunk = Proxy.git_blame_get_hunk_byindex(blameHandle, i); + hunks.Add(new BlameHunk(this.repo, rawHunk)); + } + } + + public void Dispose() + { + this.blameHandle.Dispose(); + } } } diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs index f5d45f3cf..44ecc9599 100644 --- a/LibGit2Sharp/Core/NativeMethods.cs +++ b/LibGit2Sharp/Core/NativeMethods.cs @@ -190,6 +190,13 @@ internal static extern unsafe int git_blame_file( [MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string path, git_blame_options options); + [DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)] + internal static extern unsafe int git_blame_buffer( + out git_blame* blame, + git_blame* reference, + IntPtr buffer, + UIntPtr len); + [DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)] internal static extern unsafe void git_blame_free(git_blame* blame); diff --git a/LibGit2Sharp/Core/Proxy.cs b/LibGit2Sharp/Core/Proxy.cs index 50cefc0df..050dfe305 100644 --- a/LibGit2Sharp/Core/Proxy.cs +++ b/LibGit2Sharp/Core/Proxy.cs @@ -35,6 +35,27 @@ public static unsafe BlameHandle git_blame_file( return NativeMethods.git_blame_get_hunk_byindex(blame, idx); } + public static unsafe BlameHandle git_blame_buffer( + RepositoryHandle repo, + BlameHandle reference, + byte[] buffer) + { + git_blame* ptr; + int res; + + unsafe + { + fixed (byte* p = buffer) + { + res = NativeMethods.git_blame_buffer(out ptr, reference, (IntPtr)p, (UIntPtr)buffer.Length); + } + } + + Ensure.ZeroResult(res); + + return new BlameHandle(ptr, true); + } + #endregion #region git_blob_ From 797a8d0792006c6385b0535b1b2a1596f8aef4e4 Mon Sep 17 00:00:00 2001 From: Adi Thakral Date: Fri, 28 Oct 2022 14:15:47 -0700 Subject: [PATCH 2/2] use the first blame ref for future calls --- LibGit2Sharp/BlameHunkCollection.cs | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/LibGit2Sharp/BlameHunkCollection.cs b/LibGit2Sharp/BlameHunkCollection.cs index 8783a44d7..6176c3730 100644 --- a/LibGit2Sharp/BlameHunkCollection.cs +++ b/LibGit2Sharp/BlameHunkCollection.cs @@ -16,7 +16,8 @@ public class BlameHunkCollection : IEnumerable, IDisposable private readonly IRepository repo; private readonly List hunks = new List(); private readonly RepositoryHandle repoHandle; - private readonly BlameHandle blameHandle; + private readonly BlameHandle referenceHandle; + private readonly bool shouldDisposeHandle; /// /// For easy mocking @@ -51,23 +52,27 @@ internal unsafe BlameHunkCollection(Repository repo, RepositoryHandle repoHandle } } - blameHandle = Proxy.git_blame_file(repoHandle, path, rawopts); - - this.PopulateHunks(); + referenceHandle = Proxy.git_blame_file(repoHandle, path, rawopts); + shouldDisposeHandle = true; + this.PopulateHunks(this.referenceHandle); } private unsafe BlameHunkCollection(IRepository repo, RepositoryHandle repoHandle, BlameHandle reference, byte[] buffer) { this.repo = repo; this.repoHandle = repoHandle; - this.blameHandle = Proxy.git_blame_buffer(repoHandle, reference, buffer); + this.referenceHandle = reference; + this.shouldDisposeHandle = false; - this.PopulateHunks(); + using (var blameHandle = Proxy.git_blame_buffer(repoHandle, reference, buffer)) + { + this.PopulateHunks(blameHandle); + } } public BlameHunkCollection FromBuffer(byte[] buffer) { - return new BlameHunkCollection(repo, repoHandle, this.blameHandle, buffer); + return new BlameHunkCollection(repo, repoHandle, this.referenceHandle, buffer); } /// @@ -111,7 +116,7 @@ IEnumerator IEnumerable.GetEnumerator() return GetEnumerator(); } - private unsafe void PopulateHunks() + private unsafe void PopulateHunks(BlameHandle blameHandle) { var numHunks = NativeMethods.git_blame_get_hunk_count(blameHandle); for (uint i = 0; i < numHunks; ++i) @@ -123,7 +128,10 @@ private unsafe void PopulateHunks() public void Dispose() { - this.blameHandle.Dispose(); + if (shouldDisposeHandle) + { + this.referenceHandle.Dispose(); + } } } }