Skip to content

Commit f24fbe6

Browse files
committed
Extend RepositoryOptions to accept path to alternate System and Global configuration files
Fix libgit2#157
1 parent 0690be7 commit f24fbe6

File tree

7 files changed

+128
-46
lines changed

7 files changed

+128
-46
lines changed

LibGit2Sharp.Tests/ConfigurationFixture.cs

-7
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,6 @@ private static void AssertValueInLocalConfigFile(string repoPath, string regex)
1414
AssertValueInConfigFile(configFilePath, regex);
1515
}
1616

17-
private static void AssertValueInConfigFile(string configFilePath, string regex)
18-
{
19-
var text = File.ReadAllText(configFilePath);
20-
var r = new Regex(regex, RegexOptions.Multiline).Match(text);
21-
Assert.True(r.Success, text);
22-
}
23-
2417
private static string RetrieveGlobalConfigLocation()
2518
{
2619
string[] variables = { "HOME", "USERPROFILE", };

LibGit2Sharp.Tests/RepositoryOptionsFixture.cs

+34-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.IO;
3+
using System.Text;
34
using LibGit2Sharp.Tests.TestHelpers;
45
using Xunit;
56

@@ -101,16 +102,6 @@ public void OpeningABareRepoWithoutProvidingBothWorkDirAndIndexThrows()
101102
Assert.Throws<ArgumentException>(() => repo = new Repository(BareTestRepoPath, new RepositoryOptions { WorkingDirectoryPath = newWorkdir }));
102103
}
103104

104-
[Fact]
105-
public void OpeningARepoWithAnEmptyRepositoryOptionsThrows()
106-
{
107-
var options = new RepositoryOptions();
108-
Repository repo;
109-
110-
Assert.Throws<ArgumentException>(() => repo = new Repository(BareTestRepoPath, options));
111-
Assert.Throws<ArgumentException>(() => repo = new Repository(StandardTestRepoPath, options));
112-
}
113-
114105
[Fact]
115106
public void CanSneakAdditionalCommitsIntoAStandardRepoWithoutAlteringTheWorkdirOrTheIndex()
116107
{
@@ -150,5 +141,38 @@ private string MeanwhileInAnotherDimensionAnEvilMastermindIsAtWork(string workin
150141
return sneakyRepo.Commit("Tadaaaa!", DummySignature, DummySignature).Sha;
151142
}
152143
}
144+
145+
[Fact]
146+
public void CanProvideDifferentConfigurationFilesToARepository()
147+
{
148+
string globalLocation = Path.Combine(newWorkdir, "my-global-config");
149+
string systemLocation = Path.Combine(newWorkdir, "my-system-config");
150+
151+
const string name = "Adam 'aroben' Roben";
152+
const string email = "[email protected]";
153+
154+
StringBuilder sb = new StringBuilder()
155+
.AppendLine("[user]")
156+
.AppendFormat("name = {0}{1}", name, Environment.NewLine)
157+
.AppendFormat("email = {0}{1}", email, Environment.NewLine);
158+
159+
File.WriteAllText(globalLocation, sb.ToString());
160+
161+
var options = new RepositoryOptions {
162+
GlobalConfigurationLocation = globalLocation,
163+
SystemConfigurationLocation = systemLocation,
164+
};
165+
166+
using (var repo = new Repository(BareTestRepoPath, options))
167+
{
168+
Assert.True(repo.Config.HasGlobalConfig);
169+
Assert.Equal(name, repo.Config.Get<string>("user", "name", null));
170+
Assert.Equal(email, repo.Config.Get<string>("user", "email", null));
171+
172+
repo.Config.Set("help.link", "https://twitter.com/xpaulbettsx/status/205761932626636800", ConfigurationLevel.System);
173+
}
174+
175+
AssertValueInConfigFile(systemLocation, "xpaulbettsx");
176+
}
153177
}
154178
}

LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs

+9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System;
22
using System.Collections.Generic;
33
using System.IO;
4+
using System.Text.RegularExpressions;
5+
using Xunit;
46

57
namespace LibGit2Sharp.Tests.TestHelpers
68
{
@@ -94,5 +96,12 @@ protected void InconclusiveIf(Func<bool> predicate, string message)
9496

9597
throw new SkipException(message);
9698
}
99+
100+
protected static void AssertValueInConfigFile(string configFilePath, string regex)
101+
{
102+
var text = File.ReadAllText(configFilePath);
103+
var r = new Regex(regex, RegexOptions.Multiline).Match(text);
104+
Assert.True(r.Success, text);
105+
}
97106
}
98107
}

