Skip to content

Take a name instead of an instance to update a remote #1285

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 15, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions LibGit2Sharp.Tests/BranchFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ public void QueryUnresolvableRemoteForRemoteBranch()
Remote remote = repo.Network.Remotes["origin"];
Assert.NotNull(remote);

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

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

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

// Now attempt to update the tracked branch
Branch branch = repo.CreateBranch(testBranchName);
Expand Down
2 changes: 1 addition & 1 deletion LibGit2Sharp.Tests/FetchFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ public void FetchRespectsConfiguredAutoTagSetting(TagFetchMode tagFetchMode, int
Assert.NotNull(remote);

// Update the configured autotag setting.
repo.Network.Remotes.Update(remote,
repo.Network.Remotes.Update(remoteName,
r => r.TagFetchMode = tagFetchMode);

// Perform the actual fetch.
Expand Down
101 changes: 56 additions & 45 deletions LibGit2Sharp.Tests/RefSpecFixture.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Linq;
using System.Collections.Generic;
using System.Linq;
using LibGit2Sharp.Tests.TestHelpers;
using Xunit;
using Xunit.Extensions;
Expand Down Expand Up @@ -75,25 +76,30 @@ public void CanReplaceRefSpecs(string[] newFetchRefSpecs, string[] newPushRefSpe
var path = SandboxStandardTestRepo();
using (var repo = new Repository(path))
{
var remote = repo.Network.Remotes["origin"];
var oldRefSpecs = remote.RefSpecs.ToList();

var newRemote = repo.Network.Remotes.Update(remote,
r => r.FetchRefSpecs = newFetchRefSpecs, r => r.PushRefSpecs = newPushRefSpecs);

Assert.Equal(oldRefSpecs, remote.RefSpecs.ToList());
List<RefSpec> oldRefSpecs;
using (var remote = repo.Network.Remotes["origin"])
{
oldRefSpecs = remote.RefSpecs.ToList();

var actualNewFetchRefSpecs = newRemote.RefSpecs
.Where(s => s.Direction == RefSpecDirection.Fetch)
.Select(r => r.Specification)
.ToArray();
Assert.Equal(newFetchRefSpecs, actualNewFetchRefSpecs);
repo.Network.Remotes.Update("origin",
r => r.FetchRefSpecs = newFetchRefSpecs, r => r.PushRefSpecs = newPushRefSpecs);
Assert.Equal(oldRefSpecs, remote.RefSpecs.ToList());
}

var actualNewPushRefSpecs = newRemote.RefSpecs
.Where(s => s.Direction == RefSpecDirection.Push)
.Select(r => r.Specification)
.ToArray();
Assert.Equal(newPushRefSpecs, actualNewPushRefSpecs);
using (var newRemote = repo.Network.Remotes["origin"])
{
var actualNewFetchRefSpecs = newRemote.RefSpecs
.Where(s => s.Direction == RefSpecDirection.Fetch)
.Select(r => r.Specification)
.ToArray();
Assert.Equal(newFetchRefSpecs, actualNewFetchRefSpecs);

var actualNewPushRefSpecs = newRemote.RefSpecs
.Where(s => s.Direction == RefSpecDirection.Push)
.Select(r => r.Specification)
.ToArray();
Assert.Equal(newPushRefSpecs, actualNewPushRefSpecs);
}
}
}

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

using (var repo = new Repository(path))
{
using (var remote = repo.Network.Remotes["origin"])
{
repo.Network.Remotes.Update(remote, r => r.FetchRefSpecs = fetchRefSpecs);
}
repo.Network.Remotes.Update("origin", r => r.FetchRefSpecs = fetchRefSpecs);
}

using (var repo = new Repository(path))
using (var remote = repo.Network.Remotes["origin"])
{
var remote = repo.Network.Remotes["origin"];
var actualRefSpecs = remote.RefSpecs
.Where(r => r.Direction == RefSpecDirection.Fetch)
.Select(r => r.Specification)
Expand All @@ -129,22 +132,25 @@ public void CanAddAndRemoveRefSpecs()
var path = SandboxStandardTestRepo();

using (var repo = new Repository(path))
using (var remote = repo.Network.Remotes["origin"])
{
using (var updatedRemote = repo.Network.Remotes.Update(remote,
repo.Network.Remotes.Update("origin",
r => r.FetchRefSpecs.Add(newRefSpec),
r => r.PushRefSpecs.Add(newRefSpec)))
r => r.PushRefSpecs.Add(newRefSpec));

using (var remote = repo.Network.Remotes["origin"])
{
Assert.Contains(newRefSpec, remote.FetchRefSpecs.Select(r => r.Specification));
Assert.Contains(newRefSpec, remote.PushRefSpecs.Select(r => r.Specification));
}

repo.Network.Remotes.Update("origin",
r => r.FetchRefSpecs.Remove(newRefSpec),
r => r.PushRefSpecs.Remove(newRefSpec));

using (var remote = repo.Network.Remotes["origin"])
{
Assert.Contains(newRefSpec, updatedRemote.FetchRefSpecs.Select(r => r.Specification));
Assert.Contains(newRefSpec, updatedRemote.PushRefSpecs.Select(r => r.Specification));

using (var updatedRemote2 = repo.Network.Remotes.Update(updatedRemote,
r => r.FetchRefSpecs.Remove(newRefSpec),
r => r.PushRefSpecs.Remove(newRefSpec)))
{
Assert.DoesNotContain(newRefSpec, updatedRemote2.FetchRefSpecs.Select(r => r.Specification));
Assert.DoesNotContain(newRefSpec, updatedRemote2.PushRefSpecs.Select(r => r.Specification));
}
Assert.DoesNotContain(newRefSpec, remote.FetchRefSpecs.Select(r => r.Specification));
Assert.DoesNotContain(newRefSpec, remote.PushRefSpecs.Select(r => r.Specification));
}
}
}
Expand All @@ -155,18 +161,20 @@ public void CanClearRefSpecs()
var path = SandboxStandardTestRepo();
using (var repo = new Repository(path))
{
var remote = repo.Network.Remotes["origin"];

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

remote = repo.Network.Remotes.Update(remote,
repo.Network.Remotes.Update("origin",
r => r.FetchRefSpecs.Clear(),
r => r.PushRefSpecs.Clear());

Assert.Empty(remote.FetchRefSpecs);
Assert.Empty(remote.PushRefSpecs);
Assert.Empty(remote.RefSpecs);
using (var remote = repo.Network.Remotes["origin"])
{
Assert.Empty(remote.FetchRefSpecs);
Assert.Empty(remote.PushRefSpecs);
Assert.Empty(remote.RefSpecs);
}
}
}

Expand All @@ -183,11 +191,14 @@ public void SettingInvalidRefSpecsThrows(string refSpec)
var path = SandboxStandardTestRepo();
using (var repo = new Repository(path))
{
var remote = repo.Network.Remotes["origin"];
var oldRefSpecs = remote.RefSpecs.Select(r => r.Specification).ToList();
IEnumerable<string> oldRefSpecs;
using (var remote = repo.Network.Remotes["origin"])
{
oldRefSpecs = remote.RefSpecs.Select(r => r.Specification).ToList();
}

Assert.Throws<InvalidSpecificationException>(() =>
repo.Network.Remotes.Update(remote, r => r.FetchRefSpecs.Add(refSpec)));
repo.Network.Remotes.Update("origin", r => r.FetchRefSpecs.Add(refSpec)));

var newRemote = repo.Network.Remotes["origin"];
Assert.Equal(oldRefSpecs, newRemote.RefSpecs.Select(r => r.Specification).ToList());
Expand Down
34 changes: 20 additions & 14 deletions LibGit2Sharp.Tests/RemoteFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,13 @@ public void CanSetTagFetchMode(TagFetchMode tagFetchMode)
Remote remote = repo.Network.Remotes[name];
Assert.NotNull(remote);

Remote updatedremote = repo.Network.Remotes.Update(remote,
repo.Network.Remotes.Update(name,
r => r.TagFetchMode = tagFetchMode);

Assert.Equal(tagFetchMode, updatedremote.TagFetchMode);
using (var updatedremote = repo.Network.Remotes[name])
{
Assert.Equal(tagFetchMode, updatedremote.TagFetchMode);
}
}
}

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

Remote updatedremote = repo.Network.Remotes.Update(remote,
r => r.Url = newUrl);
repo.Network.Remotes.Update(name, r => r.Url = newUrl);

Assert.Equal(newUrl, updatedremote.Url);
// with no push url set, PushUrl defaults to the fetch url
Assert.Equal(newUrl, updatedremote.PushUrl);
using (var updatedremote = repo.Network.Remotes[name])
{
Assert.Equal(newUrl, updatedremote.Url);
// with no push url set, PushUrl defaults to the fetch url
Assert.Equal(newUrl, updatedremote.PushUrl);
}
}
}

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

