Skip to content

Commit af64d64

Browse files
authored
Better organize dotnet-watch source files and clean up (#49524)
1 parent 2488777 commit af64d64

File tree

86 files changed

+247
-295
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+247
-295
lines changed

src/BuiltInTools/DotNetWatchTasks/DotNetWatchTasks.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</ItemGroup>
1111

1212
<ItemGroup>
13-
<Compile Include="..\dotnet-watch\Internal\MSBuildFileSetResult.cs" />
13+
<Compile Include="..\dotnet-watch\Build\MSBuildFileSetResult.cs" />
1414
</ItemGroup>
1515

1616
</Project>

src/BuiltInTools/dotnet-watch/Internal/MsBuildFileSetFactory.cs renamed to src/BuiltInTools/dotnet-watch/Build/MsBuildFileSetFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ internal class MSBuildFileSetFactory(
6868
reporter.Output($"MSBuild output from target '{TargetName}':");
6969
}
7070

71-
BuildUtilities.ReportBuildOutput(reporter, capturedOutput, success, projectDisplay: null);
71+
BuildOutput.ReportBuildOutput(reporter, capturedOutput, success, projectDisplay: null);
7272
if (!success)
7373
{
7474
return null;

src/BuiltInTools/dotnet-watch/DotNetWatchContext.cs renamed to src/BuiltInTools/dotnet-watch/CommandLine/DotNetWatchContext.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,13 @@ internal sealed class DotNetWatchContext
1212
public required ProcessRunner ProcessRunner { get; init; }
1313

1414
public required ProjectOptions RootProjectOptions { get; init; }
15+
16+
public MSBuildFileSetFactory CreateMSBuildFileSetFactory()
17+
=> new(
18+
RootProjectOptions.ProjectPath,
19+
RootProjectOptions.BuildArguments,
20+
EnvironmentOptions,
21+
ProcessRunner,
22+
Reporter);
1523
}
1624
}

src/BuiltInTools/dotnet-watch/HotReloadDotNetWatcher.cs renamed to src/BuiltInTools/dotnet-watch/HotReload/HotReloadDotNetWatcher.cs

Lines changed: 55 additions & 51 deletions
Large diffs are not rendered by default.

src/BuiltInTools/dotnet-watch/Internal/Ensure.cs

Lines changed: 0 additions & 27 deletions
This file was deleted.

src/BuiltInTools/dotnet-watch/Internal/MsBuildProjectFinder.cs

Lines changed: 0 additions & 53 deletions
This file was deleted.

src/BuiltInTools/dotnet-watch/Internal/ReporterTraceListener.cs

Lines changed: 0 additions & 21 deletions
This file was deleted.

src/BuiltInTools/dotnet-watch/Internal/ProcessRunner.cs renamed to src/BuiltInTools/dotnet-watch/Process/ProcessRunner.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ private sealed class ProcessState
2525
/// <param name="isUserApplication">True if the process is a user application, false if it is a helper process (e.g. msbuild).</param>
2626
public async Task<int> RunAsync(ProcessSpec processSpec, IReporter reporter, bool isUserApplication, ProcessLaunchResult? launchResult, CancellationToken processTerminationToken)
2727
{
28-
Ensure.NotNull(processSpec, nameof(processSpec));
29-
3028
var state = new ProcessState();
3129
var stopwatch = new Stopwatch();
3230

src/BuiltInTools/dotnet-watch/Program.cs

Lines changed: 81 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Diagnostics.CodeAnalysis;
5+
using System.Globalization;
46
using System.Runtime.Loader;
57
using Microsoft.Build.Locator;
68

@@ -76,14 +78,8 @@ public static async Task<int> Main(string[] args)
7678
reporter.Verbose($"Test flags: {environmentOptions.TestFlags}");
7779
}
7880

79-
string projectPath;
80-
try
81-
{
82-
projectPath = MsBuildProjectFinder.FindMsBuildProject(workingDirectory, options.ProjectPath);
83-
}
84-
catch (FileNotFoundException ex)
81+
if (!TryFindProject(workingDirectory, options, reporter, out var projectPath))
8582
{
86-
reporter.Error(ex.Message);
8783
errorCode = 1;
8884
return null;
8985
}
@@ -93,6 +89,51 @@ public static async Task<int> Main(string[] args)
9389
return new Program(console, reporter, rootProjectOptions, options, environmentOptions);
9490
}
9591

