Skip to content

Commit 5d0cb35

Browse files
author
Edward Thomson
committed
Merge pull request libgit2#1285 from libgit2/cmn/remoteupdater-name
Take a name instead of an instance to update a remote
2 parents cd8ca84 + 3b308f4 commit 5d0cb35

File tree

9 files changed

+178
-73
lines changed

9 files changed

+178
-73
lines changed

LibGit2Sharp.Tests/BranchFixture.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ public void QueryUnresolvableRemoteForRemoteBranch()
457457
Remote remote = repo.Network.Remotes["origin"];
458458
Assert.NotNull(remote);
459459

460-
repo.Network.Remotes.Update(remote, r => r.FetchRefSpecs = fetchRefSpecs);
460+
repo.Network.Remotes.Update("origin", r => r.FetchRefSpecs = fetchRefSpecs);
461461

462462
Branch branch = repo.Branches["refs/remotes/origin/master"];
463463

@@ -750,7 +750,7 @@ public void SetTrackedBranchForUnreasolvableRemoteThrows()
750750
// cannot be resolved.
751751
Remote remote = repo.Network.Remotes["origin"];
752752
Assert.NotNull(remote);
753-
repo.Network.Remotes.Update(remote, r => r.FetchRefSpecs = fetchRefSpecs);
753+
repo.Network.Remotes.Update("origin", r => r.FetchRefSpecs = fetchRefSpecs);
754754

755755
// Now attempt to update the tracked branch
756756
Branch branch = repo.CreateBranch(testBranchName);