Remote updatedremote = repo.Network.Remotes.Update(remote,
r => r.PushUrl = pushurl);
repo.Network.Remotes.Update(name, r => r.PushUrl = pushurl);

// url should not change, push url should be set to new value
Assert.Equal(url, updatedremote.Url);
Assert.Equal(pushurl, updatedremote.PushUrl);
using (var updatedremote = repo.Network.Remotes[name])
{
// url should not change, push url should be set to new value
Assert.Equal(url, updatedremote.Url);
Assert.Equal(pushurl, updatedremote.PushUrl);
}
}
}

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

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

repo.Network.Remotes.Rename("origin", "nondefault", problem => Assert.Equal("+refs/heads/*:refs/remotes/upstream/*", problem));
Expand Down
24 changes: 24 additions & 0 deletions LibGit2Sharp/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -759,5 +759,29 @@ private ConfigurationHandle Snapshot()
{
return Proxy.git_config_snapshot(configHandle);
}

/// <summary>
/// Perform a series of actions within a transaction.
///
/// The configuration will be locked during this function and the changes will be committed at the end. These
/// changes will not be visible in the configuration until the end of this method.
///
/// If the action throws an exception, the changes will be rolled back.
/// </summary>
/// <param name="action">The code to run under the transaction</param>
public virtual unsafe void WithinTransaction(Action action)
{
IntPtr txn = IntPtr.Zero;
try
{
txn = Proxy.git_config_lock(configHandle);
action();
Proxy.git_transaction_commit(txn);
}
finally
{
Proxy.git_transaction_free(txn);
}
}
}
}
9 changes: 9 additions & 0 deletions LibGit2Sharp/Core/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,9 @@ internal static extern unsafe int git_config_delete_entry(
git_config* cfg,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string name);

