Skip to content

Commit 53dc1c2

Browse files
committed
Convert Fetch into a command
1 parent 8c2538d commit 53dc1c2

File tree

9 files changed

+153
-128
lines changed

9 files changed

+153
-128
lines changed

LibGit2Sharp.Tests/FetchFixture.cs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public void CanFetchIntoAnEmptyRepository(string url)
2222

2323
using (var repo = new Repository(path))
2424
{
25-
Remote remote = repo.Network.Remotes.Add(remoteName, url);
25+
repo.Network.Remotes.Add(remoteName, url);
2626

2727
// Set up structures for the expected results
2828
// and verifying the RemoteUpdateTips callback.
@@ -44,7 +44,7 @@ public void CanFetchIntoAnEmptyRepository(string url)
4444
}
4545

4646
// Perform the actual fetch
47-
repo.Network.Fetch(remote, new FetchOptions { OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler });
47+
new Commands.Fetch(repo, remoteName, new string[0], new FetchOptions { OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler }, null).Run();
4848

4949
// Verify the expected
5050
expectedFetchState.CheckUpdatedReferences(repo);
@@ -61,13 +61,13 @@ public void CanFetchIntoAnEmptyRepositoryWithCredentials()
6161

6262
using (var repo = new Repository(path))
6363
{
64-
Remote remote = repo.Network.Remotes.Add(remoteName, Constants.PrivateRepoUrl);
64+
repo.Network.Remotes.Add(remoteName, Constants.PrivateRepoUrl);
6565

6666
// Perform the actual fetch
67-
repo.Network.Fetch(remote, new FetchOptions
67+
new Commands.Fetch(repo, remoteName, new string[0], new FetchOptions
6868
{
6969
CredentialsProvider = Constants.PrivateRepoCredentials
70-
});
70+
}, null).Run();
7171
}
7272
}
7373

@@ -81,7 +81,7 @@ public void CanFetchAllTagsIntoAnEmptyRepository(string url)
8181

8282
using (var repo = new Repository(path))
8383
{
84-
Remote remote = repo.Network.Remotes.Add(remoteName, url);
84+
repo.Network.Remotes.Add(remoteName, url);
8585

8686
// Set up structures for the expected results
8787
// and verifying the RemoteUpdateTips callback.
@@ -101,10 +101,10 @@ public void CanFetchAllTagsIntoAnEmptyRepository(string url)
101101
}
102102

103103
// Perform the actual fetch
104-
repo.Network.Fetch(remote, new FetchOptions {
104+
new Commands.Fetch(repo, remoteName, new string[0], new FetchOptions {
105105
TagFetchMode = TagFetchMode.All,
106106
OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler
107-
});
107+
}, null).Run();
108108

