Skip to content

Commit

Permalink
ProjectHotReloadSession updates (#9586)
Browse files Browse the repository at this point in the history
* Simplify early return checks

* Address TODO

* Use compound assignment

* Simplify logging code

Reduces duplication, making call sites easier to read.

* Typo

* Use pattern matching

* Simplify null checks

`CreateManagedDeltaApplier` returns a non-null value, so we don't have to perform a further check here.

* Use collection literal

---------

Co-authored-by: Xiaoyun Zhang <[email protected]>
  • Loading branch information
drewnoakes and LittleLittleCloud authored Nov 14, 2024
1 parent f92b6bf commit ddd2122
Showing 1 changed file with 40 additions and 127 deletions.
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

0 comments on commit ddd2122

Please sign in to comment.