Skip to content

Commit e734df5

Browse files
committed
Merge pull request #1180 from libgit2/typesafe-compare
Initial change to type-safe Diff.Compare
2 parents b279955 + 8a673bb commit e734df5

File tree

8 files changed

+58
-69
lines changed

8 files changed

+58
-69
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-
publicvoidCallingCompareWithAnUnsupportedGenericParamThrows()
1128-
{
1129-
varpath=SandboxStandardTestRepoGitDir();
1130-
using(varrepo=newRepository(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
publicvoidUsingPatienceAlgorithmCompareOptionProducesPatienceDiff()
11391128
{

‎LibGit2Sharp.Tests/MetaFixture.cs‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public class MetaFixture
1717
{
1818
privatestaticreadonlyHashSet<Type>explicitOnlyInterfaces=newHashSet<Type>
1919
{
20-
typeof(IBelongToARepository),
20+
typeof(IBelongToARepository),typeof(IDiffResult),
2121
};
2222

2323
[Fact]
@@ -401,6 +401,20 @@ where method.IsDefined(typeof(ExtensionAttribute), false)
401401
selectmethod;
402402
returnquery;
403403
}
404+
405+
[Fact]
406+
publicvoidAllIDiffResultsAreInChangesBuilder()
407+
{
408+
vardiff=typeof(Diff).GetField("ChangesBuilders",BindingFlags.NonPublic|BindingFlags.Static);
409+
varchangesBuilders=(System.Collections.IDictionary)diff.GetValue(null);
410+
411+
IEnumerable<Type>diffResults=typeof(Diff).Assembly.GetExportedTypes()
412+
.Where(type =>type.GetInterface("IDiffResult")!=null);
413+
414+
varnonBuilderTypes=diffResults.Where(diffResult =>!changesBuilders.Contains(diffResult));
415+
Assert.False(nonBuilderTypes.Any(),"Classes which implement IDiffResult but are not registered under ChangesBuilders in Diff:"+Environment.NewLine+
416+
string.Join(Environment.NewLine,nonBuilderTypes.Select(type =>type.FullName)));
417+
}
404418
}
405419

406420
internalstaticclassTypeExtensions

‎LibGit2Sharp/Diff.cs‎

Lines changed: 34 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,21 @@ private static IDictionary<DiffTargets, Func<Repository, TreeComparisonHandleRet
102102
{typeof(PatchStats), diff =>newPatchStats(diff)},
103103
};
104104

105+
106+
privatestaticTBuildDiffResult<T>(DiffSafeHandlediff)whereT:class,IDiffResult
107+
{
108+
Func<DiffSafeHandle,object>builder;
109+
110+
if(!ChangesBuilders.TryGetValue(typeof(T),outbuilder))
111+
{
112+
thrownewLibGit2SharpException(CultureInfo.InvariantCulture,
113+
"User-defined types passed to Compare are not supported. Supported values are:{0}",
114+
string.Join(", ",ChangesBuilders.Keys.Select(x =>x.Name)));
115+
}
116+
117+
return(T)builder(diff);
118+
}
119+
105120
/// <summary>
106121
/// Show changes between two <see cref="Blob"/>s.
107122
/// </summary>
@@ -134,7 +149,7 @@ public virtual ContentChanges Compare(Blob oldBlob, Blob newBlob, CompareOptions
134149
/// <param name="oldTree">The <see cref="Tree"/> you want to compare from.</param>
135150
/// <param name="newTree">The <see cref="Tree"/> you want to compare to.</param>
136151
/// <returns>A <see cref="TreeChanges"/> containing the changes between the <paramref name="oldTree"/> and the <paramref name="newTree"/>.</returns>
137-
publicvirtualTCompare<T>(TreeoldTree,TreenewTree)whereT:class
152+
publicvirtualTCompare<T>(TreeoldTree,TreenewTree)whereT:class,IDiffResult
138153
{
139154
returnCompare<T>(oldTree,newTree,null,null,null);
140155
}
@@ -146,7 +161,7 @@ public virtual T Compare<T>(Tree oldTree, Tree newTree) where T : class
146161
/// <param name="newTree">The <see cref="Tree"/> you want to compare to.</param>
147162
/// <param name="paths">The list of paths (either files or directories) that should be compared.</param>
148163
/// <returns>A <see cref="TreeChanges"/> containing the changes between the <paramref name="oldTree"/> and the <paramref name="newTree"/>.</returns>
149-
publicvirtualTCompare<T>(TreeoldTree,TreenewTree,IEnumerable<string>paths)whereT:class
164+
publicvirtualTCompare<T>(TreeoldTree,TreenewTree,IEnumerable<string>paths)whereT:class,IDiffResult
150165
{
151166
returnCompare<T>(oldTree,newTree,paths,null,null);
152167
}
@@ -163,7 +178,7 @@ public virtual T Compare<T>(Tree oldTree, Tree newTree, IEnumerable<string> path
163178
/// </param>
164179
/// <returns>A <see cref="TreeChanges"/> containing the changes between the <paramref name="oldTree"/> and the <paramref name="newTree"/>.</returns>
165180
publicvirtualTCompare<T>(TreeoldTree,TreenewTree,IEnumerable<string>paths,
166-
ExplicitPathsOptionsexplicitPathsOptions)whereT:class
181+
ExplicitPathsOptionsexplicitPathsOptions)whereT:class,IDiffResult
167182
{
168183
returnCompare<T>(oldTree,newTree,paths,explicitPathsOptions,null);
169184
}
@@ -176,7 +191,7 @@ public virtual T Compare<T>(Tree oldTree, Tree newTree, IEnumerable<string> path
176191
/// <param name="paths">The list of paths (either files or directories) that should be compared.</param>
177192
/// <param name="compareOptions">Additional options to define patch generation behavior.</param>
178193
/// <returns>A <see cref="TreeChanges"/> containing the changes between the <paramref name="oldTree"/> and the <paramref name="newTree"/>.</returns>
179-
publicvirtualTCompare<T>(TreeoldTree,TreenewTree,IEnumerable<string>paths,CompareOptionscompareOptions)whereT:class
194+
publicvirtualTCompare<T>(TreeoldTree,TreenewTree,IEnumerable<string>paths,CompareOptionscompareOptions)whereT:class,IDiffResult
180195
{
181196
returnCompare<T>(oldTree,newTree,paths,null,compareOptions);
182197
}
@@ -188,7 +203,7 @@ public virtual T Compare<T>(Tree oldTree, Tree newTree, IEnumerable<string> path
188203
/// <param name="newTree">The <see cref="Tree"/> you want to compare to.</param>
189204
/// <param name="compareOptions">Additional options to define patch generation behavior.</param>
190205
/// <returns>A <see cref="TreeChanges"/> containing the changes between the <paramref name="oldTree"/> and the <paramref name="newTree"/>.</returns>
191-
publicvirtualTCompare<T>(TreeoldTree,TreenewTree,CompareOptionscompareOptions)whereT:class
206+
publicvirtualTCompare<T>(TreeoldTree,TreenewTree,CompareOptionscompareOptions)whereT:class,IDiffResult
192207
{
193208
returnCompare<T>(oldTree,newTree,null,null,compareOptions);
194209
}
@@ -206,19 +221,8 @@ public virtual T Compare<T>(Tree oldTree, Tree newTree, CompareOptions compareOp
206221
/// <param name="compareOptions">Additional options to define patch generation behavior.</param>
207222
/// <returns>A <see cref="TreeChanges"/> containing the changes between the <paramref name="oldTree"/> and the <paramref name="newTree"/>.</returns>
208223
publicvirtualTCompare<T>(TreeoldTree,TreenewTree,IEnumerable<string>paths,ExplicitPathsOptionsexplicitPathsOptions,
209-
CompareOptionscompareOptions)whereT:class
224+
CompareOptionscompareOptions)whereT:class,IDiffResult
210225
{
211-
Func<DiffSafeHandle,object>builder;
212-
213-
if(!ChangesBuilders.TryGetValue(typeof(T),outbuilder))
214-
{
215-
thrownewLibGit2SharpException(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-
}
221-
222226
varcomparer=TreeToTree(repo);
223227
ObjectIdoldTreeId=oldTree!=null?oldTree.Id:null;
224228
ObjectIdnewTreeId=newTree!=null?newTree.Id:null;
@@ -236,7 +240,7 @@ public virtual T Compare<T>(Tree oldTree, Tree newTree, IEnumerable<string> path
236240

237241
using(DiffSafeHandlediff=BuildDiffList(oldTreeId,newTreeId,comparer,diffOptions,paths,explicitPathsOptions,compareOptions))
238242
{
239-
return(T)builder(diff);
243+
returnBuildDiffResult<T>(diff);
240244
}
241245
}
242246

@@ -252,7 +256,7 @@ public virtual T Compare<T>(Tree oldTree, Tree newTree, IEnumerable<string> path
252256
/// <typeparam name="T">Can be either a <see cref="TreeChanges"/> if you are only interested in the list of files modified, added, ..., or
253257
/// a <see cref="Patch"/> if you want the actual patch content for the whole diff and for individual files.</typeparam>
254258
/// <returns>A <typeparamref name="T"/> containing the changes between the <see cref="Tree"/> and the selected target.</returns>
255-
publicvirtualTCompare<T>(TreeoldTree,DiffTargetsdiffTargets)whereT:class
259+
publicvirtualTCompare<T>(TreeoldTree,DiffTargetsdiffTargets)whereT:class,IDiffResult
256260
{
257261
returnCompare<T>(oldTree,diffTargets,null,null,null);
258262
}
@@ -270,7 +274,7 @@ public virtual T Compare<T>(Tree oldTree, DiffTargets diffTargets) where T : cla
270274
/// <typeparam name="T">Can be either a <see cref="TreeChanges"/> if you are only interested in the list of files modified, added, ..., or
271275
/// a <see cref="Patch"/> if you want the actual patch content for the whole diff and for individual files.</typeparam>
272276
/// <returns>A <typeparamref name="T"/> containing the changes between the <see cref="Tree"/> and the selected target.</returns>
273-
publicvirtualTCompare<T>(TreeoldTree,DiffTargetsdiffTargets,IEnumerable<string>paths)whereT:class
277+
publicvirtualTCompare<T>(TreeoldTree,DiffTargetsdiffTargets,IEnumerable<string>paths)whereT:class,IDiffResult
274278
{
275279
returnCompare<T>(oldTree,diffTargets,paths,null,null);
276280
}
@@ -293,7 +297,7 @@ public virtual T Compare<T>(Tree oldTree, DiffTargets diffTargets, IEnumerable<s
293297
/// a <see cref="Patch"/> if you want the actual patch content for the whole diff and for individual files.</typeparam>
294298
/// <returns>A <typeparamref name="T"/> containing the changes between the <see cref="Tree"/> and the selected target.</returns>
295299
publicvirtualTCompare<T>(TreeoldTree,DiffTargetsdiffTargets,IEnumerable<string>paths,
296-
ExplicitPathsOptionsexplicitPathsOptions)whereT:class
300+
ExplicitPathsOptionsexplicitPathsOptions)whereT:class,IDiffResult
297301
{
298302
returnCompare<T>(oldTree,diffTargets,paths,explicitPathsOptions,null);
299303
}
@@ -317,19 +321,8 @@ public virtual T Compare<T>(Tree oldTree, DiffTargets diffTargets, IEnumerable<s
317321
/// a <see cref="Patch"/> if you want the actual patch content for the whole diff and for individual files.</typeparam>
318322
/// <returns>A <typeparamref name="T"/> containing the changes between the <see cref="Tree"/> and the selected target.</returns>
319323
publicvirtualTCompare<T>(TreeoldTree,DiffTargetsdiffTargets,IEnumerable<string>paths,
320-
ExplicitPathsOptionsexplicitPathsOptions,CompareOptionscompareOptions)whereT:class
324+
ExplicitPathsOptionsexplicitPathsOptions,CompareOptionscompareOptions)whereT:class,IDiffResult
321325
{
322-
Func<DiffSafeHandle,object>builder;
323-
324-
if(!ChangesBuilders.TryGetValue(typeof(T),outbuilder))
325-
{
326-
thrownewLibGit2SharpException(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-
333326
varcomparer=HandleRetrieverDispatcher[diffTargets](repo);
334327
ObjectIdoldTreeId=oldTree!=null?oldTree.Id:null;
335328

@@ -349,7 +342,7 @@ public virtual T Compare<T>(Tree oldTree, DiffTargets diffTargets, IEnumerable<s
349342

350343
using(DiffSafeHandlediff=BuildDiffList(oldTreeId,null,comparer,diffOptions,paths,explicitPathsOptions,compareOptions))
351344
{
352-
return(T)builder(diff);
345+
returnBuildDiffResult<T>(diff);
353346
}
354347
}
355348

@@ -363,7 +356,7 @@ public virtual T Compare<T>(Tree oldTree, DiffTargets diffTargets, IEnumerable<s
363356
/// <typeparam name="T">Can be either a <see cref="TreeChanges"/> if you are only interested in the list of files modified, added, ..., or
364357
/// a <see cref="Patch"/> if you want the actual patch content for the whole diff and for individual files.</typeparam>
365358
/// <returns>A <typeparamref name="T"/> containing the changes between the working directory and the index.</returns>
366-
publicvirtualTCompare<T>()whereT:class
359+
publicvirtualTCompare<T>()whereT:class,IDiffResult
367360
{
368361
returnCompare<T>(DiffModifiers.None);
369362
}
@@ -379,7 +372,7 @@ public virtual T Compare<T>() where T : class
379372
/// <typeparam name="T">Can be either a <see cref="TreeChanges"/> if you are only interested in the list of files modified, added, ..., or
380373
/// a <see cref="Patch"/> if you want the actual patch content for the whole diff and for individual files.</typeparam>
381374
/// <returns>A <typeparamref name="T"/> containing the changes between the working directory and the index.</returns>
382-
publicvirtualTCompare<T>(IEnumerable<string>paths)whereT:class
375+
publicvirtualTCompare<T>(IEnumerable<string>paths)whereT:class,IDiffResult
383376
{
384377
returnCompare<T>(DiffModifiers.None,paths);
385378
}
@@ -396,7 +389,7 @@ public virtual T Compare<T>(IEnumerable<string> paths) where T : class
396389
/// <typeparam name="T">Can be either a <see cref="TreeChanges"/> if you are only interested in the list of files modified, added, ..., or
397390
/// a <see cref="Patch"/> if you want the actual patch content for the whole diff and for individual files.</typeparam>
398391
/// <returns>A <typeparamref name="T"/> containing the changes between the working directory and the index.</returns>
399-
publicvirtualTCompare<T>(IEnumerable<string>paths,boolincludeUntracked)whereT:class
392+
publicvirtualTCompare<T>(IEnumerable<string>paths,boolincludeUntracked)whereT:class,IDiffResult
400393
{
401394
returnCompare<T>(includeUntracked?DiffModifiers.IncludeUntracked:DiffModifiers.None,paths);
402395
}
@@ -417,7 +410,7 @@ public virtual T Compare<T>(IEnumerable<string> paths, bool includeUntracked) wh
417410
/// <typeparam name="T">Can be either a <see cref="TreeChanges"/> if you are only interested in the list of files modified, added, ..., or
418411
/// a <see cref="Patch"/> if you want the actual patch content for the whole diff and for individual files.</typeparam>
419412
/// <returns>A <typeparamref name="T"/> containing the changes between the working directory and the index.</returns>
420-
publicvirtualTCompare<T>(IEnumerable<string>paths,boolincludeUntracked,ExplicitPathsOptionsexplicitPathsOptions)whereT:class
413+
publicvirtualTCompare<T>(IEnumerable<string>paths,boolincludeUntracked,ExplicitPathsOptionsexplicitPathsOptions)whereT:class,IDiffResult
421414
{
422415
returnCompare<T>(includeUntracked?DiffModifiers.IncludeUntracked:DiffModifiers.None,paths,explicitPathsOptions);
423416
}
@@ -443,7 +436,7 @@ public virtual T Compare<T>(
443436
IEnumerable<string>paths,
444437
boolincludeUntracked,
445438
ExplicitPathsOptionsexplicitPathsOptions,
446-
CompareOptionscompareOptions)whereT:class
439+
CompareOptionscompareOptions)whereT:class,IDiffResult
447440
{
448441
returnCompare<T>(includeUntracked?DiffModifiers.IncludeUntracked:DiffModifiers.None,paths,explicitPathsOptions,compareOptions);
449442
}
@@ -452,19 +445,8 @@ internal virtual T Compare<T>(
452445
DiffModifiersdiffOptions,
453446
IEnumerable<string>paths=null,
454447
ExplicitPathsOptionsexplicitPathsOptions=null,
455-
CompareOptionscompareOptions=null)whereT:class
448+
CompareOptionscompareOptions=null)whereT:class,IDiffResult
456449
{
457-
Func<DiffSafeHandle,object>builder;
458-
459-
if(!ChangesBuilders.TryGetValue(typeof(T),outbuilder))
460-
{
461-
thrownewLibGit2SharpException(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-
468450
varcomparer=WorkdirToIndex(repo);
469451

470452
if(explicitPathsOptions!=null)
@@ -479,7 +461,7 @@ internal virtual T Compare<T>(
479461

480462
using(DiffSafeHandlediff=BuildDiffList(null,null,comparer,diffOptions,paths,explicitPathsOptions,compareOptions))
481463
{
482-
return(T)builder(diff);
464+
returnBuildDiffResult<T>(diff);
483465
}
484466
}
485467

‎LibGit2Sharp/IDiffResult.cs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
namespaceLibGit2Sharp
2+
{
3+
publicinterfaceIDiffResult
4+
{}
5+
}

‎LibGit2Sharp/LibGit2Sharp.csproj‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,7 @@
380380
<CompileInclude="Core\GitCertificateSsh.cs" />
381381
<CompileInclude="Core\GitCertificateSshType.cs" />
382382
<CompileInclude="CertificateSsh.cs" />
383+
<CompileInclude="IDiffResult.cs" />
383384
</ItemGroup>
384385
<ItemGroup>
385386
<CodeAnalysisDictionaryInclude="CustomDictionary.xml" />

‎LibGit2Sharp/Patch.cs‎

Lines changed: 1 addition & 2 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-
publicclassPatch:IEnumerable<PatchEntryChanges>
19+
publicclassPatch:IEnumerable<PatchEntryChanges>,IDiffResult
2020
{
2121
privatereadonlyStringBuilderfullPatchBuilder=newStringBuilder();
2222

@@ -41,7 +41,6 @@ internal Patch(DiffSafeHandle diff)
4141
AddFileChange(delta);
4242
Proxy.git_patch_print(patch,PrintCallBack);
4343
}
44-
4544
}
4645
}
4746

‎LibGit2Sharp/PatchStats.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ 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-
publicclassPatchStats:IEnumerable<ContentChangeStats>
16+
publicclassPatchStats:IEnumerable<ContentChangeStats>,IDiffResult
1717
{
1818
privatereadonlyIDictionary<FilePath,ContentChangeStats>changes=newDictionary<FilePath,ContentChangeStats>();
1919
privatereadonlyinttotalLinesAdded;

‎LibGit2Sharp/TreeChanges.cs‎

Lines changed: 1 addition & 2 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-
publicclassTreeChanges:IEnumerable<TreeEntryChanges>
18+
publicclassTreeChanges:IEnumerable<TreeEntryChanges>,IDiffResult
1919
{
2020
privatereadonlyList<TreeEntryChanges>changes=newList<TreeEntryChanges>();
2121
privatereadonlyList<TreeEntryChanges>added=newList<TreeEntryChanges>();
@@ -91,7 +91,6 @@ IEnumerator IEnumerable.GetEnumerator()
9191

9292
#endregion
9393

94-
9594
/// <summary>
9695
/// List of <see cref="TreeEntryChanges"/> that have been been added.
9796
/// </summary>

0 commit comments

Comments
(0)