8000 Merge pull request #1123 from rcorre/search-path · repo-archive/libgit2sharp@8688f10 · GitHub
[go: up one dir, main page]

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 8688f10

Browse files
committed
Merge pull request libgit2#1123 from rcorre/search-path
Allow libgit2# to redirect the global/system/xdg config search path
2 parents e734df5 + d79eec5 commit 8688f10

File tree

5 files changed

+226
-0
lines changed

5 files changed

+226
-0
lines changed

LibGit2Sharp.Tests/ConfigurationFixture.cs

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,5 +431,127 @@ public void CannotBuildAProperSignatureFromConfigWhenFullIdentityCannotBeFoundIn
431431
Assert.Null(signature);
432432
}
433433
}
434+
435+
[Fact]
436+
public void CanSetAndGetSearchPath()
437+
{
438+
string globalPath = Path.Combine(Constants.TemporaryReposPath, Path.GetRandomFileName());
439+
string systemPath = Path.Combine(Constants.TemporaryReposPath, Path.GetRandomFileName());
440+
string xdgPath = Path.Combine(Constants.TemporaryReposPath, Path.GetRandomFileName());
441+
442+
GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, globalPath);
443+
GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.System, systemPath);
444+
GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Xdg, xdgPath);
445+
446+
Assert.Equal(globalPath, GlobalSettings.GetConfigSearchPaths(ConfigurationLevel.Global).Single());
447+
Assert.Equal(systemPath, GlobalSettings.GetConfigSearchPaths(ConfigurationLevel.System).Single());
448+
Assert.Equal(xdgPath, GlobalSettings.GetConfigSearchPaths(ConfigurationLevel.Xdg).Single());
449+
450+
// reset the search paths to their defaults
451+
GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, null);
452+
GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.System, null);
453+
GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Xdg, null);
454+
}
455+
456+
[Fact]
457+
public void CanSetAndGetMultipleSearchPaths()
458+
{
459+
string[] paths =
460+
{
461+
Path.Combine(Constants.TemporaryReposPath, Path.GetRandomFileName()),
462+
Path.Combine(Constants.TemporaryReposPath, Path.GetRandomFileName()),
463+
Path.Combine(Constants.TemporaryReposPath, Path.GetRandomFileName()),
464+
};
465+
466+
GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, paths);
467+
468+
Assert.Equal(paths, GlobalSettings.GetConfigSearchPaths(ConfigurationLevel.Global));
469+
470+
// set back to the defaults
471+
GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, null);
472+
}
473+
474+
[Fact]
475+
public void CanResetSearchPaths()
476+
{
477+
// all of these calls should reset the config path to the default
478+
Action[] resetActions =
479+
{
480+
() => GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global),
481+
() => GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, null),
482+
() => GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, string.Empty),
483+
() => GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, new string[] { }),
484+
};
485+
486+
// record the default search path
487+
GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, null);
488+
var oldPaths = GlobalSettings.GetConfigSearchPaths(ConfigurationLevel.Global);
489+
Assert.NotNull(oldPaths);
490+
491+
// generate a non-default path to set
492+
var newPaths = new string[] { Path.Combine(Constants.TemporaryReposPath, Path.GetRandomFileName()) };
493+
494+
foreach (var tryToReset in resetActions)
495+
{
496+
// change to the non-default path
497+
GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, newPaths);
498+
Assert.Equal(newPaths, GlobalSettings.GetConfigSearchPaths(ConfigurationLevel.Global));
499+
500+
// set it back to the default
501+
tryToReset();
502+
Assert.Equal(oldPaths, GlobalSettings.GetConfigSearchPaths(ConfigurationLevel.Global));
503+
}
504+
505+
// make sure the config paths are reset after the test ends
506+
GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, null);
507+
}
508+
509+
[Fact]
510+
public void CanAppendToSearchPaths()
511+
{
512+
string appendMe = Path.Combine(Constants.TemporaryReposPath, Path.GetRandomFileName());
513+
var prevPaths = GlobalSettings.GetConfigSearchPaths(ConfigurationLevel.Global);
514+
515+
// append using the special name $PATH
516+
GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, "$PATH", appendMe);
517+
518+
var currentPaths = GlobalSettings.GetConfigSearchPaths(ConfigurationLevel.Global);
519+
Assert.Equal(currentPaths, prevPaths.Concat(new[] { appendMe }));
520+
521+
// set it back to the default
522+
GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, null);
523+
}
524+
525+
[Fact]
526+
public void CanRedirectConfigAccess()
527+
{
528+
var scd1 = BuildSelfCleaningDirectory();
529+
var scd2 = BuildSelfCleaningDirectory();
530+
531+
Touch(scd1.RootedDirectoryPath, ".gitconfig");
532+
Touch(scd2.RootedDirectoryPath, ".gitconfig");
533+
534+
// redirect global access to the first path
535+
GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, scd1.RootedDirectoryPath);
536+
537+
// set a value in the first config
538+
using (var config = Configuration.BuildFrom(null))
539+
{
540+
config.Set("luggage.code", 9876, ConfigurationLevel.Global);
541+
Assert.Equal(9876, config.Get<int>("luggage.code", ConfigurationLevel.Global).Value);
542+
}
543+
544+
// redirect global config access to path2
545+
GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, scd2.RootedDirectoryPath);
546+
547+
// if the redirect succeeds, the value set in the prior config should not be visible
548+
using (var config = Configuration.BuildFrom(null))
549+
{
550+
Assert.Equal(-1, config.GetValueOrDefault<int>("luggage.code", ConfigurationLevel.Global, -1));
551+
}
552+
553+
// reset the search path to the default
554+
GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, null);
555+
}
434556
}
435557
}

