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

[dotnet-watch] Separate build from run #44699

Open
wants to merge 2 commits into
base: release/9.0.2xx
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@
<!-- Dependency from https://github.com/dotnet/arcade-services -->
<MicrosoftDotNetDarcLibVersion>1.1.0-beta.24367.3</MicrosoftDotNetDarcLibVersion>
</PropertyGroup>
<PropertyGroup>
<!-- Dependency from https://github.com/dotnet/aspire -->
<AspirePackageVersion>9.1.0-preview.1.24555.3</AspirePackageVersion>
</PropertyGroup>
<PropertyGroup>
<!-- Dependency from https://github.com/dotnet/winforms -->
<MicrosoftDotnetWinFormsProjectTemplatesPackageVersion>9.0.0-rc.2.24474.1</MicrosoftDotnetWinFormsProjectTemplatesPackageVersion>
Expand Down
9 changes: 4 additions & 5 deletions src/BuiltInTools/dotnet-watch/Aspire/AspireServiceFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,11 @@ async ValueTask<string> IAspireServerEvents.StartProjectAsync(string dcpId, Proj

var projectOptions = GetProjectOptions(projectLaunchInfo);
var sessionId = Interlocked.Increment(ref _sessionIdDispenser).ToString(CultureInfo.InvariantCulture);
await StartProjectAsync(dcpId, sessionId, projectOptions, build: false, isRestart: false, cancellationToken);
await StartProjectAsync(dcpId, sessionId, projectOptions, isRestart: false, cancellationToken);
return sessionId;
}

public async ValueTask<RunningProject> StartProjectAsync(string dcpId, string sessionId, ProjectOptions projectOptions, bool build, bool isRestart, CancellationToken cancellationToken)
public async ValueTask<RunningProject> StartProjectAsync(string dcpId, string sessionId, ProjectOptions projectOptions, bool isRestart, CancellationToken cancellationToken)
{
ObjectDisposedException.ThrowIf(_isDisposed, this);

Expand All @@ -125,9 +125,8 @@ public async ValueTask<RunningProject> StartProjectAsync(string dcpId, string se
var writeResult = outputChannel.Writer.TryWrite(line);
Debug.Assert(writeResult);
},
restartOperation: (build, cancellationToken) =>
StartProjectAsync(dcpId, sessionId, projectOptions, build, isRestart: true, cancellationToken),
build: build,
restartOperation: cancellationToken =>
StartProjectAsync(dcpId, sessionId, projectOptions, isRestart: true, cancellationToken),
cancellationToken);

