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

Skip to content

Commit 16e2dcc

Browse files
committed
Initial change to type-safe Diff.Compare
Fixes #1176.
1 parent b279955 commit 16e2dcc

File tree

8 files changed

+127
-119
lines changed

8 files changed

+127
-119
lines changed

LibGit2Sharp.Tests/DiffTreeToTreeFixture.cs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,17 +1123,6 @@ public void RetrievingDiffChangesMustAlwaysBeCaseSensitive()
11231123
}
11241124
}
11251125

1126-
[Fact]
1127-
public void CallingCompareWithAnUnsupportedGenericParamThrows()
1128-
{
1129-
var path = SandboxStandardTestRepoGitDir();
1130-
using (var repo = new Repository(path))
1131-
{
1132-
Assert.Throws<LibGit2SharpException>(() => repo.Diff.Compare<string>(default(Tree), default(Tree)));
1133-
Assert.Throws<LibGit2SharpException>(() => repo.Diff.Compare<string>());
1134-
}
1135-
}
1136-
11371126
[Fact]
11381127
public void UsingPatienceAlgorithmCompareOptionProducesPatienceDiff()
11391128
{

LibGit2Sharp/Diff.cs

Lines changed: 28 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,6 @@ private static IDictionary<DiffTargets, Func<Repository, TreeComparisonHandleRet
9595
};
9696
}
9797

