Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not crash on startup when configuration is invalid #2140

Merged
merged 6 commits into from Apr 26, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 15 additions & 15 deletions src/OmniSharp.Host/ConfigurationBuilder.cs
@@ -1,31 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.FileProviders;
using OmniSharp.Internal;
using OmniSharp.Utilities;

namespace OmniSharp
{
public class ConfigurationBuilder : IConfigurationBuilder
public class ConfigurationBuilder
{
private readonly IOmniSharpEnvironment _environment;
private readonly IConfigurationBuilder _builder;

public ConfigurationBuilder(IOmniSharpEnvironment environment)
{
_environment = environment;
_builder = new Microsoft.Extensions.Configuration.ConfigurationBuilder()
.SetBasePath(AppContext.BaseDirectory);
}

public IConfigurationBuilder Add(IConfigurationSource source)
{
_builder.Add(source);
return this;
}

public IConfigurationRoot Build()
public ConfigurationResult Build(Action<IConfigurationBuilder> additionalSetup = null)
{
var configBuilder = new Microsoft.Extensions.Configuration.ConfigurationBuilder()
.SetBasePath(AppContext.BaseDirectory)
Expand All @@ -46,10 +38,18 @@ public IConfigurationRoot Build()
optional: true,
reloadOnChange: true);

return configBuilder.Build();
}
// bootstrap additional host configuration at the end
additionalSetup?.Invoke(configBuilder);

public IDictionary<string, object> Properties => _builder.Properties;
public IList<IConfigurationSource> Sources => _builder.Sources;
try
{
var config = configBuilder.Build();
return new ConfigurationResult(config);
}
catch (Exception ex)
{
return new ConfigurationResult(ex);
}
}
}
}
25 changes: 25 additions & 0 deletions src/OmniSharp.Host/ConfigurationResult.cs
@@ -0,0 +1,25 @@
using System;
using Microsoft.Extensions.Configuration;

namespace OmniSharp
{
public class ConfigurationResult
{
public ConfigurationResult(IConfigurationRoot configuration)
{
Configuration = configuration;
}

public ConfigurationResult(Exception exception)
{
Exception = exception;
Configuration = new ConfigurationRoot(Array.Empty<IConfigurationProvider>());
}

public IConfigurationRoot Configuration { get; }

public Exception Exception { get; }

public bool HasError() => Exception != null;
}
}
10 changes: 8 additions & 2 deletions src/OmniSharp.Http/Startup.cs
Expand Up @@ -32,8 +32,8 @@ public Startup(IOmniSharpEnvironment environment, IEventEmitter eventEmitter, Pl

public IServiceProvider ConfigureServices(IServiceCollection services)
{
var configuration = new ConfigurationBuilder(_environment).Build();
var serviceProvider = CompositionHostBuilder.CreateDefaultServiceProvider(_environment, configuration, _eventEmitter, services,
var configurationResult = new ConfigurationBuilder(_environment).Build();
var serviceProvider = CompositionHostBuilder.CreateDefaultServiceProvider(_environment, configurationResult.Configuration, _eventEmitter, services,
configureLogging: builder =>
{
builder.AddConsole();
Expand All @@ -56,6 +56,12 @@ public IServiceProvider ConfigureServices(IServiceCollection services)

var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger<Startup>();

if (configurationResult.HasError())
{
logger.LogError(configurationResult.Exception, "There was an error when reading the OmniSharp configuration, starting with the default options.");
}

var assemblyLoader = serviceProvider.GetRequiredService<IAssemblyLoader>();
_compositionHost = new CompositionHostBuilder(serviceProvider)
.WithOmniSharpAssemblies()
Expand Down
15 changes: 7 additions & 8 deletions src/OmniSharp.LanguageServerProtocol/LanguageServerHost.cs
Expand Up @@ -202,24 +202,23 @@ private static LogLevel GetLogLevel(InitializeTrace initializeTrace)
application.LogLevel < logLevel ? application.LogLevel : logLevel,
application.OtherArgs.ToArray());

var configurationRoot = new Microsoft.Extensions.Configuration.ConfigurationBuilder()
.AddConfiguration(new ConfigurationBuilder(environment).Build())
.AddConfiguration(server.Configuration.GetSection("csharp"))
.AddConfiguration(server.Configuration.GetSection("omnisharp"))
.Build()
;

var configurationResult = new ConfigurationBuilder(environment).Build(b =>
b.AddConfiguration(server.Configuration.GetSection("csharp")).AddConfiguration(server.Configuration.GetSection("omnisharp")));
var eventEmitter = new LanguageServerEventEmitter(server);

services.AddSingleton(server)
.AddSingleton<ILanguageServerFacade>(server);

var serviceProvider =
CompositionHostBuilder.CreateDefaultServiceProvider(environment, configurationRoot, eventEmitter,
CompositionHostBuilder.CreateDefaultServiceProvider(environment, configurationResult.Configuration, eventEmitter,
services, GetLogBuilderAction(configureLogging, environment.LogLevel));

var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger<LanguageServerHost>();
if (configurationResult.HasError())
{
logger.LogError(configurationResult.Exception, "There was an error when reading the OmniSharp configuration, starting with the default options.");
}

var options = serviceProvider.GetRequiredService<IOptionsMonitor<OmniSharpOptions>>();
var plugins = application.CreatePluginAssemblies(options.CurrentValue, environment);
Expand Down
8 changes: 6 additions & 2 deletions src/OmniSharp.Stdio.Driver/Program.cs
Expand Up @@ -51,9 +51,9 @@ internal class Program

var environment = application.CreateEnvironment();
Configuration.ZeroBasedIndices = application.ZeroBasedIndices;
var configuration = new ConfigurationBuilder(environment).Build();
var configurationResult = new ConfigurationBuilder(environment).Build();
var writer = new SharedTextWriter(output);
var serviceProvider = CompositionHostBuilder.CreateDefaultServiceProvider(environment, configuration, new StdioEventEmitter(writer),
var serviceProvider = CompositionHostBuilder.CreateDefaultServiceProvider(environment, configurationResult.Configuration, new StdioEventEmitter(writer),
configureLogging: builder => builder.AddStdio(writer));

var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
Expand All @@ -63,6 +63,10 @@ internal class Program
var plugins = application.CreatePluginAssemblies(options.CurrentValue, environment);

var logger = loggerFactory.CreateLogger<Program>();
if (configurationResult.HasError())
{
logger.LogError(configurationResult.Exception, "There was an error when reading the OmniSharp configuration, starting with the default options.");
}
var compositionHostBuilder = new CompositionHostBuilder(serviceProvider)
.WithOmniSharpAssemblies()
.WithAssemblies(assemblyLoader.LoadByAssemblyNameOrPath(logger, plugins.AssemblyNames).ToArray());
Expand Down