[DllImport(libgit2)]
internal static extern unsafe int git_config_lock(out IntPtr txn, git_config* config);

[DllImport(libgit2)]
internal static extern unsafe int git_config_delete_multivar(
git_config* cfg,
Expand Down Expand Up @@ -1825,6 +1828,12 @@ internal static extern unsafe int git_treebuilder_insert(

[DllImport(libgit2)]
internal static extern unsafe int git_cherrypick(git_repository* repo, git_object* commit, GitCherryPickOptions options);

[DllImport(libgit2)]
internal static extern int git_transaction_commit(IntPtr txn);

[DllImport(libgit2)]
internal static extern void git_transaction_free(IntPtr txn);
}
}
// ReSharper restore InconsistentNaming
23 changes: 23 additions & 0 deletions LibGit2Sharp/Core/Proxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,15 @@ public static unsafe ConfigurationHandle git_config_snapshot(ConfigurationHandle
return new ConfigurationHandle(handle, true);
}

public static unsafe IntPtr git_config_lock(git_config* config)
{
IntPtr txn;
int res = NativeMethods.git_config_lock(out txn, config);
Ensure.ZeroResult(res);

return txn;
}

#endregion

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

#endregion

#region git_transaction_

public static void git_transaction_commit(IntPtr txn)
{
NativeMethods.git_transaction_commit(txn);
}

public static void git_transaction_free(IntPtr txn)
{
NativeMethods.git_transaction_free(txn);
}

#endregion

#region git_libgit2_

/// <summary>
Expand Down
20 changes: 20 additions & 0 deletions LibGit2Sharp/RemoteCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ internal Remote RemoteForName(string name, bool shouldThrowIfNotFound = true)
/// <param name="remote">The remote to update.</param>
/// <param name="actions">Delegate to perform updates on the remote.</param>
/// <returns>The updated remote.</returns>
[Obsolete("This method is deprecated. Use the overload with a remote name")]
public virtual Remote Update(Remote remote, params Action<RemoteUpdater>[] actions)
{
var updater = new RemoteUpdater(repository, remote);
Expand All @@ -65,6 +66,25 @@ public virtual Remote Update(Remote remote, params Action<RemoteUpdater>[] actio
return this[remote.Name];
}

/// <summary>
/// Update properties of a remote.
///
/// These updates will be performed as a bulk update at the end of the method.
/// </summary>
/// <param name="remote">The name of the remote to update.</param>
/// <param name="actions">Delegate to perform updates on the remote.</param>
public virtual void Update(string remote, params Action<RemoteUpdater>[] actions)
{
var updater = new RemoteUpdater(repository, remote);

repository.Config.WithinTransaction(() => {
foreach (Action<RemoteUpdater> action in actions)
{
action(updater);
}
});
}

/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
Expand Down
Loading