98-
private static readonly IDictionary<Type, Func<DiffSafeHandle, object>> ChangesBuilders = new Dictionary<Type, Func<DiffSafeHandle, object>>
99-
{
100-
{ typeof(Patch), diff => new Patch(diff) },
101-
{ typeof(TreeChanges), diff => new TreeChanges(diff) },
102-
{ typeof(PatchStats), diff => new PatchStats(diff) },
103-
};
104-
10598
/// <summary>
10699
/// Show changes between two <see cref="Blob"/>s.
107100
/// </summary>
@@ -134,7 +127,7 @@ public virtual ContentChanges Compare(Blob oldBlob, Blob newBlob, CompareOptions
134127
/// <param name="oldTree">The <see cref="Tree"/> you want to compare from.</param>
135128
/// <param name="newTree">The <see cref="Tree"/> you want to compare to.</param>
136129
/// <returns>A <see cref="TreeChanges"/> containing the changes between the <paramref name="oldTree"/> and the <paramref name="newTree"/>.</returns>
137-
public virtual T Compare<T>(Tree oldTree, Tree newTree) where T : class
130+
public virtual T Compare<T>(Tree oldTree, Tree newTree) where T : class, IDiffResult<T>, new()
138131
{
139132
return Compare<T>(oldTree, newTree, null, null, null);
140133
}
@@ -146,7 +139,7 @@ public virtual T Compare<T>(Tree oldTree, Tree newTree) where T : class
146139
/// <param name="newTree">The <see cref="Tree"/> you want to compare to.</param>
147140
/// <param name="paths">The list of paths (either files or directories) that should be compared.</param>
148141
/// <returns>A <see cref="TreeChanges"/> containing the changes between the <paramref name="oldTree"/> and the <paramref name="newTree"/>.</returns>
149-
public virtual T Compare<T>(Tree oldTree, Tree newTree, IEnumerable<string> paths) where T : class
142+
public virtual T Compare<T>(Tree oldTree, Tree newTree, IEnumerable<string> paths) where T : class, IDiffResult<T>, new()
150143
{
151144
return Compare<T>(oldTree, newTree, paths, null, null);
152145
}
@@ -163,7 +156,7 @@ public virtual T Compare<T>(Tree oldTree, Tree newTree, IEnumerable<string> path
163156
/// </param>
164157
/// <returns>A <see cref="TreeChanges"/> containing the changes between the <paramref name="oldTree"/> and the <paramref name="newTree"/>.</returns>
165158
public virtual T Compare<T>(Tree oldTree, Tree newTree, IEnumerable<string> paths,
166-
ExplicitPathsOptions explicitPathsOptions) where T : class
159+
ExplicitPathsOptions explicitPathsOptions) where T : class, IDiffResult<T>, new()
167160
{
168161
return Compare<T>(oldTree, newTree, paths, explicitPathsOptions, null);
169162
}
@@ -176,7 +169,7 @@ public virtual T Compare<T>(Tree oldTree, Tree newTree, IEnumerable<string> path
176169
/// <param name="paths">The list of paths (either files or directories) that should be compared.</param>
177170
/// <param name="compareOptions">Additional options to define patch generation behavior.</param>
178171
/// <returns>A <see cref="TreeChanges"/> containing the changes between the <paramref name="oldTree"/> and the <paramref name="newTree"/>.</returns>
179-
public virtual T Compare<T>(Tree oldTree, Tree newTree, IEnumerable<string> paths, CompareOptions compareOptions) where T : class
172+
public virtual T Compare<T>(Tree oldTree, Tree newTree, IEnumerable<string> paths, CompareOptions compareOptions) where T : class, IDiffResult<T>, new()
180173
{
181174
return Compare<T>(oldTree, newTree, paths, null, compareOptions);
182175
}
@@ -188,7 +181,7 @@ public virtual T Compare<T>(Tree oldTree, Tree newTree, IEnumerable<string> path
188181
/// <param name="newTree">The <see cref="Tree"/> you want to compare to.</param>
189182
/// <param name="compareOptions">Additional options to define patch generation behavior.</param>
190183
/// <returns>A <see cref="TreeChanges"/> containing the changes between the <paramref name="oldTree"/> and the <paramref name="newTree"/>.</returns>
191-
public virtual T Compare<T>(Tree oldTree, Tree newTree, CompareOptions compareOptions) where T : class
184+
public virtual T Compare<T>(Tree oldTree, Tree newTree, CompareOptions compareOptions) where T : class, IDiffResult<T>, new()
192185
{
193186
return Compare<T>(oldTree, newTree, null, null, compareOptions);
194187
}
@@ -206,18 +199,8 @@ public virtual T Compare<T>(Tree oldTree, Tree newTree, CompareOptions compareOp
206199
/// <param name="compareOptions">Additional options to define patch generation behavior.</param>
207200
/// <returns>A <see cref="TreeChanges"/> containing the changes between the <paramref name="oldTree"/> and the <paramref name="newTree"/>.</returns>
208201
public virtual T Compare<T>(Tree oldTree, Tree newTree, IEnumerable<string> paths, ExplicitPathsOptions explicitPathsOptions,
209-
CompareOptions compareOptions) where T : class
202+
CompareOptions compareOptions) where T : class, IDiffResult<T>, new()
210203
{
211-
Func<DiffSafeHandle, object> builder;
212-
213-
if (!ChangesBuilders.TryGetValue(typeof(T), out builder))
214-
{
215-
throw new LibGit2SharpException(CultureInfo.InvariantCulture,
216-
"Unexpected type '{0}' passed to Compare. Supported values are either '{1}' or '{2}'.",
217-
typeof(T),
218-
typeof(TreeChanges),
219-
typeof(Patch));
220-
}
221204

222205
var comparer = TreeToTree(repo);
223206
ObjectId oldTreeId = oldTree != null ? oldTree.Id : null;
@@ -236,7 +219,10 @@ public virtual T Compare<T>(Tree oldTree, Tree newTree, IEnumerable<string> path
236219

237220
using (DiffSafeHandle diff = BuildDiffList(oldTreeId, newTreeId, comparer, diffOptions, paths, explicitPathsOptions, compareOptions))
238221
{
239-
return (T)builder(diff);
222+
using (var proxy = new DiffSafeHandleProxy(diff))
223+
{
224+
return new T().FromNative(proxy);
225+
}
240226
}
241227
}
242228

@@ -252,7 +238,7 @@ public virtual T Compare<T>(Tree oldTree, Tree newTree, IEnumerable<string> path
252238
/// <typeparam name="T">Can be either a <see cref="TreeChanges"/> if you are only interested in the list of files modified, added, ..., or
253239
/// a <see cref="Patch"/> if you want the actual patch content for the whole diff and for individual files.</typeparam>
254240
/// <returns>A <typeparamref name="T"/> containing the changes between the <see cref="Tree"/> and the selected target.</returns>
255-
public virtual T Compare<T>(Tree oldTree, DiffTargets diffTargets) where T : class
241+
public virtual T Compare<T>(Tree oldTree, DiffTargets diffTargets) where T : class, IDiffResult<T>, new()
256242
{
257243
return Compare<T>(oldTree, diffTargets, null, null, null);
258244
}
@@ -270,7 +256,7 @@ public virtual T Compare<T>(Tree oldTree, DiffTargets diffTargets) where T : cla
270256
/// <typeparam name="T">Can be either a <see cref="TreeChanges"/> if you are only interested in the list of files modified, added, ..., or
271257
/// a <see cref="Patch"/> if you want the actual patch content for the whole diff and for individual files.</typeparam>
272258
/// <returns>A <typeparamref name="T"/> containing the changes between the <see cref="Tree"/> and the selected target.</returns>
273-
public virtual T Compare<T>(Tree oldTree, DiffTargets diffTargets, IEnumerable<string> paths) where T : class
259+
public virtual T Compare<T>(Tree oldTree, DiffTargets diffTargets, IEnumerable<string> paths) where T : class, IDiffResult<T>, new()
274260
{
275261
return Compare<T>(oldTree, diffTargets, paths, null, null);
276262
}
@@ -293,7 +279,7 @@ public virtual T Compare<T>(Tree oldTree, DiffTargets diffTargets, IEnumerable<s
293279
/// a <see cref="Patch"/> if you want the actual patch content for the whole diff and for individual files.</typeparam>
294280
/// <returns>A <typeparamref name="T"/> containing the changes between the <see cref="Tree"/> and the selected target.</returns>
295281
public virtual T Compare<T>(Tree oldTree, DiffTargets diffTargets, IEnumerable<string> paths,
296-
ExplicitPathsOptions explicitPathsOptions) where T : class
282+
ExplicitPathsOptions explicitPathsOptions) where T : class, IDiffResult<T>, new()
297283
{
298284
return Compare<T>(oldTree, diffTargets, paths, explicitPathsOptions, null);
299285
}
@@ -317,19 +303,8 @@ public virtual T Compare<T>(Tree oldTree, DiffTargets diffTargets, IEnumerable<s
317303
/// a <see cref="Patch"/> if you want the actual patch content for the whole diff and for individual files.</typeparam>
318304
/// <returns>A <typeparamref name="T"/> containing the changes between the <see cref="Tree"/> and the selected target.</returns>
319305
public virtual T Compare<T>(Tree oldTree, DiffTargets diffTargets, IEnumerable<string> paths,
320-
ExplicitPathsOptions explicitPathsOptions, CompareOptions compareOptions) where T : class
306+
ExplicitPathsOptions explicitPathsOptions, CompareOptions compareOptions) where T : class, IDiffResult<T>, new()
321307
{
322-
Func<DiffSafeHandle, object> builder;
323-
324-
if (!ChangesBuilders.TryGetValue(typeof(T), out builder))
325-
{
326-
throw new LibGit2SharpException(CultureInfo.InvariantCulture,
327-
"Unexpected type '{0}' passed to Compare. Supported values are either '{1}' or '{2}'.",
328-
typeof(T),
329-
typeof(TreeChanges),
330-
typeof(Patch));
331-
}
332-
333308
var comparer = HandleRetrieverDispatcher[diffTargets](repo);
334309
ObjectId oldTreeId = oldTree != null ? oldTree.Id : null;
335310

@@ -349,7 +324,10 @@ public virtual T Compare<T>(Tree oldTree, DiffTargets diffTargets, IEnumerable<s
349324

350325
using (DiffSafeHandle diff = BuildDiffList(oldTreeId, null, comparer, diffOptions, paths, explicitPathsOptions, compareOptions))
351326
{
352-
return (T)builder(diff);
327+
using (var proxy = new DiffSafeHandleProxy(diff))
328+
{
329+
return new T().FromNative(proxy);
330+
}
353331
}
354332
}
355333

@@ -363,7 +341,7 @@ public virtual T Compare<T>(Tree oldTree, DiffTargets diffTargets, IEnumerable<s
363341
/// <typeparam name="T">Can be either a <see cref="TreeChanges"/> if you are only interested in the list of files modified, added, ..., or
364342
/// a <see cref="Patch"/> if you want the actual patch content for the whole diff and for individual files.</typeparam>
365343
/// <returns>A <typeparamref name="T"/> containing the changes between the working directory and the index.</returns>
366-
public virtual T Compare<T>() where T : class
344+
public virtual T Compare<T>() where T : class, IDiffResult<T>, new()
367345
{
368346
return Compare<T>(DiffModifiers.None);
369347
}
@@ -379,7 +357,7 @@ public virtual T Compare<T>() where T : class
379357
/// <typeparam name="T">Can be either a <see cref="TreeChanges"/> if you are only interested in the list of files modified, added, ..., or
380358
/// a <see cref="Patch"/> if you want the actual patch content for the whole diff and for individual files.</typeparam>
381359
/// <returns>A <typeparamref name="T"/> containing the changes between the working directory and the index.</returns>
382-
public virtual T Compare<T>(IEnumerable<string> paths) where T : class
360+
public virtual T Compare<T>(IEnumerable<string> paths) where T : class, IDiffResult<T>, new()
383361
{
384362
return Compare<T>(DiffModifiers.None, paths);
385363
}
@@ -396,7 +374,7 @@ public virtual T Compare<T>(IEnumerable<string> paths) where T : class
396374
/// <typeparam name="T">Can be either a <see cref="TreeChanges"/> if you are only interested in the list of files modified, added, ..., or
397375
/// a <see cref="Patch"/> if you want the actual patch content for the whole diff and for individual files.</typeparam>
398376
/// <returns>A <typeparamref name="T"/> containing the changes between the working directory and the index.</returns>
399-
public virtual T Compare<T>(IEnumerable<string> paths, bool includeUntracked) where T : class
377+
public virtual T Compare<T>(IEnumerable<string> paths, bool includeUntracked) where T : class, IDiffResult<T>, new()
400378
{
401379
return Compare<T>(includeUntracked ? DiffModifiers.IncludeUntracked : DiffModifiers.None, paths);
402380
}
@@ -417,7 +395,7 @@ public virtual T Compare<T>(IEnumerable<string> paths, bool includeUntracked) wh
417395
/// <typeparam name="T">Can be either a <see cref="TreeChanges"/> if you are only interested in the list of files modified, added, ..., or
418396
/// a <see cref="Patch"/> if you want the actual patch content for the whole diff and for individual files.</typeparam>
419397
/// <returns>A <typeparamref name="T"/> containing the changes between the working directory and the index.</returns>
420-
public virtual T Compare<T>(IEnumerable<string> paths, bool includeUntracked, ExplicitPathsOptions explicitPathsOptions) where T : class
398+
public virtual T Compare<T>(IEnumerable<string> paths, bool includeUntracked, ExplicitPathsOptions explicitPathsOptions) where T : class, IDiffResult<T>, new()
421399
{
422400
return Compare<T>(includeUntracked ? DiffModifiers.IncludeUntracked : DiffModifiers.None, paths, explicitPathsOptions);
423401
}
@@ -443,7 +421,7 @@ public virtual T Compare<T>(
443421
IEnumerable<string> paths,
444422
bool includeUntracked,
445423
ExplicitPathsOptions explicitPathsOptions,
446-
CompareOptions compareOptions) where T : class
424+
CompareOptions compareOptions) where T : class, IDiffResult<T>, new()
447425
{
448426
return Compare<T>(includeUntracked ? DiffModifiers.IncludeUntracked : DiffModifiers.None, paths, explicitPathsOptions, compareOptions);
449427
}
@@ -452,19 +430,8 @@ internal virtual T Compare<T>(
452430
DiffModifiers diffOptions,
453431
IEnumerable<string> paths = null,
454432
ExplicitPathsOptions explicitPathsOptions = null,
455-
CompareOptions compareOptions = null) where T : class
433+
CompareOptions compareOptions = null) where T : class, IDiffResult<T>, new()
456434
{
457-
Func<DiffSafeHandle, object> builder;
458-
459-
if (!ChangesBuilders.TryGetValue(typeof(T), out builder))
460-
{
461-
throw new LibGit2SharpException(CultureInfo.InvariantCulture,
462-
"Unexpected type '{0}' passed to Compare. Supported values are either '{1}' or '{2}'.",
463-
typeof(T),
464-
typeof(TreeChanges),
465-
typeof(Patch));
466-
}
467-
468435
var comparer = WorkdirToIndex(repo);
469436

470437
if (expl 10000 icitPathsOptions != null)
@@ -479,7 +446,10 @@ internal virtual T Compare<T>(
479446

480447
using (DiffSafeHandle diff = BuildDiffList(null, null, comparer, diffOptions, paths, explicitPathsOptions, compareOptions))
481448
{
482-
return (T)builder(diff);
449+
using (var proxy = new DiffSafeHandleProxy(diff))
450+
{
451+
return new T().FromNative(proxy);
452+
}
483453
}
484454
}
485455

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
@@ -380,6 +380,8 @@
380380
<Compile Include="Core\GitCertificateSsh.cs" />
381381
<Compile Include="Core\GitCertificateSshType.cs" />
382382
<Compile Include="CertificateSsh.cs" />
383+
<Compile Include="IDiffResult.cs" />
384+
<Compile Include="DiffSafeHandleProxy.cs" />
383385
</ItemGroup>
384386
<ItemGroup>
385387
<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);
@@ -115,6 +100,25 @@ IEnumerator IEnumerable.GetEnumerator()
115100

116101
#endregion
117102

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

0 commit comments

Comments
 (0)
0