-
Notifications
You must be signed in to change notification settings - Fork 899
Exposing Packbuilder capabilities of libgit2 #1183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Thanks for this.It looks like an interesting feature to expose. A few nitpicks, though.
Regarding the API, I'm not sure exposing a From a different perspective, by taking a look at the libgit2 source code, it looks like most of the exposed functions actually delegate to /cc @carlosmn Note: Your commits do not seem to be linked with your GitHub account, you may be willing to add the email address you used to commit to your GitHub account. Cheers! |
Are you thinking of the
|
No the idea would be the opposite, the Packbuilder type would be instantiated and disposed by the
I'm not very familiar with the usage of the packbuilder. When would one want to only had one object and not its dependencies (eg. the |
That sounds just like what I was trying to describe. The thing with the object packer is that you may want to pass it around a bit, as you build up the list of objects that you want to pass.
If you know that the other repository already has the objects in question, there's no need to send them. Or you may have a plan for which object goes into which packfile if you're creating a bunch of them. |
Sorry. I misunderstood you.
The idea was, instead of...
...rather promote something like
👍 Thanks for the explanation. The xml doc should be explicit about the behavior of each method. |
Thanks @nulltoken @carlosmn for the insights.
As Carlos mentioned, for cases if you don't want to add all objects or build multiple pack files.
This works too however I don't see a big advantage of it other than using 'using (var pb = new PackBuilder())' ... if I understand you correctly, then 'PackBuilder' code will stay pretty much the same, but I need to add 'Pack(Action)' method in the 'ObjectDatabase' class
I'm working on that, if you can direct me to a concrete example showing the style used in here that will be great, |
Mostly. But,
Few thoughts:
The test project contains lots of tests that you get some inspiration from. I'm not sure to understand what kind of guidance you're looking for. Could you please elaborate a little bit more how we could help you with regards to writing tests? |
If you're making the user provide a closure to include objects, it only makes sense that you'd do the writing when the closure has finished. Otherwise you are just making them do a really weird incantation of There is then however the issue of what to do to support the |
@carlosmn Thanks for the feedback. Let's not expose |
@nulltoken thanks for your suggestions, I'm considering them all in my next commit. One a side note, I would like to be able to build a pack file from a rev walk by exposing
Regarding testing, that's what I meant. I'll look at some of these tests and I will follow its style. Thanks! |
How about a |
I was hoping to do something more like what's in http://ben.straub.cc/2013/10/02/revwalk/ that libgit2 can do.
Not sure if this going to do what we want, I think I better have I would prefer to use |
@AMSadek Let's start without the revwalk for now and make sure the API is clean and covered with tests. We'll then tackle this additional requirement. |
@nulltoken yeah that's good too. |
@nulltoken I've made some modification on my latest commit (it has some build issues still). The main change here is adding a method private static void TestMultiplePackFiles()
{
int numObjects = 0;
using (var repository = new Repository(@"\TestRepo5\.git"))
{
PackBuilder packBuilder = new PackBuilder(repository);
foreach (GitObject obj in repository.ObjectDatabase)
{
packBuilder.InsertObject(obj);
numObjects++;
if (numObjects % 100 == 0)
{
packBuilder.Write(@"\TestRepo5\.git\objects\pack-" + (numObjects/100));
packBuilder.Dispose();
packBuilder = new PackBuilder(repository);
}
}
if (numObjects % 100 != 0)
{
packBuilder.Write(@"\TestRepo5\.git\objects\pack");
packBuilder.Dispose();
}
}
} which is basically writing a separate pack file for each 100 objects. ... without exposing a |
@AMSadek Sealing the type should fix the build.
As discussed above, could we first cover with tests the first scope, then extend it? FWIW, this is why a description describing the high-level scenario you had in mind and the use cases would have been helpful in the beginning. 😉 |
@AMSadek Do you need some help pushing this forward? |
@nulltoken I wrote couple of tests already, just trying to figure a smart way to add and use the test repos I'm using for packbuilder tests. More specifically, copying the repo around, changing it's pack files, reading it again, and making sure it matches the old one ... if that makes sense. |
@nulltoken so I have have added a My next thoughts is how to enable to write multiple pack files with certain specifics or sizes.
I've updated it, have a look and let me know if it's unclear or confusing. Thanks! :) |
NB: this may be related: #192 as you need to create the |
@carlosmn thanks for referring to that
|
/// <param name="gitObject">The object to be inserted.</param> | ||
public void Add(GitObject gitObject) | ||
{ | ||
Proxy.git_packbuilder_insert(packBuilderHandle, gitObject.Id, null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're dereferencing gitObject
here without first ensuring that it is not null
.
@whoisj Thanks J for the comments, I did most of it. I will leave struct vs class comment till we settle on the design. |
Hey @nulltoken , I've done couple of cleanups and fixes to the code. Please let me know what you think, and if you suggest more testing. @carlosmn and @whoisj Also please let me know what you guys think and if you suggest more testing or modifications :). |
@AMSadek In order to move this forward, I took the liberty to update the code to try and showcase what I had in mind. You'll find below the result of this. I also slightly reworked the test initialization, which clears some warnings from the output. diff --git a/LibGit2Sharp.Tests/PackBuilderFixture.cs b/LibGit2Sharp.Tests/PackBuilderFixture.cs
index eaac988..bc097e9 100644
--- a/LibGit2Sharp.Tests/PackBuilderFixture.cs
+++ b/LibGit2Sharp.Tests/PackBuilderFixture.cs
@@ -35,13 +35,10 @@ internal void TestIfSameRepoAfterPacking(Action<IRepository, PackBuilder> packDe
// compare
string orgRepoPath = SandboxPackBuilderTestRepo();
- SelfCleaningDirectory scd = BuildSelfCleaningDirectory(orgRepoPath + "_mrr");
- string mrrRepoPath = scd.DirectoryPath;
- string mrrRepoPathPackDirPath = mrrRepoPath + "/.git/objects";
+ string mrrRepoPath = SandboxPackBuilderTestRepo();
+ string mrrRepoPathPackDirPath = Path.Combine(mrrRepoPath, "/.git/objects");
- DirectoryHelper.CopyFilesRecursively(new DirectoryInfo(orgRepoPath), new DirectoryInfo(mrrRepoPath));
DirectoryHelper.DeleteDirectory(mrrRepoPathPackDirPath);
- Directory.CreateDirectory(mrrRepoPathPackDirPath);
Directory.CreateDirectory(mrrRepoPathPackDirPath + "/pack");
PackBuilderOptions packBuilderOptions = new PackBuilderOptions(mrrRepoPathPackDirPath + "/pack");
@@ -50,7 +47,7 @@ internal void TestIfSameRepoAfterPacking(Action<IRepository, PackBuilder> packDe
{
PackBuilderResults results;
if (packDelegate != null)
- results = orgRepo.ObjectDatabase.Pack(packBuilderOptions, packDelegate);
+ results = orgRepo.ObjectDatabase.Pack(packBuilderOptions, b => packDelegate(orgRepo, b));
else
results = orgRepo.ObjectDatabase.Pack(packBuilderOptions);
@@ -93,13 +90,13 @@ internal void AddingObjectsTestDelegate(IRepository repo, PackBuilder builder)
{
foreach (Commit commit in branch.Commits)
{
- builder.AddRecursively<GitObject>(commit);
+ builder.AddRecursively(commit);
}
}
foreach (Tag tag in repo.Tags)
{
- builder.Add<GitObject>(tag.Target);
+ builder.Add(tag.Target);
}
}
@@ -176,7 +173,7 @@ public void ExceptionIfAddNullObjectID()
{
Assert.Throws<ArgumentNullException>(() =>
{
- orgRepo.ObjectDatabase.Pack(packBuilderOptions, (IRepository repo, PackBuilder builder) =>
+ orgRepo.ObjectDatabase.Pack(packBuilderOptions, builder =>
{
builder.Add(null);
});
@@ -194,7 +191,7 @@ public void ExceptionIfAddRecursivelyNullObjectID()
{
Assert.Throws<ArgumentNullException>(() =>
{
- orgRepo.ObjectDatabase.Pack(packBuilderOptions, (IRepository repo, PackBuilder builder) =>
+ orgRepo.ObjectDatabase.Pack(packBuilderOptions, builder =>
{
builder.AddRecursively(null);
});
diff --git a/LibGit2Sharp/ObjectDatabase.cs b/LibGit2Sharp/ObjectDatabase.cs
index 1ea0b72..1ee33f8 100644
--- a/LibGit2Sharp/ObjectDatabase.cs
+++ b/LibGit2Sharp/ObjectDatabase.cs
@@ -652,7 +652,7 @@ public virtual MergeTreeResult MergeCommits(Commit ours, Commit theirs, MergeTre
/// <returns>Packing results</returns>
public virtual PackBuilderResults Pack(PackBuilderOptions options)
{
- return InternalPack(options, (IRepository repo, PackBuilder builder) =>
+ return InternalPack(options, builder =>
{
foreach (GitObject obj in repo.ObjectDatabase)
{
@@ -667,7 +667,7 @@ public virtual PackBuilderResults Pack(PackBuilderOptions options)
/// <param name="options">Packing options</param>
/// <param name="packDelegate">Packing action</param>
/// <returns>Packing results</returns>
- public virtual PackBuilderResults Pack(PackBuilderOptions options, Action<IRepository, PackBuilder> packDelegate)
+ public virtual PackBuilderResults Pack(PackBuilderOptions options, Action<PackBuilder> packDelegate)
{
return InternalPack(options, packDelegate);
}
@@ -679,7 +679,7 @@ public virtual PackBuilderResults Pack(PackBuilderOptions options, Action<IRepos
/// <param name="packDelegate">Packing action. If null is passed, the pack method will invoke the default action of packing
/// all objects in an arbitrary order.</param>
/// <returns>Packing results</returns>
- private PackBuilderResults InternalPack(PackBuilderOptions options, Action<IRepository, PackBuilder> packDelegate)
+ private PackBuilderResults InternalPack(PackBuilderOptions options, Action<PackBuilder> packDelegate)
{
Ensure.ArgumentNotNull(options, "options");
Ensure.ArgumentNotNull(packDelegate, "buildDelegate");
@@ -692,7 +692,7 @@ private PackBuilderResults InternalPack(PackBuilderOptions options, Action<IRepo
builder.SetMaximumNumberOfThreads(options.MaximumNumberOfThreads);
// call the provided action
- packDelegate(repo, builder);
+ packDelegate(builder);
// writing the pack and index files
builder.Write(options.PackDirectoryPath); |
@nulltoken Thanks for doing this, I don't object to these changes. If you could, please push them to the branch or let me know if I need to reapply them on my end. |
@AMSadek Sadly, I can't push to your branch. |
@nulltoken np, I will do these changes and commit them ... probably I will revert the commit where we introduced the |
e0c3581
to
0e3b2eb
Compare
@nulltoken I've done the changes, and rebased on vNext. Thank you! |
@nulltoken I think we're good, thanks for you feedback. @AMSadek thanks for the good work. I'll merge this by end of day if there are no more concerns/comments. |
@AMSadek Last request before merge: Could you please squash those commits into one cohesive one? |
0e3b2eb
to
8b5b890
Compare
@whoisj @nulltoken Thanks! ... I've don't the squash, just need to rerun the build. |
@AMSadek I've just kicked the build... hard |
Exposing Packbuilder capabilities of libgit2
Thanks for this 🆒 addition! ✨ ✨ ✨ ✨ ✨ |
Published as NuGet pre-release package |
AWESOME!! Thanks so much guys for your great advice and feedback, I learned much from this PR. |
Maybe something like this? private static void TestMultiplePackFiles()
{
int packCount = 0;
using (var repository = new Repository(@"\TestRepo5\.git"))
{
var toPack = new List<GitObject>();
foreach (GitObject obj in repository.ObjectDatabase)
{
toPack.Add(obj);
if (toPack.Length == 100)
{
Pack(repository, toPack, ref packCount);
toPack = new List<GitObject>();
}
}
Pack(repository, toPack, ref packCount);
}
}
private static void Pack(IRepository repository, List<GitObject> toPack, ref int packCount)
{
if (toPack.Length == 0) return;
var pbo = new PackBuilderOptions(@"\TestRepo5\.git\objects\pack-" + packCount++);
repository.ObjectBuilder.Pack(pbo, pb =>
{
foreach (var o in toPack)
pb.Add(o);
});
} |
@dahlbyk How would we handle I have the feeling that we should rather rely on the |
That had occurred to me, but wasn't part of the sample code so I didn't account for it. 😈 Biggest problem at first thought is that our pack path is specified once as an option - would need some way to iterate on that. |
Agreed. Let's wait for @AMSadek's feedback |
Kindly find my answers in the recent PR #1216 :) |
This pull request is intended to expose the the pack builder capabilities of libgit2, which is one way to produce the the .pack and .idx files for a repository. Some sample scenarios would be: Creating a pack file for a new or existing repo, splitting a repo over multiple pack files, build a pack file for certain branches/commits/trees if the entire repo is quite large, or build for commits returned by a revision walker.