From 005869a26f61a181c637667b9f22c25d75747db6 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 12 Mar 2015 11:04:33 -0400 Subject: [PATCH 1/3] NativeMethods.IsRunningOnLinux -> IsRunningOnUnix --- LibGit2Sharp.Tests/BlobFixture.cs | 2 +- LibGit2Sharp.Tests/ShadowCopyFixture.cs | 2 +- LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs | 4 ++-- LibGit2Sharp/Core/NativeMethods.cs | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/LibGit2Sharp.Tests/BlobFixture.cs b/LibGit2Sharp.Tests/BlobFixture.cs index 223a4d673..29934f08c 100644 --- a/LibGit2Sharp.Tests/BlobFixture.cs +++ b/LibGit2Sharp.Tests/BlobFixture.cs @@ -222,7 +222,7 @@ public void CanTellIfTheBlobContentLooksLikeBinary() private static void SkipIfNotSupported(string autocrlf) { - InconclusiveIf(() => autocrlf == "true" && IsRunningOnLinux(), "Non-Windows does not support core.autocrlf = true"); + InconclusiveIf(() => autocrlf == "true" && IsRunningOnUnix(), "Non-Windows does not support core.autocrlf = true"); } } } diff --git a/LibGit2Sharp.Tests/ShadowCopyFixture.cs b/LibGit2Sharp.Tests/ShadowCopyFixture.cs index 5eaf4dced..a2d2e0629 100644 --- a/LibGit2Sharp.Tests/ShadowCopyFixture.cs +++ b/LibGit2Sharp.Tests/ShadowCopyFixture.cs @@ -62,7 +62,7 @@ public void CanProbeForNativeBinariesFromAShadowCopiedAssembly() string cachedAssembliesPath = Path.Combine(setup.CachePath, setup.ApplicationName); Assert.True(cachedAssemblyLocation.StartsWith(cachedAssembliesPath)); - if (!IsRunningOnLinux()) + if (!IsRunningOnUnix()) { // ...that this cache doesn't contain the `NativeBinaries` folder string cachedAssemblyParentPath = Path.GetDirectoryName(cachedAssemblyLocation); diff --git a/LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs b/LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs index 30c063190..b52adbe55 100644 --- a/LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs +++ b/LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs @@ -91,8 +91,8 @@ private static bool IsFileSystemCaseSensitiveInternal() return !isInsensitive; } - // Should match LibGit2Sharp.Core.NativeMethods.IsRunningOnLinux() - protected static bool IsRunningOnLinux() + // Should match LibGit2Sharp.Core.NativeMethods.IsRunningOnUnix() + protected static bool IsRunningOnUnix() { // see http://mono-project.com/FAQ%3a_Technical#Mono_Platforms var p = (int)Environment.OSVersion.Platform; diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs index a3e8cd095..90cb384ac 100644 --- a/LibGit2Sharp/Core/NativeMethods.cs +++ b/LibGit2Sharp/Core/NativeMethods.cs @@ -64,7 +64,7 @@ internal static void RemoveHandle() static NativeMethods() { - if (!IsRunningOnLinux()) + if (!IsRunningOnUnix()) { string originalAssemblypath = new Uri(Assembly.GetExecutingAssembly().EscapedCodeBase).LocalPath; @@ -94,8 +94,8 @@ public static string ProcessorArchitecture } } - // Should match LibGit2Sharp.Tests.TestHelpers.BaseFixture.IsRunningOnLinux() - private static bool IsRunningOnLinux() + // Should match LibGit2Sharp.Tests.TestHelpers.BaseFixture.IsRunningOnUnix() + private static bool IsRunningOnUnix() { // see http://mono-project.com/FAQ%3a_Technical#Mono_Platforms var p = (int)Environment.OSVersion.Platform; From f83c090b051a30e08c5f7925c1a48a93443706d0 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 12 Mar 2015 11:00:24 -0400 Subject: [PATCH 2/3] Introduce `GlobalSettings.NativeLibraryPath` Allow consumers to set the native library path in case they are running in a strange environment that they have little control over where the actual executing assembly lives (but do have some control over the references) and want to point the library to the native location explicitly. --- LibGit2Sharp.Tests/GlobalSettingsFixture.cs | 9 ++++ LibGit2Sharp/Core/NativeMethods.cs | 31 ++----------- LibGit2Sharp/Core/Platform.cs | 50 +++++++++++++++++++++ LibGit2Sharp/GlobalSettings.cs | 49 ++++++++++++++++++++ LibGit2Sharp/LibGit2Sharp.csproj | 1 + LibGit2Sharp/Version.cs | 2 +- 6 files changed, 113 insertions(+), 29 deletions(-) create mode 100644 LibGit2Sharp/Core/Platform.cs diff --git a/LibGit2Sharp.Tests/GlobalSettingsFixture.cs b/LibGit2Sharp.Tests/GlobalSettingsFixture.cs index 20038cb19..698595042 100644 --- a/LibGit2Sharp.Tests/GlobalSettingsFixture.cs +++ b/LibGit2Sharp.Tests/GlobalSettingsFixture.cs @@ -55,5 +55,14 @@ public void CanRetrieveValidVersionString() Assert.True(matchGroups[i].Success); } } + + [Fact] + public void TryingToResetNativeLibraryPathAfterLoadedThrows() + { + // Do something that loads the native library + Assert.NotNull(GlobalSettings.Version.Features); + + Assert.Throws(() => { GlobalSettings.NativeLibraryPath = "C:/Foo"; }); + } } } diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs index 90cb384ac..9ae799c87 100644 --- a/LibGit2Sharp/Core/NativeMethods.cs +++ b/LibGit2Sharp/Core/NativeMethods.cs @@ -64,44 +64,19 @@ internal static void RemoveHandle() static NativeMethods() { - if (!IsRunningOnUnix()) + if (Platform.OperatingSystem == OperatingSystemType.Windows) { - string originalAssemblypath = new Uri(Assembly.GetExecutingAssembly().EscapedCodeBase).LocalPath; - - string currentArchSubPath = "NativeBinaries/" + ProcessorArchitecture; - - string path = Path.Combine(Path.GetDirectoryName(originalAssemblypath), currentArchSubPath); + string path = Path.Combine(GlobalSettings.NativeLibraryPath, Platform.ProcessorArchitecture); const string pathEnvVariable = "PATH"; Environment.SetEnvironmentVariable(pathEnvVariable, - String.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", path, Path.PathSeparator, Environment.GetEnvironmentVariable(pathEnvVariable))); + String.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", path, Path.PathSeparator, Environment.GetEnvironmentVariable(pathEnvVariable))); } // See LibraryLifetimeObject description. lifetimeObject = new LibraryLifetimeObject(); } - public static string ProcessorArchitecture - { - get - { - if (Environment.Is64BitProcess) - { - return "amd64"; - } - - return "x86"; - } - } - - // Should match LibGit2Sharp.Tests.TestHelpers.BaseFixture.IsRunningOnUnix() - private static bool IsRunningOnUnix() - { - // see http://mono-project.com/FAQ%3a_Technical#Mono_Platforms - var p = (int)Environment.OSVersion.Platform; - return (p == 4) || (p == 6) || (p == 128); - } - [DllImport(libgit2)] internal static extern GitErrorSafeHandle giterr_last(); diff --git a/LibGit2Sharp/Core/Platform.cs b/LibGit2Sharp/Core/Platform.cs new file mode 100644 index 000000000..8297cc4bf --- /dev/null +++ b/LibGit2Sharp/Core/Platform.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace LibGit2Sharp.Core +{ + internal enum OperatingSystemType + { + Windows, + Unix, + MacOSX + } + + internal class Platform + { + public static string ProcessorArchitecture + { + get + { + if (Environment.Is64BitProcess) + { + return "amd64"; + } + + return "x86"; + } + } + + public static OperatingSystemType OperatingSystem + { + get + { + // See http://www.mono-project.com/docs/faq/technical/#how-to-detect-the-execution-platform + var platformId = (int)Environment.OSVersion.Platform; + + switch ((int)Environment.OSVersion.Platform) + { + case 4: + case 128: + return OperatingSystemType.Unix; + case 6: + return OperatingSystemType.MacOSX; + default: + return OperatingSystemType.Windows; + } + } + } + } +} diff --git a/LibGit2Sharp/GlobalSettings.cs b/LibGit2Sharp/GlobalSettings.cs index b6ea82454..4a8e1dd5c 100644 --- a/LibGit2Sharp/GlobalSettings.cs +++ b/LibGit2Sharp/GlobalSettings.cs @@ -1,4 +1,6 @@ using System; +using System.IO; +using System.Reflection; using LibGit2Sharp.Core; namespace LibGit2Sharp @@ -12,6 +14,17 @@ public static class GlobalSettings private static LogConfiguration logConfiguration = LogConfiguration.None; + private static string nativeLibraryPath; + + static GlobalSettings() + { + if (Platform.OperatingSystem == OperatingSystemType.Windows) + { + string managedPath = new Uri(Assembly.GetExecutingAssembly().EscapedCodeBase).LocalPath; + nativeLibraryPath = Path.Combine(Path.GetDirectoryName(managedPath), "NativeBinaries"); + } + } + /// /// Returns information related to the current LibGit2Sharp /// library. @@ -108,5 +121,41 @@ public static LogConfiguration LogConfiguration return logConfiguration; } } + + /// + /// Sets a hint path for searching for native binaries: when + /// specified, native binaries will first be searched in a + /// subdirectory of the given path corresponding to the architecture + /// (eg, "x86" or "amd64") before falling back to the default + /// path ("NativeBinaries\x86" or "NativeBinaries\amd64" next + /// to the application). + /// + /// This must be set before any other calls to the library, + /// and is not available on Unix platforms: see your dynamic + /// library loader's documentation for details. + /// + /// + public static string NativeLibraryPath + { + get + { + if (Platform.OperatingSystem != OperatingSystemType.Windows) + { + throw new LibGit2SharpException("Querying the native hint path is only supported on Windows platforms"); + } + + return nativeLibraryPath; + } + + set + { + if (Platform.OperatingSystem != OperatingSystemType.Windows) + { + throw new LibGit2SharpException("Setting the native hint path is only supported on Windows platforms"); + } + + nativeLibraryPath = value; + } + } } } diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj index a2e6e616d..3ba75e7a1 100644 --- a/LibGit2Sharp/LibGit2Sharp.csproj +++ b/LibGit2Sharp/LibGit2Sharp.csproj @@ -68,6 +68,7 @@ + diff --git a/LibGit2Sharp/Version.cs b/LibGit2Sharp/Version.cs index 8715ee9a6..34dd433df 100644 --- a/LibGit2Sharp/Version.cs +++ b/LibGit2Sharp/Version.cs @@ -98,7 +98,7 @@ private string RetrieveVersion() InformationalVersion, LibGit2SharpCommitSha, LibGit2CommitSha, - NativeMethods.ProcessorArchitecture, + Platform.ProcessorArchitecture, features); } From e56c0972df69d7fbb3443b985b513340f8821110 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 12 Mar 2015 16:24:39 -0400 Subject: [PATCH 3/3] GlobalSettings.NativeLibraryPath: throw once used --- LibGit2Sharp/Core/NativeMethods.cs | 4 +++- LibGit2Sharp/GlobalSettings.cs | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs index 9ae799c87..b633daceb 100644 --- a/LibGit2Sharp/Core/NativeMethods.cs +++ b/LibGit2Sharp/Core/NativeMethods.cs @@ -66,7 +66,9 @@ static NativeMethods() { if (Platform.OperatingSystem == OperatingSystemType.Windows) { - string path = Path.Combine(GlobalSettings.NativeLibraryPath, Platform.ProcessorArchitecture); + string nativeLibraryPath = GlobalSettings.GetAndLockNativeLibraryPath(); + + string path = Path.Combine(nativeLibraryPath, Platform.ProcessorArchitecture); const string pathEnvVariable = "PATH"; Environment.SetEnvironmentVariable(pathEnvVariable, diff --git a/LibGit2Sharp/GlobalSettings.cs b/LibGit2Sharp/GlobalSettings.cs index 4a8e1dd5c..0aebfc51d 100644 --- a/LibGit2Sharp/GlobalSettings.cs +++ b/LibGit2Sharp/GlobalSettings.cs @@ -15,6 +15,7 @@ public static class GlobalSettings private static LogConfiguration logConfiguration = LogConfiguration.None; private static string nativeLibraryPath; + private static bool nativeLibraryPathLocked; static GlobalSettings() { @@ -154,8 +155,19 @@ public static string NativeLibraryPath throw new LibGit2SharpException("Setting the native hint path is only supported on Windows platforms"); } + if (nativeLibraryPathLocked) + { + throw new LibGit2SharpException("You cannot set the native library path after it has been loaded"); + } + nativeLibraryPath = value; } } + + internal static string GetAndLockNativeLibraryPath() + { + nativeLibraryPathLocked = true; + return nativeLibraryPath; + } } }