From 7e7c1f5947bd0ac9d75cc71c15b6b285f9e439ab Mon Sep 17 00:00:00 2001 From: nulltoken Date: Sat, 30 May 2015 16:58:10 +0200 Subject: [PATCH 1/3] Drop dead code --- LibGit2Sharp.Tests/ConfigurationFixture.cs | 29 ---------------------- 1 file changed, 29 deletions(-) diff --git a/LibGit2Sharp.Tests/ConfigurationFixture.cs b/LibGit2Sharp.Tests/ConfigurationFixture.cs index 78cb71c0b..419a85dc1 100644 --- a/LibGit2Sharp.Tests/ConfigurationFixture.cs +++ b/LibGit2Sharp.Tests/ConfigurationFixture.cs @@ -14,35 +14,6 @@ private static void AssertValueInLocalConfigFile(string repoPath, string regex) AssertValueInConfigFile(configFilePath, regex); } - private static string RetrieveGlobalConfigLocation() - { - string[] variables = { "HOME", "USERPROFILE", }; - - foreach (string variable in variables) - { - string potentialLocation = Environment.GetEnvironmentVariable(variable); - if (string.IsNullOrEmpty(potentialLocation)) - { - continue; - } - - string potentialPath = Path.Combine(potentialLocation, ".gitconfig"); - - if (File.Exists(potentialPath)) - { - return potentialPath; - } - } - - throw new InvalidOperationException("Unable to determine the location of '.gitconfig' file."); - } - - private static void AssertValueInGlobalConfigFile(string regex) - { - string configFilePath = RetrieveGlobalConfigLocation(); - AssertValueInConfigFile(configFilePath, regex); - } - [Fact] public void CanUnsetAnEntryFromTheLocalConfiguration() { From 5d9f53d1a4ee303fe0082b946d256ae5f3fb9c27 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Sat, 30 May 2015 16:58:30 +0200 Subject: [PATCH 2/3] Introduce Configuration.BuildFrom() --- LibGit2Sharp.Tests/ConfigurationFixture.cs | 23 ++++- LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs | 8 +- LibGit2Sharp/Configuration.cs | 96 ++++++++++++++++--- LibGit2Sharp/Repository.cs | 2 +- 4 files changed, 111 insertions(+), 18 deletions(-) diff --git a/LibGit2Sharp.Tests/ConfigurationFixture.cs b/LibGit2Sharp.Tests/ConfigurationFixture.cs index 419a85dc1..fe88fc354 100644 --- a/LibGit2Sharp.Tests/ConfigurationFixture.cs +++ b/LibGit2Sharp.Tests/ConfigurationFixture.cs @@ -227,7 +227,7 @@ public void CanSetBooleanValue() [Fact] public void SettingLocalConfigurationOutsideAReposThrows() { - using (var config = new Configuration(null, null, null)) + using (var config = Configuration.BuildFrom(null, null, null, null)) { Assert.Throws(() => config.Set("unittests.intsetting", 3)); } @@ -366,5 +366,26 @@ public void CanTellIfASpecificStoreContainsAKey() Assert.Null(repo.Config.Get("MCHammer.You-cant-touch-this", ConfigurationLevel.System)); } } + + [Fact] + public void CanAccessConfigurationWithoutARepository() + { + var path = SandboxStandardTestRepoGitDir(); + + string globalConfigPath = CreateConfigurationWithDummyUser(Constants.Signature); + var options = new RepositoryOptions { GlobalConfigurationLocation = globalConfigPath }; + + using (var repo = new Repository(path, options)) + { + repo.Config.Set("my.key", "local"); + repo.Config.Set("my.key", "mouse", ConfigurationLevel.Global); + } + + using (var config = Configuration.BuildFrom(Path.Combine(path, ".git", "config"), globalConfigPath)) + { + Assert.Equal("local", config.Get("my.key").Value); + Assert.Equal("mouse", config.Get("my.key", ConfigurationLevel.Global).Value); + } + } } } diff --git a/LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs b/LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs index 017404760..ed3b1a092 100644 --- a/LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs +++ b/LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs @@ -337,18 +337,18 @@ protected string CreateConfigurationWithDummyUser(string name, string email) { SelfCleaningDirectory scd = BuildSelfCleaningDirectory(); Directory.CreateDirectory(scd.DirectoryPath); - string configFilePath = Path.Combine(scd.DirectoryPath, "global-config"); + string configFilePath = Path.Combine(scd.DirectoryPath, "fake-config"); - using (Configuration config = new Configuration(configFilePath)) + using (Configuration config = Configuration.BuildFrom(configFilePath)) { if (name != null) { - config.Set("user.name", name, ConfigurationLevel.Global); + config.Set("user.name", name); } if (email != null) { - config.Set("user.email", email, ConfigurationLevel.Global); + config.Set("user.email", email); } } diff --git a/LibGit2Sharp/Configuration.cs b/LibGit2Sharp/Configuration.cs index 47b14fb32..7e2c22245 100644 --- a/LibGit2Sharp/Configuration.cs +++ b/LibGit2Sharp/Configuration.cs @@ -15,12 +15,11 @@ namespace LibGit2Sharp public class Configuration : IDisposable, IEnumerable> { + private readonly FilePath repoConfigPath; private readonly FilePath globalConfigPath; private readonly FilePath xdgConfigPath; private readonly FilePath systemConfigPath; - private readonly Repository repository; - private ConfigurationSafeHandle configHandle; /// @@ -29,19 +28,18 @@ public class Configuration : IDisposable, protected Configuration() { } - internal Configuration(Repository repository, string globalConfigurationFileLocation, + internal Configuration(Repository repository, string repositoryConfigurationFileLocation, string globalConfigurationFileLocation, string xdgConfigurationFileLocation, string systemConfigurationFileLocation) { - this.repository = repository; - + repoConfigPath = repositoryConfigurationFileLocation; globalConfigPath = globalConfigurationFileLocation ?? Proxy.git_config_find_global(); xdgConfigPath = xdgConfigurationFileLocation ?? Proxy.git_config_find_xdg(); systemConfigPath = systemConfigurationFileLocation ?? Proxy.git_config_find_system(); - Init(); + Init(repository); } - private void Init() + private void Init(Repository repository) { configHandle = Proxy.git_config_new(); @@ -56,6 +54,10 @@ private void Init() Proxy.git_repository_set_config(repository.Handle, configHandle); } + else if (repoConfigPath != null) + { + Proxy.git_config_add_file_ondisk(configHandle, repoConfigPath, ConfigurationLevel.Local); + } if (globalConfigPath != null) { @@ -73,12 +75,81 @@ private void Init() } } + /// + /// Access configuration values without a repository. + /// + /// Generally you want to access configuration via an instance of instead. + /// + /// + /// Path to a Repository configuration file. + /// An instance of . + public static Configuration BuildFrom( + string repositoryConfigurationFileLocation) + { + return BuildFrom(repositoryConfigurationFileLocation, null, null, null); + } + + /// + /// Access configuration values without a repository. + /// + /// Generally you want to access configuration via an instance of instead. + /// + /// + /// Path to a Repository configuration file. + /// Path to a Global configuration file. If null, the default path for a Global configuration file will be probed. + /// An instance of . + public static Configuration BuildFrom( + string repositoryConfigurationFileLocation, + string globalConfigurationFileLocation) + { + return BuildFrom(repositoryConfigurationFileLocation, globalConfigurationFileLocation, null, null); + } + + /// + /// Access configuration values without a repository. + /// + /// Generally you want to access configuration via an instance of instead. + /// + /// + /// Path to a Repository configuration file. + /// Path to a Global configuration file. If null, the default path for a Global configuration file will be probed. + /// Path to a XDG configuration file. If null, the default path for a XDG configuration file will be probed. + /// An instance of . + public static Configuration BuildFrom( + string repositoryConfigurationFileLocation, + string globalConfigurationFileLocation, + string xdgConfigurationFileLocation) + { + return BuildFrom(repositoryConfigurationFileLocation, globalConfigurationFileLocation, xdgConfigurationFileLocation, null); + } + + /// + /// Access configuration values without a repository. + /// + /// Generally you want to access configuration via an instance of instead. + /// + /// + /// Path to a Repository configuration file. + /// Path to a Global configuration file. If null, the default path for a Global configuration file will be probed. + /// Path to a XDG configuration file. If null, the default path for a XDG configuration file will be probed. + /// Path to a System configuration file. If null, the default path for a System configuration file will be probed. + /// An instance of . + public static Configuration BuildFrom( + string repositoryConfigurationFileLocation, + string globalConfigurationFileLocation, + string xdgConfigurationFileLocation, + string systemConfigurationFileLocation) + { + return new Configuration(null, repositoryConfigurationFileLocation, globalConfigurationFileLocation, xdgConfigurationFileLocation, systemConfigurationFileLocation); + } + /// /// Access configuration values without a repository. Generally you want to access configuration via an instance of instead. /// /// Path to a Global configuration file. If null, the default path for a global configuration file will be probed. + [Obsolete("This method will be removed in the next release. Please use Configuration.BuildFrom(string, string) instead.")] public Configuration(string globalConfigurationFileLocation) - : this(null, globalConfigurationFileLocation, null, null) + : this(null, null, globalConfigurationFileLocation, null, null) { } /// @@ -86,8 +157,9 @@ public Configuration(string globalConfigurationFileLocation) /// /// Path to a Global configuration file. If null, the default path for a global configuration file will be probed. /// Path to a XDG configuration file. If null, the default path for a XDG configuration file will be probed. + [Obsolete("This method will be removed in the next release. Please use Configuration.BuildFrom(string, string, string) instead.")] public Configuration(string globalConfigurationFileLocation, string xdgConfigurationFileLocation) - : this(null, globalConfigurationFileLocation, xdgConfigurationFileLocation, null) + : this(null, null, globalConfigurationFileLocation, xdgConfigurationFileLocation, null) { } /// @@ -96,10 +168,10 @@ public Configuration(string globalConfigurationFileLocation, string xdgConfigura /// Path to a Global configuration file. If null, the default path for a global configuration file will be probed. /// Path to a XDG configuration file. If null, the default path for a XDG configuration file will be probed. /// Path to a System configuration file. If null, the default path for a system configuration file will be probed. + [Obsolete("This method will be removed in the next release. Please use Configuration.BuildFrom(string, string, string, string) instead.")] public Configuration(string globalConfigurationFileLocation, string xdgConfigurationFileLocation, string systemConfigurationFileLocation) - : this(null, globalConfigurationFileLocation, xdgConfigurationFileLocation, systemConfigurationFileLocation) - { - } + : this(null, null, globalConfigurationFileLocation, xdgConfigurationFileLocation, systemConfigurationFileLocation) + { } /// /// Determines which configuration file has been found. diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs index 79c9077bc..511204087 100644 --- a/LibGit2Sharp/Repository.cs +++ b/LibGit2Sharp/Repository.cs @@ -125,7 +125,7 @@ public Repository(string path, RepositoryOptions options) config = new Lazy( () => - RegisterForCleanup(new Configuration(this, configurationGlobalFilePath, configurationXDGFilePath, + RegisterForCleanup(new Configuration(this, null, configurationGlobalFilePath, configurationXDGFilePath, configurationSystemFilePath))); odb = new Lazy(() => new ObjectDatabase(this)); diff = new Diff(this); From ca4d15ee5e5588fa1c82b3c9398a5c26a828660a Mon Sep 17 00:00:00 2001 From: nulltoken Date: Sun, 31 May 2015 16:39:10 +0200 Subject: [PATCH 3/3] Make Configuration.BuildFrom() able to probe for the local configuration file --- LibGit2Sharp.Tests/ConfigurationFixture.cs | 28 ++++++++- LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs | 4 +- LibGit2Sharp/Configuration.cs | 59 +++++++++++++++++-- 3 files changed, 81 insertions(+), 10 deletions(-) diff --git a/LibGit2Sharp.Tests/ConfigurationFixture.cs b/LibGit2Sharp.Tests/ConfigurationFixture.cs index fe88fc354..50b6fdc7a 100644 --- a/LibGit2Sharp.Tests/ConfigurationFixture.cs +++ b/LibGit2Sharp.Tests/ConfigurationFixture.cs @@ -1,8 +1,10 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; using LibGit2Sharp.Tests.TestHelpers; using Xunit; +using Xunit.Extensions; namespace LibGit2Sharp.Tests { @@ -367,8 +369,21 @@ public void CanTellIfASpecificStoreContainsAKey() } } - [Fact] - public void CanAccessConfigurationWithoutARepository() + public static IEnumerable ConfigAccessors + { + get + { + return new List + { + new[] { new Func(p => Path.Combine(p, ".git", "config")) }, + new[] { new Func(p => Path.Combine(p, ".git")) }, + new[] { new Func(p => p) }, + }; + } + } + + [Theory, PropertyData("ConfigAccessors")] + public void CanAccessConfigurationWithoutARepository(Func localConfigurationPathProvider) { var path = SandboxStandardTestRepoGitDir(); @@ -381,11 +396,18 @@ public void CanAccessConfigurationWithoutARepository() repo.Config.Set("my.key", "mouse", ConfigurationLevel.Global); } - using (var config = Configuration.BuildFrom(Path.Combine(path, ".git", "config"), globalConfigPath)) + using (var config = Configuration.BuildFrom(localConfigurationPathProvider(path), globalConfigPath)) { Assert.Equal("local", config.Get("my.key").Value); Assert.Equal("mouse", config.Get("my.key", ConfigurationLevel.Global).Value); } } + + [Fact] + public void PassingANonExistingLocalConfigurationFileToBuildFromthrowss() + { + Assert.Throws(() => Configuration.BuildFrom( + Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()))); + } } } diff --git a/LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs b/LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs index ed3b1a092..08d7daf0d 100644 --- a/LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs +++ b/LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs @@ -336,8 +336,8 @@ protected string CreateConfigurationWithDummyUser(Signature signature) protected string CreateConfigurationWithDummyUser(string name, string email) { SelfCleaningDirectory scd = BuildSelfCleaningDirectory(); - Directory.CreateDirectory(scd.DirectoryPath); - string configFilePath = Path.Combine(scd.DirectoryPath, "fake-config"); + + string configFilePath = Touch(scd.DirectoryPath, "fake-config"); using (Configuration config = Configuration.BuildFrom(configFilePath)) { diff --git a/LibGit2Sharp/Configuration.cs b/LibGit2Sharp/Configuration.cs index 7e2c22245..b9924c952 100644 --- a/LibGit2Sharp/Configuration.cs +++ b/LibGit2Sharp/Configuration.cs @@ -31,7 +31,11 @@ protected Configuration() internal Configuration(Repository repository, string repositoryConfigurationFileLocation, string globalConfigurationFileLocation, string xdgConfigurationFileLocation, string systemConfigurationFileLocation) { - repoConfigPath = repositoryConfigurationFileLocation; + if (repositoryConfigurationFileLocation != null) + { + repoConfigPath = NormalizeConfigPath(repositoryConfigurationFileLocation); + } + globalConfigPath = globalConfigurationFileLocation ?? Proxy.git_config_find_global(); xdgConfigPath = xdgConfigurationFileLocation ?? Proxy.git_config_find_xdg(); systemConfigPath = systemConfigurationFileLocation ?? Proxy.git_config_find_system(); @@ -75,13 +79,46 @@ private void Init(Repository repository) } } + private FilePath NormalizeConfigPath(FilePath path) + { + if (File.Exists(path.Native)) + { + return path; + } + + if (!Directory.Exists(path.Native)) + { + throw new FileNotFoundException("Cannot find repository configuration file", path.Native); + } + + var configPath = Path.Combine(path.Native, "config"); + + if (File.Exists(configPath)) + { + return configPath; + } + + var gitConfigPath = Path.Combine(path.Native, ".git", "config"); + + if (File.Exists(gitConfigPath)) + { + return gitConfigPath; + } + + throw new FileNotFoundException("Cannot find repository configuration file", path.Native); + } + /// /// Access configuration values without a repository. /// /// Generally you want to access configuration via an instance of instead. /// + /// + /// can either contains a path to a file or a directory. In the latter case, + /// this can be the working directory, the .git directory or the directory containing a bare repository. + /// /// - /// Path to a Repository configuration file. + /// Path to an existing Repository configuration file. /// An instance of . public static Configuration BuildFrom( string repositoryConfigurationFileLocation) @@ -94,8 +131,12 @@ public static Configuration BuildFrom( /// /// Generally you want to access configuration via an instance of instead. /// + /// + /// can either contains a path to a file or a directory. In the latter case, + /// this can be the working directory, the .git directory or the directory containing a bare repository. + /// /// - /// Path to a Repository configuration file. + /// Path to an existing Repository configuration file. /// Path to a Global configuration file. If null, the default path for a Global configuration file will be probed. /// An instance of . public static Configuration BuildFrom( @@ -110,8 +151,12 @@ public static Configuration BuildFrom( /// /// Generally you want to access configuration via an instance of instead. /// + /// + /// can either contains a path to a file or a directory. In the latter case, + /// this can be the working directory, the .git directory or the directory containing a bare repository. + /// /// - /// Path to a Repository configuration file. + /// Path to an existing Repository configuration file. /// Path to a Global configuration file. If null, the default path for a Global configuration file will be probed. /// Path to a XDG configuration file. If null, the default path for a XDG configuration file will be probed. /// An instance of . @@ -128,8 +173,12 @@ public static Configuration BuildFrom( /// /// Generally you want to access configuration via an instance of instead. /// + /// + /// can either contains a path to a file or a directory. In the latter case, + /// this can be the working directory, the .git directory or the directory containing a bare repository. + /// /// - /// Path to a Repository configuration file. + /// Path to an existing Repository configuration file. /// Path to a Global configuration file. If null, the default path for a Global configuration file will be probed. /// Path to a XDG configuration file. If null, the default path for a XDG configuration file will be probed. /// Path to a System configuration file. If null, the default path for a System configuration file will be probed.