Skip to content

Commit 7b8e982

Browse files
committed
Merge pull request #1183 from AMSadek/AMSadek/packbuilder
Exposing Packbuilder capabilities of libgit2
2 parents 9f334aa + 8b5b890 commit 7b8e982

19 files changed

+621
-0
lines changed

LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
<Compile Include="FileHistoryFixture.cs" />
6565
<Compile Include="FilterFixture.cs" />
6666
<Compile Include="GlobalSettingsFixture.cs" />
67+
<Compile Include="PackBuilderFixture.cs" />
6768
<Compile Include="PatchStatsFixture.cs" />
6869
<Compile Include="RebaseFixture.cs" />
6970
<Compile Include="RefSpecFixture.cs" />
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
using System;
2+
using System.IO;
3+
using System.Linq;
4+
using LibGit2Sharp.Tests.TestHelpers;
5+
using Xunit;
6+
7+
namespace LibGit2Sharp.Tests
8+
{
9+
public class PackBuilderFixture : BaseFixture
10+
{
11+
[Fact]
12+
public void TestDefaultPackDelegate()
13+
{
14+
TestIfSameRepoAfterPacking(null);
15+
}
16+
17+
[Fact]
18+
public void TestCommitsPerBranchPackDelegate()
19+
{
20+
TestIfSameRepoAfterPacking(AddingObjectIdsTestDelegate);
21+
}
22+
23+
[Fact]
24+
public void TestCommitsPerBranchIdsPackDelegate()
25+
{
26+
TestIfSameRepoAfterPacking(AddingObjectsTestDelegate);
27+
}
28+
29+
internal void TestIfSameRepoAfterPacking(Action<IRepository, PackBuilder> packDelegate)
30+
{
31+
// read a repo
32+
// pack with the provided action
33+
// write the pack file in a mirror repo
34+
// read new repo
35+
// compare
36+
37+
string orgRepoPath = SandboxPackBuilderTestRepo();
38+
string mrrRepoPath = SandboxPackBuilderTestRepo();
39+
string mrrRepoPackDirPath = Path.Combine(mrrRepoPath + "/.git/objects");
40+
41+
DirectoryHelper.DeleteDirectory(mrrRepoPackDirPath);
42+
Directory.CreateDirectory(mrrRepoPackDirPath + "/pack");
43+
44+
PackBuilderOptions packBuilderOptions = new PackBuilderOptions(mrrRepoPackDirPath + "/pack");
45+
46+
using (Repository orgRepo = new Repository(orgRepoPath))
47+
{
48+
PackBuilderResults results;
49+
if (packDelegate != null)
50+
results = orgRepo.ObjectDatabase.Pack(packBuilderOptions, b => packDelegate(orgRepo, b));
51+
else
52+
results = orgRepo.ObjectDatabase.Pack(packBuilderOptions);
53+
54+
// written objects count is the same as in objects database
55+
Assert.Equal(orgRepo.ObjectDatabase.Count(), results.WrittenObjectsCount);
56+
57+
// loading a repo from the written pack file.
58+
using (Repository mrrRepo = new Repository(mrrRepoPath))
59+
{
60+
// make sure the objects of the original repo are the same as the ones in the mirror repo
61+
// doing that by making sure the count is the same, and the set difference is empty
62+
Assert.True(mrrRepo.ObjectDatabase.Count() == orgRepo.ObjectDatabase.Count() && !mrrRepo.ObjectDatabase.Except(orgRepo.ObjectDatabase).Any());
63+
64+
Assert.Equal(orgRepo.Commits.Count(), mrrRepo.Commits.Count());
65+
Assert.Equal(orgRepo.Branches.Count(), mrrRepo.Branches.Count());
66+
Assert.Equal(orgRepo.Refs.Count(), mrrRepo.Refs.Count());
67+
}
68+
}
69+
}
70+
71+
internal void AddingObjectIdsTestDelegate(IRepository repo, PackBuilder builder)
72+
{
73+
foreach (Branch branch in repo.Branches)
74+
{
75+
foreach (Commit commit in branch.Commits)
76+
{
77+
builder.AddRecursively(commit.Id);
78+
}
79+
}
80+
81+
foreach (Tag tag in repo.Tags)
82+
{
83+
builder.Add(tag.Target.Id);
84+
}
85+
}
86+
87+
internal void AddingObjectsTestDelegate(IRepository repo, PackBuilder builder)
88+
{
89+
foreach (Branch branch in repo.Branches)
90+
{
91+
foreach (Commit commit in branch.Commits)
92+
{
93+
builder.AddRecursively(commit);
94+
}
95+
}
96+
97+
foreach (Tag tag in repo.Tags)
98+
{
99+
builder.Add(tag.Target);
100+
}
101+
}
102+
103+
[Fact]
104+
public void ExceptionIfPathDoesNotExist()
105+
{
106+
PackBuilderOptions pbo;
107+
108+
Assert.Throws<DirectoryNotFoundException>(() =>
109+
{
110+
pbo = new PackBuilderOptions("aaa");
111+
});
112+
}
113+
114+
[Fact]
115+
public void ExceptionIfPathEqualsNull()
116+
{
117+
PackBuilderOptions pbo;
118+
119+
Assert.Throws<ArgumentNullException>(() =>
120+
{
121+
pbo = new PackBuilderOptions(null);
122+
});
123+
}
124+
125+
[Fact]
126+
public void ExceptionIfOptionsEqualsNull()
127+
{
128+
string orgRepoPath = SandboxPackBuilderTestRepo();
129+
130+
using (Repository orgRepo = new Repository(orgRepoPath))
131+
{
132+
Assert.Throws<ArgumentNullException>(() =>
133+
{
134+
orgRepo.ObjectDatabase.Pack(null);
135+
});
136+
}
137+
}
138+
139+
[Fact]
140+
public void ExceptionIfBuildDelegateEqualsNull()
141+
{
142+
string orgRepoPath = SandboxPackBuilderTestRepo();
143+
PackBuilderOptions packBuilderOptions = new PackBuilderOptions(orgRepoPath);
144+
145+
using (Repository orgRepo = new Repository(orgRepoPath))
146+
{
147+
Assert.Throws<ArgumentNullException>(() =>
148+
{
149+
orgRepo.ObjectDatabase.Pack(packBuilderOptions, null);
150+
});
151+
}
152+
}
153+
154+
[Fact]
155+
public void ExceptionIfNegativeNumberOfThreads()
156+
{
157+
string orgRepoPath = SandboxPackBuilderTestRepo();
158+
PackBuilderOptions packBuilderOptions = new PackBuilderOptions(orgRepoPath);
159+
160+
Assert.Throws<ArgumentException>(() =>
161+
{
162+
packBuilderOptions.MaximumNumberOfThreads = -1;
163+
});
164+
}
165+
166+
[Fact]
167+
public void ExceptionIfAddNullObjectID()
168+
{
169+
string orgRepoPath = SandboxPackBuilderTestRepo();
170+
PackBuilderOptions packBuilderOptions = new PackBuilderOptions(orgRepoPath);
171+
172+
using (Repository orgRepo = new Repository(orgRepoPath))
173+
{
174+
Assert.Throws<ArgumentNullException>(() =>
175+
{
176+
orgRepo.ObjectDatabase.Pack(packBuilderOptions, builder =>
177+
{
178+
builder.Add(null);
179+
});
180+
});
181+
}
182+
}
183+
184+
[Fact]
185+
public void ExceptionIfAddRecursivelyNullObjectID()
186+
{
187+
string orgRepoPath = SandboxPackBuilderTestRepo();
188+
PackBuilderOptions packBuilderOptions = new PackBuilderOptions(orgRepoPath);
189+
190+
using (Repository orgRepo = new Repository(orgRepoPath))
191+
{
192+
Assert.Throws<ArgumentNullException>(() =>
193+
{
194+
orgRepo.ObjectDatabase.Pack(packBuilderOptions, builder =>
195+
{
196+
builder.AddRecursively(null);
197+
});
198+
});
199+
}
200+
}
201+
}
202+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ref: refs/heads/master
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[core]
2+
repositoryformatversion = 0
3+
filemode = false
4+
bare = false
5+
logallrefupdates = true
6+
symlinks = false
7+
ignorecase = true
8+
hideDotFiles = dotGitOnly
Binary file not shown.

LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/objects/87/2129051d644790636b416d1ef1ec830c5f6b90

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
x��I
2+
B1]��>��'��[����� ��o���U/�Z�n�i"���5�S�Q�hC��.��n��<I!UP�3w�WЎRfS�+U9l�Fu����\�����\�3rD��:����-��
3+
�:� �>=?
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
872129051d644790636b416d1ef1ec830c5f6b90
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Hello
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
World

LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ static BaseFixture()
4141
private static string SubmoduleTargetTestRepoWorkingDirPath { get; set; }
4242
private static string AssumeUnchangedRepoWorkingDirPath { get; set; }
4343
public static string SubmoduleSmallTestRepoWorkingDirPath { get; set; }
44+
public static string PackBuilderTestRepoPath { get; private set; }
4445

4546
public static DirectoryInfo ResourcesDirectory { get; private set; }
4647

@@ -74,6 +75,7 @@ private static void SetUpTestEnvironment()
7475
SubmoduleTargetTestRepoWorkingDirPath = Path.Combine(sourceRelativePath, "submodule_target_wd");
7576
AssumeUnchangedRepoWorkingDirPath = Path.Combine(sourceRelativePath, "assume_unchanged_wd");
7677
SubmoduleSmallTestRepoWorkingDirPath = Path.Combine(sourceRelativePath, "submodule_small_wd");
78+
PackBuilderTestRepoPath = Path.Combine(sourceRelativePath, "packbuilder_testrepo_wd");
7779

7880
CleanupTestReposOlderThan(TimeSpan.FromMinutes(15));
7981
}
@@ -174,6 +176,11 @@ public string SandboxSubmoduleSmallTestRepo()
174176
return path;
175177
}
176178