LibGit2Sharp/Core/NativeMethods.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,25 @@ internal static extern int git_filter_unregister(
581581
[DllImport(libgit2)]
582582
internal static extern int git_libgit2_features();
583583

584+
#region git_libgit2_opts
585+
586+
// Bindings for git_libgit2_opts(int option, ...):
587+
// Currently only GIT_OPT_GET_SEARCH_PATH and GIT_OPT_SET_SEARCH_PATH are supported,
588+
// but other overloads could be added using a similar pattern.
589+
// CallingConvention.Cdecl is used to allow binding the the C varargs signature, and each possible call signature must be enumerated.
590+
// __argslist was an option, but is an undocumented feature that should likely not be used here.
591+
592+
// git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, int level, git_buf *buf)
593+
[DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)]
594+
internal static extern int git_libgit2_opts(int option, uint level, GitBuf buf);
595+
596+
// git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, int level, const char *path)
597+
[DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)]
598+
internal static extern int git_libgit2_opts(int option, uint level,
599+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))]string path);
600+
601+
#endregion
602+
584603
[DllImport(libgit2)]
585604
internal static extern int git_graph_ahead_behind(out UIntPtr ahead, out UIntPtr behind, RepositorySafeHandle repo, ref GitOid one, ref GitOid two);
586605

LibGit2Sharp/Core/Proxy.cs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3193,6 +3193,60 @@ public static BuiltInFeatures git_libgit2_features()
31933193
return (BuiltInFeatures)NativeMethods.git_libgit2_features();
31943194
}
31953195

3196+
// C# equivalent of libgit2's git_libgit2_opt_t
3197+
private enum LibGitOption
3198+
{
3199+
GetMWindowSize, // GIT_OPT_GET_MWINDOW_SIZE
3200+
SetMWindowSize, // GIT_OPT_SET_MWINDOW_SIZE
3201+
GetMWindowMappedLimit, // GIT_OPT_GET_MWINDOW_MAPPED_LIMIT
3202+
SetMWindowMappedLimit, // GIT_OPT_SET_MWINDOW_MAPPED_LIMIT
3203+
GetSearchPath, // GIT_OPT_GET_SEARCH_PATH
3204+
SetSearchPath, // GIT_OPT_SET_SEARCH_PATH
3205+
SetCacheObjectLimit, // GIT_OPT_SET_CACHE_OBJECT_LIMIT
3206+
SetCacheMaxSize, // GIT_OPT_SET_CACHE_MAX_SIZE
3207+
EnableCaching, // GIT_OPT_ENABLE_CACHING
3208+
GetCachedMemory, // GIT_OPT_GET_CACHED_MEMORY
3209+
GetTemplatePath, // GIT_OPT_GET_TEMPLATE_PATH
3210+
SetTemplatePath, // GIT_OPT_SET_TEMPLATE_PATH
3211+
SetSslCertLocations, // GIT_OPT_SET_SSL_CERT_LOCATIONS
3212+
}
3213+
3214+
/// <summary>
3215+
/// Get the paths under which libgit2 searches for the configuration file of a given level.
3216+
/// </summary>
3217+
/// <param name="level">The level (global/system/XDG) of the config.</param>
3218+
/// <returns>
3219+
/// The paths delimited by 'GIT_PATH_LIST_SEPARATOR' (<see cref="GlobalSettings.PathListSeparator"/>).
3220+
/// </returns>
3221+
public static string git_libgit2_opts_get_search_path(ConfigurationLevel level)
3222+
{
3223+
string path;
3224+
3225+
using (var buf = new GitBuf())
3226+
{
3227+
var res = NativeMethods.git_libgit2_opts((int)LibGitOption.GetSearchPath, (uint)level, buf);
3228+
Ensure.ZeroResult(res);
3229+
3230+
path = LaxUtf8Marshaler.FromNative(buf.ptr) ?? string.Empty;
3231+
}
3232+
3233+
return path;
3234+
}
3235+
3236+
/// <summary>
3237+
/// Set the path(s) under which libgit2 searches for the configuration file of a given level.
3238+
/// </summary>
3239+
/// <param name="level">The level (global/system/XDG) of the config.</param>
3240+
/// <param name="path">
3241+
/// A string of paths delimited by 'GIT_PATH_LIST_SEPARATOR' (<see cref="GlobalSettings.PathListSeparator"/>).
3242+
/// Pass null to reset the search path to the default.
3243+
/// </param>
3244+
public static void git_libgit2_opts_set_search_path(ConfigurationLevel level, string path)
3245+
{
3246+
var res = NativeMethods.git_libgit2_opts((int)LibGitOption.SetSearchPath, (uint)level, path);
3247+
Ensure.ZeroResult(res);
3248+
}
3249+
31963250
#endregion
31973251

