8000 Make Config.Get() able to target a specific store · rlazev/libgit2sharp@bbf0b7f · GitHub
[go: up one dir, main page]

Skip to content

Commit bbf0b7f

Browse files
committed
Make Config.Get() able to target a specific store
Fix libgit2#162
1 parent 3d29d95 commit bbf0b7f

File tree

4 files changed

+161
-85
lines changed

4 files changed

+161
-85
lines changed

LibGit2Sharp.Tests/ConfigurationFixture.cs

Lines changed: 74 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -66,24 +66,7 @@ public void CanUnsetAnEntryFromTheGlobalConfiguration()
6666
{
6767
SelfCleaningDirectory scd = BuildSelfCleaningDirectory();
6868

69-
string confs = Path.Combine(scd.DirectoryPath, "confs");
70-
Directory.CreateDirectory(confs);
71-
72-
string globalLocation = Path.Combine(confs, "my-global-config");
73-
string systemLocation = Path.Combine(confs, "my-system-config");
74-
75-
StringBuilder sb = new StringBuilder()
76-
.AppendLine("[Wow]")
77-
.AppendFormat("Man-I-am-totally-global = 42{0}", Environment.NewLine);
78-
79-
File.WriteAllText(globalLocation, sb.ToString());
80-
File.WriteAllText(systemLocation, string.Empty);
81-
82-
var options = new RepositoryOptions
83-
{
84-
GlobalConfigurationLocation = globalLocation,
85-
SystemConfigurationLocation = systemLocation,
86-
};
69+
var options = BuildFakeConfigs(scd);
8770

8871
using (var repo = new Repository(BareTestRepoPath, options))
8972
{
@@ -342,5 +325,78 @@ public void SettingUnsupportedTypeThrows()
342325
Assert.Throws<ArgumentException>(() => repo.Config.Set("unittests.setting", repo.Config));
343326
}
344327
}
328+
329+
[Fact]
330+
public void CanGetAnEntryFromASpecificStore()
331+
{
332+
SelfCleaningDirectory scd = BuildSelfCleaningDirectory();
333+
334+
var options = BuildFakeConfigs(scd);
335+
336+
var path = BuildTemporaryCloneOfTestRepo(StandardTestRepoPath);
337+
using (var repo = new Repository(path.RepositoryPath, options))
338+
{
339+
Assert.True(repo.Config.HasConfig(ConfigurationLevel.Local));
340+
Assert.True(repo.Config.HasConfig(ConfigurationLevel.Global));
341+
Assert.True(repo.Config.HasConfig(ConfigurationLevel.System));
342+
343+
Assert.Null(repo.Config.Get<string>("Woot.global-rocks", ConfigurationLevel.Local));
344+
345+
repo.Config.Set("Woot.this-rocks", "local");
346+
347+
Assert.Equal("global", repo.Config.Get<string>("Woot.this-rocks", ConfigurationLevel.Global).Value);
348+
Assert.Equal("system", repo.Config.Get<string>("Woot.this-rocks", ConfigurationLevel.System).Value);
349+
Assert.Equal("local", repo.Config.Get<string>("Woot.this-rocks", ConfigurationLevel.Local).Value);
350+
}
351+
}
352+
353+
[Fact]
354+
public void CanTellIfASpecificStoreContainsAKey()
355+
{
356+
SelfCleaningDirectory scd = BuildSelfCleaningDirectory();
357+
358+
var options = BuildFakeConfigs(scd);
359+
360+
using (var repo = new Repository(BareTestRepoPath, options))
361+
{
362+
Assert.True(repo.Config.HasConfig(ConfigurationLevel.System));
363+
364+
Assert.Null(repo.Config.Get<string>("MCHammer.You-cant-touch-this", ConfigurationLevel.System));
365+
}
366+
}
367+
368+
private RepositoryOptions BuildFakeConfigs(SelfCleaningDirectory scd)
369+
{
370+
var options = BuildFakeRepositoryOptions(scd);
371+
372+
StringBuilder sb = new StringBuilder()
373+
.AppendFormat("[Woot]{0}", Environment.NewLine)
374+
.AppendFormat("this-rocks = global{0}", Environment.NewLine)
375+
.AppendFormat("[Wow]{0}", Environment.NewLine)
376+
.AppendFormat("Man-I-am-totally-global = 42{0}", Environment.NewLine);
377+
File.WriteAllText(options.GlobalConfigurationLocation, sb.ToString());
378+
379+
sb = new StringBuilder()
380+
.AppendFormat("[Woot]{0}", Environment.NewLine)
381+
.AppendFormat("this-rocks = system{0}", Environment.NewLine);
382+
File.WriteAllText(options.SystemConfigurationLocation, sb.ToString());
383+
384+
return options;
385+
}
386+
387+
private RepositoryOptions BuildFakeRepositoryOptions(SelfCleaningDirectory scd)
388+
{
389+
string confs = Path.Combine(scd.DirectoryPath, "confs");
390+
Directory.CreateDirectory(confs);
391+
392+
string globalLocation = Path.Combine(confs, "my-global-config");
393+
string systemLocation = Path.Combine(confs, "my-system-config");
394+
395+
return new RepositoryOptions
396+
{
397+
GlobalConfigurationLocation = globalLocation,
398+
SystemConfigurationLocation = systemLocation,
399+
};
400+
}
345401
}
346402
}