92+
/// <summary>
93+
/// Finds a compatible MSBuild project.
94+
/// <param name="searchBase">The base directory to search</param>
95+
/// <param name="project">The filename of the project. Can be null.</param>
96+
/// </summary>
97+
private static bool TryFindProject(string searchBase, CommandLineOptions options, IReporter reporter, [NotNullWhen(true)] out string? projectPath)
98+
{
99+
projectPath = options.ProjectPath ?? searchBase;
100+
101+
if (!Path.IsPathRooted(projectPath))
102+
{
103+
projectPath = Path.Combine(searchBase, projectPath);
104+
}
105+
106+
if (Directory.Exists(projectPath))
107+
{
108+
var projects = Directory.EnumerateFileSystemEntries(projectPath, "*.*proj", SearchOption.TopDirectoryOnly)
109+
.Where(f => !".xproj".Equals(Path.GetExtension(f), StringComparison.OrdinalIgnoreCase))
110+
.ToList();
111+
112+
if (projects.Count > 1)
113+
{
114+
reporter.Error(string.Format(CultureInfo.CurrentCulture, Resources.Error_MultipleProjectsFound, projectPath));
115+
return false;
116+
}
117+
118+
if (projects.Count == 0)
119+
{
120+
reporter.Error(string.Format(CultureInfo.CurrentCulture, Resources.Error_NoProjectsFound, projectPath));
121+
return false;
122+
}
123+
124+
projectPath = projects[0];
125+
return true;
126+
}
127+
128+
if (!File.Exists(projectPath))
129+
{
130+
reporter.Error(string.Format(CultureInfo.CurrentCulture, Resources.Error_ProjectPath_NotFound, projectPath));
131+
return false;
132+
}
133+
134+
return true;
135+
}
136+
96137
// internal for testing
97138
internal async Task<int> RunAsync()
98139
{
@@ -132,8 +173,23 @@ internal async Task<int> RunAsync()
132173
return await ListFilesAsync(processRunner, shutdownCancellationToken);
133174
}
134175

135-
var watcher = CreateWatcher(processRunner, runtimeProcessLauncherFactory: null);
136-
await watcher.WatchAsync(shutdownCancellationToken);
176+
if (environmentOptions.IsPollingEnabled)
177+
{
178+
reporter.Output("Polling file watcher is enabled");
179+
}
180+
181+
var context = CreateContext(processRunner);
182+
183+
if (IsHotReloadEnabled())
184+
{
185+
var watcher = new HotReloadDotNetWatcher(context, console, runtimeProcessLauncherFactory: null);
186+
await watcher.WatchAsync(shutdownCancellationToken);
187+
}
188+
else
189+
{
190+
await DotNetWatcher.WatchAsync(context, shutdownCancellationToken);
191+
}
192+
137193
return 0;
138194
}
139195
catch (OperationCanceledException) when (shutdownCancellationToken.IsCancellationRequested)
@@ -155,49 +211,32 @@ internal async Task<int> RunAsync()
155211
}
156212

157213
// internal for testing
158-
internal Watcher CreateWatcher(ProcessRunner processRunner, IRuntimeProcessLauncherFactory? runtimeProcessLauncherFactory)
159-
{
160-
if (environmentOptions.IsPollingEnabled)
214+
internal DotNetWatchContext CreateContext(ProcessRunner processRunner)
215+
=> new()
161216
{
162-
reporter.Output("Polling file watcher is enabled");
163-
}
164-
165-
var fileSetFactory = new MSBuildFileSetFactory(
166-
rootProjectOptions.ProjectPath,
167-
rootProjectOptions.BuildArguments,
168-
environmentOptions,
169-
processRunner,
170-
reporter);
217+
Reporter = reporter,
218+
ProcessRunner = processRunner,
219+
Options = options.GlobalOptions,
220+
EnvironmentOptions = environmentOptions,
221+
RootProjectOptions = rootProjectOptions,
222+
};
171223

172-
bool enableHotReload;
224+
private bool IsHotReloadEnabled()
225+
{
173226
if (rootProjectOptions.Command != "run")
174227
{
175228
reporter.Verbose($"Command '{rootProjectOptions.Command}' does not support Hot Reload.");
176-
enableHotReload = false;
229+
return false;
177230
}
178-
else if (options.GlobalOptions.NoHotReload)
231+
232+
if (options.GlobalOptions.NoHotReload)
179233
{
180234
reporter.Verbose("Hot Reload disabled by command line switch.");
181-
enableHotReload = false;
235+
return false;
182236
}
183-
else
184-
{
185-
reporter.Report(MessageDescriptor.WatchingWithHotReload);
186-
enableHotReload = true;
187-
}
188-
189-
var context = new DotNetWatchContext
190-
{
191-
Reporter = reporter,
192-
ProcessRunner = processRunner,
193-
Options = options.GlobalOptions,
194-
EnvironmentOptions = environmentOptions,
195-
RootProjectOptions = rootProjectOptions,
196-
};
197237

198-
return enableHotReload
199-
? new HotReloadDotNetWatcher(context, console, fileSetFactory, runtimeProcessLauncherFactory)
200-
: new DotNetWatcher(context, fileSetFactory);
238+
reporter.Report(MessageDescriptor.WatchingWithHotReload);
239+
return true;
201240
}
202241

203242
private async Task<int> ListFilesAsync(ProcessRunner processRunner, CancellationToken cancellationToken)

src/BuiltInTools/dotnet-watch/Utilities/BuildUtilities.cs renamed to src/BuiltInTools/dotnet-watch/UI/BuildOutput.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
namespace Microsoft.DotNet.Watch;
77

8-
internal static partial class BuildUtilities
8+
internal static partial class BuildOutput
99
{
1010
private const string BuildEmoji = "🔨";
1111
private static readonly Regex s_buildDiagnosticRegex = GetBuildDiagnosticRegex();

0 commit comments

Comments
 (0)