if (runningProject == null)
Expand Down
6 changes: 4 additions & 2 deletions src/BuiltInTools/dotnet-watch/FileItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ namespace Microsoft.DotNet.Watcher
{
internal readonly record struct FileItem
{
public string FilePath { get; init; }
public required string FilePath { get; init; }

/// <summary>
/// List of all projects that contain this file (does not contain duplicates).
/// Empty if <see cref="Change"/> is <see cref="ChangeKind.Add"/> and the
/// item has not been assigned to a project yet.
/// </summary>
public List<string> ContainingProjectPaths { get; init; }
public required List<string> ContainingProjectPaths { get; init; }

public string? StaticWebAssetPath { get; init; }

Expand Down
3 changes: 2 additions & 1 deletion src/BuiltInTools/dotnet-watch/Filters/BuildEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using System.Diagnostics;
using Microsoft.DotNet.Watcher.Internal;
using Microsoft.Extensions.Tools.Internal;

namespace Microsoft.DotNet.Watcher.Tools
{
Expand Down Expand Up @@ -87,7 +88,7 @@ private async ValueTask<EvaluationResult> CreateEvaluationResult(CancellationTok
await FileWatcher.WaitForFileChangeAsync(
rootProjectFileSetFactory.RootProjectFile,
context.Reporter,
startedWatching: () => context.Reporter.Warn("Fix the error to continue or press Ctrl+C to exit."),
startedWatching: () => context.Reporter.Report(MessageDescriptor.FixBuildError),
cancellationToken);
}
}
Expand Down
14 changes: 7 additions & 7 deletions src/BuiltInTools/dotnet-watch/HotReload/CompilationHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public async ValueTask TerminateNonRootProcessesAndDispose(CancellationToken can
Dispose();
}

public ValueTask RestartSessionAsync(IReadOnlySet<ProjectId> projectsToBeRebuilt, CancellationToken cancellationToken)
public ValueTask RestartSessionAsync(ImmutableDictionary<ProjectId, string> projectsToBeRebuilt, CancellationToken cancellationToken)
{
// Remove previous updates to all modules that were affected by rude edits.
// All running projects that statically reference these modules have been terminated.
Expand All @@ -84,7 +84,7 @@ public ValueTask RestartSessionAsync(IReadOnlySet<ProjectId> projectsToBeRebuilt

lock (_runningProjectsAndUpdatesGuard)
{
_previousUpdates = _previousUpdates.RemoveAll(update => projectsToBeRebuilt.Contains(update.ProjectId));
_previousUpdates = _previousUpdates.RemoveAll(update => projectsToBeRebuilt.ContainsKey(update.ProjectId));
}

_hotReloadService.EndSession();
Expand Down Expand Up @@ -276,7 +276,7 @@ private static void PrepareCompilations(Solution solution, string projectPath, C
}
}

public async ValueTask<(IReadOnlySet<ProjectId> projectsToBeRebuilt, IEnumerable<RunningProject> terminatedProjects)> HandleFileChangesAsync(
public async ValueTask<(ImmutableDictionary<ProjectId, string> projectsToRebuild, ImmutableArray<RunningProject> terminatedProjects)> HandleFileChangesAsync(
Func<IEnumerable<Project>, CancellationToken, Task> restartPrompt,
CancellationToken cancellationToken)
{
Expand All @@ -292,14 +292,14 @@ private static void PrepareCompilations(Solution solution, string projectPath, C
{
// If Hot Reload is blocked (due to compilation error) we ignore the current
// changes and await the next file change.
return (ImmutableHashSet<ProjectId>.Empty, []);
return (ImmutableDictionary<ProjectId, string>.Empty, []);
}

if (updates.Status == ModuleUpdateStatus.RestartRequired)
{
if (!anyProcessNeedsRestart)
{
return (ImmutableHashSet<ProjectId>.Empty, []);
return (ImmutableDictionary<ProjectId, string>.Empty, []);
}

await restartPrompt.Invoke(updates.ProjectsToRestart, cancellationToken);
Expand All @@ -308,7 +308,7 @@ private static void PrepareCompilations(Solution solution, string projectPath, C
// except for the root process, which will terminate later on.
var terminatedProjects = await TerminateNonRootProcessesAsync(updates.ProjectsToRestart.Select(p => p.FilePath!), cancellationToken);

return (updates.ProjectsToRebuild.Select(p => p.Id).ToHashSet(), terminatedProjects);
return (updates.ProjectsToRebuild.ToImmutableDictionary(keySelector: p => p.Id, elementSelector: p => p.FilePath!), terminatedProjects);
}

Debug.Assert(updates.Status == ModuleUpdateStatus.Ready);
Expand Down Expand Up @@ -348,7 +348,7 @@ await ForEachProjectAsync(projectsToUpdate, async (runningProject, cancellationT
}
}, cancellationToken);

return (ImmutableHashSet<ProjectId>.Empty, []);
return (ImmutableDictionary<ProjectId, string>.Empty, []);
}

private async ValueTask DisplayResultsAsync(WatchHotReloadService.Updates updates, CancellationToken cancellationToken)
Expand Down
5 changes: 1 addition & 4 deletions src/BuiltInTools/dotnet-watch/HotReload/ProjectLauncher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ public EnvironmentOptions EnvironmentOptions
CancellationTokenSource processTerminationSource,
Action<OutputLine>? onOutput,
RestartOperation restartOperation,
bool build,
CancellationToken cancellationToken)
{
var projectNode = projectMap.TryGetProjectNode(projectOptions.ProjectPath, projectOptions.TargetFramework);
Expand All @@ -58,9 +57,7 @@ public EnvironmentOptions EnvironmentOptions
Executable = EnvironmentOptions.MuxerPath,
WorkingDirectory = projectOptions.WorkingDirectory,
OnOutput = onOutput,
Arguments = build || !CommandLineOptions.IsCodeExecutionCommand(projectOptions.Command)
? [projectOptions.Command, .. projectOptions.CommandArguments]
: [projectOptions.Command, "--no-build", .. projectOptions.CommandArguments]
Arguments = [projectOptions.Command, "--no-build", .. projectOptions.CommandArguments]
};

var environmentBuilder = EnvironmentVariablesBuilder.FromCurrentEnvironment();
Expand Down
1 change: 1 addition & 0 deletions src/BuiltInTools/dotnet-watch/HotReload/ProjectNodeMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ internal readonly struct ProjectNodeMap(ProjectGraph graph, IReporter reporter)
{
public readonly ProjectGraph Graph = graph;

// full path of proj file to list of nodes representing all target frameworks of the project:
public readonly IReadOnlyDictionary<string, IReadOnlyList<ProjectGraphNode>> Map =
graph.ProjectNodes.GroupBy(n => n.ProjectInstance.FullPath).ToDictionary(
keySelector: static g => g.Key,
Expand Down
3 changes: 1 addition & 2 deletions src/BuiltInTools/dotnet-watch/HotReload/RunningProject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace Microsoft.DotNet.Watcher.Tools
{
internal delegate ValueTask<RunningProject> RestartOperation(bool build, CancellationToken cancellationToken);
internal delegate ValueTask<RunningProject> RestartOperation(CancellationToken cancellationToken);

internal sealed class RunningProject(
ProjectGraphNode projectNode,
Expand Down Expand Up @@ -68,7 +68,6 @@ public void Dispose()
public async ValueTask WaitForProcessRunningAsync(CancellationToken cancellationToken)
{
await DeltaApplier.WaitForProcessRunningAsync(cancellationToken);
Reporter.Report(MessageDescriptor.BuildCompleted);
}
}
}
Loading
Loading