Skip to content

Commit 3cf04dd

Browse files
committed
Add Configuration.Find(regexp)
1 parent 123bd64 commit 3cf04dd

File tree

6 files changed

+107
-7
lines changed

6 files changed

+107
-7
lines changed

LibGit2Sharp.Tests/ConfigurationFixture.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,35 @@ public void CanEnumerateLocalConfigContainingAKeyWithNoValue()
226226
}
227227
}
228228

229+
[Fact]
230+
public void CanFindInLocalConfig()
231+
{
232+
using (var repo = new Repository(StandardTestRepoPath))
233+
{
234+
var matches = repo.Config.Find("unit");
235+
236+
Assert.NotNull(matches);
237+
Assert.Equal(new[] { "unittests.intsetting", "unittests.longsetting" },
238+
matches.Select(m => m.Key).ToArray());
239+
}
240+
}
241+
242+
[Fact]
243+
public void CanFindInGlobalConfig()
244+
{
245+
string configPath = CreateConfigurationWithDummyUser(Constants.Signature);
246+
var options = new RepositoryOptions { GlobalConfigurationLocation = configPath };
247+
248+
using (var repo = new Repository(StandardTestRepoPath, options))
249+
{
250+
var matches = repo.Config.Find(@"\.name", ConfigurationLevel.Global);
251+
252+
Assert.NotNull(matches);
253+
Assert.Equal(new[] { "user.name" },
254+
matches.Select(m => m.Key).ToArray());
255+
}
256+
}
257+
229258
[Fact]
230259
public void CanSetBooleanValue()
231260
{

LibGit2Sharp/Configuration.cs

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Globalization;
44
using System.IO;
5+
using System.Linq;
56
using System.Runtime.InteropServices;
67
using LibGit2Sharp.Core;
78
using LibGit2Sharp.Core.Handles;
@@ -235,6 +236,23 @@ public virtual void Set<T>(string key, T value, ConfigurationLevel level = Confi
235236
}
236237
}
237238

239+
/// <summary>
240+
/// Find configuration entries matching <paramref name="regexp"/>.
241+
/// </summary>
242+
/// <param name="regexp">A regular expression.</param>
243+
/// <param name="level">The configuration file into which the key should be searched for.</param>
244+
/// <returns>Matching entries.</returns>
245+
public virtual IEnumerable<ConfigurationEntry<string>> Find(string regexp,
246+
ConfigurationLevel level = ConfigurationLevel.Local)
247+
{
248+
Ensure.ArgumentNotNullOrEmptyString(regexp, "regexp");
249+
250+
using (ConfigurationSafeHandle h = RetrieveConfigurationHandle(level, true))
251+
{
252+
return Proxy.git_config_iterator_glob(h, regexp, BuildConfigEntry).ToList();
253+
}
254+
}
255+
238256
private ConfigurationSafeHandle RetrieveConfigurationHandle(ConfigurationLevel level, bool throwIfStoreHasNotBeenFound)
239257
{
240258
ConfigurationSafeHandle handle = null;
@@ -278,14 +296,16 @@ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
278296

279297
private IEnumerable<ConfigurationEntry<string>> BuildConfigEntries()
280298
{
281-
return Proxy.git_config_foreach(configHandle, entryPtr =>
282-
{
283-
var entry = (GitConfigEntry)Marshal.PtrToStructure(entryPtr, typeof(GitConfigEntry));
299+
return Proxy.git_config_foreach(configHandle, BuildConfigEntry);
300+
}
301+
302+
private static ConfigurationEntry<string> BuildConfigEntry(IntPtr entryPtr)
303+
{
304+
var entry = (GitConfigEntry)Marshal.PtrToStructure(entryPtr, typeof(GitConfigEntry));
284305

285-
return new ConfigurationEntry<string>(LaxUtf8Marshaler.FromNative(entry.namePtr),
286-
LaxUtf8Marshaler.FromNative(entry.valuePtr),
287-
(ConfigurationLevel)entry.level);
288-
});
306+
return new ConfigurationEntry<string>(LaxUtf8Marshaler.FromNative(entry.namePtr),
307+
LaxUtf8Marshaler.FromNative(entry.valuePtr),
308+
(ConfigurationLevel)entry.level);
289309
}
290310

291311
internal Signature BuildSignatureFromGlobalConfiguration(DateTimeOffset now, bool shouldThrowIfNotFound)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace LibGit2Sharp.Core.Handles
2+
{
3+
internal class ConfigurationIteratorSafeHandle : SafeHandleBase
4+
{
5+
protected override bool ReleaseHandleImpl()
6+
{
7+
Proxy.git_config_iterator_free(handle);
8+
return true;
9+
}
10+
}
11+
}

LibGit2Sharp/Core/NativeMethods.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,20 @@ internal static extern int git_config_foreach(
343343
config_foreach_callback callback,
344344
IntPtr payload);
345345

346+
[DllImport(libgit2)]
347+
internal static extern int git_config_iterator_glob_new(
348+
out ConfigurationIteratorSafeHandle iter,
349+
ConfigurationSafeHandle cfg,
350+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string regexp);
351+
352+
[DllImport(libgit2)]
353+
internal static extern int git_config_next(
354+
out IntPtr entry,
355+
ConfigurationIteratorSafeHandle iter);
356+
357+
[DllImport(libgit2)]
358+
internal static extern void git_config_iterator_free(IntPtr iter);
359+
346360
// Ordinarily we would decorate the `url` parameter with the StrictUtf8Marshaler like we do everywhere
347361
// else, but apparently doing a native->managed callback with the 64-bit version of CLR 2.0 can
348362
// sometimes vomit when using a custom IMarshaler. So yeah, don't do that. If you need the url,

LibGit2Sharp/Core/Proxy.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,31 @@ public static ICollection<TResult> git_config_foreach<TResult>(
530530
return git_foreach(resultSelector, c => NativeMethods.git_config_foreach(config, (e, p) => c(e, p), IntPtr.Zero));
531531
}
532532

533+
public static IEnumerable<ConfigurationEntry<string>> git_config_iterator_glob(
534+
ConfigurationSafeHandle config,
535+
string regexp,
536+
Func<IntPtr, ConfigurationEntry<string>> resultSelector)
537+
{
538+
return git_iterator(
539+
(out ConfigurationIteratorSafeHandle iter) =>
540+
NativeMethods.git_config_iterator_glob_new(out iter, config, regexp),
541+
(ConfigurationIteratorSafeHandle iter, out SafeHandleBase handle, out int res) =>
542+
{
543+
handle = null;
544+
545+
IntPtr entry;
546+
res = NativeMethods.git_config_next(out entry, iter);
547+
return new { EntryPtr = entry };
548+
},
549+
(handle, payload) => resultSelector(payload.EntryPtr)
550+
);
551+
}
552+
553+
public static void git_config_iterator_free(IntPtr iter)
554+
{
555+
NativeMethods.git_config_iterator_free(iter);
556+
}
557+
533558
#endregion
534559

535560
#region git_diff_

LibGit2Sharp/LibGit2Sharp.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
<Compile Include="RefSpecCollection.cs" />
7676
<Compile Include="Core\EncodingMarshaler.cs" />
7777
<Compile Include="Core\Handles\BranchIteratorSafeHandle.cs" />
78+
<Compile Include="Core\Handles\ConfigurationIteratorSafeHandle.cs" />
7879
<Compile Include="Core\PushTransferProgressCallbacks.cs" />
7980
<Compile Include="Core\PackbuilderCallbacks.cs" />
8081
<Compile Include="PushOptions.cs" />

0 commit comments

Comments
 (0)