179+
protected string SandboxPackBuilderTestRepo()
180+
{
181+
return Sandbox(PackBuilderTestRepoPath);
182+
}
183+
177184
protected string Sandbox(string sourceDirectoryPath, params string[] additionalSourcePaths)
178185
{
179186
var scd = BuildSelfCleaningDirectory();
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace LibGit2Sharp.Core.Handles
2+
{
3+
internal class PackBuilderSafeHandle : SafeHandleBase
4+
{
5+
protected override bool ReleaseHandleImpl()
6+
{
7+
Proxy.git_packbuilder_free(handle);
8+
return true;
9+
}
10+
}
11+
}

LibGit2Sharp/Core/NativeMethods.cs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,51 @@ internal static extern int git_patch_line_stats(
938938
internal delegate int git_push_transfer_progress(uint current, uint total, UIntPtr bytes, IntPtr payload);
939939
internal delegate int git_packbuilder_progress(int stage, uint current, uint total, IntPtr payload);
940940

941+
[DllImport(libgit2)]
942+
internal static extern void git_packbuilder_free(IntPtr packbuilder);
943+
944+
[DllImport(libgit2)]
945+
internal static extern int git_packbuilder_insert(
946+
PackBuilderSafeHandle packbuilder,
947+
ref GitOid id,
948+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string name);
949+
950+
[DllImport(libgit2)]
951+
internal static extern int git_packbuilder_insert_commit(
952+
PackBuilderSafeHandle packbuilder,
953+
ref GitOid id);
954+
955+
[DllImport(libgit2)]
956+
internal static extern int git_packbuilder_insert_recur(
957+
PackBuilderSafeHandle packbuilder,
958+
ref GitOid id,
959+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string name);
960+
961+
[DllImport(libgit2)]
962+
internal static extern int git_packbuilder_insert_tree(
963+
PackBuilderSafeHandle packbuilder,
964+
ref GitOid id);
965+
966+
[DllImport(libgit2)]
967+
internal static extern int git_packbuilder_new(out PackBuilderSafeHandle packbuilder, RepositorySafeHandle repo);
968+
969+
[DllImport(libgit2)]
970+
internal static extern UInt32 git_packbuilder_object_count(PackBuilderSafeHandle packbuilder);
971+
972+
[DllImport(libgit2)]
973+
internal static extern UInt32 git_packbuilder_set_threads(PackBuilderSafeHandle packbuilder, UInt32 numThreads);
974+
975+
[DllImport(libgit2)]
976+
internal static extern int git_packbuilder_write(
977+
PackBuilderSafeHandle packbuilder,
978+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictFilePathMarshaler))] FilePath path,
979+
uint mode,
980+
IntPtr progressCallback,
981+
IntPtr payload);
982+
983+
[DllImport(libgit2)]
984+
internal static extern UInt32 git_packbuilder_written(PackBuilderSafeHandle packbuilder);
985+
941986
[DllImport(libgit2)]
942987
internal static extern int git_reference_create(
943988
out ReferenceSafeHandle reference,

0 commit comments

Comments
 (0)