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

ProjectHotReloadSession updates #9586

Merged
merged 10 commits into from
Nov 14, 2024
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// 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.md file in the project root for more information.

using System.Diagnostics.CodeAnalysis;
using Microsoft.VisualStudio.Debugger.Contracts.HotReload;
using Microsoft.VisualStudio.HotReload.Components.DeltaApplier;
using static Microsoft.VisualStudio.ProjectSystem.VS.HotReload.ProjectHotReloadSessionManager;
Expand Down Expand Up @@ -55,28 +56,9 @@ public async Task ApplyChangesAsync(CancellationToken cancellationToken)

public async Task<bool> ApplyLaunchVariablesAsync(IDictionary<string, string> envVars, CancellationToken cancellationToken)
{
EnsureDeltaApplierforSession();
if (_deltaApplier is not null)
{
// TODO: Simplify this once ApplyProcessEnvironmentVariablesAsync takes an IDictionary instead of a Dictionary.
if (envVars is Dictionary<string, string> envVarsAsDictionary)
{
return await _deltaApplier.ApplyProcessEnvironmentVariablesAsync(envVarsAsDictionary, cancellationToken);
}
else
{
envVarsAsDictionary = new Dictionary<string, string>(envVars);
bool result = await _deltaApplier.ApplyProcessEnvironmentVariablesAsync(envVarsAsDictionary, cancellationToken);
foreach ((string name, string value) in envVarsAsDictionary)
{
envVars[name] = value;
}
EnsureDeltaApplierForSession();

return result;
}
}

return false;
return await _deltaApplier.ApplyProcessEnvironmentVariablesAsync(envVars, cancellationToken);
}

// TODO: remove when Web Tools is no longer calling this method.
Expand All @@ -94,17 +76,11 @@ public async Task StartSessionAsync(bool runningUnderDebugger, CancellationToken

HotReloadAgentFlags flags = runningUnderDebugger ? HotReloadAgentFlags.IsDebuggedProcess : HotReloadAgentFlags.None;
await _hotReloadAgentManagerClient.Value.AgentStartedAsync(this, flags, cancellationToken);
WriteToOutputWindow(
new HotReloadLogMessage(
HotReloadVerbosity.Minimal,
VSResources.HotReloadStartSession,
Name,
_variant
),
default);

WriteToOutputWindow(VSResources.HotReloadStartSession, default);
_sessionActive = true;
_isRunningUnderDebugger = runningUnderDebugger;
EnsureDeltaApplierforSession();
EnsureDeltaApplierForSession();
}

public async Task StopSessionAsync(CancellationToken cancellationToken)
Expand All @@ -113,14 +89,8 @@ public async Task StopSessionAsync(CancellationToken cancellationToken)
{
_sessionActive = false;
await _hotReloadAgentManagerClient.Value.AgentTerminatedAsync(this, cancellationToken);
WriteToOutputWindow(
new HotReloadLogMessage(
HotReloadVerbosity.Minimal,
VSResources.HotReloadStopSession,
Name,
_variant
),
default);

WriteToOutputWindow(VSResources.HotReloadStopSession, default);
}
}