109109
// Verify the expected
110110
expectedFetchState.CheckUpdatedReferences(repo);
@@ -124,7 +124,7 @@ public void CanFetchCustomRefSpecsIntoAnEmptyRepository(string url, string local
124124

125125
using (var repo = new Repository(path))
126126
{
127-
Remote remote = repo.Network.Remotes.Add(remoteName, url);
127+
repo.Network.Remotes.Add(remoteName, url);
128128

129129
string refSpec = string.Format("refs/heads/{2}:refs/remotes/{0}/{1}", remoteName, localBranchName, remoteBranchName);
130130

@@ -147,10 +147,10 @@ public void CanFetchCustomRefSpecsIntoAnEmptyRepository(string url, string local
147147
}
148148

149149
// Perform the actual fetch
150-
repo.Network.Fetch(remote, new string[] { refSpec }, new FetchOptions {
150+
new Commands.Fetch(repo, remoteName, new string[] { refSpec }, new FetchOptions {
151151
TagFetchMode = TagFetchMode.None,
152152
OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler
153-
});
153+
}, null).Run();
154154

155155
// Verify the expected
156156
expectedFetchState.CheckUpdatedReferences(repo);
@@ -181,7 +181,7 @@ public void FetchRespectsConfiguredAutoTagSetting(TagFetchMode tagFetchMode, int
181181
r => r.TagFetchMode = tagFetchMode);
182182

183183
// Perform the actual fetch.
184-
repo.Network.Fetch(remote);
184+
new Commands.Fetch(repo, remoteName, new string[0], null, null).Run();
185185

186186
// Verify the number of fetched tags.
187187
Assert.Equal(expectedTagCount, repo.Tags.Count());
@@ -199,7 +199,7 @@ public void CanFetchAllTagsAfterAnInitialClone()
199199

200200
using (var repo = new Repository(clonedRepoPath))
201201
{
202-
repo.Fetch("origin", new FetchOptions { TagFetchMode = TagFetchMode.All });
202+
new Commands.Fetch(repo, "origin", new string[0], new FetchOptions { TagFetchMode = TagFetchMode.All }, null).Run();
203203
}
204204
}
205205

@@ -225,17 +225,17 @@ public void FetchHonorsTheFetchPruneConfigurationEntry()
225225

226226
// No pruning when the configuration entry isn't defined
227227
Assert.Null(clonedRepo.Config.Get<bool>("fetch.prune"));
228-
clonedRepo.Fetch("origin");
228+
new Commands.Fetch(clonedRepo, "origin", new string[0], null, null).Run();
229229
Assert.Equal(5, clonedRepo.Branches.Count(b => b.IsRemote));
230230

231231
// No pruning when the configuration entry is set to false
232232
clonedRepo.Config.Set<bool>("fetch.prune", false);
233-
clonedRepo.Fetch("origin");
233+
new Commands.Fetch(clonedRepo, "origin", new string[0], null, null).Run();
234234
Assert.Equal(5, clonedRepo.Branches.Count(b => b.IsRemote));
235235

236236
// Auto pruning when the configuration entry is set to true
237237
clonedRepo.Config.Set<bool>("fetch.prune", true);
238-
clonedRepo.Fetch("origin");
238+
new Commands.Fetch(clonedRepo, "origin", new string[0], null, null).Run();
239239
Assert.Equal(4, clonedRepo.Branches.Count(b => b.IsRemote));
240240
}
241241
}

LibGit2Sharp.Tests/NetworkFixture.cs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -252,10 +252,7 @@ public void CanMergeFetchedRefs()
252252
Assert.False(repo.RetrieveStatus().Any());
253253
Assert.Equal(repo.Lookup<Commit>("refs/remotes/origin/master~1"), repo.Head.Tip);
254254

255-
using (var remote = repo.Network.Remotes[repo.Head.RemoteName])
256-
{
257-
repo.Network.Fetch(remote);
258-
}
255+
new Commands.Fetch(repo, repo.Head.RemoteName, new string[0], null, null).Run();
259256

260257
MergeOptions mergeOptions = new MergeOptions()
261258
{
@@ -282,8 +279,7 @@ public void CanPruneRefs()
282279
using (var repo = new Repository(clonedRepoPath))
283280
{
284281
repo.Network.Remotes.Add("pruner", clonedRepoPath2);
285-
var remote = repo.Network.Remotes["pruner"];
286-
repo.Network.Fetch(remote);
282+
new Commands.Fetch(repo, "pruner", new string[0], null, null).Run();
287283
Assert.NotNull(repo.Refs["refs/remotes/pruner/master"]);
288284

289285
// Remove the branch from the source repository
@@ -293,11 +289,11 @@ public void CanPruneRefs()
293289
}
294290

295291
// and by default we don't prune it
296-
repo.Network.Fetch(remote);
292+
new Commands.Fetch(repo, "pruner", new string[0], null, null).Run();
297293
Assert.NotNull(repo.Refs["refs/remotes/pruner/master"]);
298294

299295
// but we do when asked by the user
300-
repo.Network.Fetch(remote, new FetchOptions { Prune = true} );
296+
new Commands.Fetch(repo, "pruner", new string[0], new FetchOptions { Prune = true}, null).Run();
301297
Assert.Null(repo.Refs["refs/remotes/pruner/master"]);
302298
}
303299
}

LibGit2Sharp.Tests/RepositoryFixture.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ public void CanFetchFromRemoteByName()
181181

182182
using (var repo = new Repository(repoPath))
183183
{
184-
Remote remote = repo.Network.Remotes.Add(remoteName, url);
184+
repo.Network.Remotes.Add(remoteName, url);
185185

186186
// We will first fetch without specifying any Tag options.
187187
// After we verify this fetch, we will perform a second fetch
@@ -208,13 +208,13 @@ public void CanFetchFromRemoteByName()
208208
}
209209

