Skip to content

Commit

Permalink
Add a fallback flag to keep in-process build support available
Browse files Browse the repository at this point in the history
This is only needed as a compatibility switch if we have a regression
with the new support.
  • Loading branch information
jasonmalinowski committed Aug 30, 2023
1 parent 75f2235 commit d11bd4b
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,17 @@
using System.Collections.Immutable;
using System.Composition;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using Microsoft.Build.Locator;
using Microsoft.Build.Logging;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.ProjectTelemetry;
using Microsoft.CodeAnalysis.MSBuild;
using Microsoft.CodeAnalysis.MSBuild.Build;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.ProjectSystem;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost;
using Microsoft.CodeAnalysis.Workspaces.ProjectSystem;
using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.Composition;
Expand All @@ -29,8 +28,6 @@ namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace;
[Export(typeof(LanguageServerProjectSystem)), Shared]
internal sealed class LanguageServerProjectSystem
{
private readonly ProjectFileLoaderRegistry _projectFileLoaderRegistry;

/// <summary>
/// A single gate for code that is adding work to <see cref="_projectsToLoadAndReload" /> and modifying <see cref="_msbuildLoaded" />.
/// This is just we don't have code simultaneously trying to load and unload solutions at once.
Expand Down Expand Up @@ -82,9 +79,6 @@ internal sealed class LanguageServerProjectSystem
_logger = loggerFactory.CreateLogger(nameof(LanguageServerProjectSystem));
_projectLoadTelemetryReporter = projectLoadTelemetry;

// TODO: remove the DiagnosticReporter that's coupled to the Workspace here
_projectFileLoaderRegistry = new ProjectFileLoaderRegistry(workspaceFactory.Workspace.Services.SolutionServices, new DiagnosticReporter(workspaceFactory.Workspace));

_projectsToLoadAndReload = new AsyncBatchingWorkQueue<ProjectToLoad>(
TimeSpan.FromMilliseconds(100),
LoadOrReloadProjectsAsync,
Expand Down Expand Up @@ -129,13 +123,6 @@ public async Task OpenProjectsAsync(ImmutableArray<string> projectFilePaths)
if (!projectFilePaths.Any())
return;

if (await TryEnsureMSBuildLoadedAsync(Path.GetDirectoryName(projectFilePaths.First())!))
await OpenProjectsCoreAsync(projectFilePaths);
}

[MethodImpl(MethodImplOptions.NoInlining)] // Don't inline; the caller needs to ensure MSBuild is loaded before we can use MSBuild types here
private async Task OpenProjectsCoreAsync(ImmutableArray<string> projectFilePaths)
{
using (await _gate.DisposableWaitAsync())
{
_projectsToLoadAndReload.AddWork(projectFilePaths.Select(p => new ProjectToLoad(p, ProjectGuid: null)));
Expand Down Expand Up @@ -184,7 +171,15 @@ private async ValueTask LoadOrReloadProjectsAsync(ImmutableSegmentedList<Project
var stopwatch = Stopwatch.StartNew();

// TODO: support configuration switching
await using var buildHostProcessManager = new BuildHostProcessManager(_loggerFactory);

var binaryLogPath = GetMSBuildBinaryLogPath();
var runBuildInProcess = _globalOptionService.GetOption(LanguageServerProjectSystemOptionsStorage.LoadInProcess);

if (runBuildInProcess)
_logger.LogInformation("In-process project loading is enabled.");

await using var buildHostProcessManager = !runBuildInProcess ? new BuildHostProcessManager(_loggerFactory, binaryLogPath) : null;
var inProcessBuildHost = runBuildInProcess ? new BuildHost(_loggerFactory, binaryLogPath) : null;

var displayedToast = 0;

Expand All @@ -196,7 +191,7 @@ private async ValueTask LoadOrReloadProjectsAsync(ImmutableSegmentedList<Project
{
tasks.Add(Task.Run(async () =>
{
var errorKind = await LoadOrReloadProjectAsync(projectToLoad, buildHostProcessManager, cancellationToken);
var errorKind = await LoadOrReloadProjectAsync(projectToLoad, buildHostProcessManager, inProcessBuildHost, cancellationToken);
if (errorKind is LSP.MessageType.Error)
{
// We should display a toast when the value of displayedToast is 0. This will also update the value to 1 meaning we won't send any more toasts.
Expand All @@ -215,6 +210,9 @@ private async ValueTask LoadOrReloadProjectsAsync(ImmutableSegmentedList<Project
finally
{
_logger.LogInformation($"Completed (re)load of all projects in {stopwatch.Elapsed}");

if (inProcessBuildHost != null)
await inProcessBuildHost.ShutdownAsync();
}
}

Expand All @@ -231,12 +229,14 @@ private async ValueTask LoadOrReloadProjectsAsync(ImmutableSegmentedList<Project
return binaryLogPath;
}

private async Task<LSP.MessageType?> LoadOrReloadProjectAsync(ProjectToLoad projectToLoad, BuildHostProcessManager buildHostProcessManager, CancellationToken cancellationToken)
private async Task<LSP.MessageType?> LoadOrReloadProjectAsync(ProjectToLoad projectToLoad, BuildHostProcessManager? buildHostProcessManager, BuildHost? inProcessBuildHost, CancellationToken cancellationToken)
{
try
{
var projectPath = projectToLoad.Path;
var buildHost = await buildHostProcessManager.GetBuildHostAsync(projectPath, cancellationToken);

// If we have a process manager, then get an OOP process; otherwise we're still using in-proc builds so just fetch one in-process
var buildHost = inProcessBuildHost ?? await buildHostProcessManager!.GetBuildHostAsync(projectPath, cancellationToken);

if (await buildHost.IsProjectFileSupportedAsync(projectPath, cancellationToken))
{
Expand All @@ -261,7 +261,6 @@ private async ValueTask LoadOrReloadProjectsAsync(ImmutableSegmentedList<Project

if (existingProject != null)
{

projectFileInfos[loadedProjectInfo] = await existingProject.UpdateWithNewProjectInfoAsync(loadedProjectInfo);
}
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,11 @@ internal static class LanguageServerProjectSystemOptionsStorage
/// A folder to log binlogs to when running design-time builds.
/// </summary>
public static readonly Option2<string?> BinaryLogPath = new Option2<string?>("dotnet_binary_log_path", defaultValue: null, s_optionGroup);

/// <summary>
/// Whether we are doing design-time builds in-process; this is only to offer a fallback if the OOP builds are broken, and should be removed once
/// we don't have folks using this.
/// </summary>
public static readonly Option2<bool> LoadInProcess = new("dotnet_load_in_process", defaultValue: false, s_optionGroup);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ internal partial class DidChangeConfigurationNotificationHandler
LspOptionsStorage.LspEnableReferencesCodeLens,
LspOptionsStorage.LspEnableTestsCodeLens,
// Project system
LanguageServerProjectSystemOptionsStorage.BinaryLogPath);
LanguageServerProjectSystemOptionsStorage.BinaryLogPath,
LanguageServerProjectSystemOptionsStorage.LoadInProcess);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ public void VerifyLspClientOptionNames()
"background_analysis.dotnet_compiler_diagnostics_scope",
"code_lens.dotnet_enable_references_code_lens",
"code_lens.dotnet_enable_tests_code_lens",
"projects.dotnet_binary_log_path"
"projects.dotnet_binary_log_path",
"projects.dotnet_load_in_process",
}.OrderBy(name => name);

Assert.Equal(expectedNames, actualNames);
Expand Down
1 change: 0 additions & 1 deletion src/Workspaces/Core/MSBuild.BuildHost/BuildHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
using Microsoft.CodeAnalysis.MSBuild.Build;
using Microsoft.Extensions.Logging;
using Roslyn.Utilities;
using StreamJsonRpc;

namespace Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost;

Expand Down

0 comments on commit d11bd4b

Please sign in to comment.