Skip to content

Commit 60f0cb5

Browse files
committed
Adding Pack method to ObjectDatabase to supporting writing the packfile.
Reducing the access of packbuilder to internal.
1 parent f06b942 commit 60f0cb5

File tree

15 files changed

+199
-30
lines changed

15 files changed

+199
-30
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: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
using LibGit2Sharp.Tests.TestHelpers;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using Xunit;
6+
7+
namespace LibGit2Sharp.Tests
8+
{
9+
public class PackBuilderFixture : BaseFixture
10+
{
11+
[Fact]
12+
public void ObjectsWrittenSameAsOriginal()
13+
{
14+
// read a repo
15+
// pack with default action
16+
// write the pack file in a mirror repo
17+
// read new repo
18+
// compare
19+
20+
//string orgRepoPath = @"D:\TestRepos\packbuilder_testrepo_wd\packbuilder_testrepo_git_org\dot_git";
21+
//string mrrRepoPath = @"D:\TestRepos\packbuilder_testrepo_wd\packbuilder_testrepo_git_mrr_1\dot_git";
22+
//string packFilePath = @"D:\TestRepos\packbuilder_testrepo_wd\packbuilder_testrepo_git_mrr_1\dot_git\objects\pack";
23+
24+
string orgRepoPath = SandboxPackBuilderTestRepo();
25+
SelfCleaningDirectory scd = BuildSelfCleaningDirectory(orgRepoPath + "_mrr");
26+
string mrrRepoPath = scd.DirectoryPath;
27+
string mrrRepoPathPackDirPath = mrrRepoPath + "/.git/objects";
28+
29+
DirectoryHelper.CopyFilesRecursively(new DirectoryInfo(orgRepoPath), new DirectoryInfo(mrrRepoPath));
30+
DirectoryHelper.DeleteDirectory(mrrRepoPathPackDirPath);
31+
Directory.CreateDirectory(mrrRepoPathPackDirPath);
32+
Directory.CreateDirectory(mrrRepoPathPackDirPath + "/pack");
33+
34+
PackBuilderOptions packBuilderOptions = new PackBuilderOptions();
35+
packBuilderOptions.MaximumNumberOfThreads = 0;
36+
packBuilderOptions.PackFilePath = mrrRepoPathPackDirPath + "/pack";
37+
38+
Repository orgRepo = new Repository(orgRepoPath);
39+
40+
PackBuilderResults results = orgRepo.ObjectDatabase.Pack(packBuilderOptions, null);
41+
42+
// written objects count is the same as in objects database
43+
Assert.Equal(orgRepo.ObjectDatabase.Count(), results.WrittenObjectsCount);
44+
45+
// loading a repo from the written pack file.
46+
Repository mrrRepo = new Repository(mrrRepoPath);
47+
48+
// make sure the objects of the original repo are the same as the ones in the mirror repo
49+
// doing that by making sure the count is the same, and the set differnce is empty
50+
Assert.True(mrrRepo.ObjectDatabase.Count() == orgRepo.ObjectDatabase.Count() && !mrrRepo.ObjectDatabase.Except(orgRepo.ObjectDatabase).Any());
51+
52+
Assert.Equal(orgRepo.Commits.Count(), mrrRepo.Commits.Count());
53+
Assert.Equal(orgRepo.Branches.Count(), mrrRepo.Branches.Count());
54+
Assert.Equal(orgRepo.Refs.Count(), mrrRepo.Refs.Count());
55+
56+
orgRepo.Dispose();
57+
mrrRepo.Dispose();
58+
}
59+
60+
[Fact]
61+
public void ObjectsWrittenSameAsOriginalUsingDelegate()
62+
{
63+
string orgRepoPath = SandboxPackBuilderTestRepo();
64+
SelfCleaningDirectory scd = BuildSelfCleaningDirectory(orgRepoPath + "_mrr");
65+
string mrrRepoPath = scd.DirectoryPath;
66+
string mrrRepoPathPackDirPath = mrrRepoPath + "/.git/objects";
67+
68+
DirectoryHelper.CopyFilesRecursively(new DirectoryInfo(orgRepoPath), new DirectoryInfo(mrrRepoPath));
69+
DirectoryHelper.DeleteDirectory(mrrRepoPathPackDirPath);
70+
Directory.CreateDirectory(mrrRepoPathPackDirPath);
71+
Directory.CreateDirectory(mrrRepoPathPackDirPath + "/pack");
72+
73+
PackBuilderOptions packBuilderOptions = new PackBuilderOptions();
74+
packBuilderOptions.MaximumNumberOfThreads = 0;
75+
packBuilderOptions.PackFilePath = mrrRepoPathPackDirPath + "/pack";
76+
77+
Repository orgRepo = new Repository(orgRepoPath);
78+
79+
// pack using the custom build method
80+
PackBuilderResults results = orgRepo.ObjectDatabase.Pack(packBuilderOptions, TestBuildDelegate);
81+
82+
// written objects count is the same as in objects database
83+
Assert.Equal(results.WrittenObjectsCount, orgRepo.ObjectDatabase.Count());
84+
85+
// loading a repo from the written pack file.
86+
Repository mrrRepo = new Repository(mrrRepoPath);
87+
88+
// make sure the objects of the original repo are the same as the ones in the mirror repo
89+
// doing that by making sure the count is the same, and the set differnce is empty
90+
Assert.True(mrrRepo.ObjectDatabase.Count() == orgRepo.ObjectDatabase.Count() && !mrrRepo.ObjectDatabase.Except(orgRepo.ObjectDatabase).Any());
91+
92+
Assert.Equal(orgRepo.Commits.Count(), mrrRepo.Commits.Count());
93+
Assert.Equal(orgRepo.Branches.Count(), mrrRepo.Branches.Count());
94+
Assert.Equal(orgRepo.Refs.Count(), mrrRepo.Refs.Count());
95+
96+
orgRepo.Dispose();
97+
mrrRepo.Dispose();
98+
}
99+
100+
internal void TestBuildDelegate (PackBuilder builder)
101+
{
102+
foreach(Branch branch in builder.Repository.Branches)
103+
{
104+
foreach (Commit commit in branch.Commits)
105+
{
106+
builder.AddRecursively(commit);
107+
}
108+
}
109+
}
110+
}
111+
}
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();

