-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Fix a couple of issues with dotnet-watch #17608
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -53,11 +53,6 @@ public static async Task ReceiveDeltas(HotReloadAgent hotReloadAgent) | |
Log("Attempting to apply deltas."); | ||
|
||
hotReloadAgent.ApplyDeltas(update.Deltas); | ||
|
||
// We want to base this off of mvids, but we'll figure that out eventually. | ||
var applyResult = update.ChangedFile is string changedFile && changedFile.EndsWith(".razor", StringComparison.Ordinal) ? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I changed the heuristic about when we refresh the browser in web apps - we won't it if it looks like a Blazor app (presence of any .razor file). Works better than relying on individual files. |
||
ApplyResult.Success : | ||
ApplyResult.Success_RefreshBrowser; | ||
pipeClient.WriteByte((byte)ApplyResult.Success); | ||
|
||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -115,6 +115,8 @@ public async ValueTask<bool> TryHandleFileChange(DotNetWatchContext context, Fil | |
{ | ||
_reporter.Verbose("No deltas modified. Applying changes to clear diagnostics."); | ||
await _deltaApplier.Apply(context, file.FilePath, updates, cancellationToken); | ||
// Even if there were diagnostics, continue treating this as a success | ||
_reporter.Output("No hot reload changes to apply."); | ||
} | ||
else | ||
{ | ||
|
@@ -123,7 +125,8 @@ public async ValueTask<bool> TryHandleFileChange(DotNetWatchContext context, Fil | |
} | ||
|
||
HotReloadEventSource.Log.HotReloadEnd(HotReloadEventSource.StartType.CompilationHandler); | ||
// Even if there were diagnostics, continue treating this as a success | ||
// Return true so that the watcher continues to keep the current hot reload session alive. If there were errors, this allows the user to fix errors and continue | ||
// working on the running app. | ||
return true; | ||
} | ||
|
||
|
@@ -145,6 +148,11 @@ public async ValueTask<bool> TryHandleFileChange(DotNetWatchContext context, Fil | |
var applyState = await _deltaApplier.Apply(context, file.FilePath, updates, cancellationToken); | ||
_reporter.Verbose($"Received {(applyState ? "successful" : "failed")} apply from delta applier."); | ||
HotReloadEventSource.Log.HotReloadEnd(HotReloadEventSource.StartType.CompilationHandler); | ||
if (applyState) | ||
{ | ||
_reporter.Output($"Hot reload of changes succeeded."); | ||
} | ||
|
||
return applyState; | ||
} | ||
|
||
|
@@ -171,7 +179,7 @@ private ImmutableArray<string> GetDiagnostics(Solution solution, CancellationTok | |
if (item.Severity == DiagnosticSeverity.Error) | ||
{ | ||
var diagnostic = CSharpDiagnosticFormatter.Instance.Format(item); | ||
_reporter.Output(diagnostic); | ||
_reporter.Output("\x1B[40m\x1B[31m" + diagnostic); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pretty red color |
||
projectDiagnostics = projectDiagnostics.Add(diagnostic); | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,10 +17,11 @@ namespace Microsoft.DotNet.Watcher.Tools | |
{ | ||
internal class DefaultDeltaApplier : IDeltaApplier | ||
{ | ||
private static readonly string _namedPipeName = Guid.NewGuid().ToString(); | ||
private readonly IReporter _reporter; | ||
private readonly string _namedPipeName = Guid.NewGuid().ToString(); | ||
private Task _task; | ||
private NamedPipeServerStream _pipe; | ||
private bool _refreshBrowserAfterFileChange; | ||
|
||
public DefaultDeltaApplier(IReporter reporter) | ||
{ | ||
|
@@ -29,14 +30,8 @@ public DefaultDeltaApplier(IReporter reporter) | |
|
||
public bool SuppressBrowserRefreshAfterApply { get; init; } | ||
|
||
public async ValueTask InitializeAsync(DotNetWatchContext context, CancellationToken cancellationToken) | ||
public ValueTask InitializeAsync(DotNetWatchContext context, CancellationToken cancellationToken) | ||
{ | ||
if (_pipe is not null) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why was this removed? It seems like good hygiene to have it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Turns out we were newing up these instances in every hot reload loop. So this was never true. Also why the named pipe name is a static because we were only configuring it once. |
||
{ | ||
_pipe.Close(); | ||
await _pipe.DisposeAsync(); | ||
} | ||
|
||
_pipe = new NamedPipeServerStream(_namedPipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.CurrentUserOnly); | ||
_task = _pipe.WaitForConnectionAsync(cancellationToken); | ||
|
||
|
@@ -48,7 +43,15 @@ public async ValueTask InitializeAsync(DotNetWatchContext context, CancellationT | |
// Configure the app for EnC | ||
context.ProcessSpec.EnvironmentVariables["DOTNET_MODIFIABLE_ASSEMBLIES"] = "debug"; | ||
context.ProcessSpec.EnvironmentVariables["DOTNET_HOTRELOAD_NAMEDPIPE_NAME"] = _namedPipeName; | ||
|
||
// If there's any .razor file, we'll assume this is a blazor app and not cause a browser refresh. | ||
if (!SuppressBrowserRefreshAfterApply) | ||
{ | ||
_refreshBrowserAfterFileChange = !context.FileSet.Any(f => f.FilePath.EndsWith(".razor", StringComparison.Ordinal)); | ||
} | ||
} | ||
|
||
return default; | ||
} | ||
|
||
public async ValueTask<bool> Apply(DotNetWatchContext context, string changedFile, ImmutableArray<WatchHotReloadService.Update> solutionUpdate, CancellationToken cancellationToken) | ||
|
@@ -110,11 +113,14 @@ public async ValueTask<bool> Apply(DotNetWatchContext context, string changedFil | |
|
||
if (!SuppressBrowserRefreshAfterApply && context.BrowserRefreshServer is not null) | ||
{ | ||
if (result == ApplyResult.Success_RefreshBrowser) | ||
// For a Web app, we have the option of either letting the app update the UI or | ||
// refresh the browser. In general, for Blazor apps, we will choose not to refresh the UI | ||
// and for other apps we'll always refresh | ||
if (_refreshBrowserAfterFileChange) | ||
{ | ||
await context.BrowserRefreshServer.ReloadAsync(cancellationToken); | ||
} | ||
else if (result == ApplyResult.Success) | ||
else | ||
{ | ||
await context.BrowserRefreshServer.SendJsonSerlialized(new HotReloadApplied()); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -98,6 +98,5 @@ internal enum ApplyResult | |
{ | ||
Failed = -1, | ||
Success = 0, | ||
Success_RefreshBrowser = 1, | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -67,7 +67,13 @@ public Program(IConsole console, string workingDirectory) | |
// AppContext.BaseDirectory = $sdkRoot\$sdkVersion\DotnetTools\dotnet-watch\$version\tools\net6.0\any\ | ||
// MSBuild.dll is located at $sdkRoot\$sdkVersion\MSBuild.dll | ||
var sdkRootDirectory = Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "..", ".."); | ||
#if DEBUG | ||
// In the usual case, use the SDK that contains the dotnet-watch. However during local testing, it's | ||
// much more common to run dotnet-watch from a different SDK. Use the ambient SDK in that case. | ||
MSBuildLocator.RegisterDefaults(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Annoying local build issue where it would use the dogfood SDK. This was causing the annoying FailFast error that I poked you about. |
||
#else | ||
MSBuildLocator.RegisterMSBuildPath(sdkRootDirectory); | ||
#endif | ||
|
||
Ensure.NotNull(console, nameof(console)); | ||
Ensure.NotNullOrEmpty(workingDirectory, nameof(workingDirectory)); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We were applying these deltas, but I missed storing them.