using System; using System.Collections.Generic; using System.IO; using System.Reflection; using LibGit2Sharp.Core; namespace LibGit2Sharp { /// /// Global settings for libgit2 and LibGit2Sharp. /// public static class GlobalSettings { private static readonly Lazy version = new Lazy(Version.Build); private static readonly Dictionary registeredFilters; 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"); } registeredFilters = new Dictionary(); } /// /// Returns information related to the current LibGit2Sharp /// library. /// public static Version Version { get { return version.Value; } } /// /// Registers a new as a custom /// smart-protocol transport with libgit2. Any Git remote with /// the scheme registered will delegate to the given transport /// for all communication with the server. use this transport to communicate /// with the server This is not commonly /// used: some callers may want to re-use an existing connection to /// perform fetch / push operations to a remote. /// /// Note that this configuration is global to an entire process /// and does not honor application domains. /// /// The type of SmartSubtransport to register /// The scheme (eg "http" or "gopher") to register public static SmartSubtransportRegistration RegisterSmartSubtransport(string scheme) where T : SmartSubtransport, new() { Ensure.ArgumentNotNull(scheme, "scheme"); var registration = new SmartSubtransportRegistration(scheme); try { Proxy.git_transport_register(registration.Scheme, registration.FunctionPointer, registration.RegistrationPointer); } catch (Exception) { registration.Free(); throw; } return registration; } /// /// Unregisters a previously registered /// as a custom smart-protocol transport with libgit2. /// /// The type of SmartSubtransport to register /// The previous registration public static void UnregisterSmartSubtransport(SmartSubtransportRegistration registration) where T : SmartSubtransport, new() { Ensure.ArgumentNotNull(registration, "registration"); Proxy.git_transport_unregister(registration.Scheme); registration.Free(); } /// /// Registers a new to receive /// information logging information from libgit2 and LibGit2Sharp. /// /// Note that this configuration is global to an entire process /// and does not honor application domains. /// public static LogConfiguration LogConfiguration { set { Ensure.ArgumentNotNull(value, "value"); logConfiguration = value; if (logConfiguration.Level == LogLevel.None) { Proxy.git_trace_set(0, null); } else { Proxy.git_trace_set(value.Level, value.GitTraceCallback); Log.Write(LogLevel.Info, "Logging enabled at level {0}", value.Level); } } get { 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; } /// /// Takes a snapshot of the currently registered filters. /// /// An array of . public static IEnumerable GetRegisteredFilters() { lock (registeredFilters) { FilterRegistration[] array = new FilterRegistration[registeredFilters.Count]; registeredFilters.Values.CopyTo(array, 0); return array; } } /// /// Register a filter globally with a default priority of 200 allowing the custom filter /// to imitate a core Git filter driver. It will be run last on checkout and first on checkin. /// public static FilterRegistration RegisterFilter(Filter filter) { return RegisterFilter(filter, 200); } /// /// Registers a to be invoked when matches .gitattributes 'filter=name' /// /// The filter to be invoked at run time. /// The priroty of the filter to invoked. /// A value of 0 () will be run first on checkout and last on checkin. /// A value of 200 () will be run last on checkout and first on checkin. /// /// A object used to manage the lifetime of the registration. public static FilterRegistration RegisterFilter(Filter filter, int priority) { Ensure.ArgumentNotNull(filter, "filter"); if (priority < FilterRegistration.FilterPriorityMin || priority > FilterRegistration.FilterPriorityMax) { throw new ArgumentOutOfRangeException("priority", priority, String.Format(System.Globalization.CultureInfo.InvariantCulture, "Filter priorities must be within the inclusive range of [{0}, {1}].", FilterRegistration.FilterPriorityMin, FilterRegistration.FilterPriorityMax)); } FilterRegistration registration = null; lock (registeredFilters) { // if the filter has already been registered if (registeredFilters.ContainsKey(filter)) { throw new EntryExistsException("The filter has already been registered.", GitErrorCode.Exists, GitErrorCategory.Filter); } // allocate the registration object registration = new FilterRegistration(filter, priority); // add the filter and registration object to the global tracking list registeredFilters.Add(filter, registration); } return registration; } /// /// Unregisters the associated filter. /// /// Registration object with an associated filter. public static void DeregisterFilter(FilterRegistration registration) { Ensure.ArgumentNotNull(registration, "registration"); lock (registeredFilters) { var filter = registration.Filter; // do nothing if the filter isn't registered if (registeredFilters.ContainsKey(filter)) { // remove the register from the global tracking list registeredFilters.Remove(filter); // clean up native allocations registration.Free(); } } } internal static void DeregisterFilter(Filter filter) { System.Diagnostics.Debug.Assert(filter != null); // do nothing if the filter isn't registered if (registeredFilters.ContainsKey(filter)) { var registration = registeredFilters[filter]; // unregister the filter DeregisterFilter(registration); } } /// /// Get the paths under which libgit2 searches for the configuration file of a given level. /// /// The level (global/system/XDG) of the config. /// The paths that are searched public static IEnumerable GetConfigSearchPaths(ConfigurationLevel level) { return Proxy.git_libgit2_opts_get_search_path(level).Split(Path.PathSeparator); } /// /// Set the paths under which libgit2 searches for the configuration file of a given level. /// /// . /// /// The level (global/system/XDG) of the config. /// /// The new search paths to set. /// Pass null to reset to the default. /// The special string "$PATH" will be substituted with the current search path. /// public static void SetConfigSearchPaths(ConfigurationLevel level, params string[] paths) { var pathString = (paths == null) ? null : string.Join(Path.PathSeparator.ToString(), paths); Proxy.git_libgit2_opts_set_search_path(level, pathString); } } }