LibGit2Sharp/ObjectDatabase.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,5 +643,39 @@ public virtual MergeTreeResult MergeCommits(Commit ours, Commit theirs, MergeTre
643643
return mergeResult;
644644
}
645645
}
646+
647+
public virtual PackBuilderResults Pack(PackBuilderOptions options, Action<PackBuilder> buildDelegate)
648+
{
649+
PackBuilderResults results = new PackBuilderResults();
650+
PackBuilder builder = new PackBuilder(repo);
651+
652+
// set pre-build options
653+
builder.SetMaximumNumberOfThreads(options.MaximumNumberOfThreads);
654+
655+
if (buildDelegate == null)
656+
{
657+
// if no build delegate is provided, just insert all objects one by one.
658+
foreach (GitObject obj in this)
659+
{
660+
Console.WriteLine();
661+
builder.Add(obj);
662+
}
663+
}
664+
else
665+
{
666+
// call the provided action
667+
buildDelegate(builder);
668+
}
669+
670+
// writing the pack file
671+
builder.Write(options.PackFilePath);
672+
673+
// adding the results to the PackBuilderResults object
674+
results.WrittenObjectsCount = builder.WrittenObjectsCount;
675+
676+
// dispose and return
677+
builder.Dispose();
678+
return results;
679+
}
646680
}
647681
}

