-
Notifications
You must be signed in to change notification settings - Fork 4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Launch the build host process and run design-time builds in it
This implements the basic launching of the build hsot process, setting up the RPC channel, and running the design-time builds in that process. Right now this only works for .NET Core projects.
- Loading branch information
1 parent
bf6fcbb
commit 69e1b40
Showing
12 changed files
with
346 additions
and
24 deletions.
There are no files selected for viewing
111 changes: 111 additions & 0 deletions
111
...uageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/BuildHostProcessManager.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System.Diagnostics; | ||
using System.Runtime.InteropServices; | ||
using System.Threading; | ||
using Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost; | ||
using Roslyn.Utilities; | ||
using StreamJsonRpc; | ||
|
||
namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace; | ||
|
||
internal sealed class BuildHostProcessManager : IDisposable | ||
{ | ||
private readonly SemaphoreSlim _gate = new(initialCount: 1); | ||
private BuildHostProcess? _process; | ||
|
||
public async Task<IBuildHost> GetBuildHostAsync(CancellationToken cancellationToken) | ||
{ | ||
using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) | ||
{ | ||
if (_process == null) | ||
{ | ||
_process = new BuildHostProcess(LaunchDotNetCoreBuildHost()); | ||
_process.Disconnected += BuildHostProcess_Disconnected; | ||
} | ||
|
||
return _process.BuildHost; | ||
} | ||
} | ||
|
||
#pragma warning disable VSTHRD100 // Avoid async void methods: We're responding to Process.Exited, so an async void event handler is all we can do | ||
private async void BuildHostProcess_Disconnected(object? sender, EventArgs e) | ||
#pragma warning restore VSTHRD100 // Avoid async void methods | ||
{ | ||
Contract.ThrowIfNull(sender, $"{nameof(BuildHostProcess)}.{nameof(BuildHostProcess.Disconnected)} was raised with a null sender."); | ||
|
||
using (await _gate.DisposableWaitAsync().ConfigureAwait(false)) | ||
{ | ||
if (_process == sender) | ||
{ | ||
_process.Dispose(); | ||
_process = null; | ||
} | ||
} | ||
} | ||
|
||
private static Process LaunchDotNetCoreBuildHost() | ||
{ | ||
var processStartInfo = new ProcessStartInfo() | ||
{ | ||
FileName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "dotnet.exe" : "dotnet", | ||
CreateNoWindow = true, | ||
UseShellExecute = false, | ||
RedirectStandardInput = true, | ||
RedirectStandardOutput = true, | ||
}; | ||
|
||
// We need to roll forward to the latest runtime, since the project may be using an SDK (or an SDK required runtime) newer than we ourselves built with. | ||
// We set the environment variable since --roll-forward LatestMajor doesn't roll forward to prerelease SDKs otherwise. | ||
processStartInfo.ArgumentList.Add("--roll-forward"); | ||
processStartInfo.ArgumentList.Add("LatestMajor"); | ||
processStartInfo.Environment["DOTNET_ROLL_FORWARD_TO_PRERELEASE"] = "1"; | ||
|
||
processStartInfo.ArgumentList.Add(typeof(IBuildHost).Assembly.Location); | ||
var process = Process.Start(processStartInfo); | ||
Contract.ThrowIfNull(process, "Process.Start failed to launch a process."); | ||
return process; | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
_process?.Dispose(); | ||
} | ||
|
||
private sealed class BuildHostProcess : IDisposable | ||
{ | ||
private readonly Process _process; | ||
private readonly JsonRpc _jsonRpc; | ||
|
||
public BuildHostProcess(Process process) | ||
{ | ||
_process = process; | ||
|
||
_process.EnableRaisingEvents = true; | ||
_process.Exited += Process_Exited; | ||
|
||
var messageHandler = new HeaderDelimitedMessageHandler(sendingStream: _process.StandardInput.BaseStream, receivingStream: _process.StandardOutput.BaseStream, new JsonMessageFormatter()); | ||
|
||
_jsonRpc = new JsonRpc(messageHandler); | ||
_jsonRpc.StartListening(); | ||
BuildHost = _jsonRpc.Attach<IBuildHost>(); | ||
} | ||
|
||
private void Process_Exited(object? sender, EventArgs e) | ||
{ | ||
Disconnected?.Invoke(this, EventArgs.Empty); | ||
} | ||
|
||
public IBuildHost BuildHost { get; } | ||
|
||
public event EventHandler? Disconnected; | ||
|
||
public void Dispose() | ||
{ | ||
_jsonRpc.Dispose(); | ||
} | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.CodeAnalysis.Host; | ||
using Microsoft.CodeAnalysis.MSBuild; | ||
using Microsoft.CodeAnalysis.MSBuild.Build; | ||
using Roslyn.Utilities; | ||
using StreamJsonRpc; | ||
|
||
namespace Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost; | ||
|
||
internal sealed class BuildHost : IBuildHost | ||
{ | ||
private readonly JsonRpc _jsonRpc; | ||
private readonly ProjectFileLoaderRegistry _projectFileLoaderRegistry; | ||
private readonly ProjectBuildManager _buildManager; | ||
|
||
public BuildHost(JsonRpc jsonRpc, SolutionServices solutionServices) | ||
{ | ||
_jsonRpc = jsonRpc; | ||
_projectFileLoaderRegistry = new ProjectFileLoaderRegistry(solutionServices, new DiagnosticReporter(new AdhocWorkspace())); | ||
_buildManager = new ProjectBuildManager(System.Collections.Immutable.ImmutableDictionary<string, string>.Empty); | ||
_buildManager.StartBatchBuild(); | ||
} | ||
|
||
public Task<bool> IsProjectFileSupportedAsync(string projectFilePath, CancellationToken cancellationToken) | ||
{ | ||
return Task.FromResult(_projectFileLoaderRegistry.TryGetLoaderFromProjectPath(projectFilePath, DiagnosticReportingMode.Ignore, out var _)); | ||
} | ||
|
||
public async Task<IRemoteProjectFile> LoadProjectFileAsync(string projectFilePath, CancellationToken cancellationToken) | ||
{ | ||
Contract.ThrowIfFalse(_projectFileLoaderRegistry.TryGetLoaderFromProjectPath(projectFilePath, out var projectLoader)); | ||
return new RemoteProjectFile(await projectLoader.LoadProjectFileAsync(projectFilePath, _buildManager, cancellationToken).ConfigureAwait(false)); | ||
} | ||
|
||
public void Shutdown() | ||
{ | ||
_buildManager.EndBatchBuild(); | ||
_jsonRpc.Dispose(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost; | ||
|
||
/// <summary> | ||
/// The RPC interface implemented by this host; called via JSON-RPC. | ||
/// </summary> | ||
internal interface IBuildHost | ||
{ | ||
/// <summary> | ||
/// Returns whether this project's language is supported. | ||
/// </summary> | ||
Task<bool> IsProjectFileSupportedAsync(string path, CancellationToken cancellationToken); | ||
|
||
Task<IRemoteProjectFile> LoadProjectFileAsync(string path, CancellationToken cancellationToken); | ||
|
||
void Shutdown(); | ||
} |
23 changes: 23 additions & 0 deletions
23
src/Workspaces/Core/MSBuild.BuildHost/IRemoteProjectFile.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System; | ||
using System.Collections.Immutable; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.CodeAnalysis.MSBuild; | ||
using Microsoft.CodeAnalysis.MSBuild.Logging; | ||
using StreamJsonRpc; | ||
|
||
namespace Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost; | ||
|
||
/// <summary> | ||
/// A trimmed down interface of <see cref="IProjectFile"/> that is usable for RPC to the build host process and meets all the requirements of being an <see cref="RpcMarshalableAttribute"/> interface. | ||
/// </summary> | ||
[RpcMarshalable] | ||
internal interface IRemoteProjectFile : IDisposable | ||
{ | ||
Task<ImmutableArray<ProjectFileInfo>> GetProjectFileInfosAsync(CancellationToken cancellationToken); | ||
Task<ImmutableArray<DiagnosticLogItem>> GetDiagnosticLogItemsAsync(CancellationToken cancellationToken); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.