Skip to content
Draft
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
23 changes: 9 additions & 14 deletions src/BuiltInTools/Watch/Browser/BrowserLauncher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@

using System.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using Microsoft.Build.Graph;
using Microsoft.DotNet.HotReload;
using Microsoft.DotNet.ProjectTools;
using Microsoft.Extensions.Logging;

namespace Microsoft.DotNet.Watch;
Expand All @@ -26,7 +25,7 @@ public void InstallBrowserLaunchTrigger(
AbstractBrowserRefreshServer? server,
CancellationToken cancellationToken)
{
if (!CanLaunchBrowser(projectOptions, out var launchProfile))
if (!CanLaunchBrowser(projectOptions, out var profileLaunchUrl))
{
if (environmentOptions.TestFlags.HasFlag(TestFlags.MockBrowser))
{
Expand All @@ -42,7 +41,7 @@ public void InstallBrowserLaunchTrigger(
ImmutableInterlocked.Update(ref _browserLaunchAttempted, static (set, key) => set.Add(key), projectNode.GetProjectInstanceId()))
{
// first build iteration of a root project:
var launchUrl = GetLaunchUrl(launchProfile.LaunchUrl, url);
var launchUrl = GetLaunchUrl(profileLaunchUrl, url);
LaunchBrowser(launchUrl, server);
}
else if (server != null)
Expand Down Expand Up @@ -99,9 +98,9 @@ private void LaunchBrowser(string launchUrl, AbstractBrowserRefreshServer? serve
}
}

private bool CanLaunchBrowser(ProjectOptions projectOptions, [NotNullWhen(true)] out LaunchSettingsProfile? launchProfile)
private bool CanLaunchBrowser(ProjectOptions projectOptions, out string? launchUrl)
{
launchProfile = null;
launchUrl = null;

if (environmentOptions.SuppressLaunchBrowser)
{
Expand All @@ -114,20 +113,16 @@ private bool CanLaunchBrowser(ProjectOptions projectOptions, [NotNullWhen(true)]
return false;
}

launchProfile = GetLaunchProfile(projectOptions);
if (launchProfile is not { LaunchBrowser: true })
var launchProfile = projectOptions.GetLaunchProfile(logger);
if (launchProfile is not ProjectLaunchProfile { LaunchBrowser: true, LaunchUrl: var url})
{
logger.LogDebug("launchSettings does not allow launching browsers.");
return false;
}

logger.Log(MessageDescriptor.ConfiguredToLaunchBrowser);
return true;
}

private LaunchSettingsProfile GetLaunchProfile(ProjectOptions projectOptions)
{
return (projectOptions.NoLaunchProfile == true
? null : LaunchSettingsProfile.ReadLaunchProfile(projectOptions.ProjectPath, projectOptions.LaunchProfileName, logger)) ?? new();
launchUrl = url;
return true;
}
}
2 changes: 2 additions & 0 deletions src/BuiltInTools/Watch/Build/BuildNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ internal static class TargetNames
{
public const string Compile = nameof(Compile);
public const string Restore = nameof(Restore);
public const string CompileDesignTime = nameof(CompileDesignTime);
public const string GenerateComputedBuildStaticWebAssets = nameof(GenerateComputedBuildStaticWebAssets);
public const string ReferenceCopyLocalPathsOutputGroup = nameof(ReferenceCopyLocalPathsOutputGroup);
}
Expand All @@ -54,4 +55,5 @@ internal static class ProjectCapability
public const string Aspire = nameof(Aspire);
public const string AspNetCore = nameof(AspNetCore);
public const string WebAssembly = nameof(WebAssembly);
public const string SupportsHotReload = nameof(SupportsHotReload);
}
12 changes: 8 additions & 4 deletions src/BuiltInTools/Watch/Build/EvaluationResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,13 @@ public static ImmutableDictionary<string, string> GetGlobalBuildOptions(IEnumera
// populated by design-time build.
var projectInstance = project.ProjectInstance.DeepCopy();

// skip outer build project nodes:
if (projectInstance.GetPropertyValue(PropertyNames.TargetFramework) == "")
var compileTarget = projectInstance.Targets.ContainsKey(TargetNames.CompileDesignTime)
? TargetNames.CompileDesignTime
: projectInstance.Targets.ContainsKey(TargetNames.Compile)
? TargetNames.Compile
: null;

if (compileTarget == null)
{
continue;
}
Expand All @@ -105,7 +110,7 @@ public static ImmutableDictionary<string, string> GetGlobalBuildOptions(IEnumera

using (var loggers = buildReporter.GetLoggers(projectInstance.FullPath, "DesignTimeBuild"))
{
if (!projectInstance.Build([TargetNames.Compile, .. customCollectWatchItems], loggers))
if (!projectInstance.Build([compileTarget, .. customCollectWatchItems], loggers))
{
logger.LogError("Failed to build project '{Path}'.", projectInstance.FullPath);
loggers.ReportOutput();
Expand All @@ -116,7 +121,6 @@ public static ImmutableDictionary<string, string> GetGlobalBuildOptions(IEnumera
var projectPath = projectInstance.FullPath;
var projectDirectory = Path.GetDirectoryName(projectPath)!;

// TODO: Compile and AdditionalItems should be provided by Roslyn
var items = projectInstance.GetItems(ItemNames.Compile)
.Concat(projectInstance.GetItems(ItemNames.AdditionalFiles))
.Concat(projectInstance.GetItems(ItemNames.Watch));
Expand Down
44 changes: 44 additions & 0 deletions src/BuiltInTools/Watch/Context/ProjectOptions.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.CompilerServices;
using Microsoft.DotNet.ProjectTools;
using Microsoft.Extensions.Logging;

namespace Microsoft.DotNet.Watch;

internal sealed record ProjectOptions
{
private StrongBox<LaunchProfile?>? _lazyLaunchProfile;

public required bool IsRootProject { get; init; }
public required string ProjectPath { get; init; }
public required string WorkingDirectory { get; init; }
Expand Down Expand Up @@ -33,4 +39,42 @@ internal sealed record ProjectOptions
/// </summary>
public bool IsCodeExecutionCommand
=> Command is "run" or "test";

public LaunchProfile? GetLaunchProfile(ILogger logger)
{
return (_lazyLaunchProfile ??= new StrongBox<LaunchProfile?>(ReadProfile())).Value;

LaunchProfile? ReadProfile()
{
if (NoLaunchProfile)
{
return null;
}

var launchSettingsPath = LaunchSettings.TryFindLaunchSettingsFile(ProjectPath, LaunchProfileName, (message, isError) =>
{
if (isError)
{
logger.LogError(message);
}
else
{
logger.LogWarning(message);
}
});

if (launchSettingsPath == null)
{
return null;
}

var result = LaunchSettings.ReadProfileSettingsFromFile(launchSettingsPath, LaunchProfileName);
if (result.FailureReason != null)
{
logger.LogError("Failed to read launch settings from '{LaunchSettingsPath}': {FailureReason}", launchSettingsPath, result.FailureReason);
}

return result.Profile;
}
}
}
4 changes: 3 additions & 1 deletion src/BuiltInTools/Watch/HotReload/HotReloadDotNetWatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Microsoft.Build.Graph;
using Microsoft.CodeAnalysis;
using Microsoft.DotNet.HotReload;
using Microsoft.DotNet.ProjectTools;
using Microsoft.Extensions.Logging;

namespace Microsoft.DotNet.Watch
Expand Down Expand Up @@ -246,7 +247,8 @@ void FileChangedCallback(ChangedPath change)
continue;
}

if (!rootProjectCapabilities.Contains("SupportsHotReload"))
if (rootProjectOptions.GetLaunchProfile(_context.Logger) is not ExecutableLaunchProfile &&
!rootProjectCapabilities.Contains(ProjectCapability.SupportsHotReload))
{
_context.Logger.LogWarning("Project '{Name}' does not support Hot Reload and must be rebuilt.", rootProject.GetDisplayName());

Expand Down
120 changes: 0 additions & 120 deletions src/BuiltInTools/Watch/Process/LaunchSettingsProfile.cs

This file was deleted.

8 changes: 7 additions & 1 deletion src/BuiltInTools/Watch/Process/ProjectLauncher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Globalization;
using Microsoft.DotNet.HotReload;
using Microsoft.DotNet.ProjectTools;
using Microsoft.Extensions.Logging;

namespace Microsoft.DotNet.Watch;
Expand Down Expand Up @@ -41,7 +42,12 @@ public EnvironmentOptions EnvironmentOptions
return null;
}

if (!projectNode.IsNetCoreApp(Versions.Version6_0))
var launchProfile = projectOptions.GetLaunchProfile(context.Logger);

// TODO: extract TFM from Exe
// If an executable profile is being used to launch the application the TFM of the project is irrelevant.
if (launchProfile is not ExecutableLaunchProfile &&
!projectNode.IsNetCoreApp(Versions.Version6_0))
{
Logger.LogError($"Hot Reload based watching is only supported in .NET 6.0 or newer apps. Use --no-hot-reload switch or update the project's launchSettings.json to disable this feature.");
return null;
Expand Down
4 changes: 2 additions & 2 deletions src/BuiltInTools/dotnet-watch/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"dotnet-watch": {
"commandName": "Project",
"commandLineArgs": "--verbose -bl",
"workingDirectory": "C:\\bugs\\9756\\aspire-watch-start-issue\\Aspire.AppHost",
"workingDirectory": "C:\\Temp\\Traversal",
"environmentVariables": {
"DOTNET_WATCH_DEBUG_SDK_DIRECTORY": "$(RepoRoot)artifacts\\bin\\redist\\$(Configuration)\\dotnet\\sdk\\$(Version)",
"DCP_IDE_REQUEST_TIMEOUT_SECONDS": "100000",
Expand All @@ -13,4 +13,4 @@
}
}
}
}
}
Loading
Loading