public RepositoryAnalysisManager(
     IRepositoryManager repositoryManager,
     IRepositorySourceManager repositorySourceManager,
     IEnumerable <IDependencyScraperManager> dependencyScraperManagers,
     IEnumerable <IDeriveRepositoryTypeAndImplementations> typeAndImplementationDerivers,
     IDeriveRepositoryDevOpsIntegrations devOpsIntegrationsDeriver,
     IDistributedCache distributedCache,
     ILogger <RepositoryAnalysisManager> logger,
     Caching cachingSettings)
 {
     this.repositoryManager             = repositoryManager;
     this.repositorySourceManager       = repositorySourceManager;
     this.dependencyScraperManagers     = dependencyScraperManagers;
     this.typeAndImplementationDerivers = typeAndImplementationDerivers;
     this.devOpsIntegrationsDeriver     = devOpsIntegrationsDeriver;
     this.distributedCache = distributedCache;
     this.logger           = logger;
     this.cachingSettings  = cachingSettings;
 }
        public static void RegisterExtensions(IServiceCollection services, IConfiguration configuration)
        {
            var typeAndImplementationDerivers = new List <IDeriveRepositoryTypeAndImplementations>();
            IDeriveRepositoryDevOpsIntegrations devOpsIntegrationDeriver = null;

            var internalExtensionAssembly = typeof(ExtensionAssembly).GetTypeInfo().Assembly;

            // Load internal extensions
            var extensionAssemblyConfiguration = new ContainerConfiguration().WithAssembly(internalExtensionAssembly);

            using (var extensionAssemblyContainer = extensionAssemblyConfiguration.CreateContainer())
            {
                var internalTypeAndImplementationDerivers = extensionAssemblyContainer.GetExports <IDeriveRepositoryTypeAndImplementations>();

                foreach (var typeAndImplementationDeriver in internalTypeAndImplementationDerivers)
                {
                    Log.Logger.Information($"Loading internal IDeriveRepositoryTypeAndImplementations {typeAndImplementationDeriver.GetType().Name}");
                }

                typeAndImplementationDerivers.AddRange(internalTypeAndImplementationDerivers);
            }

            // Load external extensions
            List <Assembly> externalPluginDirectoryAssemblies = null;

            try
            {
                // For some reason when the MEF container is created it needs help resolving dependency references
                AssemblyLoadContext.Default.Resolving += ResolveAssemblyDependency;

                var externalPluginDirectory = Path.Combine(Directory.GetCurrentDirectory(), "Plugins");

                Log.Logger.Information($"Scanning directory {externalPluginDirectory} for external plugins");

                // Load any external extensions in the defined plugin directory
                externalPluginDirectoryAssemblies = LoadAssembliesFromDirectory(externalPluginDirectory);

                if (!externalPluginDirectoryAssemblies.Any())
                {
                    Log.Logger.Information($"No external plugins found");
                }
                else
                {
                    var externalAssemblyConfiguration = new ContainerConfiguration().WithAssemblies(externalPluginDirectoryAssemblies);

                    using (var externalAssemblyContainer = externalAssemblyConfiguration.CreateContainer())
                    {
                        var loadedExternalTypeAndImplementationDerivers = externalAssemblyContainer.GetExports <IDeriveRepositoryTypeAndImplementations>();

                        foreach (var externalTypeAndImplementationDeriver in loadedExternalTypeAndImplementationDerivers)
                        {
                            Log.Logger.Information($"Loading external IDeriveRepositoryTypeAndImplementations {externalTypeAndImplementationDeriver.GetType().Name}");
                        }

                        typeAndImplementationDerivers.AddRange(loadedExternalTypeAndImplementationDerivers);

                        if (externalAssemblyContainer.TryGetExport <IDeriveRepositoryDevOpsIntegrations>(out var loadedExternalDevOpsImplementationDerivers))
                        {
                            Log.Logger.Information($"Loading external IDeriveRepositoryDevOpsIntegrations {loadedExternalDevOpsImplementationDerivers.GetType().Name}");

                            devOpsIntegrationDeriver = loadedExternalDevOpsImplementationDerivers;
                        }
                    }
                }
            }
            catch (ReflectionTypeLoadException ex)
            {
                Log.Logger.Error(ex, "!!!! Error when loading external plugin assemblies !!!!!\n");
                foreach (var loaderException in ex.LoaderExceptions)
                {
                    Log.Logger.Error(loaderException, string.Empty);
                }
            }
            catch (Exception ex)
            {
                Log.Logger.Error(ex, "!!!! Error when loading external plugin assemblies !!!!!\n");
            }

            // Now add any lists of extension types that we found in the container
            services.AddTransient((serviceProvider) => typeAndImplementationDerivers.AsEnumerable());

            if (devOpsIntegrationDeriver != null)
            {
                services.AddTransient((serviceProvider) => devOpsIntegrationDeriver);
            }
            else
            {
                Log.Logger.Information("No external IDeriveRepositoryDevOpsIntegrations found, loading NoOp implementation");

                services.AddTransient <IDeriveRepositoryDevOpsIntegrations>((serviceProvider) => new NoOpDevOpsIntegrationDeriver());
            }


            Assembly ResolveAssemblyDependency(AssemblyLoadContext assemblyLoadContext, AssemblyName assemblyName)
            {
                var matchingAssembly = externalPluginDirectoryAssemblies.FirstOrDefault(assembly => assembly.FullName == assemblyName.FullName);

                return(matchingAssembly);
            }

            List <Assembly> LoadAssembliesFromDirectory(string directory)
            {
                var assemblies = new List <Assembly>();

                if (Directory.Exists(directory))
                {
                    var filePaths = Directory.GetFiles(directory);

                    // Print out all the files found in the plugin directory for debugging purposes
                    foreach (var filePath in filePaths)
                    {
                        Log.Logger.Debug($"Found file {filePath}");
                    }

                    var assemblyFilePaths = filePaths.Where(filePath => filePath.EndsWith(".dll"));

                    foreach (var assemblyFilePath in assemblyFilePaths)
                    {
                        try
                        {
                            Log.Logger.Debug($"Attempting to load assembly {assemblyFilePath}");

                            var assembly = Assembly.LoadFile(assemblyFilePath);
                            assemblies.Add(assembly);
                        }
                        catch (Exception ex)
                        {
                            Log.Logger.Error(ex.Message);
                        }
                    }
                }
                else
                {
                    Log.Logger.Information($"The plugin directory {directory} was not found");
                }

                return(assemblies);
            }
        }