8000 Initial change to type-safe Diff.Compare · libgit2/libgit2sharp@8ebafe7 · GitHub
[go: up one dir, main page]

Skip to content

Commit 8ebafe7

Browse files
committed
Initial change to type-safe Diff.Compare
Fixes #1176.
1 parent 15df381 commit 8ebafe7

File tree

8 files changed

+113
-108
lines changed

8 files changed

+113
-108
lines changed

LibGit2Sharp.Tests/DiffTreeToTreeFixture.cs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,16 +1108,5 @@ public void RetrievingDiffChangesMustAlwaysBeCaseSensitive()
11081108
Assert.Equal(ChangeKind.Modified, changes["A.TXT"].Status);
11091109
}
11101110
}
1111-
1112-
[Fact]
1113-
public void CallingCompareWithAnUnsupportedGenericParamThrows()
1114-
{
1115-
var path = SandboxStandardTestRepoGitDir();
1116-
using (var repo = new Repository(path))
1117-
{
1118-
Assert.Throws<LibGit2SharpException>(() => repo.Diff.Compare<string>(default(Tree), default(Tree)));
1119-
Assert.Throws<LibGit2SharpException>(() => repo.Diff.Compare<string>());
1120-
}
1121-
}
11221111
}
11231112
}

LibGit2Sharp/Diff.cs

Lines changed: 13 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,6 @@ private static IDictionary<DiffTargets, Func<Repository, TreeComparisonHandleRet
9191
};
9292
}
9393

94-
private static readonly IDictionary<Type, Func<DiffSafeHandle, object>> ChangesBuilders = new Dictionary<Type, Func<DiffSafeHandle, object>>
95-
{
96-
{ typeof(Patch), diff => new Patch(diff) },
97-
{ typeof(TreeChanges), diff => new TreeChanges(diff) },
98-
{ typeof(PatchStats), diff => new PatchStats(diff) },
99-
};
100-
10194
/// <summary>
10295
/// Show changes between two <see cref="Blob"/>s.
10396
/// </summary>
@@ -126,17 +119,8 @@ public virtual ContentChanges Compare(Blob oldBlob, Blob newBlob, CompareOptions
126119
/// <param name="compareOptions">Additional options to define patch generation behavior.</param>
127120
/// <returns>A <see cref="TreeChanges"/> containing the changes between the <paramref name="oldTree"/> and the <paramref name="newTree"/>.</returns>
128121
public virtual T Compare<T>(Tree oldTree, Tree newTree, IEnumerable<string> paths = null, ExplicitPathsOptions explicitPathsOptions = null,
129-
CompareOptions compareOptions = null) where T : class
122+
CompareOptions compareOptions = null) where T : class, IDiffResult<T>, new()
130123
{
131-
Func<DiffSafeHandle, object> builder;
132-
133-
if (!ChangesBuilders.TryGetValue(typeof (T), out builder))
134-
{
135-
throw new LibGit2SharpException(string.Format(CultureInfo.InvariantCulture,
136-
"Unexpected type '{0}' passed to Compare. Supported values are either '{1}' or '{2}'.", typeof (T),
137-
typeof (TreeChanges), typeof (Patch)));
138-
}
139-
140124
var comparer = TreeToTree(repo);
141125
ObjectId oldTreeId = oldTree != null ? oldTree.Id : null;
142126
ObjectId newTreeId = newTree != null ? newTree.Id : null;
@@ -153,10 +137,10 @@ public virtual T Compare<T>(Tree oldTree, Tree newTree, IEnumerable<string> path
153137
}
154138
}
155139

156-
using (DiffSafeHandle diff = BuildDiffList(oldTreeId, newTreeId, comparer,
157-
diffOptions, paths, explicitPathsOptions, compareOptions))
140+
using (var diff = new DiffSafeHandleProxy(BuildDiffList(oldTreeId, newTreeId, comparer,
141+
diffOptions, paths, explicitPathsOptions, compareOptions)))
158142
{
159-
return (T)builder(diff);
143+
return new T().FromNative(diff);
160144
}
161145
}
162146