Expand All @@ -130,56 +100,26 @@ public async ValueTask ApplyUpdatesAsync(ImmutableArray<ManagedHotReloadUpdate>
{
if (!_sessionActive)
{
WriteToOutputWindow(
new HotReloadLogMessage(
HotReloadVerbosity.Detailed,
$"{nameof(ApplyUpdatesAsync)} called but the session is not active.",
Name,
_variant
),
default);
WriteToOutputWindow($"{nameof(ApplyUpdatesAsync)} called but the session is not active.", default, HotReloadVerbosity.Detailed);
return;
}

if (_deltaApplier is null)
{
WriteToOutputWindow(
new HotReloadLogMessage(
HotReloadVerbosity.Detailed,
$"{nameof(ApplyUpdatesAsync)} called but we have no delta applier.",
Name,
_variant
),
default);
}

if (!_sessionActive || _deltaApplier is null)
{
WriteToOutputWindow($"{nameof(ApplyUpdatesAsync)} called but we have no delta applier.", default, HotReloadVerbosity.Detailed);
return;
}

try
{
WriteToOutputWindow(
new HotReloadLogMessage(
HotReloadVerbosity.Detailed,
VSResources.HotReloadSendingUpdates,
Name,
_variant
),
cancellationToken);
WriteToOutputWindow(VSResources.HotReloadSendingUpdates, cancellationToken, HotReloadVerbosity.Detailed);

ApplyResult result = await _deltaApplier.ApplyUpdatesAsync(updates, cancellationToken);
if (result == ApplyResult.Success || result == ApplyResult.SuccessRefreshUI)

if (result is ApplyResult.Success or ApplyResult.SuccessRefreshUI)
{
WriteToOutputWindow(
new HotReloadLogMessage(
HotReloadVerbosity.Detailed,
VSResources.HotReloadApplyUpdatesSuccessful,
Name,
_variant
),
cancellationToken);
WriteToOutputWindow(VSResources.HotReloadApplyUpdatesSuccessful, cancellationToken, HotReloadVerbosity.Detailed);

if (_callback is not null)
{
await _callback.OnAfterChangesAppliedAsync(cancellationToken);
Expand All @@ -188,17 +128,10 @@ public async ValueTask ApplyUpdatesAsync(ImmutableArray<ManagedHotReloadUpdate>
}
catch (Exception ex)
{
string message = $"{ex.GetType()}: {ex.Message}";

WriteToOutputWindow(
new HotReloadLogMessage(
HotReloadVerbosity.Minimal,
string.Format(VSResources.HotReloadApplyUpdatesFailure, message),
Name,
_variant,
errorLevel: HotReloadDiagnosticErrorLevel.Error
),
cancellationToken);
string.Format(VSResources.HotReloadApplyUpdatesFailure, $"{ex.GetType()}: {ex.Message}"),
cancellationToken,
errorLevel: HotReloadDiagnosticErrorLevel.Error);
throw;
}
}
Expand All @@ -210,47 +143,28 @@ public async ValueTask<ImmutableArray<string>> GetCapabilitiesAsync(Cancellation
{
return await _deltaApplier.GetCapabilitiesAsync(cancellationToken);
}
return ImmutableArray<string>.Empty;

return [];
}

public ValueTask ReportDiagnosticsAsync(ImmutableArray<ManagedHotReloadDiagnostic> diagnostics, CancellationToken cancellationToken)
{
WriteToOutputWindow(
new HotReloadLogMessage(
HotReloadVerbosity.Minimal,
VSResources.HotReloadErrorsInApplication,
Name,
_variant,
errorLevel: HotReloadDiagnosticErrorLevel.Error
),
cancellationToken);
WriteToOutputWindow(VSResources.HotReloadErrorsInApplication, cancellationToken, errorLevel: HotReloadDiagnosticErrorLevel.Error);

foreach (ManagedHotReloadDiagnostic diagnostic in diagnostics)
{
WriteToOutputWindow(
new HotReloadLogMessage(
HotReloadVerbosity.Minimal,
$"{diagnostic.FilePath}({diagnostic.Span.StartLine},{diagnostic.Span.StartColumn},{diagnostic.Span.EndLine},{diagnostic.Span.EndColumn}): {diagnostic.Message}",
Name,
_variant,
errorLevel: HotReloadDiagnosticErrorLevel.Error
),
cancellationToken);
$"{diagnostic.FilePath}({diagnostic.Span.StartLine},{diagnostic.Span.StartColumn},{diagnostic.Span.EndLine},{diagnostic.Span.EndColumn}): {diagnostic.Message}",
cancellationToken,
errorLevel: HotReloadDiagnosticErrorLevel.Error);
}

return new ValueTask(Task.CompletedTask);
}

public async ValueTask RestartAsync(CancellationToken cancellationToken)
{
WriteToOutputWindow(
new HotReloadLogMessage(
HotReloadVerbosity.Minimal,
VSResources.HotReloadRestartInProgress,
Name,
_variant
),
cancellationToken);
WriteToOutputWindow(VSResources.HotReloadRestartInProgress, cancellationToken);


if (_callback is IProjectHotReloadSessionCallback2 callBack2)
Expand All @@ -265,14 +179,7 @@ public async ValueTask RestartAsync(CancellationToken cancellationToken)

public async ValueTask StopAsync(CancellationToken cancellationToken)
{
WriteToOutputWindow(
new HotReloadLogMessage(
HotReloadVerbosity.Minimal,
VSResources.HotReloadStoppingApplication,
Name,
_variant
),
cancellationToken);
WriteToOutputWindow(VSResources.HotReloadStoppingApplication, cancellationToken);

await _callback.StopProjectAsync(cancellationToken);

Expand All @@ -284,18 +191,24 @@ public ValueTask<bool> SupportsRestartAsync(CancellationToken cancellationToken)
return new ValueTask<bool>(_callback.SupportsRestart);
}

private void WriteToOutputWindow(HotReloadLogMessage hotReloadLogMessage, CancellationToken cancellationToken)
private void WriteToOutputWindow(string message, CancellationToken cancellationToken, HotReloadVerbosity verbosity = HotReloadVerbosity.Minimal, HotReloadDiagnosticErrorLevel errorLevel = HotReloadDiagnosticErrorLevel.Info)
{
_hotReloadOutputService.Value.WriteLine(hotReloadLogMessage, cancellationToken);
_hotReloadOutputService.Value.WriteLine(
new HotReloadLogMessage(
verbosity,
message,
Name,
_variant,
errorLevel: errorLevel),
cancellationToken);
}

private void EnsureDeltaApplierforSession()
[MemberNotNull(nameof(_deltaApplier))]
private void EnsureDeltaApplierForSession()
{
if (_deltaApplier is null)
{
_deltaApplier = _callback.GetDeltaApplier()
?? _deltaApplierCreator.Value.CreateManagedDeltaApplier(_runtimeVersion);
}
_deltaApplier ??= _callback.GetDeltaApplier() ?? _deltaApplierCreator.Value.CreateManagedDeltaApplier(_runtimeVersion);

Assumes.NotNull(_deltaApplier);
}

public ValueTask<int?> GetTargetLocalProcessIdAsync(CancellationToken cancellationToken)
Expand Down
Loading