Adding completion extension loading and execution logic (#833)

* Adding ICompletionExtension interface

* Adding extension loading and execution logic

* Fixing compilation error in VS 2017

* Using MEF for completion extension discovery

* using await on GetCompletionItems

* Adding an integration test for completion extension and update the completion extension interface

* Update the completion extension test

* Fix issues based on review comments

* Remove try/cache based on review comments, fix a integration test.

* More changes based on review comments

* Fixing SendResult logic for completion extension loading

* Only load completion extension from the assembly passed in, add more comments in the test

* Adding right assert messages in the test.

* More fixes based on review comments

* Dropping ICompletionExtensionProvider, load assembly only if it's loaded at the first time or updated since last load.

* Fix based on the latest review comments

* Adding missing TSQL functions in default completion list

* Update jsonrpc documentation for completion/extLoad
This commit is contained in:
Shengyu Fu
2019-07-19 12:04:03 -07:00
committed by Karl Burtram
parent e3ec6eb739
commit e1b9890f5c
18 changed files with 1000 additions and 354 deletions

View File

@@ -5,6 +5,7 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Composition.Convention;
using System.Composition.Hosting;
@@ -19,7 +20,7 @@ namespace Microsoft.SqlTools.Extensibility
{
public class ExtensionServiceProvider : RegisteredServiceProvider
{
private static readonly string[] defaultInclusionList =
private static readonly string[] defaultInclusionList =
{
"microsofsqltoolscredentials.dll",
"microsoft.sqltools.hosting.dll",
@@ -36,8 +37,8 @@ namespace Microsoft.SqlTools.Extensibility
public static ExtensionServiceProvider CreateDefaultServiceProvider(string[] inclusionList = null)
{
// only allow loading MEF dependencies from our assemblies until we can
// better seperate out framework assemblies and extension assemblies
// only allow loading MEF dependencies from our assemblies until we can
// better seperate out framework assemblies and extension assemblies
return CreateFromAssembliesInDirectory(inclusionList ?? defaultInclusionList);
}
@@ -114,8 +115,24 @@ namespace Microsoft.SqlTools.Extensibility
base.Register<T>(() => store.GetExports<T>());
}
}
/// <summary>
/// Merges in new assemblies to the existing container configuration.
/// </summary>
public void AddAssembliesToConfiguration(IEnumerable<Assembly> assemblies)
{
Validate.IsNotNull(nameof(assemblies), assemblies);
var previousConfig = config;
this.config = conventions => {
// Chain in the existing configuration function's result, then include additional
// assemblies
ContainerConfiguration containerConfig = previousConfig(conventions);
return containerConfig.WithAssemblies(assemblies, conventions);
};
}
}
/// <summary>
/// A store for MEF exports of a specific type. Provides basic wrapper functionality around MEF to standarize how
/// we lookup types and return to callers.
@@ -125,7 +142,7 @@ namespace Microsoft.SqlTools.Extensibility
private CompositionHost host;
private IList exports;
private Type contractType;
/// <summary>
/// Initializes the store with a type to lookup exports of, and a function that configures the
/// lookup parameters.
@@ -150,7 +167,7 @@ namespace Microsoft.SqlTools.Extensibility
{
return CreateAssemblyStore<T>(typeof(ExtensionStore).GetTypeInfo().Assembly);
}
public static ExtensionStore CreateAssemblyStore<T>(Assembly assembly)
{
Validate.IsNotNull(nameof(assembly), assembly);
@@ -162,7 +179,7 @@ namespace Microsoft.SqlTools.Extensibility
{
string assemblyPath = typeof(ExtensionStore).GetTypeInfo().Assembly.Location;
string directory = Path.GetDirectoryName(assemblyPath);
return new ExtensionStore(typeof(T), (conventions) =>
return new ExtensionStore(typeof(T), (conventions) =>
new ContainerConfiguration().WithAssembliesInPath(directory, conventions));
}
@@ -174,7 +191,7 @@ namespace Microsoft.SqlTools.Extensibility
}
return exports.Cast<T>();
}
private ConventionBuilder GetExportBuilder()
{
// Define exports as matching a parent type, export as that parent type
@@ -183,7 +200,7 @@ namespace Microsoft.SqlTools.Extensibility
return builder;
}
}
public static class ContainerConfigurationExtensions
{
public static ContainerConfiguration WithAssembliesInPath(this ContainerConfiguration configuration, string path, SearchOption searchOption = SearchOption.TopDirectoryOnly)
@@ -230,7 +247,7 @@ namespace Microsoft.SqlTools.Extensibility
var apiApplicationFileInfo = new FileInfo($"{folderPath}{Path.DirectorySeparatorChar}{assemblyName.Name}.dll");
if (File.Exists(apiApplicationFileInfo.FullName))
{
// Creating a new AssemblyContext instance for the same folder puts us at risk
// Creating a new AssemblyContext instance for the same folder puts us at risk
// of loading the same DLL in multiple contexts, which leads to some unpredictable
// behavior in the loader. See https://github.com/dotnet/coreclr/issues/19632