diff --git a/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj b/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj index be9654a64..0be3440c6 100644 --- a/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj +++ b/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj @@ -64,6 +64,7 @@ + diff --git a/LibGit2Sharp.Tests/PackBuilderFixture.cs b/LibGit2Sharp.Tests/PackBuilderFixture.cs new file mode 100644 index 000000000..44e358158 --- /dev/null +++ b/LibGit2Sharp.Tests/PackBuilderFixture.cs @@ -0,0 +1,202 @@ +using System; +using System.IO; +using System.Linq; +using LibGit2Sharp.Tests.TestHelpers; +using Xunit; + +namespace LibGit2Sharp.Tests +{ + public class PackBuilderFixture : BaseFixture + { + [Fact] + public void TestDefaultPackDelegate() + { + TestIfSameRepoAfterPacking(null); + } + + [Fact] + public void TestCommitsPerBranchPackDelegate() + { + TestIfSameRepoAfterPacking(AddingObjectIdsTestDelegate); + } + + [Fact] + public void TestCommitsPerBranchIdsPackDelegate() + { + TestIfSameRepoAfterPacking(AddingObjectsTestDelegate); + } + + internal void TestIfSameRepoAfterPacking(Action packDelegate) + { + // read a repo + // pack with the provided action + // write the pack file in a mirror repo + // read new repo + // compare + + string orgRepoPath = SandboxPackBuilderTestRepo(); + string mrrRepoPath = SandboxPackBuilderTestRepo(); + string mrrRepoPackDirPath = Path.Combine(mrrRepoPath + "/.git/objects"); + + DirectoryHelper.DeleteDirectory(mrrRepoPackDirPath); + Directory.CreateDirectory(mrrRepoPackDirPath + "/pack"); + + PackBuilderOptions packBuilderOptions = new PackBuilderOptions(mrrRepoPackDirPath + "/pack"); + + using (Repository orgRepo = new Repository(orgRepoPath)) + { + PackBuilderResults results; + if (packDelegate != null) + results = orgRepo.ObjectDatabase.Pack(packBuilderOptions, b => packDelegate(orgRepo, b)); + else + results = orgRepo.ObjectDatabase.Pack(packBuilderOptions); + + // written objects count is the same as in objects database + Assert.Equal(orgRepo.ObjectDatabase.Count(), results.WrittenObjectsCount); + + // loading a repo from the written pack file. + using (Repository mrrRepo = new Repository(mrrRepoPath)) + { + // make sure the objects of the original repo are the same as the ones in the mirror repo + // doing that by making sure the count is the same, and the set difference is empty + Assert.True(mrrRepo.ObjectDatabase.Count() == orgRepo.ObjectDatabase.Count() && !mrrRepo.ObjectDatabase.Except(orgRepo.ObjectDatabase).Any()); + + Assert.Equal(orgRepo.Commits.Count(), mrrRepo.Commits.Count()); + Assert.Equal(orgRepo.Branches.Count(), mrrRepo.Branches.Count()); + Assert.Equal(orgRepo.Refs.Count(), mrrRepo.Refs.Count()); + } + } + } + + internal void AddingObjectIdsTestDelegate(IRepository repo, PackBuilder builder) + { + foreach (Branch branch in repo.Branches) + { + foreach (Commit commit in branch.Commits) + { + builder.AddRecursively(commit.Id); + } + } + + foreach (Tag tag in repo.Tags) + { + builder.Add(tag.Target.Id); + } + } + + internal void AddingObjectsTestDelegate(IRepository repo, PackBuilder builder) + { + foreach (Branch branch in repo.Branches) + { + foreach (Commit commit in branch.Commits) + { + builder.AddRecursively(commit); + } + } + + foreach (Tag tag in repo.Tags) + { + builder.Add(tag.Target); + } + } + + [Fact] + public void ExceptionIfPathDoesNotExist() + { + PackBuilderOptions pbo; + + Assert.Throws(() => + { + pbo = new PackBuilderOptions("aaa"); + }); + } + + [Fact] + public void ExceptionIfPathEqualsNull() + { + PackBuilderOptions pbo; + + Assert.Throws(() => + { + pbo = new PackBuilderOptions(null); + }); + } + + [Fact] + public void ExceptionIfOptionsEqualsNull() + { + string orgRepoPath = SandboxPackBuilderTestRepo(); + + using (Repository orgRepo = new Repository(orgRepoPath)) + { + Assert.Throws(() => + { + orgRepo.ObjectDatabase.Pack(null); + }); + } + } + + [Fact] + public void ExceptionIfBuildDelegateEqualsNull() + { + string orgRepoPath = SandboxPackBuilderTestRepo(); + PackBuilderOptions packBuilderOptions = new PackBuilderOptions(orgRepoPath); + + using (Repository orgRepo = new Repository(orgRepoPath)) + { + Assert.Throws(() => + { + orgRepo.ObjectDatabase.Pack(packBuilderOptions, null); + }); + } + } + + [Fact] + public void ExceptionIfNegativeNumberOfThreads() + { + string orgRepoPath = SandboxPackBuilderTestRepo(); + PackBuilderOptions packBuilderOptions = new PackBuilderOptions(orgRepoPath); + + Assert.Throws(() => + { + packBuilderOptions.MaximumNumberOfThreads = -1; + }); + } + + [Fact] + public void ExceptionIfAddNullObjectID() + { + string orgRepoPath = SandboxPackBuilderTestRepo(); + PackBuilderOptions packBuilderOptions = new PackBuilderOptions(orgRepoPath); + + using (Repository orgRepo = new Repository(orgRepoPath)) + { + Assert.Throws(() => + { + orgRepo.ObjectDatabase.Pack(packBuilderOptions, builder => + { + builder.Add(null); + }); + }); + } + } + + [Fact] + public void ExceptionIfAddRecursivelyNullObjectID() + { + string orgRepoPath = SandboxPackBuilderTestRepo(); + PackBuilderOptions packBuilderOptions = new PackBuilderOptions(orgRepoPath); + + using (Repository orgRepo = new Repository(orgRepoPath)) + { + Assert.Throws(() => + { + orgRepo.ObjectDatabase.Pack(packBuilderOptions, builder => + { + builder.AddRecursively(null); + }); + }); + } + } + } +} diff --git a/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/HEAD b/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/HEAD new file mode 100644 index 000000000..cb089cd89 --- /dev/null +++ b/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/config b/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/config new file mode 100644 index 000000000..78387c50b --- /dev/null +++ b/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/config @@ -0,0 +1,8 @@ +[core] + repositoryformatversion = 0 + filemode = false + bare = false + logallrefupdates = true + symlinks = false + ignorecase = true + hideDotFiles = dotGitOnly diff --git a/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/index b/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/index new file mode 100644 index 000000000..1af67f2d4 Binary files /dev/null and b/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/index differ diff --git a/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/objects/87/2129051d644790636b416d1ef1ec830c5f6b90 b/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/objects/87/2129051d644790636b416d1ef1ec830c5f6b90 new file mode 100644 index 000000000..3c800a797 --- /dev/null +++ b/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/objects/87/2129051d644790636b416d1ef1ec830c5f6b90 @@ -0,0 +1,3 @@ +xI +B1]>'[ oU/Zni"5SQhC.n=? \ No newline at end of file diff --git a/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/objects/88/e38705fdbd3608cddbe904b67c731f3234c45b b/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/objects/88/e38705fdbd3608cddbe904b67c731f3234c45b new file mode 100644 index 000000000..783449ff9 Binary files /dev/null and b/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/objects/88/e38705fdbd3608cddbe904b67c731f3234c45b differ diff --git a/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/objects/cc/628ccd10742baea8241c5924df992b5c019f71 b/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/objects/cc/628ccd10742baea8241c5924df992b5c019f71 new file mode 100644 index 000000000..6b011038d Binary files /dev/null and b/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/objects/cc/628ccd10742baea8241c5924df992b5c019f71 differ diff --git a/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/objects/ce/013625030ba8dba906f756967f9e9ca394464a b/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/objects/ce/013625030ba8dba906f756967f9e9ca394464a new file mode 100644 index 000000000..6802d4949 Binary files /dev/null and b/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/objects/ce/013625030ba8dba906f756967f9e9ca394464a differ diff --git a/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/refs/heads/master b/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/refs/heads/master new file mode 100644 index 000000000..2ed6cd9fa --- /dev/null +++ b/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/dot_git/refs/heads/master @@ -0,0 +1 @@ +872129051d644790636b416d1ef1ec830c5f6b90 diff --git a/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/hello.txt b/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/hello.txt new file mode 100644 index 000000000..e965047ad --- /dev/null +++ b/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/hello.txt @@ -0,0 +1 @@ +Hello diff --git a/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/world.txt b/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/world.txt new file mode 100644 index 000000000..216e97ce0 --- /dev/null +++ b/LibGit2Sharp.Tests/Resources/packbuilder_testrepo_wd/world.txt @@ -0,0 +1 @@ +World diff --git a/LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs b/LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs index 3c1f6e2e0..c1fbefb7f 100644 --- a/LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs +++ b/LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs @@ -41,6 +41,7 @@ static BaseFixture() private static string SubmoduleTargetTestRepoWorkingDirPath { get; set; } private static string AssumeUnchangedRepoWorkingDirPath { get; set; } public static string SubmoduleSmallTestRepoWorkingDirPath { get; set; } + public static string PackBuilderTestRepoPath { get; private set; } public static DirectoryInfo ResourcesDirectory { get; private set; } @@ -74,6 +75,7 @@ private static void SetUpTestEnvironment() SubmoduleTargetTestRepoWorkingDirPath = Path.Combine(sourceRelativePath, "submodule_target_wd"); AssumeUnchangedRepoWorkingDirPath = Path.Combine(sourceRelativePath, "assume_unchanged_wd"); SubmoduleSmallTestRepoWorkingDirPath = Path.Combine(sourceRelativePath, "submodule_small_wd"); + PackBuilderTestRepoPath = Path.Combine(sourceRelativePath, "packbuilder_testrepo_wd"); CleanupTestReposOlderThan(TimeSpan.FromMinutes(15)); } @@ -174,6 +176,11 @@ public string SandboxSubmoduleSmallTestRepo() return path; } + protected string SandboxPackBuilderTestRepo() + { + return Sandbox(PackBuilderTestRepoPath); + } + protected string Sandbox(string sourceDirectoryPath, params string[] additionalSourcePaths) { var scd = BuildSelfCleaningDirectory(); diff --git a/LibGit2Sharp/Core/Handles/PackBuilderSafeHandle.cs b/LibGit2Sharp/Core/Handles/PackBuilderSafeHandle.cs new file mode 100644 index 000000000..060fefc10 --- /dev/null +++ b/LibGit2Sharp/Core/Handles/PackBuilderSafeHandle.cs @@ -0,0 +1,11 @@ +namespace LibGit2Sharp.Core.Handles +{ + internal class PackBuilderSafeHandle : SafeHandleBase + { + protected override bool ReleaseHandleImpl() + { + Proxy.git_packbuilder_free(handle); + return true; + } + } +} diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs index 718fe1487..0e3d6b3fc 100644 --- a/LibGit2Sharp/Core/NativeMethods.cs +++ b/LibGit2Sharp/Core/NativeMethods.cs @@ -938,6 +938,51 @@ internal static extern int git_patch_line_stats( internal delegate int git_push_transfer_progress(uint current, uint total, UIntPtr bytes, IntPtr payload); internal delegate int git_packbuilder_progress(int stage, uint current, uint total, IntPtr payload); + [DllImport(libgit2)] + internal static extern void git_packbuilder_free(IntPtr packbuilder); + + [DllImport(libgit2)] + internal static extern int git_packbuilder_insert( + PackBuilderSafeHandle packbuilder, + ref GitOid id, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string name); + + [DllImport(libgit2)] + internal static extern int git_packbuilder_insert_commit( + PackBuilderSafeHandle packbuilder, + ref GitOid id); + + [DllImport(libgit2)] + internal static extern int git_packbuilder_insert_recur( + PackBuilderSafeHandle packbuilder, + ref GitOid id, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string name); + + [DllImport(libgit2)] + internal static extern int git_packbuilder_insert_tree( + PackBuilderSafeHandle packbuilder, + ref GitOid id); + + [DllImport(libgit2)] + internal static extern int git_packbuilder_new(out PackBuilderSafeHandle packbuilder, RepositorySafeHandle repo); + + [DllImport(libgit2)] + internal static extern UInt32 git_packbuilder_object_count(PackBuilderSafeHandle packbuilder); + + [DllImport(libgit2)] + internal static extern UInt32 git_packbuilder_set_threads(PackBuilderSafeHandle packbuilder, UInt32 numThreads); + + [DllImport(libgit2)] + internal static extern int git_packbuilder_write( + PackBuilderSafeHandle packbuilder, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictFilePathMarshaler))] FilePath path, + uint mode, + IntPtr progressCallback, + IntPtr payload); + + [DllImport(libgit2)] + internal static extern UInt32 git_packbuilder_written(PackBuilderSafeHandle packbuilder); + [DllImport(libgit2)] internal static extern int git_reference_create( out ReferenceSafeHandle reference, diff --git a/LibGit2Sharp/Core/Proxy.cs b/LibGit2Sharp/Core/Proxy.cs index 2c9cf12bf..dec711d24 100644 --- a/LibGit2Sharp/Core/Proxy.cs +++ b/LibGit2Sharp/Core/Proxy.cs @@ -1547,6 +1547,77 @@ public static Tuple git_patch_line_stats(PatchSafeHandle patch) #endregion + #region git_packbuilder_ + + public static void git_packbuilder_free(IntPtr packbuilder) + { + NativeMethods.git_packbuilder_free(packbuilder); + } + + public static PackBuilderSafeHandle git_packbuilder_new(RepositorySafeHandle repo) + { + PackBuilderSafeHandle handle; + + int res = NativeMethods.git_packbuilder_new(out handle, repo); + Ensure.ZeroResult(res); + + return handle; + } + + public static void git_packbuilder_insert(PackBuilderSafeHandle packbuilder, ObjectId targetId, string name) + { + GitOid oid = targetId.Oid; + + int res = NativeMethods.git_packbuilder_insert(packbuilder, ref oid, name); + Ensure.ZeroResult(res); + } + + internal static void git_packbuilder_insert_commit(PackBuilderSafeHandle packbuilder, ObjectId targetId) + { + GitOid oid = targetId.Oid; + + int res = NativeMethods.git_packbuilder_insert_commit(packbuilder, ref oid); + Ensure.ZeroResult(res); + } + + internal static void git_packbuilder_insert_tree(PackBuilderSafeHandle packbuilder, ObjectId targetId) + { + GitOid oid = targetId.Oid; + + int res = NativeMethods.git_packbuilder_insert_tree(packbuilder, ref oid); + Ensure.ZeroResult(res); + } + + public static void git_packbuilder_insert_recur(PackBuilderSafeHandle packbuilder, ObjectId targetId, string name) + { + GitOid oid = targetId.Oid; + + int res = NativeMethods.git_packbuilder_insert_recur(packbuilder, ref oid, name); + Ensure.ZeroResult(res); + } + + public static uint git_packbuilder_set_threads(PackBuilderSafeHandle packbuilder, uint numThreads) + { + return NativeMethods.git_packbuilder_set_threads(packbuilder, numThreads); + } + + public static void git_packbuilder_write(PackBuilderSafeHandle packbuilder, FilePath path) + { + int res = NativeMethods.git_packbuilder_write(packbuilder, path, 0, IntPtr.Zero, IntPtr.Zero); + Ensure.ZeroResult(res); + } + + public static uint git_packbuilder_object_count(PackBuilderSafeHandle packbuilder) + { + return NativeMethods.git_packbuilder_object_count(packbuilder); + } + + public static uint git_packbuilder_written(PackBuilderSafeHandle packbuilder) + { + return NativeMethods.git_packbuilder_written(packbuilder); + } + #endregion + #region git_rebase public static RebaseSafeHandle git_rebase_init( diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj index 3fc9f59b5..8254b811a 100644 --- a/LibGit2Sharp/LibGit2Sharp.csproj +++ b/LibGit2Sharp/LibGit2Sharp.csproj @@ -73,6 +73,7 @@ + @@ -129,6 +130,7 @@ + diff --git a/LibGit2Sharp/ObjectDatabase.cs b/LibGit2Sharp/ObjectDatabase.cs index 5376fdb87..0adb09afd 100644 --- a/LibGit2Sharp/ObjectDatabase.cs +++ b/LibGit2Sharp/ObjectDatabase.cs @@ -643,5 +643,66 @@ public virtual MergeTreeResult MergeCommits(Commit ours, Commit theirs, MergeTre return mergeResult; } } + + /// + /// Packs all the objects in the and write a pack (.pack) and index (.idx) files for them. + /// + /// Packing options + /// This method will invoke the default action of packing all objects in an arbitrary order. + /// Packing results + public virtual PackBuilderResults Pack(PackBuilderOptions options) + { + return InternalPack(options, builder => + { + foreach (GitObject obj in repo.ObjectDatabase) + { + builder.Add(obj.Id); + } + }); + } + + /// + /// Packs objects in the chosen by the packDelegate action + /// and write a pack (.pack) and index (.idx) files for them + /// + /// Packing options + /// Packing action + /// Packing results + public virtual PackBuilderResults Pack(PackBuilderOptions options, Action packDelegate) + { + return InternalPack(options, packDelegate); + } + + /// + /// Packs objects in the and write a pack (.pack) and index (.idx) files for them. + /// For internal use only. + /// + /// Packing options + /// Packing action + /// Packing results + private PackBuilderResults InternalPack(PackBuilderOptions options, Action packDelegate) + { + Ensure.ArgumentNotNull(options, "options"); + Ensure.ArgumentNotNull(packDelegate, "packDelegate"); + + PackBuilderResults results = new PackBuilderResults(); + + using (PackBuilder builder = new PackBuilder(repo)) + { + // set pre-build options + builder.SetMaximumNumberOfThreads(options.MaximumNumberOfThreads); + + // call the provided action + packDelegate(builder); + + // writing the pack and index files + builder.Write(options.PackDirectoryPath); + + // adding the results to the PackBuilderResults object + results.WrittenObjectsCount = builder.WrittenObjectsCount; + } + + return results; + } } } diff --git a/LibGit2Sharp/PackBuilder.cs b/LibGit2Sharp/PackBuilder.cs new file mode 100644 index 000000000..02ea76dc7 --- /dev/null +++ b/LibGit2Sharp/PackBuilder.cs @@ -0,0 +1,206 @@ +using System; +using System.IO; +using LibGit2Sharp.Core; +using LibGit2Sharp.Core.Handles; + +namespace LibGit2Sharp +{ + /// + /// Representation of a git PackBuilder. + /// + public sealed class PackBuilder : IDisposable + { + private readonly PackBuilderSafeHandle packBuilderHandle; + private readonly Repository repo; + + /// + /// Constructs a PackBuilder for a . + /// + internal PackBuilder(Repository repository) + { + Ensure.ArgumentNotNull(repository, "repository"); + + repo = repository; + packBuilderHandle = Proxy.git_packbuilder_new(repo.Handle); + } + + /// + /// Inserts a single to the PackBuilder. + /// For an optimal pack it's mandatory to insert objects in recency order, commits followed by trees and blobs. (quoted from libgit2 API ref) + /// + /// The object to be inserted. + /// if the gitObject is null + public void Add(T gitObject) where T : GitObject + { + Ensure.ArgumentNotNull(gitObject, "gitObject"); + + Add(gitObject.Id); + } + + /// + /// Recursively inserts a and its referenced objects. + /// Inserts the object as well as any object it references. + /// + /// The object to be inserted recursively. + /// if the gitObject is null + public void AddRecursively(T gitObject) where T : GitObject + { + Ensure.ArgumentNotNull(gitObject, "gitObject"); + + AddRecursively(gitObject.Id); + } + + /// + /// Inserts a single object to the PackBuilder by its . + /// For an optimal pack it's mandatory to insert objects in recency order, commits followed by trees and blobs. (quoted from libgit2 API ref) + /// + /// The object ID to be inserted. + /// if the id is null + public void Add(ObjectId id) + { + Ensure.ArgumentNotNull(id, "id"); + + Proxy.git_packbuilder_insert(packBuilderHandle, id, null); + } + + /// + /// Recursively inserts an object and its referenced objects by its . + /// Inserts the object as well as any object it references. + /// + /// The object ID to be recursively inserted. + /// if the id is null + public void AddRecursively(ObjectId id) + { + Ensure.ArgumentNotNull(id, "id"); + + Proxy.git_packbuilder_insert_recur(packBuilderHandle, id, null); + } + + /// + /// Disposes the PackBuilder object. + /// + public void Dispose() + { + packBuilderHandle.SafeDispose(); + } + + /// + /// Writes the pack file and corresponding index file to path. + /// + /// The path that pack and index files will be written to it. + internal void Write(string path) + { + Proxy.git_packbuilder_write(packBuilderHandle, path); + } + + /// + /// Sets number of threads to spawn. + /// + /// Returns the number of actual threads to be used. + /// The Number of threads to spawn. An argument of 0 ensures using all available CPUs + internal int SetMaximumNumberOfThreads(int nThread) + { + // Libgit2 set the number of threads to 1 by default, 0 ensures git_online_cpus + return (int)Proxy.git_packbuilder_set_threads(packBuilderHandle, (uint)nThread); + } + + /// + /// Number of objects the PackBuilder will write out. + /// + internal long ObjectsCount + { + get { return Proxy.git_packbuilder_object_count(packBuilderHandle); } + } + + /// + /// Number of objects the PackBuilder has already written out. + /// This is only correct after the pack file has been written. + /// + internal long WrittenObjectsCount + { + get { return Proxy.git_packbuilder_written(packBuilderHandle); } + } + + internal PackBuilderSafeHandle Handle + { + get { return packBuilderHandle; } + } + } + + /// + /// The results of pack process of the . + /// + public struct PackBuilderResults + { + /// + /// Number of objects the PackBuilder has already written out. + /// + public long WrittenObjectsCount { get; internal set; } + } + + /// + /// Packing options of the . + /// + public sealed class PackBuilderOptions + { + /// + /// Constructor + /// + /// Directory path to write the pack and index files to it + /// The default value for maximum number of threads to spawn is 0 which ensures using all available CPUs. + /// if packDirectory is null or empty + /// if packDirectory doesn't exist + public PackBuilderOptions(string packDirectory) + { + PackDirectoryPath = packDirectory; + MaximumNumberOfThreads = 0; + } + + /// + /// Directory path to write the pack and index files to it. + /// + public string PackDirectoryPath + { + set + { + Ensure.ArgumentNotNullOrEmptyString(value, "packDirectory"); + + if (!Directory.Exists(value)) + { + throw new DirectoryNotFoundException("The Directory " + value + " does not exist."); + } + + path = value; + } + get + { + return path; + } + } + + /// + /// Maximum number of threads to spawn. + /// The default value is 0 which ensures using all available CPUs. + /// + public int MaximumNumberOfThreads + { + set + { + if (value < 0) + { + throw new ArgumentException("Argument can not be negative", "MaximumNumberOfThreads"); + } + + nThreads = value; + } + get + { + return nThreads; + } + + } + + private string path; + private int nThreads; + } +}