LibGit2Sharp.Tests/FetchFixture.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ public void FetchRespectsConfiguredAutoTagSetting(TagFetchMode tagFetchMode, int
177177
Assert.NotNull(remote);
178178

179179
// Update the configured autotag setting.
180-
repo.Network.Remotes.Update(remote,
180+
repo.Network.Remotes.Update(remoteName,
181181
r => r.TagFetchMode = tagFetchMode);
182182

183183
// Perform the actual fetch.

LibGit2Sharp.Tests/RefSpecFixture.cs

Lines changed: 56 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Linq;
1+
using System.Collections.Generic;
2+
using System.Linq;
23
using LibGit2Sharp.Tests.TestHelpers;
34
using Xunit;
45
using Xunit.Extensions;
@@ -75,25 +76,30 @@ public void CanReplaceRefSpecs(string[] newFetchRefSpecs, string[] newPushRefSpe
7576
var path = SandboxStandardTestRepo();
7677
using (var repo = new Repository(path))
7778
{
78-
var remote = repo.Network.Remotes["origin"];
79-
var oldRefSpecs = remote.RefSpecs.ToList();
80-
81-
var newRemote = repo.Network.Remotes.Update(remote,
82-
r => r.FetchRefSpecs = newFetchRefSpecs, r => r.PushRefSpecs = newPushRefSpecs);
83-
84-
Assert.Equal(oldRefSpecs, remote.RefSpecs.ToList());
79+
List<RefSpec> oldRefSpecs;
80+
using (var remote = repo.Network.Remotes["origin"])
81+
{
82+
oldRefSpecs = remote.RefSpecs.ToList();
8583

86-
var actualNewFetchRefSpecs = newRemote.RefSpecs
87-
.Where(s => s.Direction == RefSpecDirection.Fetch)
88-
.Select(r => r.Specification)
89-
.ToArray();
90-
Assert.Equal(newFetchRefSpecs, actualNewFetchRefSpecs);
84+
repo.Network.Remotes.Update("origin",
85+
r => r.FetchRefSpecs = newFetchRefSpecs, r => r.PushRefSpecs = newPushRefSpecs);
86+
Assert.Equal(oldRefSpecs, remote.RefSpecs.ToList());
87+
}
9188

92-
var actualNewPushRefSpecs = newRemote.RefSpecs
93-
.Where(s => s.Direction == RefSpecDirection.Push)
94-
.Select(r => r.Specification)
95-
.ToArray();
96-
Assert.Equal(newPushRefSpecs, actualNewPushRefSpecs);
89+
using (var newRemote = repo.Network.Remotes["origin"])
90+
{
91+
var actualNewFetchRefSpecs = newRemote.RefSpecs
92+
.Where(s => s.Direction == RefSpecDirection.Fetch)
93+
.Select(r => r.Specification)
94+
.ToArray();
95+
Assert.Equal(newFetchRefSpecs, actualNewFetchRefSpecs);
96+
97+
var actualNewPushRefSpecs = newRemote.RefSpecs
98+
.Where(s => s.Direction == RefSpecDirection.Push)
99+
.Select(r => r.Specification)
100+
.ToArray();
101+
Assert.Equal(newPushRefSpecs, actualNewPushRefSpecs);
102+
}
97103
}
98104
}
99105

@@ -105,15 +111,12 @@ public void RemoteUpdaterSavesRefSpecsPermanently()
105111

106112
using (var repo = new Repository(path))
107113
{
108-
using (var remote = repo.Network.Remotes["origin"])
109-
{
110-
repo.Network.Remotes.Update(remote, r => r.FetchRefSpecs = fetchRefSpecs);
111-
}
114+
repo.Network.Remotes.Update("origin", r => r.FetchRefSpecs = fetchRefSpecs);
112115
}
113116

114117
using (var repo = new Repository(path))
118+
using (var remote = repo.Network.Remotes["origin"])
115119
{
116-
var remote = repo.Network.Remotes["origin"];
117120
var actualRefSpecs = remote.RefSpecs
118121
.Where(r => r.Direction == RefSpecDirection.Fetch)
119122
.Select(r => r.Specification)
@@ -129,22 +132,25 @@ public void CanAddAndRemoveRefSpecs()
129132
var path = SandboxStandardTestRepo();
130133

131134
using (var repo = new Repository(path))
132-
using (var remote = repo.Network.Remotes["origin"])
133135
{
134-
using (var updatedRemote = repo.Network.Remotes.Update(remote,
136+
repo.Network.Remotes.Update("origin",
135137
r => r.FetchRefSpecs.Add(newRefSpec),
136-
r => r.PushRefSpecs.Add(newRefSpec)))
138+
r => r.PushRefSpecs.Add(newRefSpec));
139+
140+
using (var remote = repo.Network.Remotes["origin"])
141+
{
142+
Assert.Contains(newRefSpec, remote.FetchRefSpecs.Select(r => r.Specification));
143+
Assert.Contains(newRefSpec, remote.PushRefSpecs.Select(r => r.Specification));
144+
}
145+
146+
repo.Network.Remotes.Update("origin",
147+
r => r.FetchRefSpecs.Remove(newRefSpec),
148+
r => r.PushRefSpecs.Remove(newRefSpec));
149+
150+
using (var remote = repo.Network.Remotes["origin"])
137151
{
138-
Assert.Contains(newRefSpec, updatedRemote.FetchRefSpecs.Select(r => r.Specification));
139-
Assert.Contains(newRefSpec, updatedRemote.PushRefSpecs.Select(r => r.Specification));
140-
141-
using (var updatedRemote2 = repo.Network.Remotes.Update(updatedRemote,
142-
r => r.FetchRefSpecs.Remove(newRefSpec),
143-
r => r.PushRefSpecs.Remove(newRefSpec)))
144-
{
145-
Assert.DoesNotContain(newRefSpec, updatedRemote2.FetchRefSpecs.Select(r => r.Specification));
146-
Assert.DoesNotContain(newRefSpec, updatedRemote2.PushRefSpecs.Select(r => r.Specification));
147-
}
152+
Assert.DoesNotContain(newRefSpec, remote.FetchRefSpecs.Select(r => r.Specification));
153+
Assert.DoesNotContain(newRefSpec, remote.PushRefSpecs.Select(r => r.Specification));
148154
}
149155
}
150156
}
@@ -155,18 +161,20 @@ public void CanClearRefSpecs()
155161
var path = SandboxStandardTestRepo();
156162
using (var repo = new Repository(path))
157163
{
158-
var remote = repo.Network.Remotes["origin"];
159164

160165
// Push refspec does not exist in cloned repository
161-
remote = repo.Network.Remotes.Update(remote, r => r.PushRefSpecs.Add("+refs/test:refs/test"));
166+
repo.Network.Remotes.Update("origin", r => r.PushRefSpecs.Add("+refs/test:refs/test"));
162167

163-
remote = repo.Network.Remotes.Update(remote,
168+
repo.Network.Remotes.Update("origin",
164169
r => r.FetchRefSpecs.Clear(),
165170
r => r.PushRefSpecs.Clear());
166171

167-
Assert.Empty(remote.FetchRefSpecs);
168-
Assert.Empty(remote.PushRefSpecs);
169-
Assert.Empty(remote.RefSpecs);
172+
using (var remote = repo.Network.Remotes["origin"])
173+
{
174+
Assert.Empty(remote.FetchRefSpecs);
175+
Assert.Empty(remote.PushRefSpecs);
176+
Assert.Empty(remote.RefSpecs);
177+
}
170178
}
171179
}
172180

@@ -183,11 +191,14 @@ public void SettingInvalidRefSpecsThrows(string refSpec)
183191
var path = SandboxStandardTestRepo();
184192
using (var repo = new Repository(path))
185193
{
186-
var remote = repo.Network.Remotes["origin"];
187-
var oldRefSpecs = remote.RefSpecs.Select(r => r.Specification).ToList();
194+
IEnumerable<string> oldRefSpecs;
195+
using (var remote = repo.Network.Remotes["origin"])
196+
{
197+
oldRefSpecs = remote.RefSpecs.Select(r => r.Specification).ToList();
198+
}
188199

189200
Assert.Throws<InvalidSpecificationException>(() =>
190-
repo.Network.Remotes.Update(remote, r => r.FetchRefSpecs.Add(refSpec)));
201+
repo.Network.Remotes.Update("origin", r => r.FetchRefSpecs.Add(refSpec)));
191202

192203
var newRemote = repo.Network.Remotes["origin"];
193204
Assert.Equal(oldRefSpecs, newRemote.RefSpecs.Select(r => r.Specification).ToList());

LibGit2Sharp.Tests/RemoteFixture.cs

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,13 @@ public void CanSetTagFetchMode(TagFetchMode tagFetchMode)
6666
Remote remote = repo.Network.Remotes[name];
6767
Assert.NotNull(remote);
6868

69-
Remote updatedremote = repo.Network.Remotes.Update(remote,
69+
repo.Network.Remotes.Update(name,
7070
r => r.TagFetchMode = tagFetchMode);
7171

72-
Assert.Equal(tagFetchMode, updatedremote.TagFetchMode);
72+
using (var updatedremote = repo.Network.Remotes[name])
73+
{
74+
Assert.Equal(tagFetchMode, updatedremote.TagFetchMode);
75+
}
7376
}
7477
}
7578

@@ -87,12 +90,14 @@ public void CanSetRemoteUrl()
8790
Remote remote = repo.Network.Remotes[name];
8891
Assert.NotNull(remote);
8992

90-
Remote updatedremote = repo.Network.Remotes.Update(remote,
91-
r => r.Url = newUrl);
93+
repo.Network.Remotes.Update(name, r => r.Url = newUrl);
9294

93-
Assert.Equal(newUrl, updatedremote.Url);
94-
// with no push url set, PushUrl defaults to the fetch url
95-
Assert.Equal(newUrl, updatedremote.PushUrl);
95+
using (var updatedremote = repo.Network.Remotes[name])
96+
{
97+
Assert.Equal(newUrl, updatedremote.Url);
98+
// with no push url set, PushUrl defaults to the fetch url
99+
Assert.Equal(newUrl, updatedremote.PushUrl);
100+
}
96101
}
97102
}
98103

