Skip to content

Commit 275afda

Browse files
committed
Merge pull request #946 from libgit2/dahlbyk/register-custom-filters
Custom filter Streams
2 parents b3878f1 + e070901 commit 275afda

21 files changed

+294
-185
lines changed
983 KB
Binary file not shown.
-981 KB
Binary file not shown.
746 KB
Binary file not shown.
-745 KB
Binary file not shown.

LibGit2Sharp.Tests/FilterFixture.cs

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using System.Collections.Generic;
33
using System.IO;
44
using System.Linq;
5-
using LibGit2Sharp.Core;
65
using LibGit2Sharp.Tests.TestHelpers;
76
using Xunit;
87

@@ -13,7 +12,7 @@ public class FilterFixture : BaseFixture
1312
private const int GitPassThrough = -30;
1413

1514
readonly Func<FilterSource, IEnumerable<string>, int> checkPassThrough = (source, attr) => GitPassThrough;
16-
readonly Func<GitBufReader, GitBufWriter, int> successCallback = (reader, writer) => 0;
15+
readonly Func<Stream, Stream, int> successCallback = (reader, writer) => 0;
1716
readonly Func<FilterSource, IEnumerable<string>, int> checkSuccess = (source, attr) => 0;
1817

1918
private const string FilterName = "the-filter";
@@ -106,7 +105,7 @@ public void ApplyCallbackMadeWhenCheckCallbackReturnsZero()
106105
{
107106
bool called = false;
108107

109-
Func<GitBufReader, GitBufWriter, int> applyCallback = (reader, writer) =>
108+
Func<Stream, Stream, int> applyCallback = (reader, writer) =>
110109
{
111110
called = true;
112111
return 0; //successCallback
@@ -131,7 +130,7 @@ public void ApplyCallbackNotMadeWhenCheckCallbackReturnsPassThrough()
131130
{
132131
bool called = false;
133132

134-
Func<GitBufReader, GitBufWriter, int> applyCallback = (reader, writer) =>
133+
Func<Stream, Stream, int> applyCallback = (reader, writer) =>
135134
{
136135
called = true;
137136
return 0;
@@ -271,7 +270,7 @@ public void WhenStagingFileApplyIsCalledWithCleanForCorrectPath()
271270
string repoPath = InitNewRepository();
272271
bool called = false;
273272

274-
Func<GitBufReader, GitBufWriter, int> clean = (reader, writer) =>
273+
Func<Stream, Stream, int> clean = (reader, writer) =>
275274
{
276275
called = true;
277276
return GitPassThrough;
@@ -297,7 +296,7 @@ public void CleanFilterWritesOutputToObjectTree()
297296

298297
string repoPath = InitNewRepository();
299298

300-
Func<GitBufReader, GitBufWriter, int> cleanCallback = SubstitutionCipherFilter.RotateByThirteenPlaces;
299+
Func<Stream, Stream, int> cleanCallback = SubstitutionCipherFilter.RotateByThirteenPlaces;
301300

302301
var filter = new FakeFilter(FilterName + 16, attributes, checkSuccess, cleanCallback);
303302

@@ -327,7 +326,7 @@ public void WhenCheckingOutAFileFileSmudgeWritesCorrectFileToWorkingDirectory()
327326
const string branchName = "branch";
328327
string repoPath = InitNewRepository();
329328

330-
Func<GitBufReader, GitBufWriter, int> smudgeCallback = SubstitutionCipherFilter.RotateByThirteenPlaces;
329+
Func<Stream, Stream, int> smudgeCallback = SubstitutionCipherFilter.RotateByThirteenPlaces;
331330

332331
var filter = new FakeFilter(FilterName + 17, attributes, checkSuccess, null, smudgeCallback);
333332
GlobalSettings.RegisterFilter(filter);
@@ -341,6 +340,54 @@ public void WhenCheckingOutAFileFileSmudgeWritesCorrectFileToWorkingDirectory()
341340
GlobalSettings.DeregisterFilter(filter.Name);
342341
}
343342

343+
[Fact]
344+
public void FilterStreamsAreCoherent()
345+
{
346+
string repoPath = InitNewRepository();
347+
348+
bool? inputCanWrite = null, inputCanRead = null, inputCanSeek = null;
349+
bool? outputCanWrite = null, outputCanRead = null, outputCanSeek = null;
350+
351+
Func<Stream, Stream, int> assertor = (input, output) =>
352+
{
353+
inputCanRead = input.CanRead;
354+
inputCanWrite = input.CanWrite;
355+
inputCanSeek = input.CanSeek;
356+
357+
outputCanRead = output.CanRead;
358+
outputCanWrite = output.CanWrite;
359+
outputCanSeek = output.CanSeek;
360+
361+
return GitPassThrough;
362+
};
363+
364+
var filter = new FakeFilter(FilterName + 18, attributes, checkSuccess, assertor, assertor);
365+
366+
GlobalSettings.RegisterFilter(filter);
367+
368+
using (var repo = CreateTestRepository(repoPath))
369+
{
370+
StageNewFile(repo);
371+
}
372+
373+
GlobalSettings.DeregisterFilter(filter.Name);
374+
375+
Assert.True(inputCanRead.HasValue);
376+
Assert.True(inputCanWrite.HasValue);
377+
Assert.True(inputCanSeek.HasValue);
378+
Assert.True(outputCanRead.HasValue);
379+
Assert.True(outputCanWrite.HasValue);
380+
Assert.True(outputCanSeek.HasValue);
381+
382+
Assert.True(inputCanRead.Value);
383+
Assert.False(inputCanWrite.Value);
384+
Assert.False(inputCanSeek.Value);
385+
386+
Assert.False(outputCanRead.Value);
387+
Assert.True(outputCanWrite.Value);
388+
Assert.False(outputCanSeek.Value);
389+
}
390+
344391
private FileInfo CheckoutFileForSmudge(string repoPath, string branchName, string content)
345392
{
346393
FileInfo expectedPath;
@@ -394,14 +441,14 @@ public EmptyFilter(string name, IEnumerable<string> attributes)
394441
class FakeFilter : Filter
395442
{
396443
private readonly Func<FilterSource, IEnumerable<string>, int> checkCallBack;
397-
private readonly Func<GitBufReader, GitBufWriter, int> cleanCallback;
398-
private readonly Func<GitBufReader, GitBufWriter, int> smudgeCallback;
444+
private readonly Func<Stream, Stream, int> cleanCallback;
445+
private readonly Func<Stream, Stream, int> smudgeCallback;
399446
private readonly Func<int> initCallback;
400447

401448
public FakeFilter(string name, IEnumerable<string> attributes,
402449
Func<FilterSource, IEnumerable<string>, int> checkCallBack = null,
403-
Func<GitBufReader, GitBufWriter, int> cleanCallback = null,
404-
Func<GitBufReader, GitBufWriter, int> smudgeCallback = null,
450+
Func<Stream, Stream, int> cleanCallback = null,
451+
Func<Stream, Stream, int> smudgeCallback = null,
405452
Func<int> initCallback = null)
406453
: base(name, attributes)
407454
{
@@ -416,12 +463,12 @@ protected override int Check(IEnumerable<string> attributes, FilterSource filter
416463
return checkCallBack != null ? checkCallBack(filterSource, attributes) : base.Check(attributes, filterSource);
417464
}
418465

419-
protected override int Clean(string path, GitBufReader input, GitBufWriter output)
466+
protected override int Clean(string path, Stream input, Stream output)
420467
{
421468
return cleanCallback != null ? cleanCallback(input, output) : base.Clean(path, input, output);
422469
}
423470

424-
protected override int Smudge(string path, GitBufReader input, GitBufWriter output)
471+
protected override int Smudge(string path, Stream input, Stream output)
425472
{
426473
return smudgeCallback != null ? smudgeCallback(input, output) : base.Smudge(path, input, output);
427474
}

LibGit2Sharp.Tests/SubstitutionCipherFilterFixture.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,4 @@ private static Blob CommitOnBranchAndReturnDatabaseBlob(Repository repo, string
9696
return blob;
9797
}
9898
}
99-
}
99+
}
Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System.Collections.Generic;
2+
using System.IO;
23
using System.Text;
3-
using LibGit2Sharp.Core;
44

55
namespace LibGit2Sharp.Tests.TestHelpers
66
{
@@ -21,34 +21,41 @@ protected override int Check(IEnumerable<string> attributes, FilterSource filter
2121
return base.Check(attributes, filterSource);
2222
}
2323

24-
protected override int Clean(string path, GitBufReader input, GitBufWriter output)
24+
protected override int Clean(string path, Stream input, Stream output)
2525
{
2626
CleanCalledCount++;
2727
return RotateByThirteenPlaces(input, output);
2828
}
2929

30-
protected override int Smudge(string path, GitBufReader input, GitBufWriter output)
30+
protected override int Smudge(string path, Stream input, Stream output)
3131
{
3232
SmudgeCalledCount++;
3333
return RotateByThirteenPlaces(input, output);
3434
}
3535

36-
public static int RotateByThirteenPlaces(GitBufReader input, GitBufWriter output)
36+
public static int RotateByThirteenPlaces(Stream input, Stream output)
3737
{
38-
var inputString = Encoding.UTF8.GetString(input.ReadAll());
39-
char[] array = inputString.ToCharArray();
40-
char value;
41-
for (int i = 0; i < inputString.Length; i++)
38+
39+
using (var streamReader = new StreamReader(input, Encoding.UTF8))
4240
{
43-
value = inputString[i];
44-
if ((value >= 'a' && value <= 'm') || (value >= 'A' && value <= 'M'))
45-
array[i] = (char)(value + 13);
46-
else if ((value >= 'n' && value <= 'z') || (value >= 'N' && value <= 'Z'))
47-
array[i] = (char)(value - 13);
41+
var inputString = streamReader.ReadToEnd();
42+
char[] array = inputString.ToCharArray();
43+
for (int i = 0; i < inputString.Length; i++)
44+
{
45+
var value = inputString[i];
46+
if ((value >= 'a' && value <= 'm') || (value >= 'A' && value <= 'M'))
47+
array[i] = (char)(value + 13);
48+
else if ((value >= 'n' && value <= 'z') || (value >= 'N' && value <= 'Z'))
49+
array[i] = (char)(value - 13);
50+
}
51+
52+
using (var streamWriter = new StreamWriter(output, Encoding.UTF8))
53+
{
54+
streamWriter.Write(array);
55+
}
56+
57+
return 0;
4858
}
49-
var outputString = new string(array);
50-
output.Write(Encoding.UTF8.GetBytes(outputString));
51-
return 0;
5259
}
5360
}
54-
}
61+
}

LibGit2Sharp/Core/GitBufReadStream.cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using System;
2+
using System.Globalization;
3+
using System.IO;
4+
using LibGit2Sharp.Core.Handles;
5+
6+
namespace LibGit2Sharp.Core
7+
{
8+
/// <summary>
9+
/// Reads data from a <see cref="GitBuf"/> pointer
10+
/// </summary>
11+
internal class GitBufReadStream : UnmanagedMemoryStream
12+
{
13+
internal GitBufReadStream(IntPtr gitBufPointer)
14+
: this(gitBufPointer.MarshalAs<GitBuf>())
15+
{ }
16+
17+
private unsafe GitBufReadStream(GitBuf gitBuf)
18+
: base((byte*)gitBuf.ptr,
19+
ConvertToLong(gitBuf.size),
20+
ConvertToLong(gitBuf.asize),
21+
FileAccess.Read)
22+
{ }
23+
24+
private static long ConvertToLong(UIntPtr len)
25+
{
26+
if (len.ToUInt64() > long.MaxValue)
27+
{
28+
throw new InvalidOperationException(
29+
string.Format(
30+
CultureInfo.InvariantCulture,
31+
"Provided length ({0}) exceeds long.MaxValue ({1}).",
32+
len.ToUInt64(), long.MaxValue));
33+
}
34+
35+
return (long)len.ToUInt64();
36+
}
37+
38+
public override long Seek(long offset, SeekOrigin loc)
39+
{
40+
throw new NotSupportedException();
41+
}
42+
43+
public override bool CanSeek
44+
{
45+
get { return false; }
46+
}
47+
}
48+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
using System;
2+
using System.IO;
3+
using LibGit2Sharp.Core.Handles;
4+
5+
namespace LibGit2Sharp.Core
6+
{
7+
internal class GitBufWriteStream : Stream
8+
{
9+
private readonly IntPtr gitBufPointer;
10+
11+
internal GitBufWriteStream(IntPtr gitBufPointer)
12+
{
13+
this.gitBufPointer = gitBufPointer;
14+
15+
//Preallocate the buffer
16+
Proxy.git_buf_grow(gitBufPointer, 1024);
17+
}
18+
19+
public override void Flush()
20+
{
21+
}
22+
23+
public override long Seek(long offset, SeekOrigin origin)
24+
{
25+
throw new NotSupportedException();
26+
}
27+
28+
public override void SetLength(long value)
29+
{
30+
throw new NotSupportedException();
31+
}
32+
33+
public override int Read(byte[] buffer, int offset, int count)
34+
{
35+
throw new NotSupportedException();
36+
}
37+
38+
public override void Write(byte[] buffer, int offset, int count)
39+
{
40+
AutoGrowBuffer(count);
41+
42+
Proxy.git_buf_put(gitBufPointer, buffer, offset, count);
43+
}
44+
45+
private void AutoGrowBuffer(int count)
46+
{
47+
var gitBuf = gitBufPointer.MarshalAs<GitBuf>();
48+
49+
var asize = (uint)gitBuf.asize;
50+
var size = (uint)gitBuf.size;
51+
52+
var isBufferLargeEnoughToHoldTheNewData = (asize - size) > count;
53+
var filledBufferPercentage = (100.0 * size / asize);
54+
55+
if (isBufferLargeEnoughToHoldTheNewData && filledBufferPercentage < 90)
56+
{
57+
return;
58+
}
59+
60+
var targetSize = (uint)(1.5 * (asize + count));
61+
62+
Proxy.git_buf_grow(gitBufPointer, targetSize);
63+
}
64+
65+
public override bool CanRead
66+
{
67+
get { return false; }
68+
}
69+
70+
public override bool CanSeek
71+
{
72+
get { return false; }
73+
}
74+
75+
public override bool CanWrite
76+
{
77+
get { return true; }
78+
}
79+
80+
public override long Length
81+
{
82+
get { throw new NotSupportedException(); }
83+
}
84+
85+
public override long Position
86+
{
87+
get { throw new NotSupportedException(); }
88+
set { throw new NotSupportedException(); }
89+
}
90+
}
91+
}

LibGit2Sharp/Core/NativeDllName.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ namespace LibGit2Sharp.Core
22
{
33
internal static class NativeDllName
44
{
5-
public const string Name = "git2-e0902fb";
5+
public const string Name = "git2-a2012c4";
66
}
77
}

LibGit2Sharp/Core/NativeMethods.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,10 +219,10 @@ internal static extern int git_branch_remote_name(
219219
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string canonical_branch_name);
220220

221221
[DllImport(libgit2)]
222-
internal static extern int git_buf_grow(GitBuf buffer, UIntPtr targetSize);
222+
internal static extern int git_buf_grow(IntPtr buffer, UIntPtr targetSize);
223223

224224
[DllImport(libgit2)]
225-
internal static extern int git_buf_set(GitBuf buffer, IntPtr data, UIntPtr targetSize);
225+
internal static extern int git_buf_put(IntPtr buffer, IntPtr data, UIntPtr len);
226226

227227
[DllImport(libgit2)]
228228
internal static extern int git_remote_rename(

0 commit comments

Comments
 (0)