210210
// Perform the actual fetch
211-
repo.Fetch(remote.Name, new FetchOptions { OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler });
211+
new Commands.Fetch(repo, remoteName, new string[0], new FetchOptions { OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler }, null).Run();
212212

213213
// Verify the expected state
214214
expectedFetchState.CheckUpdatedReferences(repo);
215215

216216
// Now fetch the rest of the tags
217-
repo.Fetch(remote.Name, new FetchOptions { TagFetchMode = TagFetchMode.All });
217+
new Commands.Fetch(repo, remoteName, new string[0], new FetchOptions { TagFetchMode = TagFetchMode.All }, null).Run();
218218

219219
// Verify that the "nearly-dangling" tag is now in the repo.
220220
Tag nearlyDanglingTag = repo.Tags["nearly-dangling"];

LibGit2Sharp.Tests/SmartSubtransportFixture.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public void CustomSmartSubtransportTest(string scheme, string url)
4141

4242
using (var repo = new Repository(repoPath))
4343
{
44-
Remote remote = repo.Network.Remotes.Add(remoteName, url);
44+
repo.Network.Remotes.Add(remoteName, url);
4545

4646
// Set up structures for the expected results
4747
// and verifying the RemoteUpdateTips callback.
@@ -63,7 +63,9 @@ public void CustomSmartSubtransportTest(string scheme, string url)
6363
}
6464

6565
// Perform the actual fetch
66-
repo.Network.Fetch(remote, new FetchOptions { OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler, TagFetchMode = TagFetchMode.Auto });
66+
new Commands.Fetch(repo, remoteName, new string[0],
67+
new FetchOptions { OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler, TagFetchMode = TagFetchMode.Auto },
68+
null).Run();
6769