@@ -114,12 +119,14 @@ public void CanSetRemotePushUrl()
114119
Assert.Equal(url, remote.Url);
115120
Assert.Equal(url, remote.PushUrl);
116121

117-
Remote updatedremote = repo.Network.Remotes.Update(remote,
118-
r => r.PushUrl = pushurl);
122+
repo.Network.Remotes.Update(name, r => r.PushUrl = pushurl);
119123

120-
// url should not change, push url should be set to new value
121-
Assert.Equal(url, updatedremote.Url);
122-
Assert.Equal(pushurl, updatedremote.PushUrl);
124+
using (var updatedremote = repo.Network.Remotes[name])
125+
{
126+
// url should not change, push url should be set to new value
127+
Assert.Equal(url, updatedremote.Url);
128+
Assert.Equal(pushurl, updatedremote.PushUrl);
129+
}
123130
}
124131
}
125132

@@ -292,8 +299,7 @@ public void ReportsRemotesWithNonDefaultRefSpecs()
292299
{
293300
Assert.NotNull(repo.Network.Remotes["origin"]);
294301

295-
repo.Network.Remotes.Update(
296-
repo.Network.Remotes["origin"],
302+
repo.Network.Remotes.Update("origin",
297303
r => r.FetchRefSpecs = new[] { "+refs/heads/*:refs/remotes/upstream/*" });
298304

299305
repo.Network.Remotes.Rename("origin", "nondefault", problem => Assert.Equal("+refs/heads/*:refs/remotes/upstream/*", problem));

LibGit2Sharp/Configuration.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,5 +759,29 @@ private ConfigurationHandle Snapshot()
759759
{
760760
return Proxy.git_config_snapshot(configHandle);
761761
}
762+
763+
/// <summary>
764+
/// Perform a series of actions within a transaction.
765+
///
766+
/// The configuration will be locked during this function and the changes will be committed at the end. These
767+
/// changes will not be visible in the configuration until the end of this method.
768+
///
769+
/// If the action throws an exception, the changes will be rolled back.
770+
/// </summary>
771+
/// <param name="action">The code to run under the transaction</param>
772+
public virtual unsafe void WithinTransaction(Action action)
773+
{
774+
IntPtr txn = IntPtr.Zero;
775+
try
776+
{
777+
txn = Proxy.git_config_lock(configHandle);
778+
action();
779+
Proxy.git_transaction_commit(txn);
780+
}
781+
finally
782+
{
783+
Proxy.git_transaction_free(txn);
784+
}
785+
}
762786
}
763787
}

