Skip to content

Extend RepositoryOptions to accept path to alternate System and Global config files #160

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions LibGit2Sharp.Tests/ConfigurationFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,6 @@ private static void AssertValueInLocalConfigFile(string repoPath, string regex)
AssertValueInConfigFile(configFilePath, regex);
}

private static void AssertValueInConfigFile(string configFilePath, string regex)
{
var text = File.ReadAllText(configFilePath);
var r = new Regex(regex, RegexOptions.Multiline).Match(text);
Assert.True(r.Success, text);
}

private static string RetrieveGlobalConfigLocation()
{
string[] variables = { "HOME", "USERPROFILE", };
Expand Down
44 changes: 34 additions & 10 deletions LibGit2Sharp.Tests/RepositoryOptionsFixture.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Text;
using LibGit2Sharp.Tests.TestHelpers;
using Xunit;

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

[Fact]
public void OpeningARepoWithAnEmptyRepositoryOptionsThrows()
{
var options = new RepositoryOptions();
Repository repo;

Assert.Throws<ArgumentException>(() => repo = new Repository(BareTestRepoPath, options));
Assert.Throws<ArgumentException>(() => repo = new Repository(StandardTestRepoPath, options));
}

[Fact]
public void CanSneakAdditionalCommitsIntoAStandardRepoWithoutAlteringTheWorkdirOrTheIndex()
{
Expand Down Expand Up @@ -150,5 +141,38 @@ private string MeanwhileInAnotherDimensionAnEvilMastermindIsAtWork(string workin
return sneakyRepo.Commit("Tadaaaa!", DummySignature, DummySignature).Sha;
}
}

[Fact]
public void CanProvideDifferentConfigurationFilesToARepository()
{
string globalLocation = Path.Combine(newWorkdir, "my-global-config");
string systemLocation = Path.Combine(newWorkdir, "my-system-config");

const string name = "Adam 'aroben' Roben";
const string email = "adam@github.com";

StringBuilder sb = new StringBuilder()
.AppendLine("[user]")
.AppendFormat("name = {0}{1}", name, Environment.NewLine)
.AppendFormat("email = {0}{1}", email, Environment.NewLine);

File.WriteAllText(globalLocation, sb.ToString());

var options = new RepositoryOptions {
GlobalConfigurationLocation = globalLocation,
SystemConfigurationLocation = systemLocation,
};

using (var repo = new Repository(BareTestRepoPath, options))
{
Assert.True(repo.Config.HasGlobalConfig);
Assert.Equal(name, repo.Config.Get<string>("user", "name", null));
Assert.Equal(email, repo.Config.Get<string>("user", "email", null));

repo.Config.Set("help.link", "https://twitter.com/xpaulbettsx/status/205761932626636800", ConfigurationLevel.System);
}

AssertValueInConfigFile(systemLocation, "xpaulbettsx");
}
}
}
9 changes: 9 additions & 0 deletions LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using Xunit;

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

throw new SkipException(message);
}

protected static void AssertValueInConfigFile(string configFilePath, string regex)
{
var text = File.ReadAllText(configFilePath);
var r = new Regex(regex, RegexOptions.Multiline).Match(text);
Assert.True(r.Success, text);
}
}
}
64 changes: 41 additions & 23 deletions LibGit2Sharp/Configuration.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using LibGit2Sharp.Core;
using LibGit2Sharp.Core.Handles;

Expand All @@ -20,21 +21,56 @@ public class Configuration : IDisposable
private ConfigurationSafeHandle globalHandle;
private ConfigurationSafeHandle localHandle;

internal Configuration(Repository repository)
internal Configuration(Repository repository, string globalConfigurationFileLocation, string systemConfigurationFileLocation)
{
this.repository = repository;

globalConfigPath = ConvertPath(NativeMethods.git_config_find_global);
systemConfigPath = ConvertPath(NativeMethods.git_config_find_system);
globalConfigPath = globalConfigurationFileLocation ?? ConvertPath(NativeMethods.git_config_find_global);
systemConfigPath = systemConfigurationFileLocation ?? ConvertPath(NativeMethods.git_config_find_system);

Init();
}

private void Init()
{
if (repository != null)
{
Ensure.Success(NativeMethods.git_config_new(out localHandle));

string repoConfigLocation = Path.Combine(repository.Info.Path, "config");
Ensure.Success(NativeMethods.git_config_add_file_ondisk(localHandle, repoConfigLocation, 3));

if (globalConfigPath != null)
{
Ensure.Success(NativeMethods.git_config_add_file_ondisk(localHandle, globalConfigPath, 2));
}

if (systemConfigPath != null)
{
Ensure.Success(NativeMethods.git_config_add_file_ondisk(localHandle, systemConfigPath, 1));
}

NativeMethods.git_repository_set_config(repository.Handle, localHandle);
}

if (globalConfigPath != null)
{
Ensure.Success(NativeMethods.git_config_open_ondisk(out globalHandle, globalConfigPath));
}

if (systemConfigPath != null)
{
Ensure.Success(NativeMethods.git_config_open_ondisk(out systemHandle, systemConfigPath));
}
}