LibGit2Sharp/PackBuilder.cs

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,67 +10,57 @@ namespace LibGit2Sharp
1010
public sealed class PackBuilder : IDisposable
1111
{
1212
private readonly PackBuilderSafeHandle packBuilderHandle;
13+
internal Repository repo;
1314

1415
/// <summary>
1516
/// Constructs a packbuilder from a repository.
1617
/// </summary>
17-
public PackBuilder(IRepository repository)
18+
internal PackBuilder(Repository repository)
1819
{
19-
Repository repo = (Repository)repository;
20+
repo = repository;
2021
packBuilderHandle = Proxy.git_packbuilder_new(repo.Handle);
2122
}
2223

2324
/// <summary>
24-
/// Insert a single object to the packbuilder.
25+
/// Inserts a single object to the packbuilder.
2526
/// For an optimal pack it's mandatory to insert objects in recency order, commits followed by trees and blobs. (quoted from libgit2 API ref)
2627
/// </summary>
2728
/// <param name="gitObject">The object to be inserted.</param>
28-
public void InsertObject(GitObject gitObject)
29+
public void Add(GitObject gitObject)
2930
{
3031
Proxy.git_packbuilder_insert(packBuilderHandle, gitObject.Id, null);
3132
}
3233

3334
/// <summary>
34-
/// Insert a <see cref="Tag"/> object to the packbuilder.
35+
/// Recursively insert an object and its referenced objects. Inserts the object as well as any object it references.
3536
/// </summary>
36-
/// <param name="tag">The tag object to be inserted.</param>
37-
public void InsertTag(Tag tag)
37+
/// <param name="gitObject">The object to be recursively inserted.</param>
38+
public void AddRecursively(GitObject gitObject)
3839
{
39-
Proxy.git_packbuilder_insert(packBuilderHandle, tag.Target.Id, null);
40+
Proxy.git_packbuilder_insert_recur(packBuilderHandle, gitObject.Id, null);
4041
}
4142

42-
/// <summary>
43-
/// Insert a commit object. This will add a commit as well as the completed referenced tree.
44-
/// </summary>
45-
/// <param name="commit">The commit object to be inserted.</param>
46-
public void InsertCommit(Commit commit)
43+
public Repository Repository
4744
{
48-
Proxy.git_packbuilder_insert_commit(packBuilderHandle, commit.Id);
45+
get { return repo; }
4946
}
5047

51-
/// <summary>
52-
/// Insert a root tree object. This will add the tree as well as all referenced trees and blobs.
53-
/// </summary>
54-
/// <param name="tree">The tree object to be inserted.</param>
55-
public void InsertTree(Tree tree)
56-
{
57-
Proxy.git_packbuilder_insert_tree(packBuilderHandle, tree.Id);
58-
}
48+
//================
5949

6050
/// <summary>
61-
/// Recursively insert an object and its referenced objects. Inserts the object as well as any object it references.
51+
/// Insert a <see cref="Tag"/> object to the packbuilder.
6252
/// </summary>
63-
/// <param name="gitObject">The object to be recursively inserted.</param>
64-
public void InsertRecursively(GitObject gitObject)
53+
/// <param name="tag">The tag object to be inserted.</param>
54+
internal void InsertTag(Tag tag)
6555
{
66-
Proxy.git_packbuilder_insert_recur(packBuilderHandle, gitObject.Id, null);
56+
Proxy.git_packbuilder_insert(packBuilderHandle, tag.Target.Id, null);
6757
}
6858

6959
/// <summary>
7060
/// Writes the new pack file and corresponding index file to path.
7161
/// </summary>
7262
/// <param name="path">The path that pack and index files will be written to it.</param>
73-
public void Write(string path)
63+
internal void Write(string path)
7464
{
7565
Proxy.git_packbuilder_write(packBuilderHandle, path);
7666
}
@@ -88,7 +78,7 @@ public void Dispose()
8878
/// </summary>
8979
/// <returns> Returns the number of actual threads to be used.</returns>
9080
/// <param name="nThread">The Number of threads to spawn. An argument of 0 enusures using all available CPUs</param>
91-
public int SetMaximumNumberOfThreads(int nThread)
81+
internal int SetMaximumNumberOfThreads(int nThread)
9282
{
9383
// Libgit2 set the number of threads to 1 by default, 0 ensures git_online_cpus
9484
return (int)Proxy.git_packbuilder_set_threads(packBuilderHandle, (uint)nThread);
@@ -97,15 +87,15 @@ public int SetMaximumNumberOfThreads(int nThread)
9787
/// <summary>
9888
/// Get the total number of objects the packbuilder will write out.
9989
/// </summary>
100-
public long ObjectsCount
90+
internal long ObjectsCount
10191
{
10292
get { return Proxy.git_packbuilder_object_count(packBuilderHandle); }
10393
}
10494

10595
/// <summary>
10696
/// Get the number of objects the packbuilder has already written out. This is only correct after the packfile has been written.
10797
/// </summary>
108-
public long WrittenObjectsCount
98+
internal long WrittenObjectsCount
10999
{
110100
get { return Proxy.git_packbuilder_written(packBuilderHandle); }
111101
}
@@ -115,4 +105,15 @@ internal PackBuilderSafeHandle Handle
115105
get { return packBuilderHandle; }
116106
}
117107
}
108+
109+
public sealed class PackBuilderResults
110+
{
111+
public long WrittenObjectsCount { get; set; }
112+
}
113+
114+
public sealed class PackBuilderOptions
115+
{
116+
public string PackFilePath { get; set; }
117+
public int MaximumNumberOfThreads { get; set; }
118+
}
118119
}

0 commit comments

Comments
 (0)