diff --git a/CHANGELOG.md b/CHANGELOG.md index 8228c81ac9..2f8b14aef0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # Changelog All changes to the project will be documented in this file. +## [1.33.1] - not released yet +* Fixed a bug where some internal services didn't respect the disabling of a project system ([#1543](https://github.com/OmniSharp/omnisharp-roslyn/pull/1543)) + ## [1.33.0] - 2019-07-01 * Added support for `.editorconfig` files to control formatting settings, analyzers, coding styles and naming conventions. The feature is currently opt-into and needs to be enabled using OmniSharp configuration ([#31](https://github.com/OmniSharp/omnisharp-roslyn/issues/31), PR: [#1526](https://github.com/OmniSharp/omnisharp-roslyn/pull/1526)) ```JSON diff --git a/src/OmniSharp.Abstractions/Plugins/Plugin.cs b/src/OmniSharp.Abstractions/Plugins/Plugin.cs index 4e13c6be07..60957d4535 100644 --- a/src/OmniSharp.Abstractions/Plugins/Plugin.cs +++ b/src/OmniSharp.Abstractions/Plugins/Plugin.cs @@ -35,6 +35,7 @@ public Plugin(ILogger logger, PluginConfig config) public string Language { get; } public IEnumerable Extensions { get; } public bool EnabledByDefault { get; } = true; + public bool Initialized { get; private set; } public Task Handle(string endpoint, TRequest request) { @@ -101,6 +102,8 @@ public void Dispose() public void Initalize(IConfiguration configuration) { + if (Initialized) return; + Initialized = true; Task.Run(() => Run()); } diff --git a/src/OmniSharp.Abstractions/Services/IProjectSystem.cs b/src/OmniSharp.Abstractions/Services/IProjectSystem.cs index ab459e2bb2..587bcc89b8 100644 --- a/src/OmniSharp.Abstractions/Services/IProjectSystem.cs +++ b/src/OmniSharp.Abstractions/Services/IProjectSystem.cs @@ -12,6 +12,11 @@ public interface IProjectSystem IEnumerable Extensions { get; } bool EnabledByDefault { get; } + /// + /// Flag indicating that the project system has been sucessfully initialized. + /// + bool Initialized { get; } + /// /// Initialize the project system. /// diff --git a/src/OmniSharp.Cake/CakeProjectSystem.cs b/src/OmniSharp.Cake/CakeProjectSystem.cs index 63d1b60860..667e21eeb1 100644 --- a/src/OmniSharp.Cake/CakeProjectSystem.cs +++ b/src/OmniSharp.Cake/CakeProjectSystem.cs @@ -36,13 +36,12 @@ public class CakeProjectSystem : IProjectSystem private readonly ILogger _logger; private readonly ConcurrentDictionary _projects; private readonly Lazy _compilationOptions; - private CakeOptions _options; - public string Key { get; } = "Cake"; public string Language { get; } = Constants.LanguageNames.Cake; public IEnumerable Extensions { get; } = new[] { ".cake" }; public bool EnabledByDefault { get; } = true; + public bool Initialized { get; private set; } [ImportingConstructor] public CakeProjectSystem( @@ -70,6 +69,8 @@ public CakeProjectSystem( public void Initalize(IConfiguration configuration) { + if (Initialized) return; + _options = new CakeOptions(); configuration.Bind(_options); @@ -103,6 +104,8 @@ public void Initalize(IConfiguration configuration) // Watch .cake files _fileSystemWatcher.Watch(".cake", OnCakeFileChanged); + + Initialized = true; } private void AddCakeFile(string cakeFilePath) diff --git a/src/OmniSharp.DotNet/DotNetProjectSystem.cs b/src/OmniSharp.DotNet/DotNetProjectSystem.cs index de4ed7ad5b..cdf75adfe9 100644 --- a/src/OmniSharp.DotNet/DotNetProjectSystem.cs +++ b/src/OmniSharp.DotNet/DotNetProjectSystem.cs @@ -28,7 +28,6 @@ namespace OmniSharp.DotNet public class DotNetProjectSystem : IProjectSystem { private const string CompilationConfiguration = "Debug"; - private readonly IOmniSharpEnvironment _environment; private readonly OmniSharpWorkspace _workspace; private readonly IDotNetCliService _dotNetCliService; @@ -37,7 +36,6 @@ public class DotNetProjectSystem : IProjectSystem private readonly IFileSystemWatcher _fileSystemWatcher; private readonly ILogger _logger; private readonly ProjectStatesCache _projectStates; - private DotNetWorkspace _workspaceContext; private bool _enableRestorePackages; @@ -66,6 +64,7 @@ public DotNetProjectSystem( public string Language { get; } = LanguageNames.CSharp; public IEnumerable Extensions { get; } = new string[] { ".cs" }; public bool EnabledByDefault { get; } = false; + public bool Initialized { get; private set; } Task IProjectSystem.GetWorkspaceModelAsync(WorkspaceInformationRequest request) { @@ -103,6 +102,8 @@ Task IProjectSystem.GetProjectModelAsync(string filePath) public void Initalize(IConfiguration configuration) { + if (Initialized) return; + _logger.LogInformation($"Initializing in {_environment.TargetDirectory}"); if (!bool.TryParse(configuration["enablePackageRestore"], out _enableRestorePackages)) @@ -115,6 +116,8 @@ public void Initalize(IConfiguration configuration) _workspaceContext = new DotNetWorkspace(_environment.TargetDirectory); Update(allowRestore: true); + + Initialized = true; } public void Update(bool allowRestore) diff --git a/src/OmniSharp.Host/Endpoint/LanguagePredicateHandler.cs b/src/OmniSharp.Host/Endpoint/LanguagePredicateHandler.cs index 4908876389..69300291bf 100644 --- a/src/OmniSharp.Host/Endpoint/LanguagePredicateHandler.cs +++ b/src/OmniSharp.Host/Endpoint/LanguagePredicateHandler.cs @@ -16,7 +16,7 @@ public LanguagePredicateHandler(IEnumerable projectSystems) public string GetLanguageForFilePath(string filePath) { - foreach (var projectSystem in _projectSystems) + foreach (var projectSystem in _projectSystems.Where(project => project.Initialized)) { if (projectSystem.Extensions.Any(extension => filePath.EndsWith(extension, StringComparison.OrdinalIgnoreCase))) { diff --git a/src/OmniSharp.MSBuild/ProjectSystem.cs b/src/OmniSharp.MSBuild/ProjectSystem.cs index 17f407ec02..be5141f276 100644 --- a/src/OmniSharp.MSBuild/ProjectSystem.cs +++ b/src/OmniSharp.MSBuild/ProjectSystem.cs @@ -41,19 +41,16 @@ internal class ProjectSystem : IProjectSystem private readonly ILogger _logger; private readonly IAnalyzerAssemblyLoader _assemblyLoader; private readonly ImmutableArray _eventSinks; - private readonly object _gate = new object(); - private readonly Queue _projectsToProcess; - private PackageDependencyChecker _packageDependencyChecker; private ProjectManager _manager; private ProjectLoader _loader; private MSBuildOptions _options; private string _solutionFileOrRootPath; - public string Key { get; } = "MsBuild"; public string Language { get; } = LanguageNames.CSharp; public IEnumerable Extensions { get; } = new[] { ".cs" }; public bool EnabledByDefault { get; } = true; + public bool Initialized { get; private set; } [ImportingConstructor] public ProjectSystem( @@ -82,13 +79,14 @@ public ProjectSystem( _fileSystemHelper = fileSystemHelper; _loggerFactory = loggerFactory; _eventSinks = eventSinks.ToImmutableArray(); - _projectsToProcess = new Queue(); _logger = loggerFactory.CreateLogger(); _assemblyLoader = assemblyLoader; } public void Initalize(IConfiguration configuration) { + if (Initialized) return; + _options = new MSBuildOptions(); ConfigurationBinder.Bind(configuration, _options); @@ -105,6 +103,7 @@ public void Initalize(IConfiguration configuration) _loader = new ProjectLoader(_options, _environment.TargetDirectory, _propertyOverrides, _loggerFactory, _sdksPathResolver); _manager = new ProjectManager(_loggerFactory, _options, _eventEmitter, _fileSystemWatcher, _metadataFileReferenceCache, _packageDependencyChecker, _loader, _workspace, _assemblyLoader, _eventSinks); + Initialized = true; if (_options.LoadProjectsOnDemand) { diff --git a/src/OmniSharp.Roslyn/ProjectEventForwarder.cs b/src/OmniSharp.Roslyn/ProjectEventForwarder.cs index bb0f16fb26..6930de013a 100644 --- a/src/OmniSharp.Roslyn/ProjectEventForwarder.cs +++ b/src/OmniSharp.Roslyn/ProjectEventForwarder.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Composition; +using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using OmniSharp.Eventing; @@ -85,7 +86,7 @@ private async Task GetProjectInformationAsync(string { var response = new ProjectInformationResponse(); - foreach (var projectSystem in _projectSystems) + foreach (var projectSystem in _projectSystems.Where(project => project.Initialized)) { var project = await projectSystem.GetProjectModelAsync(fileName); if (project != null) diff --git a/src/OmniSharp.Roslyn/ProjectInformationService.cs b/src/OmniSharp.Roslyn/ProjectInformationService.cs index 71a31f61f5..eead9f6824 100644 --- a/src/OmniSharp.Roslyn/ProjectInformationService.cs +++ b/src/OmniSharp.Roslyn/ProjectInformationService.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Composition; +using System.Linq; using System.Threading.Tasks; using OmniSharp.Mef; using OmniSharp.Models.ProjectInformation; @@ -23,7 +24,7 @@ public async Task Handle(ProjectInformationRequest r { var response = new ProjectInformationResponse(); - foreach (var projectSystem in _projectSystems) + foreach (var projectSystem in _projectSystems.Where(project => project.Initialized)) { var project = await projectSystem.GetProjectModelAsync(request.FileName); response.Add($"{projectSystem.Key}Project", project); diff --git a/src/OmniSharp.Roslyn/WorkspaceInformationService.cs b/src/OmniSharp.Roslyn/WorkspaceInformationService.cs index e7edaccb44..69fbcb56c4 100644 --- a/src/OmniSharp.Roslyn/WorkspaceInformationService.cs +++ b/src/OmniSharp.Roslyn/WorkspaceInformationService.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Composition; +using System.Linq; using System.Threading.Tasks; using OmniSharp.Mef; using OmniSharp.Models.WorkspaceInformation; @@ -23,7 +24,7 @@ public async Task Handle(WorkspaceInformationReque { var response = new WorkspaceInformationResponse(); - foreach (var projectSystem in _projectSystems) + foreach (var projectSystem in _projectSystems.Where(project => project.Initialized)) { var workspaceModel = await projectSystem.GetWorkspaceModelAsync(request); response.Add(projectSystem.Key, workspaceModel); diff --git a/src/OmniSharp.Script/ScriptProjectSystem.cs b/src/OmniSharp.Script/ScriptProjectSystem.cs index 3f9737985d..718c321016 100644 --- a/src/OmniSharp.Script/ScriptProjectSystem.cs +++ b/src/OmniSharp.Script/ScriptProjectSystem.cs @@ -22,16 +22,13 @@ namespace OmniSharp.Script public class ScriptProjectSystem : IProjectSystem { private const string CsxExtension = ".csx"; - private readonly ConcurrentDictionary _projects = new ConcurrentDictionary(); private readonly ScriptContextProvider _scriptContextProvider; private readonly OmniSharpWorkspace _workspace; private readonly IOmniSharpEnvironment _env; private readonly ILogger _logger; private readonly IFileSystemWatcher _fileSystemWatcher; - private readonly ILoggerFactory _loggerFactory; private readonly FileSystemHelper _fileSystemHelper; - private ScriptOptions _scriptOptions; private Lazy _scriptContext; @@ -41,7 +38,6 @@ public ScriptProjectSystem(OmniSharpWorkspace workspace, IOmniSharpEnvironment e { _workspace = workspace; _env = env; - _loggerFactory = loggerFactory; _fileSystemWatcher = fileSystemWatcher; _fileSystemHelper = fileSystemHelper; _logger = loggerFactory.CreateLogger(); @@ -52,9 +48,12 @@ public ScriptProjectSystem(OmniSharpWorkspace workspace, IOmniSharpEnvironment e public string Language { get; } = LanguageNames.CSharp; public IEnumerable Extensions { get; } = new[] { CsxExtension }; public bool EnabledByDefault { get; } = true; + public bool Initialized { get; private set; } public void Initalize(IConfiguration configuration) { + if (Initialized) return; + _scriptOptions = new ScriptOptions(); ConfigurationBinder.Bind(configuration, _scriptOptions); @@ -84,6 +83,8 @@ public void Initalize(IConfiguration configuration) // Watch CSX files in order to add/remove them in workspace _fileSystemWatcher.Watch(CsxExtension, OnCsxFileChanged); + + Initialized = true; } private void OnCsxFileChanged(string filePath, FileChangeType changeType) diff --git a/tests/OmniSharp.Cake.Tests/CakeProjectSystemFacts.cs b/tests/OmniSharp.Cake.Tests/CakeProjectSystemFacts.cs index aecf30e7b3..419effe6a4 100644 --- a/tests/OmniSharp.Cake.Tests/CakeProjectSystemFacts.cs +++ b/tests/OmniSharp.Cake.Tests/CakeProjectSystemFacts.cs @@ -1,4 +1,5 @@ -using System.IO; +using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis; @@ -71,6 +72,20 @@ public async Task AllProjectsShouldUseLatestLanguageVersion() } } + [Fact] + public async Task DoesntParticipateInWorkspaceInfoResponseWhenDisabled() + { + using (var testProject = await TestAssets.Instance.GetTestProjectAsync("CakeProject", shadowCopy: false)) + using (var host = CreateOmniSharpHost(testProject.Directory, configurationData: new Dictionary + { + ["cake:enabled"] = "false" + })) + { + var workspaceInfo = await GetWorkspaceInfoAsync(host); + Assert.Null(workspaceInfo); + } + } + private static async Task GetWorkspaceInfoAsync(OmniSharpTestHost host) { var service = host.GetWorkspaceInformationService(); @@ -82,6 +97,8 @@ private static async Task GetWorkspaceInfoAsync(Omni var response = await service.Handle(request); + if (!response.ContainsKey("Cake")) return null; + return (CakeContextModelCollection)response["Cake"]; } diff --git a/tests/OmniSharp.Http.Tests/EndpointMiddlewareFacts.cs b/tests/OmniSharp.Http.Tests/EndpointMiddlewareFacts.cs index 780f51e85d..2aa6ebcf1e 100644 --- a/tests/OmniSharp.Http.Tests/EndpointMiddlewareFacts.cs +++ b/tests/OmniSharp.Http.Tests/EndpointMiddlewareFacts.cs @@ -78,6 +78,7 @@ class FakeProjectSystem : IProjectSystem public string Language { get; } = LanguageNames.CSharp; public IEnumerable Extensions { get; } = new[] { ".cs" }; public bool EnabledByDefault { get; } = true; + public bool Initialized { get; } = true; public Task GetWorkspaceModelAsync(WorkspaceInformationRequest request) { diff --git a/tests/OmniSharp.MSBuild.Tests/WorkspaceInformationTests.cs b/tests/OmniSharp.MSBuild.Tests/WorkspaceInformationTests.cs index bbef8022b6..f73b43651d 100644 --- a/tests/OmniSharp.MSBuild.Tests/WorkspaceInformationTests.cs +++ b/tests/OmniSharp.MSBuild.Tests/WorkspaceInformationTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; @@ -241,5 +242,19 @@ public async Task ProjectWithWildcardPackageReference() Assert.Equal(3, project.SourceFiles.Count); } } + + [Fact] + public async Task DoesntParticipateInWorkspaceInfoResponseWhenDisabled() + { + using (var testProject = await TestAssets.Instance.GetTestProjectAsync("ProjectAndSolution")) + using (var host = CreateOmniSharpHost(testProject.Directory, configurationData: new Dictionary + { + ["msbuild:enabled"] = "false" + })) + { + var workspaceInfo = await host.RequestMSBuildWorkspaceInfoAsync(); + Assert.Null(workspaceInfo); + } + } } } diff --git a/tests/OmniSharp.Script.Tests/WorkspaceInformationTests.cs b/tests/OmniSharp.Script.Tests/WorkspaceInformationTests.cs index 208e282e9a..1d0b627bb9 100644 --- a/tests/OmniSharp.Script.Tests/WorkspaceInformationTests.cs +++ b/tests/OmniSharp.Script.Tests/WorkspaceInformationTests.cs @@ -186,6 +186,20 @@ public async Task DotnetCoreScriptWithNuget() } } + [Fact] + public async Task DoesntParticipateInWorkspaceInfoResponseWhenDisabled() + { + using (var testProject = TestAssets.Instance.GetTestScript("SingleCsiScript")) + using (var host = CreateOmniSharpHost(testProject.Directory, configurationData: new Dictionary + { + ["script:enabled"] = "false" + })) + { + var workspaceInfo = await GetWorkspaceInfoAsync(host); + Assert.Null(workspaceInfo); + } + } + private string GetMsCorlibPath() => Assembly.Load(new AssemblyName("mscorlib"))?.Location; private void VerifyCorLib(ScriptContextModel project, bool expected = true) @@ -208,6 +222,8 @@ private static async Task GetWorkspaceInfoAsync(Om var response = await service.Handle(request); + if (!response.ContainsKey("Script")) return null; + return (ScriptContextModelCollection)response["Script"]; } } diff --git a/tests/TestUtility/TestHostExtensions.cs b/tests/TestUtility/TestHostExtensions.cs index 9c8dfc66a6..ce941f0ae2 100644 --- a/tests/TestUtility/TestHostExtensions.cs +++ b/tests/TestUtility/TestHostExtensions.cs @@ -54,6 +54,8 @@ public static async Task RequestMSBuildWorkspaceInfoAsync( var response = await service.Handle(request); + if (!response.ContainsKey("MsBuild")) return null; + return (MSBuildWorkspaceInfo)response["MsBuild"]; }