@@ -179,17 +163,8 @@ public virtual T Compare<T>(Tree oldTree, Tree newTree, IEnumerable<string> path
179163
/// a <see cref="Patch"/> if you want the actual patch content for the whole diff and for individual files.</typeparam>
180164
/// <returns>A <typeparamref name="T"/> containing the changes between the <see cref="Tree"/> and the selected target.</returns>
181165
public virtual T Compare<T>(Tree oldTree, DiffTargets diffTargets, IEnumerable<string> paths = null,
182-
ExplicitPathsOptions explicitPathsOptions = null, CompareOptions compareOptions = null) where T : class
166+
ExplicitPathsOptions explicitPathsOptions = null, CompareOptions compareOptions = null) where T : class, IDiffResult<T>, new()
183167
{
184-
Func<DiffSafeHandle, object> builder;
185-
186-
if (!ChangesBuilders.TryGetValue(typeof (T), out builder))
187-
{
188-
throw new LibGit2SharpException(string.Format(CultureInfo.InvariantCulture,
189-
"Unexpected type '{0}' passed to Compare. Supported values are either '{1}' or '{2}'.", typeof (T),
190-
typeof (TreeChanges), typeof (Patch)));
191-
}
192-
193168
var comparer = HandleRetrieverDispatcher[diffTargets](repo);
194169
ObjectId oldTreeId = oldTree != null ? oldTree.Id : null;
195170

@@ -208,10 +183,10 @@ public virtual T Compare<T>(Tree oldTree, DiffTargets diffTargets, IEnumerable<s
208183
}
209184
}
210185

211-
using (DiffSafeHandle diff = BuildDiffList(oldTreeId, null, comparer,
212-
diffOptions, paths, explicitPathsOptions, compareOptions))
186+
using (var diff = new DiffSafeHandleProxy(BuildDiffList(oldTreeId, null, comparer,
187+
diffOptions, paths, explicitPathsOptions, compareOptions)))
213188
{
214-
return (T)builder(diff);
189+
return new T().FromNative(diff);
215190
}
216191
}
217192

@@ -233,23 +208,14 @@ public virtual T Compare<T>(Tree oldTree, DiffTargets diffTargets, IEnumerable<s
233208
/// a <see cref="Patch"/> if you want the actual patch content for the whole diff and for individual files.</typeparam>
234209
/// <returns>A <typeparamref name="T"/> containing the changes between the working directory and the index.</returns>
235210
public virtual T Compare<T>(IEnumerable<string> paths = null, bool includeUntracked = false, ExplicitPathsOptions explicitPathsOptions = null,
236-
CompareOptions compareOptions = null) where T : class
211+
CompareOptions compareOptions = null) where T : class, IDiffResult<T>, new()
237212
{
238213
return Compare<T>(includeUntracked ? DiffModifiers.IncludeUntracked : DiffModifiers.None, paths, explicitPathsOptions, compareOptions);
239214
}
240215

241216
internal virtual T Compare<T>(DiffModifiers diffOptions, IEnumerable<string> paths = null,
242-
ExplicitPathsOptions explicitPathsOptions = null, CompareOptions compareOptions = null) where T : class
217+
ExplicitPathsOptions explicitPathsOptions = null, CompareOptions compareOptions = null) where T : class, IDiffResult<T>, new()
243218
{
244-
Func<DiffSafeHandle, object> builder;
245-
246-
if (!ChangesBuilders.TryGetValue(typeof (T), out builder))
247-
{
248-
throw new LibGit2SharpException(string.Format(CultureInfo.InvariantCulture,
249-
"Unexpected type '{0}' passed to Compare. Supported values are either '{1}' or '{2}'.", typeof (T),
250-
typeof (TreeChanges), typeof (Patch)));
251-
}
252-
253219
var comparer = WorkdirToIndex(repo);
254220

255221
if (explicitPathsOptions != null)
@@ -263,10 +229,10 @@ internal virtual T Compare<T>(DiffModifiers diffOptions, IEnumerable<string> pat
263229
}
264230
}
265231

266-
using (DiffSafeHandle diff = BuildDiffList(null, null, comparer,
267-
diffOptions, paths, explicitPathsOptions, compareOptions))
232+
using (var diff = new DiffSafeHandleProxy(BuildDiffList(null, null, comparer,
233+
diffOptions, paths, explicitPathsOptions, compareOptions)))
268234
{
269-
return (T)builder(diff);
235+
return new T().FromNative(diff);
270236
}
271237
}
272238

LibGit2Sharp/DiffSafeHandleProxy.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System;
2+
using LibGit2Sharp.Core.Handles;
3+
4+
namespace LibGit2Sharp
5+
{
6+
public class DiffSafeHandleProxy : IDisposable
7+
{
8+
internal readonly DiffSafeHandle nativeHandle;
9+
10+
internal DiffSafeHandleProxy(DiffSafeHandle handle)
11+
{
12+
nativeHandle = handle;
13+
}
14+
15+
#region IDisposable implementation
16+
17+
void IDisposable.Dispose()
18+
{
19+
nativeHandle.Dispose();
20+
}
21+
22+
#endregion
23+
}
24+
}
25+