LibGit2Sharp/Configuration.cs

+46-23
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Globalization;
4+
using System.IO;
45
using LibGit2Sharp.Core;
56
using LibGit2Sharp.Core.Handles;
67

@@ -20,21 +21,61 @@ public class Configuration : IDisposable
2021
private ConfigurationSafeHandle globalHandle;
2122
private ConfigurationSafeHandle localHandle;
2223

23-
internal Configuration(Repository repository)
24+
internal Configuration(Repository repository, string globalConfigurationFileLocation, string systemConfigurationFileLocation)
2425
{
2526
this.repository = repository;
2627

27-
globalConfigPath = ConvertPath(NativeMethods.git_config_find_global);
28-
systemConfigPath = ConvertPath(NativeMethods.git_config_find_system);
28+
globalConfigPath = globalConfigurationFileLocation ?? ConvertPath(NativeMethods.git_config_find_global);
29+
systemConfigPath = systemConfigurationFileLocation ?? ConvertPath(NativeMethods.git_config_find_system);
2930

3031
Init();
3132
}
3233

34+
private void Init()
35+
{
36+
if (repository != null)
37+
{
38+
//TODO: push back this logic into libgit2.
39+
// As stated by @carlosmn "having a helper function to load the defaults and then allowing you
40+
// to modify it before giving it to git_repository_open_ext() would be a good addition, I think."
41+
// -- Agreed :)
42+
43+
Ensure.Success(NativeMethods.git_config_new(out localHandle));
44+
45+
string repoConfigLocation = Path.Combine(repository.Info.Path, "config");
46+
Ensure.Success(NativeMethods.git_config_add_file_ondisk(localHandle, repoConfigLocation, 3));
47+
48+
if (globalConfigPath != null)
49+
{
50+
Ensure.Success(NativeMethods.git_config_add_file_ondisk(localHandle, globalConfigPath, 2));
51+
}
52+
53+
if (systemConfigPath != null)
54+
{
55+
Ensure.Success(NativeMethods.git_config_add_file_ondisk(localHandle, systemConfigPath, 1));
56+
}
57+
58+
NativeMethods.git_repository_set_config(repository.Handle, localHandle);
59+
}
60+
61+
if (globalConfigPath != null)
62+
{
63+
Ensure.Success(NativeMethods.git_config_open_ondisk(out globalHandle, globalConfigPath));
64+
}
65+
66+
if (systemConfigPath != null)
67+
{
68+
Ensure.Success(NativeMethods.git_config_open_ondisk(out systemHandle, systemConfigPath));
69+
}
70+
}
71+
3372
/// <summary>
3473
/// Access configuration values without a repository. Generally you want to access configuration via an instance of <see cref = "Repository" /> instead.
3574
/// </summary>
36-
public Configuration()
37-
: this(null)
75+
/// <param name="globalConfigurationFileLocation">Path to a Global configuration file. If null, the default path for a global configuration file will be probed.</param>
76+
/// <param name="systemConfigurationFileLocation">Path to a System configuration file. If null, the default path for a system configuration file will be probed.</param>
77+
public Configuration(string globalConfigurationFileLocation = null, string systemConfigurationFileLocation = null)
78+
: this(null, globalConfigurationFileLocation, systemConfigurationFileLocation)
3879
{
3980
}
4081

@@ -246,24 +287,6 @@ public T Get<T>(string[] keyParts, T defaultValue)
246287
return Get(string.Join(".", keyParts), defaultValue);
247288
}
248289

