Skip to content

Commit

Permalink
Merge pull request #1720 from kzu/multivar
Browse files Browse the repository at this point in the history
Add support for adding and clearing multi-valued configuration
  • Loading branch information
bording committed Oct 9, 2019
2 parents 6740402 + 4081885 commit 0e8a3ca
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 9 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

language: csharp
dist: xenial
dotnet: 2.1.506
dotnet: 2.1.802
mono: none
osx_image: xcode8.3

Expand Down
113 changes: 113 additions & 0 deletions LibGit2Sharp.Tests/ConfigurationFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,119 @@ public void CanUnsetAnEntryFromTheGlobalConfiguration()
}
}

[Fact]
public void CanAddAndReadMultivarFromTheLocalConfiguration()
{
string path = SandboxStandardTestRepo();
using (var repo = new Repository(path))
{
Assert.Empty(repo.Config
.OfType<ConfigurationEntry<string>>()
.Where(x => x.Key == "unittests.plugin"));

repo.Config.Add("unittests.plugin", "value1", ConfigurationLevel.Local);
repo.Config.Add("unittests.plugin", "value2", ConfigurationLevel.Local);

Assert.Equal(new[] { "value1", "value2" }, repo.Config
.OfType<ConfigurationEntry<string>>()
.Where(x => x.Key == "unittests.plugin" && x.Level == ConfigurationLevel.Local)
.Select(x => x.Value)
.ToArray());
}
}

[Fact]
public void CanAddAndReadMultivarFromTheGlobalConfiguration()
{
string path = SandboxBareTestRepo();
using (var repo = new Repository(path))
{
Assert.True(repo.Config.HasConfig(ConfigurationLevel.Global));
Assert.Empty(repo.Config
.OfType<ConfigurationEntry<string>>()
.Where(x => x.Key == "unittests.plugin"));

repo.Config.Add("unittests.plugin", "value1", ConfigurationLevel.Global);
repo.Config.Add("unittests.plugin", "value2", ConfigurationLevel.Global);

Assert.Equal(new[] { "value1", "value2" }, repo.Config
.OfType<ConfigurationEntry<string>>()
.Where(x => x.Key == "unittests.plugin")
.Select(x => x.Value)
.ToArray());
}
}

[Fact]
public void CanUnsetAllFromTheGlobalConfiguration()
{
string path = SandboxBareTestRepo();
using (var repo = new Repository(path))
{
Assert.True(repo.Config.HasConfig(ConfigurationLevel.Global));
Assert.Empty(repo.Config
.OfType<ConfigurationEntry<string>>()
.Where(x => x.Key == "unittests.plugin")
.Select(x => x.Value)
.ToArray());

repo.Config.Add("unittests.plugin", "value1", ConfigurationLevel.Global);
repo.Config.Add("unittests.plugin", "value2", ConfigurationLevel.Global);

Assert.Equal(2, repo.Config
.OfType<ConfigurationEntry<string>>()
.Where(x => x.Key == "unittests.plugin" && x.Level == ConfigurationLevel.Global)
.Select(x => x.Value)
.Count());

repo.Config.UnsetAll("unittests.plugin");

Assert.Equal(2, repo.Config
.OfType<ConfigurationEntry<string>>()
.Where(x => x.Key == "unittests.plugin" && x.Level == ConfigurationLevel.Global)
.Select(x => x.Value)
.Count());

repo.Config.UnsetAll("unittests.plugin", ConfigurationLevel.Global);

Assert.Empty(repo.Config
.OfType<ConfigurationEntry<string>>()
.Where(x => x.Key == "unittests.plugin")
.Select(x => x.Value)
.ToArray());
}
}

[Fact]
public void CanUnsetAllFromTheLocalConfiguration()
{
string path = SandboxStandardTestRepo();
using (var repo = new Repository(path))
{
Assert.True(repo.Config.HasConfig(ConfigurationLevel.Global));
Assert.Empty(repo.Config
.OfType<ConfigurationEntry<string>>()
.Where(x => x.Key == "unittests.plugin")
.Select(x => x.Value)
.ToArray());

repo.Config.Add("unittests.plugin", "value1");
repo.Config.Add("unittests.plugin", "value2");

Assert.Equal(2, repo.Config
.OfType<ConfigurationEntry<string>>()
.Where(x => x.Key == "unittests.plugin" && x.Level == ConfigurationLevel.Local)
.Select(x => x.Value)
.Count());

repo.Config.UnsetAll("unittests.plugin");

Assert.Empty(repo.Config
.OfType<ConfigurationEntry<string>>()
.Where(x => x.Key == "unittests.plugin"));
}
}