6870
// Verify the expected
6971
expectedFetchState.CheckUpdatedReferences(repo);
@@ -99,7 +101,7 @@ public void CanUseCredentials(string scheme, string url, string user, string pas
99101

100102
using (var repo = new Repository(scd.DirectoryPath))
101103
{
102-
Remote remote = repo.Network.Remotes.Add(remoteName, url);
104+
repo.Network.Remotes.Add(remoteName, url);
103105

104106
// Set up structures for the expected results
105107
// and verifying the RemoteUpdateTips callback.
@@ -113,9 +115,10 @@ public void CanUseCredentials(string scheme, string url, string user, string pas
113115
}
114116

115117
// Perform the actual fetch
116-
repo.Network.Fetch(remote, new FetchOptions { OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler, TagFetchMode = TagFetchMode.Auto,
118+
new Commands.Fetch(repo, remoteName, new string[0], new FetchOptions {
119+
OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler, TagFetchMode = TagFetchMode.Auto,
117120
CredentialsProvider = (_user, _valid, _hostname) => new UsernamePasswordCredentials() { Username = "libgit3", Password = "libgit3" },
118-
});
121+
}, null).Run();
119122

120123
// Verify the expected
121124
expectedFetchState.CheckUpdatedReferences(repo);

LibGit2Sharp/Commands/Fetch.cs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
using System.Collections.Generic;
2+
using LibGit2Sharp;
3+
using LibGit2Sharp.Core;
4+
using LibGit2Sharp.Core.Handles;
5+
6+
namespace LibGit2Sharp.Commands
7+
{
8+
/// <summary>
9+
/// Fetch from a particular remote or the default
10+
/// </summary>
11+
public class Fetch
12+
{
13+
private readonly Repository repository;
14+
private readonly string remote;
15+
private readonly FetchOptions options;
16+
private readonly string logMessage;
17+
private readonly IEnumerable<string> refspecs;
18+
19+
/// <summary>
20+
/// Initializes a new instance of the <see cref="LibGit2Sharp.Commands.Fetch"/> class.
21+
/// </summary>
22+
/// <param name="repository">The repository in which to fetch.</param>
23+
/// <param name="remote">The remote to fetch from</param>
24+
/// <param name="options">Fetch options.</param>
25+
/// <param name="logMessage">Log message for any ref updates.</param>
26+
/// <param name="refspecs">List of refspecs to apply as active.</param>
27+
public Fetch(Repository repository, string remote, IEnumerable<string> refspecs, FetchOptions options, string logMessage)
28+
{
29+
Ensure.ArgumentNotNull(remote, "remote");
30+
31+
this.repository = repository;
32+
this.remote = remote;
33+
this.options = options ?? new FetchOptions();
34+
this.logMessage = logMessage;
35+
this.refspecs = refspecs;
36+
}
37+
38+
private RemoteHandle RemoteFromNameOrUrl()
39+
{
40+
RemoteHandle handle = null;
41+
handle = Proxy.git_remote_lookup(repository.Handle, remote, false);
42+
43+
// If that wasn't the name of a remote, let's use it as a url
44+
if (handle == null)
45+
{
46+
handle = Proxy.git_remote_create_anonymous(repository.Handle, remote);
47+
}
48+
49+
return handle;
50+
}
51+
52+
/// <summary>
53+
/// Run this command
54+
/// </summary>
55+
public void Run()
56+
{
57+
using (var remoteHandle = RemoteFromNameOrUrl())
58+
{
59+
60+
var callbacks = new RemoteCallbacks(options);
61+
GitRemoteCallbacks gitCallbacks = callbacks.GenerateCallbacks();
62+
63+
// It is OK to pass the reference to the GitCallbacks directly here because libgit2 makes a copy of
64+
// the data in the git_remote_callbacks structure. If, in the future, libgit2 changes its implementation
65+
// to store a reference to the git_remote_callbacks structure this would introduce a subtle bug
66+
// where the managed layer could move the git_remote_callbacks to a different location in memory,
67+
// but libgit2 would still reference the old address.
68+
//
69+
// Also, if GitRemoteCallbacks were a class instead of a struct, we would need to guard against
70+
// GC occuring in between setting the remote callbacks and actual usage in one of the functions afterwords.
71+
var fetchOptions = new GitFetchOptions
72+
{
73+
RemoteCallbacks = gitCallbacks,
74+
download_tags = Proxy.git_remote_autotag(remoteHandle),
75+
};
76+
77+
if (options.TagFetchMode.HasValue)
78+
{
79+
fetchOptions.download_tags = options.TagFetchMode.Value;
80+
}
81+
82+
if (options.Prune.HasValue)
83+
{
84+
fetchOptions.Prune = options.Prune.Value ? FetchPruneStrategy.Prune : FetchPruneStrategy.NoPrune;
85+
}
86+
else
87+
{
88+
fetchOptions.Prune = FetchPruneStrategy.FromConfigurationOrDefault;
89+
}
90+
91+
Proxy.git_remote_fetch(remoteHandle, refspecs, fetchOptions, logMessage);
92+
}
93+
94+
}
95+
}
96+
}
97+

LibGit2Sharp/Commands/Pull.cs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,13 @@ public MergeResult Run()
4343
throw new LibGit2SharpException("There is no tracking information for the current branch.");
4444
}
4545

46-
using (var remote = repository.Network.Remotes.RemoteForName(currentBranch.RemoteName))
46+
if (currentBranch.RemoteName == null)
4747
{
48-
if (remote == null)
49-
{
50-
throw new LibGit2SharpException("No upstream remote for the current branch.");
51-
}
52-
53-
repository.Network.Fetch(remote, options.FetchOptions);
54-
return repository.MergeFetchedRefs(merger, options.MergeOptions);
48+
throw new LibGit2SharpException("No upstream remote for the current branch.");
5549
}
50+
51+
new Commands.Fetch(repository, currentBranch.RemoteName, new string[0], options.FetchOptions, null).Run();
52+
return repository.MergeFetchedRefs(merger, options.MergeOptions);
5653
}
5754
}
5855
}

LibGit2Sharp/LibGit2Sharp.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,7 @@
351351
<Compile Include="Core\GitCredential.cs" />
352352
<Compile Include="Core\GitCredentialUserpass.cs" />
353353
<Compile Include="Commands\Pull.cs" />
354+
<Compile Include="Commands\Fetch.cs" />
354355
</ItemGroup>
355356
<ItemGroup>
356357
<CodeAnalysisDictionary Include="CustomDictionary.xml" />

0 commit comments

Comments
 (0)