249-
private void Init()
250-
{
251-
if (repository != null)
252-
{
253-
Ensure.Success(NativeMethods.git_repository_config(out localHandle, repository.Handle));
254-
}
255-
256-
if (globalConfigPath != null)
257-
{
258-
Ensure.Success(NativeMethods.git_config_open_ondisk(out globalHandle, globalConfigPath));
259-
}
260-
261-
if (systemConfigPath != null)
262-
{
263-
Ensure.Success(NativeMethods.git_config_open_ondisk(out systemHandle, systemConfigPath));
264-
}
265-
}
266-
267290
private void Save()
268291
{
269292
Dispose(true);

LibGit2Sharp/Core/NativeMethods.cs

+14
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,15 @@ public static extern int git_config_get_string(
181181
ConfigurationSafeHandle cfg,
182182
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string name);
183183

184+
[DllImport(libgit2)]
185+
public static extern int git_config_add_file_ondisk(
186+
ConfigurationSafeHandle cfg,
187+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(FilePathMarshaler))] FilePath path,
188+
int priority);
189+
190+
[DllImport(libgit2)]
191+
public static extern int git_config_new(out ConfigurationSafeHandle cfg);
192+
184193
[DllImport(libgit2)]
185194
public static extern int git_config_open_global(out ConfigurationSafeHandle cfg);
186195

@@ -547,6 +556,11 @@ public static extern int git_repository_open(
547556
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(FilePathMarshaler))]
548557
public static extern FilePath git_repository_path(RepositorySafeHandle repository);
549558

559+
[DllImport(libgit2)]
560+
public static extern void git_repository_set_config(
561+
RepositorySafeHandle repository,
562+
ConfigurationSafeHandle index);
563+
550564
[DllImport(libgit2)]
551565
public static extern void git_repository_set_index(
552566
RepositorySafeHandle repository,

LibGit2Sharp/Repository.cs

+7-6
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,14 @@ public Repository(string path, RepositoryOptions options = null)
5151

5252
Func<Index> indexBuilder = () => new Index(this);
5353

54+
string configurationGlobalFilePath = null;
55+
string configurationSystemFilePath = null;
56+
5457
if (options != null)
5558
{
5659
bool isWorkDirNull = string.IsNullOrEmpty(options.WorkingDirectoryPath);
5760
bool isIndexNull = string.IsNullOrEmpty(options.IndexPath);
5861

59-
if (isWorkDirNull && isIndexNull)
60-
{
61-
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "At least one member of the {0} instance has to be provided.", typeof(RepositoryOptions).Name));
62-
}
63-
6462
if (isBare && (isWorkDirNull ^ isIndexNull))
6563
{
6664
throw new ArgumentException("When overriding the opening of a bare repository, both RepositoryOptions.WorkingDirectoryPath an RepositoryOptions.IndexPath have to be provided.");
@@ -77,6 +75,9 @@ public Repository(string path, RepositoryOptions options = null)
7775
{
7876
Ensure.Success(NativeMethods.git_repository_set_workdir(handle, options.WorkingDirectoryPath));
7977
}
78+
79+
configurationGlobalFilePath = options.GlobalConfigurationLocation;
80+
configurationSystemFilePath = options.SystemConfigurationLocation;
8081
}
8182

8283
if (!isBare)
@@ -89,7 +90,7 @@ public Repository(string path, RepositoryOptions options = null)
8990
branches = new BranchCollection(this);
9091
tags = new TagCollection(this);
9192
info = new Lazy<RepositoryInformation>(() => new RepositoryInformation(this, isBare));
92-
config = new Lazy<Configuration>(() => RegisterForCleanup(new Configuration(this)));
93+
config = new Lazy<Configuration>(() => RegisterForCleanup(new Configuration(this, configurationGlobalFilePath, configurationSystemFilePath)));
9394
remotes = new Lazy<RemoteCollection>(() => new RemoteCollection(this));
9495
odb = new Lazy<ObjectDatabase>(() => new ObjectDatabase(this));
9596
diff = new Diff(this);

LibGit2Sharp/RepositoryOptions.cs

+18
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,23 @@ public class RepositoryOptions
2525
/// </para>
2626
/// </summary>
2727
public string IndexPath { get; set; }
28+
29+
/// <summary>
30+
/// Overrides the probed location of the Global configuration file of a repository.
31+
/// <para>
32+
/// The path has either to lead to an existing valid configuration file,
33+
/// or to a non existent configuration file which will be eventually created.
34+
/// </para>
35+
/// </summary>
36+
public string GlobalConfigurationLocation { get; set; }
37+
38+
/// <summary>
39+
/// Overrides the probed location of the System configuration file of a repository.
40+
/// <para>
41+
/// The path has to lead to an existing valid configuration file,
42+
/// or to a non existent configuration file which will be eventually created.
43+
/// </para>
44+
/// </summary>
45+
public string SystemConfigurationLocation { get; set; }
2846
}
2947
}

0 commit comments

Comments
 (0)