[Fact]
public void CanReadBooleanValue()
{
Expand Down
75 changes: 69 additions & 6 deletions LibGit2Sharp/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -233,33 +233,47 @@ public void Dispose()
/// Unset a configuration variable (key and value) in the local configuration.
/// </summary>
/// <param name="key">The key to unset.</param>
public virtual void Unset(string key)
public virtual bool Unset(string key)
{
Unset(key, ConfigurationLevel.Local);
return Unset(key, ConfigurationLevel.Local);
}

/// <summary>
/// Unset a configuration variable (key and value).
/// </summary>
/// <param name="key">The key to unset.</param>
/// <param name="level">The configuration file which should be considered as the target of this operation</param>
public virtual void Unset(string key, ConfigurationLevel level)
public virtual bool Unset(string key, ConfigurationLevel level)
{
Ensure.ArgumentNotNullOrEmptyString(key, "key");

using (ConfigurationHandle h = RetrieveConfigurationHandle(level, true, configHandle))
{
Proxy.git_config_delete(h, key);
return Proxy.git_config_delete(h, key);
}
}

internal void UnsetMultivar(string key, ConfigurationLevel level)
/// <summary>
/// Unset all configuration values in a multivar variable (key and value) in the local configuration.
/// </summary>
/// <param name="key">The key to unset.</param>
public virtual bool UnsetAll(string key)
{
return UnsetAll(key, ConfigurationLevel.Local);
}

/// <summary>
/// Unset all configuration values in a multivar variable (key and value).
/// </summary>
/// <param name="key">The key to unset.</param>
/// <param name="level">The configuration file which should be considered as the target of this operation</param>
public virtual bool UnsetAll(string key, ConfigurationLevel level)
{
Ensure.ArgumentNotNullOrEmptyString(key, "key");

using (ConfigurationHandle h = RetrieveConfigurationHandle(level, true, configHandle))
{
Proxy.git_config_delete_multivar(h, key);
return Proxy.git_config_delete_multivar(h, key);
}
}

Expand Down Expand Up @@ -634,6 +648,55 @@ public virtual void Set<T>(string key, T value, ConfigurationLevel level)
}
}

/// <summary>
/// Adds a configuration value for a multivalue key in the local configuration. Keys are in the form 'section.name'.
/// <para>
/// For example in order to add the value for this in a .git\config file:
///
/// [test]
/// plugin = first
///
/// You would call:
///
/// repo.Config.Add("test.plugin", "first");
/// </para>
/// </summary>
/// <typeparam name="T">The configuration value type</typeparam>
/// <param name="key">The key parts</param>
/// <param name="value">The value</param>
public virtual void Add(string key, string value)
{
Add(key, value, ConfigurationLevel.Local);
}

/// <summary>
/// Adds a configuration value for a multivalue key. Keys are in the form 'section.name'.
/// <para>
/// For example in order to add the value for this in a .git\config file:
///
/// [test]
/// plugin = first
///
/// You would call:
///
/// repo.Config.Add("test.plugin", "first");
/// </para>
/// </summary>
/// <typeparam name="T">The configuration value type</typeparam>
/// <param name="key">The key parts</param>
/// <param name="value">The value</param>
/// <param name="level">The configuration file which should be considered as the target of this operation</param>
public virtual void Add(string key, string value, ConfigurationLevel level)
{
Ensure.ArgumentNotNull(value, "value");
Ensure.ArgumentNotNullOrEmptyString(key, "key");

using (ConfigurationHandle h = RetrieveConfigurationHandle(level, true, configHandle))
{
Proxy.git_config_add_string(h, key, value);
}
}

/// <summary>
/// Find configuration entries matching <paramref name="regexp"/>.
/// </summary>
Expand Down
7 changes: 7 additions & 0 deletions LibGit2Sharp/Core/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,13 @@ private sealed class NativeShutdownObject : CriticalFinalizerObject
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string name,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string regexp);

[DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)]
internal static extern unsafe int git_config_set_multivar(
git_config* cfg,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string name,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string regexp,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string value);

[DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)]
internal static extern int git_config_find_global(GitBuf global_config_path);

Expand Down
8 changes: 8 additions & 0 deletions LibGit2Sharp/Core/Proxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,14 @@ public static unsafe void git_config_set_string(ConfigurationHandle config, stri
Ensure.ZeroResult(res);
}

static readonly string non_existing_regex = Guid.NewGuid().ToString();

public static unsafe void git_config_add_string(ConfigurationHandle config, string name, string value)
{
int res = NativeMethods.git_config_set_multivar(config, name, non_existing_regex, value);
Ensure.ZeroResult(res);
}

public static unsafe ICollection<TResult> git_config_foreach<TResult>(
ConfigurationHandle config,
Func<IntPtr, TResult> resultSelector)
Expand Down
4 changes: 2 additions & 2 deletions LibGit2Sharp/RemoteUpdater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ private IEnumerable<string> GetFetchRefSpecs()

private void SetFetchRefSpecs(IEnumerable<string> value)
{
repo.Config.UnsetMultivar(string.Format("remote.{0}.fetch", remoteName), ConfigurationLevel.Local);
repo.Config.UnsetAll(string.Format("remote.{0}.fetch", remoteName), ConfigurationLevel.Local);

foreach (var url in value)
{
Expand All @@ -74,7 +74,7 @@ private IEnumerable<string> GetPushRefSpecs()

private void SetPushRefSpecs(IEnumerable<string> value)
{
repo.Config.UnsetMultivar(string.Format("remote.{0}.push", remoteName), ConfigurationLevel.Local);
repo.Config.UnsetAll(string.Format("remote.{0}.push", remoteName), ConfigurationLevel.Local);

foreach (var url in value)
{
Expand Down

0 comments on commit 0e8a3ca

Please sign in to comment.