LibGit2Sharp/Configuration.cs

Lines changed: 61 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@ public class Configuration : IDisposable,
2121

2222
private readonly Repository repository;
2323

24-
private ConfigurationSafeHandle systemHandle;
25-
private ConfigurationSafeHandle globalHandle;
26-
private ConfigurationSafeHandle localHandle;
24+
private ConfigurationSafeHandle configHandle;
2725

2826
/// <summary>
2927
/// Needed for mocking purposes.
@@ -43,39 +41,28 @@ internal Configuration(Repository repository, string globalConfigurationFileLoca
4341

4442
private void Init()
4543
{
44+
configHandle = Proxy.git_config_new();
45+
4646
if (repository != null)
4747
{
4848
//TODO: push back this logic into libgit2.
4949
// As stated by @carlosmn "having a helper function to load the defaults and then allowing you
5050
// to modify it before giving it to git_repository_open_ext() would be a good addition, I think."
5151
// -- Agreed :)
52-
53-
localHandle = Proxy.git_config_new();
54-
5552
string repoConfigLocation = Path.Combine(repository.Info.Path, "config");
56-
Proxy.git_config_add_file_ondisk(localHandle, repoConfigLocation, (uint)ConfigurationLevel.Local);
53+
Proxy.git_config_add_file_ondisk(configHandle, repoConfigLocation, ConfigurationLevel.Local);
5754

58-
if (globalConfigPath != null)
59-
{
60-
Proxy.git_config_add_file_ondisk(localHandle, globalConfigPath, (uint)ConfigurationLevel.Global);
61-
}
62-
63-
if (systemConfigPath != null)
64-
{
65-
Proxy.git_config_add_file_ondisk(localHandle, systemConfigPath, (uint)ConfigurationLevel.System);
66-
}
67-
68-
Proxy.git_repository_set_config(repository.Handle, localHandle);
55+
Proxy.git_repository_set_config(repository.Handle, configHandle);
6956
}
7057

7158
if (globalConfigPath != null)
7259
{
73-
globalHandle = Proxy.git_config_open_ondisk(globalConfigPath);
60+
Proxy.git_config_add_file_ondisk(configHandle, globalConfigPath, ConfigurationLevel.Global);
7461
}
7562

7663
if (systemConfigPath != null)
7764
{
78-
systemHandle = Proxy.git_config_open_ondisk(systemConfigPath);
65+
Proxy.git_config_add_file_ondisk(configHandle, systemConfigPath, ConfigurationLevel.System);
7966
}
8067
}
8168

@@ -112,7 +99,10 @@ public virtual bool HasSystemConfig
11299
/// </summary>
113100
public virtual bool HasConfig(ConfigurationLevel level)
114101
{
115-
return RetrieveConfigurationHandle(level, false) != null;
102+
using (ConfigurationSafeHandle handle = RetrieveConfigurationHandle(level, false))
103+
{
104+
return handle != null;
105+
}
116106
}
117107

118108
#region IDisposable Members
@@ -138,13 +128,9 @@ public virtual void Unset(string key, ConfigurationLevel level = ConfigurationLe
138128
{
139129
Ensure.ArgumentNotNullOrEmptyString(key, "key");
140130

141-
ConfigurationSafeHandle h = RetrieveConfigurationHandle(level, true);
142-
143-
bool success = Proxy.git_config_delete(h, key);
144-
145-
if (success)
131+
using (ConfigurationSafeHandle h = RetrieveConfigurationHandle(level, true))
146132
{
147-
Save();
133+
Proxy.git_config_delete(h, key);
148134
}
149135
}
150136

@@ -153,9 +139,7 @@ public virtual void Unset(string key, ConfigurationLevel level = ConfigurationLe
153139
/// </summary>
154140
protected virtual void Dispose(bool disposing)
155141
{
156-
localHandle.SafeDispose();
157-
globalHandle.SafeDispose();
158-
systemHandle.SafeDispose();
142+
configHandle.SafeDispose();
159143
}
160144

161145
/// <summary>
@@ -182,20 +166,43 @@ public ConfigurationEntry<T> Get<T>(string key)
182166
{
183167
Ensure.ArgumentNotNullOrEmptyString(key, "key");
184168

185-
ConfigurationSafeHandle handle = (localHandle ?? globalHandle) ?? systemHandle;
186-
187-
if (handle == null)
188-
{
189-
throw new LibGit2SharpException("Could not find a local, global or system level configuration.");
190-
}
191-
192-
return Proxy.git_config_get_entry<T>(handle, key);
169+
return Proxy.git_config_get_entry<T>(configHandle, key);
193170
}
194171

195-
private void Save()
172+
/// <summary>
173+
/// Get a configuration value for a key. Keys are in the form 'section.name'.
174+
/// <para>
175+
/// For example in order to get the value for this in a .git\config file:
176+
///
177+
/// <code>
178+
/// [core]
179+
/// bare = true
180+
/// </code>
181+
///
182+
/// You would call:
183+
///
184+
/// <code>
185+
/// bool isBare = repo.Config.Get&lt;bool&gt;("core.bare").Value;
186+
/// </code>
187+
/// </para>
188+
/// </summary>
189+
/// <typeparam name = "T">The configuration value type</typeparam>
190+
/// <param name = "key">The key</param>
191+
/// <param name = "level">The configuration file into which the key should be searched for</param>
192+
/// <returns>The <see cref="ConfigurationEntry{T}"/>, or null if not set</returns>
193+
public ConfigurationEntry<T> Get<T>(string key, ConfigurationLevel level)
196194
{
197-
Dispose(true);
198-
Init();
195+
Ensure.ArgumentNotNullOrEmptyString(key, "key");
196+
197+
using (ConfigurationSafeHandle handle = RetrieveConfigurationHandle(level, false))
198+
{
199+
if (handle == null)
200+
{
201+
return null;
202+
}
203+
204+
return Proxy.git_config_get_entry<T>(handle, key);
205+
}
199206
}
200207

201208
/// <summary>
@@ -219,35 +226,31 @@ public virtual void Set<T>(string key, T value, ConfigurationLevel level = Confi
219226
{
220227
Ensure.ArgumentNotNullOrEmptyString(key, "key");
221228

222-
ConfigurationSafeHandle h = RetrieveConfigurationHandle(level, true);
223-
224-
if (!configurationTypedUpdater.ContainsKey(typeof(T)))
229+
using (ConfigurationSafeHandle h = RetrieveConfigurationHandle(level, true))
225230
{
226-
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Generic Argument of type '{0}' is not supported.", typeof(T).FullName));
227-
}
231+
if (!configurationTypedUpdater.ContainsKey(typeof(T)))
232+
{
233+
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Generic Argument of type '{0}' is not supported.", typeof(T).FullName));
234+
}
228235

229-
configurationTypedUpdater[typeof(T)](key, value, h);
230-
Save();
236+
configurationTypedUpdater[typeof(T)](key, value, h);
237+
}
231238
}
232239

233240
private ConfigurationSafeHandle RetrieveConfigurationHandle(ConfigurationLevel level, bool throwIfStoreHasNotBeenFound)
234241
{
235-
Func<Configuration, ConfigurationSafeHandle> handleRetriever;
236-
if (!configurationHandleRetriever.TryGetValue(level, out handleRetriever))
242+
ConfigurationSafeHandle handle = null;
243+
if (configHandle != null)
237244
{
238-
throw new ArgumentException(
239-
string.Format(CultureInfo.InvariantCulture, "Configuration level has an unexpected value ('{0}').",
240-
level), "level");
245+
handle = Proxy.git_config_open_level(configHandle, level);
241246
}
242247

243-
ConfigurationSafeHandle h = handleRetriever(this);
244-
245-
if (h == null && throwIfStoreHasNotBeenFound)
248+
if (handle == null && throwIfStoreHasNotBeenFound)
246249
{
247250
throw new LibGit2SharpException("No matching configuration file has been found.");
248251
}
249252

250-
return h;
253+
return handle;
251254
}
252255

253256
private static Action<string, object, ConfigurationSafeHandle> GetUpdater<T>(Action<ConfigurationSafeHandle, string, T> setter)
@@ -263,13 +266,6 @@ private static Action<string, object, ConfigurationSafeHandle> GetUpdater<T>(Act
263266
{ typeof(string), GetUpdater<string>(Proxy.git_config_set_string) },
264267
};
265268

266-
private readonly static IDictionary<ConfigurationLevel, Func<Configuration, ConfigurationSafeHandle>> configurationHandleRetriever = new Dictionary<ConfigurationLevel, Func<Configuration, ConfigurationSafeHandle>>
267-
{
268-
{ ConfigurationLevel.Local, cfg => cfg.localHandle },
269-
{ ConfigurationLevel.Global, cfg => cfg.globalHandle },
270-
{ ConfigurationLevel.System, cfg => cfg.systemHandle },
271-
};
272-
273269
IEnumerator<ConfigurationEntry<string>> IEnumerable<ConfigurationEntry<String>>.GetEnumerator()
274270
{
275271
return BuildConfigEntries().Cast<ConfigurationEntry<string>>().GetEnumerator();
@@ -288,7 +284,7 @@ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
288284

289285
private ICollection<ConfigurationEntry> BuildConfigEntries()
290286
{
291-
return Proxy.git_config_foreach(localHandle, entryPtr =>
287+
return Proxy.git_config_foreach(configHandle, entryPtr =>
292288
{
293289
var entry = (GitConfigEntry)Marshal.PtrToStructure(entryPtr, typeof(GitConfigEntry));
294290

LibGit2Sharp/Core/NativeMethods.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,12 @@ internal static extern int git_config_add_file_ondisk(
247247
[DllImport(libgit2)]
248248
internal static extern int git_config_new(out ConfigurationSafeHandle cfg);
249249

250+
[DllImport(libgit2)]
251+
internal static extern int git_config_open_level(
252+
out ConfigurationSafeHandle cfg,
253+
ConfigurationSafeHandle parent,
254+
uint level);
255+
250256
[DllImport(libgit2)]
251257
internal static extern int git_config_open_ondisk(
252258
out ConfigurationSafeHandle cfg,

LibGit2Sharp/Core/Proxy.cs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,11 +318,11 @@ public static ObjectId git_commit_tree_oid(GitObjectSafeHandle obj)
318318

319319
#region git_config_
320320

321-
public static void git_config_add_file_ondisk(ConfigurationSafeHandle config, FilePath path, uint level)
321+
public static void git_config_add_file_ondisk(ConfigurationSafeHandle config, FilePath path, ConfigurationLevel level)
322322
{
323323
using (ThreadAffinity())
324324
{
325-
int res = NativeMethods.git_config_add_file_ondisk(config, path, level, true);
325+
int res = NativeMethods.git_config_add_file_ondisk(config, path, (uint)level, true);
326326
Ensure.Success(res);
327327
}
328328
}
@@ -397,6 +397,24 @@ public static ConfigurationSafeHandle git_config_new()
397397
}
398398
}
399399

400+
public static ConfigurationSafeHandle git_config_open_level(ConfigurationSafeHandle parent, ConfigurationLevel level)
401+
{
402+
using (ThreadAffinity())
403+
{
404+
ConfigurationSafeHandle handle;
405+
int res = NativeMethods.git_config_open_level(out handle, parent, (uint)level);
406+
407+
if (res == (int)GitErrorCode.NotFound)
408+
{
409+
return null;
410+
}
411+
412+
Ensure.Success(res);
413+
414+
return handle;
415+
}
416+
}
417+
400418
public static ConfigurationSafeHandle git_config_open_ondisk(FilePath path)
401419
{
402420
using (ThreadAffinity())

0 commit comments

Comments
 (0)
0