diff options
author | Edward Thomson <ethomson@microsoft.com> | 2013-01-29 21:56:36 +0400 |
---|---|---|
committer | nulltoken <emeric.fermas@gmail.com> | 2013-01-31 23:19:48 +0400 |
commit | d255379ad3f96fc37dc4643ea72a2901b98ac328 (patch) | |
tree | 4ae975e669e1166c9f2e8f92fd001e2765b5c084 | |
parent | f4cc029b29c12eb79359e8ae7cc78900b64ba2ae (diff) |
Introduce repo.Network.FetchHeads
-rw-r--r-- | LibGit2Sharp.Tests/FetchHeadFixture.cs | 126 | ||||
-rw-r--r-- | LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj | 1 | ||||
-rw-r--r-- | LibGit2Sharp/Core/NativeMethods.cs | 13 | ||||
-rw-r--r-- | LibGit2Sharp/Core/Proxy.cs | 39 | ||||
-rw-r--r-- | LibGit2Sharp/FetchHead.cs | 59 | ||||
-rw-r--r-- | LibGit2Sharp/LibGit2Sharp.csproj | 2 | ||||
-rw-r--r-- | LibGit2Sharp/Network.cs | 39 | ||||
-rw-r--r-- | LibGit2Sharp/Repository.cs | 13 |
8 files changed, 292 insertions, 0 deletions
diff --git a/LibGit2Sharp.Tests/FetchHeadFixture.cs b/LibGit2Sharp.Tests/FetchHeadFixture.cs new file mode 100644 index 00000000..059a0e75 --- /dev/null +++ b/LibGit2Sharp.Tests/FetchHeadFixture.cs @@ -0,0 +1,126 @@ +using LibGit2Sharp.Tests.TestHelpers; +using System; +using System.IO; +using System.Linq; +using Xunit; +using Xunit.Extensions; + +namespace LibGit2Sharp.Tests +{ + public class FetchHeadFixture : BaseFixture + { + [Fact] + public void FetchHeadIsEmptyByDefault() + { + var scd = BuildSelfCleaningDirectory(); + using (var repo = Repository.Init(scd.RootedDirectoryPath)) + { + Assert.Equal(0, repo.Network.FetchHeads.Count()); + } + } + + private class FetchHeadExpected + { + public String Name { get; set; } + public String RemoteName { get; set; } + public String Url { get; set; } + public string TargetSha { get; set; } + public bool ForMerge { get; set; } + } + + [Theory] + [InlineData("git://github.com/libgit2/TestGitRepository.git")] + public void CanIterateFetchHead(string url) + { + var scd = BuildSelfCleaningDirectory(); + using (var repo = Repository.Clone(url, scd.RootedDirectoryPath)) + { + repo.Reset(ResetOptions.Hard, "HEAD~2"); + + // Create a file, stage it, and commit it. + String filename = "b.txt"; + String fullPath = Path.Combine(repo.Info.WorkingDirectory, filename); + File.WriteAllText(fullPath, ""); + repo.Index.Stage(filename); + repo.Commit("comment", Constants.Signature, Constants.Signature); + + // Issue the fetch. + repo.Fetch("origin"); + + // Retrieve the fetch heads and verify the expected result. + var expected = new[] { + new FetchHeadExpected + { + Name = "FETCH_HEAD[0]", + RemoteName = "refs/heads/master", + Url = "git://github.com/libgit2/TestGitRepository.git", + TargetSha = "49322bb17d3acc9146f98c97d078513228bbf3c0", + ForMerge = true, + }, + new FetchHeadExpected + { + Name = "FETCH_HEAD[1]", + RemoteName = "refs/heads/first-merge", + Url = "git://github.com/libgit2/TestGitRepository.git", + TargetSha = "0966a434eb1a025db6b71485ab63a3bfbea520b6", + ForMerge = false, + }, + new FetchHeadExpected + { + Name = "FETCH_HEAD[2]", + RemoteName = "refs/heads/no-parent", + Url = "git://github.com/libgit2/TestGitRepository.git", + TargetSha = "42e4e7c5e507e113ebbb7801b16b52cf867b7ce1", + ForMerge = false, + }, + new FetchHeadExpected + { + Name = "FETCH_HEAD[3]", + RemoteName = "refs/tags/annotated_tag", + Url = "git://github.com/libgit2/TestGitRepository.git", + TargetSha = "d96c4e80345534eccee5ac7b07fc7603b56124cb", + ForMerge = false, + }, + new FetchHeadExpected + { + Name = "FETCH_HEAD[4]", + RemoteName = "refs/tags/blob", + Url = "git://github.com/libgit2/TestGitRepository.git", + TargetSha = "55a1a760df4b86a02094a904dfa511deb5655905", + ForMerge = false, + }, + new FetchHeadExpected + { + Name = "FETCH_HEAD[5]", + RemoteName = "refs/tags/commit_tree", + Url = "git://github.com/libgit2/TestGitRepository.git", + TargetSha = "8f50ba15d49353813cc6e20298002c0d17b0a9ee", + ForMerge = false, + }, + }; + + VerifyFetchHead(repo.Network.FetchHeads.ToArray(), expected); + } + } + + private static void VerifyFetchHead(FetchHead[] actual, FetchHeadExpected[] expected) + { + Assert.NotNull(actual); + Assert.NotNull(expected); + + Assert.Equal(actual.Count(), expected.Count()); + + int i = 0; + foreach (FetchHead fetchHead in actual) + { + Assert.Equal(fetchHead.CanonicalName, expected[i].Name); + Assert.Equal(fetchHead.RemoteCanonicalName, expected[i].RemoteName); + Assert.Equal(fetchHead.Url, expected[i].Url); + Assert.Equal(fetchHead.Target.Sha, expected[i].TargetSha); + Assert.Equal(fetchHead.ForMerge, expected[i].ForMerge); + + i++; + } + } + } +} diff --git a/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj b/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj index feb184c3..770c38d6 100644 --- a/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj +++ b/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj @@ -60,6 +60,7 @@ <Compile Include="CheckoutFixture.cs" /> <Compile Include="CloneFixture.cs" /> <Compile Include="IgnoreFixture.cs" /> + <Compile Include="FetchHeadFixture.cs" /> <Compile Include="MergeFixture.cs" /> <Compile Include="CleanFixture.cs" /> <Compile Include="CurrentOperationFixture.cs" /> diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs index 22a08581..21bcff21 100644 --- a/LibGit2Sharp/Core/NativeMethods.cs +++ b/LibGit2Sharp/Core/NativeMethods.cs @@ -720,6 +720,19 @@ namespace LibGit2Sharp.Core [MarshalAs(UnmanagedType.Bool)] bool across_fs, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(FilePathMarshaler))] FilePath ceiling_dirs); + internal delegate int git_repository_fetchhead_foreach_cb( + IntPtr remote_name, + IntPtr remote_url, + ref GitOid oid, + [MarshalAs(UnmanagedType.Bool)] bool is_merge, + IntPtr payload); + + [DllImport(libgit2)] + internal static extern int git_repository_fetchhead_foreach( + RepositorySafeHandle repo, + git_repository_fetchhead_foreach_cb cb, + IntPtr payload); + [DllImport(libgit2)] internal static extern void git_repository_free(IntPtr repo); diff --git a/LibGit2Sharp/Core/Proxy.cs b/LibGit2Sharp/Core/Proxy.cs index cb45a1b1..defc3e48 100644 --- a/LibGit2Sharp/Core/Proxy.cs +++ b/LibGit2Sharp/Core/Proxy.cs @@ -1346,6 +1346,19 @@ namespace LibGit2Sharp.Core return RepositoryStateChecker(repo, NativeMethods.git_repository_head_detached); } + public static ICollection<TResult> git_repository_fetchhead_foreach<TResult>( + RepositorySafeHandle repo, + Func<string, string, GitOid, bool, TResult> resultSelector) + { + return git_foreach( + resultSelector, + c => NativeMethods.git_repository_fetchhead_foreach( + repo, + (IntPtr w, IntPtr x, ref GitOid y, bool z, IntPtr p) + => c(Utf8Marshaler.FromNative(w), Utf8Marshaler.FromNative(x), y, z, p), IntPtr.Zero), + GitErrorCode.NotFound); + } + public static void git_repository_free(IntPtr repo) { NativeMethods.git_repository_free(repo); @@ -1882,6 +1895,32 @@ namespace LibGit2Sharp.Core } } + public delegate TResult Func<T1, T2, T3, T4, T5, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); + + private static ICollection<TResult> git_foreach<T1, T2, T3, T4, TResult>( + Func<T1, T2, T3, T4, TResult> resultSelector, + Func<Func<T1, T2, T3, T4, IntPtr, int>, int> iterator, + params GitErrorCode[] ignoredErrorCodes) + { + using (ThreadAffinity()) + { + var result = new List<TResult>(); + var res = iterator((w, x, y, z, payload) => + { + result.Add(resultSelector(w, x, y, z)); + return 0; + }); + + if (ignoredErrorCodes != null && ignoredErrorCodes.Contains((GitErrorCode)res)) + { + return new TResult[0]; + } + + Ensure.Success(res); + return result; + } + } + private static unsafe class Libgit2UnsafeHelper { public static IList<string> BuildListOf(UnSafeNativeMethods.git_strarray strArray) diff --git a/LibGit2Sharp/FetchHead.cs b/LibGit2Sharp/FetchHead.cs new file mode 100644 index 00000000..09f39f9f --- /dev/null +++ b/LibGit2Sharp/FetchHead.cs @@ -0,0 +1,59 @@ +using System; +using System.Globalization; + +namespace LibGit2Sharp +{ + /// <summary> + /// Represents a local reference data from a remote repository which + /// has been retreived through a Fetch process. + /// </summary> + public class FetchHead : ReferenceWrapper<GitObject> + { + /// <summary> + /// Needed for mocking purposes. + /// </summary> + protected FetchHead() + { } + + internal FetchHead(Repository repo, string remoteCanonicalName, + string url, ObjectId targetId, bool forMerge, int index) + : base(repo, new DirectReference( + string.Format(CultureInfo.InvariantCulture, "FETCH_HEAD[{0}]", index), + repo, targetId), r => r.CanonicalName) + { + Url = url; + ForMerge = forMerge; + RemoteCanonicalName = remoteCanonicalName; + } + + protected override string Shorten() + { + return CanonicalName; + } + + /// <summary> + /// Gets the canonical name of the reference this <see cref="FetchHead"/> + /// points to in the remote repository it's been fetched from. + /// </summary> + public virtual string RemoteCanonicalName { get; private set; } + + /// <summary> + /// Gets the <see cref="GitObject"/> that this fetch head points to. + /// </summary> + public virtual GitObject Target + { + get { return TargetObject; } + } + + /// <summary> + /// The URL of the remote repository this <see cref="FetchHead"/> + /// has been built from. + /// </summary> + public virtual String Url { get; private set; } + + /// <summary> + /// Determines if this fetch head entry has been explicitly fetched. + /// </summary> + public virtual bool ForMerge { get; private set; } + } +} diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj index b659dbcb..f30476e2 100644 --- a/LibGit2Sharp/LibGit2Sharp.csproj +++ b/LibGit2Sharp/LibGit2Sharp.csproj @@ -65,6 +65,7 @@ <Compile Include="Changes.cs" /> <Compile Include="CheckoutCallbacks.cs" /> <Compile Include="CheckoutOptions.cs" /> + <Compile Include="Network.cs" /> <Compile Include="OrphanedHeadException.cs" /> <Compile Include="UnmergedIndexEntriesException.cs" /> <Compile Include="Commit.cs" /> @@ -89,6 +90,7 @@ <Compile Include="Credentials.cs" /> <Compile Include="DiffOptions.cs" /> <Compile Include="DiffTargets.cs" /> + <Compile Include="FetchHead.cs" /> <Compile Include="Handlers.cs" /> <Compile Include="Ignore.cs" /> <Compile Include="MergeConflictException.cs" /> diff --git a/LibGit2Sharp/Network.cs b/LibGit2Sharp/Network.cs new file mode 100644 index 00000000..859f73df --- /dev/null +++ b/LibGit2Sharp/Network.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using LibGit2Sharp.Core; + +namespace LibGit2Sharp +{ + /// <summary> + /// Provides access to network functionality for a repository. + /// </summary> + public class Network + { + private readonly Repository repository; + + /// <summary> + /// Needed for mocking purposes. + /// </summary> + protected Network() + { } + + internal Network(Repository repository) + { + this.repository = repository; + } + + /// <summary> + /// The heads that have been updated during the last fetch. + /// </summary> + public virtual IEnumerable<FetchHead> FetchHeads + { + get + { + int i = 0; + + return Proxy.git_repository_fetchhead_foreach( + repository.Handle, + (name, url, oid, isMerge) => new FetchHead(repository, name, url, new ObjectId(oid), isMerge, i++)); + } + } + } +} diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs index 1f4885a5..0ff084a0 100644 --- a/LibGit2Sharp/Repository.cs +++ b/LibGit2Sharp/Repository.cs @@ -31,6 +31,7 @@ namespace LibGit2Sharp private readonly Diff diff; private readonly NoteCollection notes; private readonly Lazy<ObjectDatabase> odb; + private readonly Network network; private readonly Stack<IDisposable> toCleanup = new Stack<IDisposable>(); private readonly Ignore ignore; private static readonly Lazy<string> versionRetriever = new Lazy<string>(RetrieveVersion); @@ -104,6 +105,7 @@ namespace LibGit2Sharp diff = new Diff(this); notes = new NoteCollection(this); ignore = new Ignore(this); + network = new Network(this); EagerlyLoadTheConfigIfAnyPathHaveBeenPassed(options); } @@ -199,6 +201,17 @@ namespace LibGit2Sharp } /// <summary> + /// Provides access to network functionality for a repository. + /// </summary> + public Network Network + { + get + { + return network; + } + } + + /// <summary> /// Gets the database. /// </summary> public ObjectDatabase ObjectDatabase |