diff --git a/CHANGELOG.md b/CHANGELOG.md index f8766572a..9f0ef9a82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # LibGit2Sharp releases +## v0.2.0 + + - [Fix] Fix Repository.Info.IsEmpty + - [Fix] Fix default CommitCollection sorting behavior + - [Fix] Fix creation of reference to prevent it from choking on corrupted ones + - [Fix] Fix interop issue in a IIS hosted application + - [Upd] Update CommitCollection API to query commits + - [Upd] Update CommitCollection API to query commits + - [Upd] Update libgit2 binaries to 4191d52 + ## v0.1.1 - [Fix] Fix NuGet packaging diff --git a/CI-build.msbuild b/CI-build.msbuild index db091172a..81be16c6d 100644 --- a/CI-build.msbuild +++ b/CI-build.msbuild @@ -1,35 +1,35 @@ - - - - - Release + + - $(MSBuildProjectDirectory)\LibGit2Sharp\obj\ - $(MSBuildProjectDirectory)\LibGit2Sharp.Tests\obj\ - $(MSBuildProjectDirectory)\build\ - - - - - - + + Release - - - - - - - $(MSBuildProjectDirectory)\LibGit2Sharp\obj\ + $(MSBuildProjectDirectory)\LibGit2Sharp.Tests\obj\ + $(MSBuildProjectDirectory)\build\ + + + + + + + + + + + + + + - - - - + + + - + \ No newline at end of file diff --git a/Lib/git2-0.dll b/Lib/git2-0.dll new file mode 100644 index 000000000..82a3754bf Binary files /dev/null and b/Lib/git2-0.dll differ diff --git a/Lib/git2.dll b/Lib/git2.dll deleted file mode 100644 index 3b2f252ea..000000000 Binary files a/Lib/git2.dll and /dev/null differ diff --git a/LibGit2Sharp.Tests/CommitFixture.cs b/LibGit2Sharp.Tests/CommitFixture.cs index e3effe9fc..b275cc275 100644 --- a/LibGit2Sharp.Tests/CommitFixture.cs +++ b/LibGit2Sharp.Tests/CommitFixture.cs @@ -18,7 +18,7 @@ public void CanCountCommits() { using (var repo = new Repository(Constants.TestRepoPath)) { - repo.Commits.Count.ShouldEqual(7); + repo.Commits.Count().ShouldEqual(7); } } @@ -28,11 +28,11 @@ public void CanCorrectlyCountCommitsWhenSwitchingToAnotherBranch() using (var repo = new Repository(Constants.TestRepoPath)) { repo.Branches.Checkout("test"); - repo.Commits.Count.ShouldEqual(2); + repo.Commits.Count().ShouldEqual(2); repo.Commits.First().Id.Sha.ShouldEqual("e90810b8df3e80c413d903f631643c716887138d"); repo.Branches.Checkout("master"); - repo.Commits.Count.ShouldEqual(7); + repo.Commits.Count().ShouldEqual(7); repo.Commits.First().Id.Sha.ShouldEqual("4c062a6361ae6959e06292c1fa5e2822d9c96345"); } } @@ -67,7 +67,7 @@ public void CanEnumerateCommitsFromSha() int count = 0; using (var repo = new Repository(Constants.TestRepoPath)) { - foreach (var commit in repo.Commits.StartingAt("a4a7dce85cf63874e984719f4fdd239f5145052f")) + foreach (var commit in repo.Commits.QueryBy(new Filter { Since = "a4a7dce85cf63874e984719f4fdd239f5145052f" })) { commit.ShouldNotBeNull(); count++; @@ -77,14 +77,25 @@ public void CanEnumerateCommitsFromSha() } [Test] - public void BuildingACommitCollectionFromUnknownShaOrInvalidReferenceThrows() + public void QueryingTheCommitHistoryWithUnknownShaOrInvalidReferenceThrows() { using (var repo = new Repository(Constants.TestRepoPath)) { - Assert.Throws(() => repo.Commits.StartingAt(Constants.UnknownSha)); - Assert.Throws(() => repo.Commits.StartingAt("refs/heads/deadbeef")); - Assert.Throws(() => repo.Commits.StartingAt(repo.Branches["deadbeef"])); - Assert.Throws(() => repo.Commits.StartingAt(repo.Refs["refs/heads/deadbeef"])); + Assert.Throws(() => repo.Commits.QueryBy(new Filter { Since = Constants.UnknownSha})); + Assert.Throws(() => repo.Commits.QueryBy(new Filter { Since = "refs/heads/deadbeef"})); + Assert.Throws(() => repo.Commits.QueryBy(new Filter { Since = repo.Branches["deadbeef"]})); + Assert.Throws(() => repo.Commits.QueryBy(new Filter { Since = repo.Refs["refs/heads/deadbeef"] })); + } + } + + [Test] + public void QueryingTheCommitHistoryWithBadParamsThrows() + { + using (var repo = new Repository(Constants.TestRepoPath)) + { + Assert.Throws(() => repo.Commits.QueryBy(new Filter { Since = string.Empty })); + Assert.Throws(() => repo.Commits.QueryBy(new Filter { Since = null })); + Assert.Throws(() => repo.Commits.QueryBy(null)); } } @@ -95,7 +106,7 @@ public void CanEnumerateCommitsWithReverseTimeSorting() int count = 0; using (var repo = new Repository(Constants.TestRepoPath)) { - foreach (var commit in repo.Commits.StartingAt("a4a7dce85cf63874e984719f4fdd239f5145052f").SortBy(GitSortOptions.Time | GitSortOptions.Reverse)) + foreach (var commit in repo.Commits.QueryBy(new Filter { Since = "a4a7dce85cf63874e984719f4fdd239f5145052f", SortBy = GitSortOptions.Time | GitSortOptions.Reverse })) { commit.ShouldNotBeNull(); commit.Sha.StartsWith(expectedShas[count]); @@ -110,7 +121,7 @@ public void CanEnumerateCommitsWithReverseTopoSorting() { using (var repo = new Repository(Constants.TestRepoPath)) { - var commits = repo.Commits.StartingAt("a4a7dce85cf63874e984719f4fdd239f5145052f").SortBy(GitSortOptions.Topological | GitSortOptions.Reverse).ToList(); + var commits = repo.Commits.QueryBy(new Filter { Since = "a4a7dce85cf63874e984719f4fdd239f5145052f", SortBy = GitSortOptions.Time | GitSortOptions.Reverse }).ToList(); foreach (var commit in commits) { commit.ShouldNotBeNull(); @@ -129,7 +140,7 @@ public void CanEnumerateCommitsWithTimeSorting() int count = 0; using (var repo = new Repository(Constants.TestRepoPath)) { - foreach (var commit in repo.Commits.StartingAt("a4a7dce85cf63874e984719f4fdd239f5145052f").SortBy(GitSortOptions.Time)) + foreach (var commit in repo.Commits.QueryBy(new Filter { Since = "a4a7dce85cf63874e984719f4fdd239f5145052f", SortBy = GitSortOptions.Time })) { commit.ShouldNotBeNull(); commit.Sha.StartsWith(expectedShas[count]); @@ -144,7 +155,7 @@ public void CanEnumerateCommitsWithTopoSorting() { using (var repo = new Repository(Constants.TestRepoPath)) { - var commits = repo.Commits.StartingAt("a4a7dce85cf63874e984719f4fdd239f5145052f").SortBy(GitSortOptions.Topological).ToList(); + var commits = repo.Commits.QueryBy(new Filter { Since = "a4a7dce85cf63874e984719f4fdd239f5145052f", SortBy = GitSortOptions.Topological }).ToList(); foreach (var commit in commits) { commit.ShouldNotBeNull(); @@ -158,14 +169,14 @@ public void CanEnumerateCommitsWithTopoSorting() } [Test] - public void CanLookupCommitAlt() + public void CanEnumerateUsingTwoCommitsAsBoundaries() { using (var repo = new Repository(Constants.TestRepoPath)) { - var commit = repo.Commits[sha]; - commit.Message.ShouldEqual("testing\n"); - commit.MessageShort.ShouldEqual("testing"); - commit.Sha.ShouldEqual(sha); + var commits = repo.Commits.QueryBy(new Filter { Since = "refs/heads/br2", Until = "refs/heads/packed-test" }); + + IEnumerable abbrevShas = commits.Select(c => c.Id.Sha.Substring(0, 7)).ToArray(); + CollectionAssert.AreEquivalent(new[] { "a4a7dce", "c47800c", "9fd738e" }, abbrevShas); } } @@ -220,23 +231,5 @@ public void CanReadCommitWithMultipleParents() commit.Parents.Count().ShouldEqual(2); } } - - [Test] - public void PushingEmptyShaThrows() - { - using (var repo = new Repository(Constants.TestRepoPath)) - { - Assert.Throws(() => repo.Commits.StartingAt(string.Empty)); - } - } - - [Test] - public void PushingNullShaThrows() - { - using (var repo = new Repository(Constants.TestRepoPath)) - { - Assert.Throws(() => repo.Commits.StartingAt((string) null)); - } - } } } \ No newline at end of file diff --git a/LibGit2Sharp.Tests/RepositoryFixture.cs b/LibGit2Sharp.Tests/RepositoryFixture.cs index 9a3c91dd3..760b02061 100644 --- a/LibGit2Sharp.Tests/RepositoryFixture.cs +++ b/LibGit2Sharp.Tests/RepositoryFixture.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Linq; using LibGit2Sharp.Tests.TestHelpers; using NUnit.Framework; @@ -57,6 +58,11 @@ private static void AssertInitializedRepository(Repository repo) repo.Info.IsHeadDetached.ShouldBeFalse(); repo.Head.TargetIdentifier.ShouldEqual("refs/heads/master"); repo.Head.ResolveToDirectReference().ShouldBeNull(); + + repo.Commits.Count().ShouldEqual(0); + repo.Commits.QueryBy(new Filter { Since = repo.Head }).Count().ShouldEqual(0); + repo.Commits.QueryBy(new Filter { Since = "HEAD" }).Count().ShouldEqual(0); + repo.Commits.QueryBy(new Filter { Since = "refs/heads/master" }).Count().ShouldEqual(0); } [Test] @@ -233,22 +239,5 @@ public void CheckingForObjectExistenceWithBadParamsThrows() Assert.Throws(() => repo.HasObject(null)); } } - - [Test] - public void CheckForDetachedHeadOnNewRepo() - { - using (var scd = new SelfCleaningDirectory()) - { - var dir = Repository.Init(scd.DirectoryPath, true); - Path.IsPathRooted(dir).ShouldBeTrue(); - Directory.Exists(dir).ShouldBeTrue(); - - using (var repo = new Repository(dir)) - { - repo.Info.IsEmpty.ShouldBeTrue(); - repo.Info.IsHeadDetached.ShouldBeFalse(); - } - } - } } } \ No newline at end of file diff --git a/LibGit2Sharp/Branch.cs b/LibGit2Sharp/Branch.cs index 3918ee6b7..9b0eb9325 100644 --- a/LibGit2Sharp/Branch.cs +++ b/LibGit2Sharp/Branch.cs @@ -70,9 +70,9 @@ public bool IsCurrentRepositoryHead /// /// Gets the commits on this branch. (Starts walking from the References's target). /// - public CommitCollection Commits + public ICommitCollection Commits { - get { return repo.Commits.StartingAt(this); } + get { return repo.Commits.QueryBy(new Filter{Since = this}); } } #region IEquatable Members @@ -149,5 +149,14 @@ private static string ShortenName(string branchName) { return !Equals(left, right); } + + /// + /// Returns the , a representation of the current . + /// + /// The that represents the current . + public override string ToString() + { + return CanonicalName; + } } } \ No newline at end of file diff --git a/LibGit2Sharp/Commit.cs b/LibGit2Sharp/Commit.cs index a67ff6efa..b9368ec69 100644 --- a/LibGit2Sharp/Commit.cs +++ b/LibGit2Sharp/Commit.cs @@ -89,8 +89,8 @@ internal static Commit BuildFromPtr(IntPtr obj, ObjectId id, Repository repo) return new Commit(id, treeId, repo) { - Message = NativeMethods.git_commit_message(obj), - MessageShort = NativeMethods.git_commit_message_short(obj), + Message = NativeMethods.git_commit_message(obj).MarshallAsString(), + MessageShort = NativeMethods.git_commit_message_short(obj).MarshallAsString(), Author = new Signature(NativeMethods.git_commit_author(obj)), Committer = new Signature(NativeMethods.git_commit_committer(obj)), }; diff --git a/LibGit2Sharp/CommitCollection.cs b/LibGit2Sharp/CommitCollection.cs index 7be815047..35d3be7a4 100644 --- a/LibGit2Sharp/CommitCollection.cs +++ b/LibGit2Sharp/CommitCollection.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Globalization; using LibGit2Sharp.Core; namespace LibGit2Sharp @@ -8,10 +9,11 @@ namespace LibGit2Sharp /// /// A collection of commits in a /// - public class CommitCollection : IEnumerable + public class CommitCollection : IQueryableCommitCollection { private readonly Repository repo; private ObjectId pushedObjectId; + private ObjectId hiddenObjectId; private readonly GitSortOptions sortOptions; /// @@ -34,30 +36,6 @@ internal CommitCollection(Repository repo, GitSortOptions sortingStrategy) sortOptions = sortingStrategy; } - /// - /// Gets the with the specified sha. (This is identical to calling Lookup/(sha) on the repo) - /// - public Commit this[string sha] - { - get { return repo.Lookup(sha); } - } - - /// - /// Gets the count of commits (This is a fast count that does not hydrate real commit objects) - /// - public int Count - { - get - { - var count = 0; - using (var enumerator = new CommitEnumerator(repo, pushedObjectId, sortOptions)) - { - while (enumerator.MoveNext()) count++; - } - return count; - } - } - /// /// Gets the current sorting strategy applied when enumerating the collection /// @@ -76,10 +54,10 @@ public IEnumerator GetEnumerator() { if (pushedObjectId == null) { - throw new NotImplementedException(); + throw new InvalidOperationException(); } - return new CommitEnumerator(repo, pushedObjectId, sortOptions); + return new CommitEnumerator(repo, pushedObjectId, hiddenObjectId, sortOptions); } /// @@ -94,32 +72,49 @@ IEnumerator IEnumerable.GetEnumerator() #endregion /// - /// Sorts according to the specified strategy. + /// Returns the list of commits of the repository matching the specified . /// - /// The sorting strategy to be applied when enumerating the commits. - /// - public CommitCollection SortBy(GitSortOptions sortingStrategy) + /// The options used to control which commits will be returned. + /// A collection of commits, ready to be enumerated. + public ICommitCollection QueryBy(Filter filter) { - return new CommitCollection(repo, sortingStrategy) { pushedObjectId = pushedObjectId }; + Ensure.ArgumentNotNull(filter, "filter"); + Ensure.ArgumentNotNull(filter.Since, "filter.Since"); + + string sinceIdentifier = filter.Since.ToString(); + + if ((repo.Info.IsEmpty) && PointsAtTheHead(sinceIdentifier)) + { + return new EmptyCommitCollection(filter.SortBy); + } + + ObjectId sinceObjectId = RetrieveCommitId(sinceIdentifier); + ObjectId untilObjectId = null; + + if (filter.Until != null) + { + untilObjectId = RetrieveCommitId(filter.Until.ToString()); + } + + return new CommitCollection(repo, filter.SortBy) { pushedObjectId = sinceObjectId, hiddenObjectId = untilObjectId}; } - /// - /// Starts enumeratoring the at the specified sha. - /// - /// The sha or reference canonical name to use. - /// - public CommitCollection StartingAt(string shaOrReferenceName) + private ObjectId RetrieveCommitId(string shaOrReferenceName) { - Ensure.ArgumentNotNullOrEmptyString(shaOrReferenceName, "shaOrReferenceName"); - GitObject gitObj = repo.Lookup(shaOrReferenceName); - if (gitObj == null) // TODO: Should we check the type? Git-log allows TagAnnotation oid as parameter. But what about Blobs and Trees? + // TODO: Should we check the type? Git-log allows TagAnnotation oid as parameter. But what about Blobs and Trees? + if (gitObj == null) { - throw new ArgumentException(string.Format("No valid object identified as '{0}' has been found in the repository.", shaOrReferenceName), "shaOrReferenceName"); + throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "No valid git object pointed at by '{0}' exists in the repository.", shaOrReferenceName)); } - return new CommitCollection(repo, sortOptions) { pushedObjectId = gitObj.Id }; + return gitObj.Id; + } + + private static bool PointsAtTheHead(string shaOrRefName) + { + return ("HEAD".Equals(shaOrRefName, StringComparison.Ordinal) || "refs/heads/master".Equals(shaOrRefName, StringComparison.Ordinal)); } #region Nested type: CommitEnumerator @@ -130,7 +125,7 @@ private class CommitEnumerator : IEnumerator private readonly RevWalkerSafeHandle handle; private ObjectId currentOid; - public CommitEnumerator(Repository repo, ObjectId pushedOid, GitSortOptions sortingStrategy) + public CommitEnumerator(Repository repo, ObjectId pushedOid, ObjectId hiddenOid, GitSortOptions sortingStrategy) { this.repo = repo; int res = NativeMethods.git_revwalk_new(out handle, repo.Handle); @@ -138,6 +133,7 @@ public CommitEnumerator(Repository repo, ObjectId pushedOid, GitSortOptions sort Sort(sortingStrategy); Push(pushedOid); + Hide(hiddenOid); } #region IEnumerator Members @@ -207,6 +203,18 @@ private void Push(ObjectId pushedOid) Ensure.Success(res); } + private void Hide(ObjectId hiddenOid) + { + if (hiddenOid == null) + { + return; + } + + var oid = hiddenOid.Oid; + int res = NativeMethods.git_revwalk_hide(handle, ref oid); + Ensure.Success(res); + } + private void Sort(GitSortOptions options) { NativeMethods.git_revwalk_sorting(handle, options); diff --git a/LibGit2Sharp/CommitCollectionExtensions.cs b/LibGit2Sharp/CommitCollectionExtensions.cs deleted file mode 100644 index cde489a61..000000000 --- a/LibGit2Sharp/CommitCollectionExtensions.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using LibGit2Sharp.Core; - -namespace LibGit2Sharp -{ - public static class CommitCollectionExtensions - { - /// - /// Starts enumerating the at the specified branch. - /// - /// The commit collection to enumerate. - /// The branch. - /// - public static CommitCollection StartingAt(this CommitCollection commitCollection, Branch branch) - { - Ensure.ArgumentNotNull(branch, "branch"); - - Commit commit = branch.Tip; - - if (commit == null) - { - throw new ArgumentException(string.Format("No valid object identified as '{0}' has been found in the repository.", branch.CanonicalName), "branch"); - } - - return commitCollection.StartingAt(commit.Sha); - } - - /// - /// Starts enumerating the at the specified reference. - /// - /// The commit collection to enumerate. - /// The reference. - /// - public static CommitCollection StartingAt(this CommitCollection commitCollection, Reference reference) - { - Ensure.ArgumentNotNull(reference, "reference"); - - return commitCollection.StartingAt(reference.ResolveToDirectReference().CanonicalName); - } - } -} diff --git a/LibGit2Sharp/Core/Ensure.cs b/LibGit2Sharp/Core/Ensure.cs index 4cbc60991..e0813fd4b 100644 --- a/LibGit2Sharp/Core/Ensure.cs +++ b/LibGit2Sharp/Core/Ensure.cs @@ -47,7 +47,7 @@ public static void Success(int result) return; } - string errorMessage = NativeMethods.git_lasterror(); + string errorMessage = NativeMethods.git_lasterror().MarshallAsString(); throw new ApplicationException( String.Format(CultureInfo.InvariantCulture, "An error was raised by libgit2. Error code = {0} ({1}).{2}{3}", Enum.GetName(typeof(GitErrorCode), result), result, Environment.NewLine, errorMessage)); diff --git a/LibGit2Sharp/Core/GitErrorCode.cs b/LibGit2Sharp/Core/GitErrorCode.cs index ef015a32b..05ae747c9 100644 --- a/LibGit2Sharp/Core/GitErrorCode.cs +++ b/LibGit2Sharp/Core/GitErrorCode.cs @@ -18,136 +18,136 @@ internal enum GitErrorCode /// /// Input was not a properly formatted Git object id. /// - GIT_ENOTOID = (GIT_ERROR - 1), + GIT_ENOTOID = -2, /// /// Input does not exist in the scope searched. /// - GIT_ENOTFOUND = (GIT_ERROR - 2), + GIT_ENOTFOUND = -3, /// /// Not enough space available. /// - GIT_ENOMEM = (GIT_ERROR - 3), + GIT_ENOMEM = -4, /// /// Consult the OS error information. /// - GIT_EOSERR = (GIT_ERROR - 4), + GIT_EOSERR = -5, /// /// The specified object is of invalid type /// - GIT_EOBJTYPE = (GIT_ERROR - 5), - - /// - /// The specified object has its data corrupted - /// - GIT_EOBJCORRUPTED = (GIT_ERROR - 6), + GIT_EOBJTYPE = -6, /// /// The specified repository is invalid /// - GIT_ENOTAREPO = (GIT_ERROR - 7), + GIT_ENOTAREPO = -7, /// /// The object type is invalid or doesn't match /// - GIT_EINVALIDTYPE = (GIT_ERROR - 8), + GIT_EINVALIDTYPE = -8, /// /// The object cannot be written that because it's missing internal data /// - GIT_EMISSINGOBJDATA = (GIT_ERROR - 9), + GIT_EMISSINGOBJDATA = -9, /// /// The packfile for the ODB is corrupted /// - GIT_EPACKCORRUPTED = (GIT_ERROR - 10), + GIT_EPACKCORRUPTED = -10, /// /// Failed to adquire or release a file lock /// - GIT_EFLOCKFAIL = (GIT_ERROR - 11), + GIT_EFLOCKFAIL = -11, /// /// The Z library failed to inflate/deflate an object's data /// - GIT_EZLIB = (GIT_ERROR - 12), + GIT_EZLIB = -12, /// /// The queried object is currently busy /// - GIT_EBUSY = (GIT_ERROR - 13), + GIT_EBUSY = -13, /// /// The index file is not backed up by an existing repository /// - GIT_EBAREINDEX = (GIT_ERROR - 14), + GIT_EBAREINDEX = -14, /// /// The name of the reference is not valid /// - GIT_EINVALIDREFNAME = (GIT_ERROR - 15), + GIT_EINVALIDREFNAME = -15, /// /// The specified reference has its data corrupted /// - GIT_EREFCORRUPTED = (GIT_ERROR - 16), + GIT_EREFCORRUPTED = -16, /// /// The specified symbolic reference is too deeply nested /// - GIT_ETOONESTEDSYMREF = (GIT_ERROR - 17), + GIT_ETOONESTEDSYMREF = -17, /// /// The pack-refs file is either corrupted of its format is not currently supported /// - GIT_EPACKEDREFSCORRUPTED = (GIT_ERROR - 18), + GIT_EPACKEDREFSCORRUPTED = -18, /// /// The path is invalid /// - GIT_EINVALIDPATH = (GIT_ERROR - 19), + GIT_EINVALIDPATH = -19, /// /// The revision walker is empty; there are no more commits left to iterate /// - GIT_EREVWALKOVER = (GIT_ERROR - 20), + GIT_EREVWALKOVER = -20, /// /// The state of the reference is not valid /// - GIT_EINVALIDREFSTATE = (GIT_ERROR - 21), + GIT_EINVALIDREFSTATE = -21, /// /// This feature has not been implemented yet /// - GIT_ENOTIMPLEMENTED = (GIT_ERROR - 22), + GIT_ENOTIMPLEMENTED = -22, /// /// A reference with this name already exists /// - GIT_EEXISTS = (GIT_ERROR - 23), + GIT_EEXISTS = -23, /// /// The given integer literal is too large to be parsed /// - GIT_EOVERFLOW = (GIT_ERROR - 24), + GIT_EOVERFLOW = -24, /// /// The given literal is not a valid number /// - GIT_ENOTNUM = (GIT_ERROR - 25), + GIT_ENOTNUM = -25, /// /// Streaming error /// - GIT_ESTREAM = (GIT_ERROR - 26), + GIT_ESTREAM = -26, /// /// invalid arguments to function /// - GIT_EINVALIDARGS = (GIT_ERROR - 27), + GIT_EINVALIDARGS = -27, + + /// + /// The specified object has its data corrupted + /// + GIT_EOBJCORRUPTED = -28, } } \ No newline at end of file diff --git a/LibGit2Sharp/Core/IntPtrExtensions.cs b/LibGit2Sharp/Core/IntPtrExtensions.cs new file mode 100644 index 000000000..b6378b071 --- /dev/null +++ b/LibGit2Sharp/Core/IntPtrExtensions.cs @@ -0,0 +1,13 @@ +using System; +using System.Runtime.InteropServices; + +namespace LibGit2Sharp.Core +{ + internal static class IntPtrExtensions + { + public static string MarshallAsString(this IntPtr intPtr) + { + return Marshal.PtrToStringAnsi(intPtr); + } + } +} \ No newline at end of file diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs index 5ac4ff051..7cddc630e 100644 --- a/LibGit2Sharp/Core/NativeMethods.cs +++ b/LibGit2Sharp/Core/NativeMethods.cs @@ -3,12 +3,10 @@ namespace LibGit2Sharp.Core { - internal class NativeMethods + internal static class NativeMethods { - const string libgit2 = "git2.dll"; + const string libgit2 = "git2-0.dll"; - private NativeMethods() { } - [DllImport(libgit2)] public static extern IntPtr git_blob_rawcontent(IntPtr blob); @@ -25,12 +23,10 @@ private NativeMethods() { } public static extern int git_commit_create_o(out GitOid oid, RepositorySafeHandle repo, string updateRef, IntPtr author, IntPtr committer, string message, IntPtr tree, int parentCount, IntPtr parents); [DllImport(libgit2)] - [return: MarshalAs(UnmanagedType.AnsiBStr)] - public static extern string git_commit_message(IntPtr commit); + public static extern IntPtr git_commit_message(IntPtr commit); [DllImport(libgit2)] - [return: MarshalAs(UnmanagedType.AnsiBStr)] - public static extern string git_commit_message_short(IntPtr commit); + public static extern IntPtr git_commit_message_short(IntPtr commit); [DllImport(libgit2)] public static extern int git_commit_parent(out IntPtr parentCommit, IntPtr commit, uint n); @@ -63,8 +59,7 @@ private NativeMethods() { } public static extern int git_index_open_inrepo(out IndexSafeHandle index, RepositorySafeHandle repo); [DllImport(libgit2)] - [return: MarshalAs(UnmanagedType.AnsiBStr)] - public static extern string git_lasterror(); + public static extern IntPtr git_lasterror(); [DllImport(libgit2)] public static extern void git_object_close(IntPtr obj); @@ -113,8 +108,7 @@ private NativeMethods() { } public static extern int git_reference_lookup(out IntPtr reference, RepositorySafeHandle repo, string name); [DllImport(libgit2)] - [return: MarshalAs(UnmanagedType.AnsiBStr)] - public static extern string git_reference_name(IntPtr reference); + public static extern IntPtr git_reference_name(IntPtr reference); [DllImport(libgit2)] public static extern IntPtr git_reference_oid(IntPtr reference); @@ -135,8 +129,7 @@ private NativeMethods() { } public static extern int git_reference_set_target(IntPtr reference, string target); [DllImport(libgit2)] - [return: MarshalAs(UnmanagedType.AnsiBStr)] - public static extern string git_reference_target(IntPtr reference); + public static extern IntPtr git_reference_target(IntPtr reference); [DllImport(libgit2)] public static extern GitReferenceType git_reference_type(IntPtr reference); @@ -158,16 +151,17 @@ private NativeMethods() { } public static extern int git_repository_open(out RepositorySafeHandle repository, string path); [DllImport(libgit2)] - [return: MarshalAs(UnmanagedType.AnsiBStr)] - public static extern string git_repository_path(RepositorySafeHandle repository); + public static extern IntPtr git_repository_path(RepositorySafeHandle repository); [DllImport(libgit2)] - [return: MarshalAs(UnmanagedType.AnsiBStr)] - public static extern string git_repository_workdir(RepositorySafeHandle repository); + public static extern IntPtr git_repository_workdir(RepositorySafeHandle repository); [DllImport(libgit2)] public static extern void git_revwalk_free(IntPtr walker); + [DllImport(libgit2)] + public static extern int git_revwalk_hide(RevWalkerSafeHandle walker, ref GitOid oid); + [DllImport(libgit2)] public static extern int git_revwalk_new(out RevWalkerSafeHandle walker, RepositorySafeHandle repo); @@ -199,12 +193,10 @@ private NativeMethods() { } public static extern int git_tag_delete(RepositorySafeHandle repo, string tagName); [DllImport(libgit2)] - [return: MarshalAs(UnmanagedType.AnsiBStr)] - public static extern string git_tag_message(IntPtr tag); + public static extern IntPtr git_tag_message(IntPtr tag); [DllImport(libgit2)] - [return: MarshalAs(UnmanagedType.AnsiBStr)] - public static extern string git_tag_name(IntPtr tag); + public static extern IntPtr git_tag_name(IntPtr tag); [DllImport(libgit2)] public static extern IntPtr git_tag_tagger(IntPtr tag); @@ -228,8 +220,7 @@ private NativeMethods() { } public static extern IntPtr git_tree_entry_id(IntPtr tree); [DllImport(libgit2)] - [return: MarshalAs(UnmanagedType.AnsiBStr)] - public static extern string git_tree_entry_name(IntPtr entry); + public static extern IntPtr git_tree_entry_name(IntPtr entry); [DllImport(libgit2)] public static extern int git_tree_entrycount(IntPtr tree); diff --git a/LibGit2Sharp/Core/UnSafeNativeMethods.cs b/LibGit2Sharp/Core/UnSafeNativeMethods.cs index 22c9ccf5a..6c5b85753 100644 --- a/LibGit2Sharp/Core/UnSafeNativeMethods.cs +++ b/LibGit2Sharp/Core/UnSafeNativeMethods.cs @@ -3,11 +3,9 @@ namespace LibGit2Sharp.Core { - internal unsafe class UnSafeNativeMethods + internal static unsafe class UnSafeNativeMethods { - private const string libgit2 = "git2.dll"; - - private UnSafeNativeMethods() { } + private const string libgit2 = "git2-0.dll"; [DllImport(libgit2)] public static extern int git_reference_listall(git_strarray* array, RepositorySafeHandle repo, GitReferenceType flags); diff --git a/LibGit2Sharp/DirectReference.cs b/LibGit2Sharp/DirectReference.cs index cc79e5d7c..7a3feb9a7 100644 --- a/LibGit2Sharp/DirectReference.cs +++ b/LibGit2Sharp/DirectReference.cs @@ -1,18 +1,37 @@ -namespace LibGit2Sharp +using System; + +namespace LibGit2Sharp { /// /// A DirectReference points directly to a /// public class DirectReference : Reference { + private readonly Func targetResolver; + private bool resolved; + private GitObject target; + + internal DirectReference(Func targetResolver) + { + this.targetResolver = targetResolver; + } + /// /// Gets the target of this /// - public GitObject Target { get; internal set; } - - protected override object ProvideAdditionalEqualityComponent() + public GitObject Target { - return Target; + get + { + if (resolved) + { + return target; + } + + target = targetResolver(); + resolved = true; + return target; + } } /// diff --git a/LibGit2Sharp/EmptyCommitCollection.cs b/LibGit2Sharp/EmptyCommitCollection.cs new file mode 100644 index 000000000..31d5537b4 --- /dev/null +++ b/LibGit2Sharp/EmptyCommitCollection.cs @@ -0,0 +1,53 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace LibGit2Sharp +{ + internal class EmptyCommitCollection : IQueryableCommitCollection + { + internal EmptyCommitCollection(GitSortOptions sortedBy) + { + SortedBy = sortedBy; + } + + /// + /// Returns an enumerator that iterates through the collection. + /// + /// + /// A that can be used to iterate through the collection. + /// + /// 1 + public IEnumerator GetEnumerator() + { + return Enumerable.Empty().GetEnumerator(); + } + + /// + /// Returns the list of commits of the repository matching the specified . + /// + /// The options used to control which commits will be returned. + /// A collection of commits, ready to be enumerated. + public ICommitCollection QueryBy(Filter filter) + { + return new EmptyCommitCollection(filter.SortBy); + } + + /// + /// Returns an enumerator that iterates through a collection. + /// + /// + /// An object that can be used to iterate through the collection. + /// + /// 2 + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// Gets the current sorting strategy applied when enumerating the collection. + /// + public GitSortOptions SortedBy { get; private set; } + } +} \ No newline at end of file diff --git a/LibGit2Sharp/Filter.cs b/LibGit2Sharp/Filter.cs new file mode 100644 index 000000000..5985ddf30 --- /dev/null +++ b/LibGit2Sharp/Filter.cs @@ -0,0 +1,43 @@ +namespace LibGit2Sharp +{ + /// + /// Options used to filter out the commits of the repository when querying its history. + /// + public class Filter + { + /// + /// Initializes a new instance of . + /// + public Filter() + { + SortBy = GitSortOptions.Time; + Since = "HEAD"; + } + + /// + /// The ordering stragtegy to use. + /// + /// By default, the commits are shown in reverse chronological order. + /// + /// + public GitSortOptions SortBy { get; set; } + + /// + /// The pointer to the commit to consider as a starting point. + /// + /// Can be either a containing the sha or reference canonical name to use, a or a . + /// By default, the will be used as boundary. + /// + /// + public object Since { get; set; } + + + /// + /// The pointer to the commit which will be excluded (along with its ancestors) from the enumeration. + /// + /// Can be either a containing the sha or reference canonical name to use, a or a . + /// + /// + public object Until { get; set; } + } +} \ No newline at end of file diff --git a/LibGit2Sharp/ICommitCollection.cs b/LibGit2Sharp/ICommitCollection.cs new file mode 100644 index 000000000..2d8633a07 --- /dev/null +++ b/LibGit2Sharp/ICommitCollection.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; + +namespace LibGit2Sharp +{ + public interface ICommitCollection : IEnumerable + { + /// + /// Gets the current sorting strategy applied when enumerating the collection. + /// + GitSortOptions SortedBy { get; } + } +} \ No newline at end of file diff --git a/LibGit2Sharp/IQueryableCommitCollection.cs b/LibGit2Sharp/IQueryableCommitCollection.cs new file mode 100644 index 000000000..e4329b285 --- /dev/null +++ b/LibGit2Sharp/IQueryableCommitCollection.cs @@ -0,0 +1,12 @@ +namespace LibGit2Sharp +{ + public interface IQueryableCommitCollection : ICommitCollection + { + /// + /// Returns the list of commits of the repository matching the specified . + /// + /// The options used to control which commits will be returned. + /// A collection of commits, ready to be enumerated. + ICommitCollection QueryBy(Filter filter); + } +} \ No newline at end of file diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj index 4579d277f..66db0fbeb 100644 --- a/LibGit2Sharp/LibGit2Sharp.csproj +++ b/LibGit2Sharp/LibGit2Sharp.csproj @@ -47,7 +47,6 @@ - @@ -58,6 +57,7 @@ + @@ -71,15 +71,19 @@ + + + + @@ -99,11 +103,13 @@ - - git2.dll + + + + + git2-0.dll PreserveNewest - diff --git a/LibGit2Sharp/ObjectId.cs b/LibGit2Sharp/ObjectId.cs index d576a769a..a1368098a 100644 --- a/LibGit2Sharp/ObjectId.cs +++ b/LibGit2Sharp/ObjectId.cs @@ -31,13 +31,10 @@ internal ObjectId(GitOid oid) /// Initializes a new instance of the class. /// /// The byte array. - public ObjectId(byte[] rawId) + public ObjectId(byte[] rawId) : this(new GitOid{Id = rawId} ) { Ensure.ArgumentNotNull(rawId, "rawId"); Ensure.ArgumentConformsTo(rawId, b => b.Length == rawSize, "rawId"); - - oid = new GitOid { Id = rawId }; - Sha = Stringify(oid); } /// @@ -110,7 +107,7 @@ private static string Stringify(GitOid oid) { var hex = new byte[hexSize]; NativeMethods.git_oid_fmt(hex, ref oid); - return Encoding.UTF8.GetString(hex); + return Encoding.ASCII.GetString(hex); } /// diff --git a/LibGit2Sharp/Properties/AssemblyInfo.cs b/LibGit2Sharp/Properties/AssemblyInfo.cs index 691ebf24d..3ef680950 100644 --- a/LibGit2Sharp/Properties/AssemblyInfo.cs +++ b/LibGit2Sharp/Properties/AssemblyInfo.cs @@ -41,5 +41,5 @@ // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.1.1")] -[assembly: AssemblyFileVersion("0.1.1")] \ No newline at end of file +[assembly: AssemblyVersion("0.2.0")] +[assembly: AssemblyFileVersion("0.2.0")] \ No newline at end of file diff --git a/LibGit2Sharp/Reference.cs b/LibGit2Sharp/Reference.cs index 442f5367d..387df15e5 100644 --- a/LibGit2Sharp/Reference.cs +++ b/LibGit2Sharp/Reference.cs @@ -11,7 +11,7 @@ namespace LibGit2Sharp public abstract class Reference : IEquatable { private static readonly LambdaEqualityHelper equalityHelper = - new LambdaEqualityHelper(new Func[] { x => x.CanonicalName, x => x.ProvideAdditionalEqualityComponent() }); + new LambdaEqualityHelper(new Func[] { x => x.CanonicalName, x => x.TargetIdentifier }); /// /// Gets the full name of this reference. @@ -26,8 +26,8 @@ internal static T BuildFromPtr(IntPtr ptr, Repository repo) where T : class return default(T); } - var name = NativeMethods.git_reference_name(ptr); - var type = NativeMethods.git_reference_type(ptr); + string name = NativeMethods.git_reference_name(ptr).MarshallAsString(); + GitReferenceType type = NativeMethods.git_reference_type(ptr); Reference reference; string targetIdentifier; @@ -36,7 +36,7 @@ internal static T BuildFromPtr(IntPtr ptr, Repository repo) where T : class { case GitReferenceType.Symbolic: IntPtr resolveRef; - targetIdentifier = NativeMethods.git_reference_target(ptr); + targetIdentifier = NativeMethods.git_reference_target(ptr).MarshallAsString(); int res = NativeMethods.git_reference_resolve(out resolveRef, ptr); if (res == (int) GitErrorCode.GIT_ENOTFOUND) @@ -57,8 +57,8 @@ internal static T BuildFromPtr(IntPtr ptr, Repository repo) where T : class var targetId = new ObjectId(oid); targetIdentifier = targetId.Sha; - var target = repo.Lookup(targetId); - reference = new DirectReference { CanonicalName = name, Target = target, TargetIdentifier = targetIdentifier}; + var targetResolver = new Func(() => repo.Lookup(targetId)); + reference = new DirectReference(targetResolver) { CanonicalName = name, TargetIdentifier = targetIdentifier}; break; default: @@ -88,8 +88,6 @@ internal static T BuildFromPtr(IntPtr ptr, Repository repo) where T : class Enum.GetName(typeof (GitReferenceType), type))); } - protected abstract object ProvideAdditionalEqualityComponent(); - /// /// Recursively peels the target of the reference until a direct reference is encountered. /// @@ -155,5 +153,14 @@ public override int GetHashCode() { return !Equals(left, right); } + + /// + /// Returns the , a representation of the current . + /// + /// The that represents the current . + public override string ToString() + { + return CanonicalName; + } } } \ No newline at end of file diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs index f1671e6f2..bd6f88496 100644 --- a/LibGit2Sharp/Repository.cs +++ b/LibGit2Sharp/Repository.cs @@ -27,8 +27,8 @@ public Repository(string path) var res = NativeMethods.git_repository_open(out handle, PosixPathHelper.ToPosix(path)); Ensure.Success(res); - string normalizedPath = NativeMethods.git_repository_path(handle); - string normalizedWorkDir = NativeMethods.git_repository_workdir(handle); + string normalizedPath = NativeMethods.git_repository_path(handle).MarshallAsString(); + string normalizedWorkDir = NativeMethods.git_repository_workdir(handle).MarshallAsString(); Info = new RepositoryInformation(this, normalizedPath, normalizedWorkDir, normalizedWorkDir == null); @@ -49,7 +49,7 @@ internal RepositorySafeHandle Handle /// Shortcut to return the reference to HEAD /// /// - + public Reference Head { get { return Refs["HEAD"]; } @@ -75,9 +75,9 @@ public ReferenceCollection Refs /// Lookup and enumerate commits in the repository. /// Iterating this collection directly starts walking from the HEAD. /// - public CommitCollection Commits + public IQueryableCommitCollection Commits { - get { return commits.StartingAt(Head); } + get { return (IQueryableCommitCollection)commits.QueryBy(new Filter { Since = Head }); } } /// @@ -164,7 +164,7 @@ public static string Init(string path, bool bare = false) var res = NativeMethods.git_repository_init(out repo, PosixPathHelper.ToPosix(path), bare); Ensure.Success(res); - string normalizedPath = NativeMethods.git_repository_path(repo); + string normalizedPath = NativeMethods.git_repository_path(repo).MarshallAsString(); repo.Dispose(); return PosixPathHelper.ToNative(normalizedPath); @@ -219,7 +219,7 @@ public GitObject Lookup(string shaOrReferenceName, GitObjectType type = GitObjec private static bool IsReferencePeelable(Reference reference) { - return reference != null && ((reference is DirectReference) ||(reference is SymbolicReference && ((SymbolicReference)reference).Target != null)); + return reference != null && ((reference is DirectReference) || (reference is SymbolicReference && ((SymbolicReference)reference).Target != null)); } } } \ No newline at end of file diff --git a/LibGit2Sharp/SymbolicReference.cs b/LibGit2Sharp/SymbolicReference.cs index 0ddc5be67..e1a8290aa 100644 --- a/LibGit2Sharp/SymbolicReference.cs +++ b/LibGit2Sharp/SymbolicReference.cs @@ -10,11 +10,6 @@ public class SymbolicReference : Reference /// public Reference Target { get; internal set; } - protected override object ProvideAdditionalEqualityComponent() - { - return Target; - } - /// /// Recursively peels the target of the reference until a direct reference is encountered. /// diff --git a/LibGit2Sharp/TagAnnotation.cs b/LibGit2Sharp/TagAnnotation.cs index 005e7ccde..47280e3c0 100644 --- a/LibGit2Sharp/TagAnnotation.cs +++ b/LibGit2Sharp/TagAnnotation.cs @@ -41,8 +41,8 @@ internal static TagAnnotation BuildFromPtr(IntPtr obj, ObjectId id) return new TagAnnotation(id) { - Message = NativeMethods.git_tag_message(obj), - Name = NativeMethods.git_tag_name(obj), + Message = NativeMethods.git_tag_message(obj).MarshallAsString(), + Name = NativeMethods.git_tag_name(obj).MarshallAsString(), Tagger = new Signature(NativeMethods.git_tag_tagger(obj)), TargetId = new ObjectId(oid) }; diff --git a/LibGit2Sharp/TreeEntry.cs b/LibGit2Sharp/TreeEntry.cs index 72f42baaf..20eea0d67 100755 --- a/LibGit2Sharp/TreeEntry.cs +++ b/LibGit2Sharp/TreeEntry.cs @@ -22,7 +22,7 @@ public TreeEntry(IntPtr obj, ObjectId parentTreeId, Repository repo) targetOid = new ObjectId((GitOid)Marshal.PtrToStructure(gitTreeEntryId, typeof(GitOid))); Attributes = NativeMethods.git_tree_entry_attributes(obj); - Name = NativeMethods.git_tree_entry_name(obj); + Name = NativeMethods.git_tree_entry_name(obj).MarshallAsString(); } public int Attributes { get; private set; } diff --git a/backlog.md b/backlog.md index 2f6074ce8..40f9479dd 100644 --- a/backlog.md +++ b/backlog.md @@ -4,8 +4,6 @@ - Build a LibGit2Sharp.Sample NuGet package - Publish source and PDBs at symbolsource.org (cf. http://blog.davidebbo.com/2011/04/easy-way-to-publish-nuget-packages-with.html and http://nuget.codeplex.com/discussions/257709) - - Bind git_revwalk_hide() as CommitCollection.Until() - - Fix FluentInterface .StartingAt() and .Until() in order to prevent .StartIngAt().StartingAt(), .Until().Until() and .Until().StartingAt() - Add to Epoch a DateTimeOffset extension method ToRelativeFormat() in order to show dates relative to the current time, e.g. "2 hours ago". (cf. https://github.com/git/git/blob/master/date.c#L89) - Add branch renaming (public Branch Move(string oldName, string newName, bool allowOverwrite = false)) - Turn duplicated strings "refs/xxx" into properties of a generic Constants helper type diff --git a/nuget.package/LibGit2Sharp.nuspec b/nuget.package/LibGit2Sharp.nuspec index 49a6c85cb..1dc2dc502 100644 --- a/nuget.package/LibGit2Sharp.nuspec +++ b/nuget.package/LibGit2Sharp.nuspec @@ -2,7 +2,7 @@ LibGit2Sharp - 0.1.1 + 0.2.0 LibGit2Sharp contributors nulltoken https://github.com/libgit2/libgit2sharp/raw/master/LICENSE.md @@ -15,7 +15,7 @@ - +