using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using DelftTools.Shell.Core; using DelftTools.Utils; using DelftTools.Utils.Collections; using DelftTools.Utils.IO; using DelftTools.Utils.Reflection; using DeltaShell.Core.Properties; using Mono.Addins; namespace DeltaShell.Core { /// /// This class wraps the MonoAddins AddinManager for the sole purpose of providing similar functionality under test. Bleh. /// public static class PluginManager { private static readonly List AllPlugins = new List(); private static bool testMode; public static void RegisterAdditionalPlugins(IEnumerable plugins) { AllPlugins.AddRange(plugins); } public static void Initialize(string pluginsDirectory) { if (pluginsDirectory != null) { pluginsDirectory = Path.GetFullPath(pluginsDirectory); // load all assemblies since they can be located in different directory var pluginDirectories = FileUtils.GetDirectoriesRelative(pluginsDirectory); foreach (var pluginDirectory in pluginDirectories) { var path = Path.Combine(pluginsDirectory, pluginDirectory); AssemblyUtils.LoadAllAssembliesFromDirectory(path).ToList(); } var registryPath = SettingsHelper.GetApplicationLocalUserSettingsDirectory(); // Initialize using the provided (DeltaShellApplication) assembly (OpenMi is started as dll and so the EntryAssembly and the CallingAssembly are incorrect). var assembly = typeof(DeltaShellApplication).Assembly; var methodInitialize = AddinManager.AddinEngine.GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).First(m => m.Name == "Initialize"); // initialize AddinEngine (without console messages -> internally the Initialize call will run Registry.Update with a verbose console logger (only when there is no cache)) WithoutConsoleMessage(() => methodInitialize.Invoke(AddinManager.AddinEngine, new object[] { assembly, registryPath, pluginsDirectory, null })); // Force local scanning (disable isolation) AddinManager.Registry.RegisterExtension(new ForceLocalAddinFileSystemExtension()); AddinManager.Registry.Update(new MonoAddinsConsoleLogger(2) { LogAssemblyScanErrors = false }); // Reset addin roots AddinManager.Registry.ResetConfiguration(); // Activate mono addin roots AddinManager.Registry.GetAddinRoots() .Where(m => !AddinManager.IsAddinLoaded(m.Id)) .ForEach(m => AddinManager.LoadAddin(new ConsoleProgressStatus(0), m.Id)); testMode = false; } else { testMode = true; } } public static IEnumerable GetPlugins() where T : IPlugin { var plugins = (testMode ? AllPlugins.OfType() : AddinManager.GetExtensionObjects().OfType()) .OrderBy(p => p.GetType().FullName) //order by name (arbitrary) for deterministic loading order .ToList(); ThrowOnNonUniquePluginNames(plugins); return plugins; } public static void Reset() { AllPlugins.Clear(); } [Conditional("DEBUG")] private static void ThrowOnNonUniquePluginNames(IList plugins) where T : IPlugin { var names = plugins.Select(p => p.Name).ToList(); var distinctNames = names.Distinct().ToList(); if (names.Count == distinctNames.Count) { return; //no problems } distinctNames.ForEach(name => names.Remove(name)); var nonUniquePlugins = plugins.Where(p => names.Contains(p.Name)); throw new InvalidOperationException( string.Format(Resources.PluginManager_ThrowOnNonUniquePluginNames_Multiple_plugins_with_the_same_name_s___0__1_, Environment.NewLine, string.Join(Environment.NewLine, nonUniquePlugins.Select(p => p.GetType().Name).ToArray()))); } private static void WithoutConsoleMessage(Action action) { Console.SetOut(new StringWriter()); try { action(); } finally { Console.SetOut(new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = true }); } } } }