LibGit2Sharp/IDiffResult.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
3+
namespace LibGit2Sharp
4+
{
5+
public interface IDiffResult<T> where T:class
6+
{
7+
T FromNative(DiffSafeHandleProxy diff);
8+
}
9+
}
10+

LibGit2Sharp/LibGit2Sharp.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,8 @@
339339
<Compile Include="Core\RawContentStream.cs" />
340340
<Compile Include="Core\Handles\OdbStreamSafeHandle.cs" />
341341
<Compile Include="SupportedCredentialTypes.cs" />
342+
<Compile Include="IDiffResult.cs" />
343+
<Compile Include="DiffSafeHandleProxy.cs" />
342344
</ItemGroup>
343345
<ItemGroup>
344346
<CodeAnalysisDictionary Include="CustomDictionary.xml" />

LibGit2Sharp/Patch.cs

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace LibGit2Sharp
1616
/// deleted, modified, ..., then consider using a simpler <see cref="TreeChanges"/>.</para>
1717
/// </summary>
1818
[DebuggerDisplay("{DebuggerDisplay,nq}")]
19-
public class Patch : IEnumerable<PatchEntryChanges>
19+
public class Patch : IEnumerable<PatchEntryChanges>, IDiffResult<Patch>
2020
{
2121
private readonly StringBuilder fullPatchBuilder = new StringBuilder();
2222

@@ -27,24 +27,9 @@ public class Patch : IEnumerable<PatchEntryChanges>
2727
/// <summary>
2828
/// Needed for mocking purposes.
2929
/// </summary>
30-
protected Patch()
30+
public Patch()
3131
{ }
3232

33-
internal Patch(DiffSafeHandle diff)
34-
{
35-
int count = Proxy.git_diff_num_deltas(diff);
36-
for (int i = 0; i < count; i++)
37-
{
38-
using (var patch = Proxy.git_patch_from_diff(diff, i))
39-
{
40-
var delta = Proxy.git_diff_get_delta(diff, i);
41-
AddFileChange(delta);
42-
Proxy.git_patch_print(patch, PrintCallBack);
43-
}
44-
45-
}
46-
}
47-
4833
private void AddFileChange(GitDiffDelta delta)
4934
{
5035
var treeEntryChanges = new TreeEntryChanges(delta);
@@ -113,6 +98,25 @@ IEnumerator IEnumerable.GetEnumerator()
11398

11499
#endregion
115100

101+
#region IDiffResult implementation
102+
103+
Patch IDiffResult<Patch>.FromNative(DiffSafeHandleProxy diff)
104+
{
105+
int count = Proxy.git_diff_num_deltas(diff.nativeHandle);
106+
for (int i = 0; i < count; i++)
107+
{
108+
using (var patch = Proxy.git_patch_from_diff(diff.nativeHandle, i))
109+
{
110+
var delta = Proxy.git_diff_get_delta(diff.nativeHandle, i);
111+
AddFileChange(delta);
112+
Proxy.git_patch_print(patch, PrintCallBack);
113+
}
114+
}
115+
return this;
116+
}
117+
118+
#endregion
119+
116120
/// <summary>
117121
/// Gets the <see cref="ContentChanges"/> corresponding to the specified <paramref name="path"/>.
118122
/// </summary>

LibGit2Sharp/PatchStats.cs

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,40 +13,18 @@ namespace LibGit2Sharp
1313
/// <para>The individual patches for each file can be accessed through the indexer of this class.</para>
1414
/// </summary>
1515
[DebuggerDisplay("{DebuggerDisplay,nq}")]
16-
public class PatchStats : IEnumerable<ContentChangeStats>
16+
public class PatchStats : IEnumerable<ContentChangeStats>, IDiffResult<PatchStats>
1717
{
1818
private readonly IDictionary<FilePath, ContentChangeStats> changes = new Dictionary<FilePath, ContentChangeStats>();
19-
private readonly int totalLinesAdded;
20-
private readonly int totalLinesDeleted;
19+
private int totalLinesAdded;
20+
private int totalLinesDeleted;
2121

2222
/// <summary>
2323
/// For mocking.
2424
/// </summary>
25-
protected PatchStats()
25+
public PatchStats()
2626
{ }
2727

28-
internal PatchStats(DiffSafeHandle diff)
29-
{
30-
int count = Proxy.git_diff_num_deltas(diff);
31-
for (int i = 0; i < count; i++)
32-
{
33-
using (var patch = Proxy.git_patch_from_diff(diff, i))
34-
{
35-
var delta = Proxy.git_diff_get_delta(diff, i);
36-
var pathPtr = delta.NewFile.Path != IntPtr.Zero ? delta.NewFile.Path : delta.OldFile.Path;
37-
var newFilePath = LaxFilePathMarshaler.FromNative(pathPtr);
38-
39-
var stats = Proxy.git_patch_line_stats(patch);
40-
int added = stats.Item1;
41-
int deleted = stats.Item2;
42-
changes.Add(newFilePath, new ContentChangeStats(added, deleted));
43-
totalLinesAdded += added;
44-
totalLinesDeleted += deleted;
45-
}
46-
47-
}
48-
}
49-
5028
#region IEnumerable<ContentChanges> Members
5129

5230
/// <summary>
@@ -69,6 +47,32 @@ IEnumerator IEnumerable.GetEnumerator()
6947

7048
#endregion
7149

50+
#region IDiffResult implementation
51+
52+
PatchStats IDiffResult<PatchStats>.FromNative(DiffSafeHandleProxy diff)
53+
{
54+
int count = Proxy.git_diff_num_deltas(diff.nativeHandle);
55+
for (int i = 0; i < count; i++)
56+
{
57+
using (var patch = Proxy.git_patch_from_diff(diff.nativeHandle, i))
58+
{
59+
var delta = Proxy.git_diff_get_delta(diff.nativeHandle, i);
60+
var pathPtr = delta.NewFile.Path != IntPtr.Zero ? delta.NewFile.Path : delta.OldFile.Path;
61+
var newFilePath = LaxFilePathMarshaler.FromNative(pathPtr);
62+
63+
var stats = Proxy.git_patch_line_stats(patch);
64+
int added = stats.Item1;
65+
int deleted = stats.Item2;
66+
changes.Add(newFilePath, new ContentChangeStats(added, deleted));
67+
totalLinesAdded += added;
68+
totalLinesDeleted += deleted;
69+
}
70+
}
71+
return this;
72+
}
73+
74+
#endregion
75+
7276
/// <summary>
7377
/// Gets the <see cref="ContentChangeStats"/> corresponding to the specified <paramref name="path"/>.
7478
/// </summary>

LibGit2Sharp/TreeChanges.cs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ namespace LibGit2Sharp
1515
/// <para>To obtain the actual patch of the diff, use the <see cref="Patch"/> class when calling Compare.</para>.
1616
/// </summary>
1717
[DebuggerDisplay("{DebuggerDisplay,nq}")]
18-
public class TreeChanges : IEnumerable<TreeEntryChanges>
18+
public class TreeChanges : IEnumerable<TreeEntryChanges>, IDiffResult<TreeChanges>
1919
{
2020
private readonly IDictionary<FilePath, TreeEntryChanges> changes = new Dictionary<FilePath, TreeEntryChanges>();
2121
private readonly List<TreeEntryChanges> added = new List<TreeEntryChanges>();
@@ -45,14 +45,9 @@ private static IDictionary<ChangeKind, Action<TreeChanges, TreeEntryChanges>> Bu
4545
/// <summary>
4646
/// Needed for mocking purposes.
4747
/// </summary>
48-
protected TreeChanges()
48+
public TreeChanges()
4949
{ }
5050

51-
internal TreeChanges(DiffSafeHandle diff)
52-
{
53-
Proxy.git_diff_foreach(diff, FileCallback, null, null);
54-
}
55-
5651
private int FileCallback(GitDiffDelta delta, float progress, IntPtr payload)
5752
{
5853
AddFileChange(delta);
@@ -89,6 +84,16 @@ IEnumerator IEnumerable.GetEnumerator()
8984

9085
#endregion
9186

87+
#region IDiffResult implementation
88+
89+
TreeChanges IDiffResult<TreeChanges>.FromNative(DiffSafeHandleProxy diff)
90+
{
91+
Proxy.git_diff_foreach(diff.nativeHandle, FileCallback, null, null);
92+
return this;
93+
}
94+
95+
#endregion
96+
9297
/// <summary>
9398
/// Gets the <see cref="TreeEntryChanges"/> corresponding to the specified <paramref name="path"/>.
9499
/// </summary>

0 commit comments

Comments
 (0)
0