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/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.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..b633daceb 100644 --- a/LibGit2Sharp/Core/NativeMethods.cs +++ b/LibGit2Sharp/Core/NativeMethods.cs @@ -64,44 +64,21 @@ internal static void RemoveHandle() static NativeMethods() { - if (!IsRunningOnLinux()) + if (Platform.OperatingSystem == OperatingSystemType.Windows) { - string originalAssemblypath = new Uri(Assembly.GetExecutingAssembly().EscapedCodeBase).LocalPath; + string nativeLibraryPath = GlobalSettings.GetAndLockNativeLibraryPath(); - string currentArchSubPath = "NativeBinaries/" + ProcessorArchitecture; - - string path = Path.Combine(Path.GetDirectoryName(originalAssemblypath), currentArchSubPath); + string path = Path.Combine(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.IsRunningOnLinux() - private static bool IsRunningOnLinux() - { - // 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..0aebfc51d 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,18 @@ public static class GlobalSettings private static LogConfiguration logConfiguration = LogConfiguration.None; + private static string nativeLibraryPath; + private static bool nativeLibraryPathLocked; + + 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 +122,52 @@ 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"); + } + + 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; + } } } 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); }