31983252
private static ICollection<TResult> git_foreach<T, TResult>(

LibGit2Sharp/GlobalSettings.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.IO;
44
using System.Reflection;
5+
using System.Collections.Generic;
56
using LibGit2Sharp.Core;
67

78
namespace LibGit2Sharp
@@ -272,5 +273,32 @@ internal static void DeregisterFilter(Filter filter)
272273
DeregisterFilter(registration);
273274
}
274275
}
276+
277+
/// <summary>
278+
/// Get the paths under which libgit2 searches for the configuration file of a given level.
279+
/// </summary>
280+
/// <param name="level">The level (global/system/XDG) of the config.</param>
281+
/// <returns>The paths that are searched</returns>
282+
public static IEnumerable<string> GetConfigSearchPaths(ConfigurationLevel level)
283+
{
284+
return Proxy.git_libgit2_opts_get_search_path(level).Split(Path.PathSeparator);
285+
}
286+
287+
/// <summary>
288+
/// Set the paths under which libgit2 searches for the configuration file of a given level.
289+
///
290+
/// <seealso cref="RepositoryOptions"/>.
291+
/// </summary>
292+
/// <param name="level">The level (global/system/XDG) of the config.</param>
293+
/// <param name="paths">
294+
/// The new search paths to set.
295+
/// Pass null to reset to the default.
296+
/// The special string "$PATH" will be substituted with the current search path.
297+
/// </param>
298+
public static void SetConfigSearchPaths(ConfigurationLevel level, params string[] paths)
299+
{
300+
var pathString = (paths == null) ? null : string.Join(Path.PathSeparator.ToString(), paths);
301+
Proxy.git_libgit2_opts_set_search_path(level, pathString);
302+
}
275303
}
276304
}

LibGit2Sharp/RepositoryOptions.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public sealed class RepositoryOptions
3232
/// The path has either to lead to an existing valid configuration file,
3333
/// or to a non existent configuration file which will be eventually created.
3434
/// </para>
35+
/// <seealso cref="GlobalSettings.SetConfigSearchPaths"/>.
3536
/// </summary>
3637
public string GlobalConfigurationLocation { get; set; }
3738

@@ -41,6 +42,7 @@ public sealed class RepositoryOptions
4142
/// The path has either to lead to an existing valid configuration file,
4243
/// or to a non existent configuration file which will be eventually created.
4344
/// </para>
45+
/// <seealso cref="GlobalSettings.SetConfigSearchPaths"/>.
4446
/// </summary>
4547
public string XdgConfigurationLocation { get; set; }
4648

@@ -50,6 +52,7 @@ public sealed class RepositoryOptions
5052
/// The path has to lead to an existing valid configuration file,
5153
/// or to a non existent configuration file which will be eventually created.
5254
/// </para>
55+
/// <seealso cref="GlobalSettings.SetConfigSearchPaths"/>.
5356
/// </summary>
5457
public string SystemConfigurationLocation { get; set; }
5558

0 commit comments

Comments
 (0)
0