LibGit2Sharp/Core/NativeMethods.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,9 @@ internal static extern unsafe int git_config_delete_entry(
342342
git_config* cfg,
343343
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string name);
344344

345+
[DllImport(libgit2)]
346+
internal static extern unsafe int git_config_lock(out IntPtr txn, git_config* config);
347+
345348
[DllImport(libgit2)]
346349
internal static extern unsafe int git_config_delete_multivar(
347350
git_config* cfg,
@@ -1825,6 +1828,12 @@ internal static extern unsafe int git_treebuilder_insert(
18251828

18261829
[DllImport(libgit2)]
18271830
internal static extern unsafe int git_cherrypick(git_repository* repo, git_object* commit, GitCherryPickOptions options);
1831+
1832+
[DllImport(libgit2)]
1833+
internal static extern int git_transaction_commit(IntPtr txn);
1834+
1835+
[DllImport(libgit2)]
1836+
internal static extern void git_transaction_free(IntPtr txn);
18281837
}
18291838
}
18301839
// ReSharper restore InconsistentNaming

LibGit2Sharp/Core/Proxy.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,15 @@ public static unsafe ConfigurationHandle git_config_snapshot(ConfigurationHandle
635635
return new ConfigurationHandle(handle, true);
636636
}
637637

638+
public static unsafe IntPtr git_config_lock(git_config* config)
639+
{
640+
IntPtr txn;
641+
int res = NativeMethods.git_config_lock(out txn, config);
642+
Ensure.ZeroResult(res);
643+
644+
return txn;
645+
}
646+
638647
#endregion
639648

640649
#region git_cred_
@@ -3197,6 +3206,20 @@ public static unsafe ObjectId git_treebuilder_write(TreeBuilderHandle bld)
31973206

31983207
#endregion
31993208

3209+
#region git_transaction_
3210+
3211+
public static void git_transaction_commit(IntPtr txn)
3212+
{
3213+
NativeMethods.git_transaction_commit(txn);
3214+
}
3215+
3216+
public static void git_transaction_free(IntPtr txn)
3217+
{
3218+
NativeMethods.git_transaction_free(txn);
3219+
}
3220+
3221+
#endregion
3222+
32003223
#region git_libgit2_
32013224

32023225
/// <summary>

LibGit2Sharp/RemoteCollection.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ internal Remote RemoteForName(string name, bool shouldThrowIfNotFound = true)
5353
/// <param name="remote">The remote to update.</param>
5454
/// <param name="actions">Delegate to perform updates on the remote.</param>
5555
/// <returns>The updated remote.</returns>
56+
[Obsolete("This method is deprecated. Use the overload with a remote name")]
5657
public virtual Remote Update(Remote remote, params Action<RemoteUpdater>[] actions)
5758
{
5859
var updater = new RemoteUpdater(repository, remote);
@@ -65,6 +66,25 @@ public virtual Remote Update(Remote remote, params Action<RemoteUpdater>[] actio
6566
return this[remote.Name];
6667
}
6768

69+
/// <summary>
70+
/// Update properties of a remote.
71+
///
72+
/// These updates will be performed as a bulk update at the end of the method.
73+
/// </summary>
74+
/// <param name="remote">The name of the remote to update.</param>
75+
/// <param name="actions">Delegate to perform updates on the remote.</param>
76+
public virtual void Update(string remote, params Action<RemoteUpdater>[] actions)
77+
{
78+
var updater = new RemoteUpdater(repository, remote);
79+
80+
repository.Config.WithinTransaction(() => {
81+
foreach (Action<RemoteUpdater> action in actions)
82+
{
83+
action(updater);
84+
}
85+
});
86+
}
87+
6888
/// <summary>
6989
/// Returns an enumerator that iterates through the collection.
7090
/// </summary>

0 commit comments

Comments
 (0)