diff --git a/LibGit2Sharp.Tests/ConfigurationFixture.cs b/LibGit2Sharp.Tests/ConfigurationFixture.cs
index 39c37769..9917d92a 100644
--- a/LibGit2Sharp.Tests/ConfigurationFixture.cs
+++ b/LibGit2Sharp.Tests/ConfigurationFixture.cs
@@ -226,6 +226,35 @@ namespace LibGit2Sharp.Tests
}
}
+ [Fact]
+ public void CanFindInLocalConfig()
+ {
+ using (var repo = new Repository(StandardTestRepoPath))
+ {
+ var matches = repo.Config.Find("unit");
+
+ Assert.NotNull(matches);
+ Assert.Equal(new[] { "unittests.intsetting", "unittests.longsetting" },
+ matches.Select(m => m.Key).ToArray());
+ }
+ }
+
+ [Fact]
+ public void CanFindInGlobalConfig()
+ {
+ string configPath = CreateConfigurationWithDummyUser(Constants.Signature);
+ var options = new RepositoryOptions { GlobalConfigurationLocation = configPath };
+
+ using (var repo = new Repository(StandardTestRepoPath, options))
+ {
+ var matches = repo.Config.Find(@"\.name", ConfigurationLevel.Global);
+
+ Assert.NotNull(matches);
+ Assert.Equal(new[] { "user.name" },
+ matches.Select(m => m.Key).ToArray());
+ }
+ }
+
[Fact]
public void CanSetBooleanValue()
{
diff --git a/LibGit2Sharp/Configuration.cs b/LibGit2Sharp/Configuration.cs
index 3734554d..8a2aa8b2 100644
--- a/LibGit2Sharp/Configuration.cs
+++ b/LibGit2Sharp/Configuration.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
+using System.Linq;
using System.Runtime.InteropServices;
using LibGit2Sharp.Core;
using LibGit2Sharp.Core.Handles;
@@ -235,6 +236,23 @@ namespace LibGit2Sharp
}
}
+ ///
+ /// Find configuration entries matching .
+ ///
+ /// A regular expression.
+ /// The configuration file into which the key should be searched for.
+ /// Matching entries.
+ public virtual IEnumerable> Find(string regexp,
+ ConfigurationLevel level = ConfigurationLevel.Local)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(regexp, "regexp");
+
+ using (ConfigurationSafeHandle h = RetrieveConfigurationHandle(level, true))
+ {
+ return Proxy.git_config_iterator_glob(h, regexp, BuildConfigEntry).ToList();
+ }
+ }
+
private ConfigurationSafeHandle RetrieveConfigurationHandle(ConfigurationLevel level, bool throwIfStoreHasNotBeenFound)
{
ConfigurationSafeHandle handle = null;
@@ -278,14 +296,16 @@ namespace LibGit2Sharp
private IEnumerable> BuildConfigEntries()
{
- return Proxy.git_config_foreach(configHandle, entryPtr =>
- {
- var entry = (GitConfigEntry)Marshal.PtrToStructure(entryPtr, typeof(GitConfigEntry));
+ return Proxy.git_config_foreach(configHandle, BuildConfigEntry);
+ }
- return new ConfigurationEntry(LaxUtf8Marshaler.FromNative(entry.namePtr),
- LaxUtf8Marshaler.FromNative(entry.valuePtr),
- (ConfigurationLevel)entry.level);
- });
+ private static ConfigurationEntry BuildConfigEntry(IntPtr entryPtr)
+ {
+ var entry = (GitConfigEntry)Marshal.PtrToStructure(entryPtr, typeof(GitConfigEntry));
+
+ return new ConfigurationEntry(LaxUtf8Marshaler.FromNative(entry.namePtr),
+ LaxUtf8Marshaler.FromNative(entry.valuePtr),
+ (ConfigurationLevel)entry.level);
}
internal Signature BuildSignatureFromGlobalConfiguration(DateTimeOffset now, bool shouldThrowIfNotFound)
diff --git a/LibGit2Sharp/Core/Handles/ConfigurationIteratorSafeHandle.cs b/LibGit2Sharp/Core/Handles/ConfigurationIteratorSafeHandle.cs
new file mode 100644
index 00000000..0d2cb6ab
--- /dev/null
+++ b/LibGit2Sharp/Core/Handles/ConfigurationIteratorSafeHandle.cs
@@ -0,0 +1,11 @@
+namespace LibGit2Sharp.Core.Handles
+{
+ internal class ConfigurationIteratorSafeHandle : SafeHandleBase
+ {
+ protected override bool ReleaseHandleImpl()
+ {
+ Proxy.git_config_iterator_free(handle);
+ return true;
+ }
+ }
+}
diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs
index b43e6a99..c250a08d 100644
--- a/LibGit2Sharp/Core/NativeMethods.cs
+++ b/LibGit2Sharp/Core/NativeMethods.cs
@@ -343,6 +343,20 @@ namespace LibGit2Sharp.Core
config_foreach_callback callback,
IntPtr payload);
+ [DllImport(libgit2)]
+ internal static extern int git_config_iterator_glob_new(
+ out ConfigurationIteratorSafeHandle iter,
+ ConfigurationSafeHandle cfg,
+ [MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string regexp);
+
+ [DllImport(libgit2)]
+ internal static extern int git_config_next(
+ out IntPtr entry,
+ ConfigurationIteratorSafeHandle iter);
+
+ [DllImport(libgit2)]
+ internal static extern void git_config_iterator_free(IntPtr iter);
+
// Ordinarily we would decorate the `url` parameter with the StrictUtf8Marshaler like we do everywhere
// else, but apparently doing a native->managed callback with the 64-bit version of CLR 2.0 can
// sometimes vomit when using a custom IMarshaler. So yeah, don't do that. If you need the url,
diff --git a/LibGit2Sharp/Core/Proxy.cs b/LibGit2Sharp/Core/Proxy.cs
index d824a408..82119b2d 100644
--- a/LibGit2Sharp/Core/Proxy.cs
+++ b/LibGit2Sharp/Core/Proxy.cs
@@ -530,6 +530,31 @@ namespace LibGit2Sharp.Core
return git_foreach(resultSelector, c => NativeMethods.git_config_foreach(config, (e, p) => c(e, p), IntPtr.Zero));
}
+ public static IEnumerable> git_config_iterator_glob(
+ ConfigurationSafeHandle config,
+ string regexp,
+ Func> resultSelector)
+ {
+ return git_iterator(
+ (out ConfigurationIteratorSafeHandle iter) =>
+ NativeMethods.git_config_iterator_glob_new(out iter, config, regexp),
+ (ConfigurationIteratorSafeHandle iter, out SafeHandleBase handle, out int res) =>
+ {
+ handle = null;
+
+ IntPtr entry;
+ res = NativeMethods.git_config_next(out entry, iter);
+ return new { EntryPtr = entry };
+ },
+ (handle, payload) => resultSelector(payload.EntryPtr)
+ );
+ }
+
+ public static void git_config_iterator_free(IntPtr iter)
+ {
+ NativeMethods.git_config_iterator_free(iter);
+ }
+
#endregion
#region git_diff_
diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj
index 513db6a5..d9cd8c73 100644
--- a/LibGit2Sharp/LibGit2Sharp.csproj
+++ b/LibGit2Sharp/LibGit2Sharp.csproj
@@ -75,6 +75,7 @@
+