/// <summary>
/// Access configuration values without a repository. Generally you want to access configuration via an instance of <see cref = "Repository" /> instead.
/// </summary>
public Configuration()
: this(null)
/// <param name="globalConfigurationFileLocation">Path to a Global configuration file. If null, the default path for a global configuration file will be probed.</param>
/// <param name="systemConfigurationFileLocation">Path to a System configuration file. If null, the default path for a system configuration file will be probed.</param>
public Configuration(string globalConfigurationFileLocation = null, string systemConfigurationFileLocation = null)
: this(null, globalConfigurationFileLocation, systemConfigurationFileLocation)
{
}

Expand Down Expand Up @@ -246,24 +282,6 @@ public T Get<T>(string[] keyParts, T defaultValue)
return Get(string.Join(".", keyParts), defaultValue);
}

private void Init()
{
if (repository != null)
{
Ensure.Success(NativeMethods.git_repository_config(out localHandle, repository.Handle));
}

if (globalConfigPath != null)
{
Ensure.Success(NativeMethods.git_config_open_ondisk(out globalHandle, globalConfigPath));
}

if (systemConfigPath != null)
{
Ensure.Success(NativeMethods.git_config_open_ondisk(out systemHandle, systemConfigPath));
}
}

private void Save()
{
Dispose(true);
Expand Down
14 changes: 14 additions & 0 deletions LibGit2Sharp/Core/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,15 @@ public static extern int git_config_get_string(
ConfigurationSafeHandle cfg,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string name);

[DllImport(libgit2)]
public static extern int git_config_add_file_ondisk(
ConfigurationSafeHandle cfg,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(FilePathMarshaler))] FilePath path,
int priority);

[DllImport(libgit2)]
public static extern int git_config_new(out ConfigurationSafeHandle cfg);

[DllImport(libgit2)]
public static extern int git_config_open_global(out ConfigurationSafeHandle cfg);

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

[DllImport(libgit2)]
public static extern void git_repository_set_config(
RepositorySafeHandle repository,
ConfigurationSafeHandle index);

[DllImport(libgit2)]
public static extern void git_repository_set_index(
RepositorySafeHandle repository,
Expand Down
13 changes: 7 additions & 6 deletions LibGit2Sharp/Repository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,14 @@ public Repository(string path, RepositoryOptions options = null)

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

string configurationGlobalFilePath = null;
string configurationSystemFilePath = null;

if (options != null)
{
bool isWorkDirNull = string.IsNullOrEmpty(options.WorkingDirectoryPath);
bool isIndexNull = string.IsNullOrEmpty(options.IndexPath);

if (isWorkDirNull && isIndexNull)
{
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "At least one member of the {0} instance has to be provided.", typeof(RepositoryOptions).Name));
}

if (isBare && (isWorkDirNull ^ isIndexNull))
{
throw new ArgumentException("When overriding the opening of a bare repository, both RepositoryOptions.WorkingDirectoryPath an RepositoryOptions.IndexPath have to be provided.");
Expand All @@ -77,6 +75,9 @@ public Repository(string path, RepositoryOptions options = null)
{
Ensure.Success(NativeMethods.git_repository_set_workdir(handle, options.WorkingDirectoryPath));
}

configurationGlobalFilePath = options.GlobalConfigurationLocation;
configurationSystemFilePath = options.SystemConfigurationLocation;
}

if (!isBare)
Expand All @@ -89,7 +90,7 @@ public Repository(string path, RepositoryOptions options = null)
branches = new BranchCollection(this);
tags = new TagCollection(this);
info = new Lazy<RepositoryInformation>(() => new RepositoryInformation(this, isBare));
config = new Lazy<Configuration>(() => RegisterForCleanup(new Configuration(this)));
config = new Lazy<Configuration>(() => RegisterForCleanup(new Configuration(this, configurationGlobalFilePath, configurationSystemFilePath)));
remotes = new Lazy<RemoteCollection>(() => new RemoteCollection(this));
odb = new Lazy<ObjectDatabase>(() => new ObjectDatabase(this));
diff = new Diff(this);
Expand Down
18 changes: 18 additions & 0 deletions LibGit2Sharp/RepositoryOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,23 @@ public class RepositoryOptions
/// </para>
/// </summary>
public string IndexPath { get; set; }

/// <summary>
/// Overrides the probed location of the Global configuration file of a repository.
/// <para>
/// The path has either to lead to an existing valid configuration file,
/// or to a non existent configuration file which will be eventually created.
/// </para>
/// </summary>
public string GlobalConfigurationLocation { get; set; }

/// <summary>
/// Overrides the probed location of the System configuration file of a repository.
/// <para>
/// The path has to lead to an existing valid configuration file,
/// or to a non existent configuration file which will be eventually created.
/// </para>
/// </summary>
public string SystemConfigurationLocation { get; set; }
}
}