示例#1
0
        public async Task ProcessAsync_AddsNoRestoreSwitch()
        {
            // Arrange
            var filter = new NoRestoreFilter();

            var context = new DotNetWatchContext
            {
                Iteration   = 0,
                ProcessSpec = new ProcessSpec
                {
                    Arguments = _arguments,
                }
            };
            await filter.ProcessAsync(context, default);

            context.ChangedFile = new FileItem {
                FilePath = "Program.cs"
            };
            context.Iteration++;

            // Act
            await filter.ProcessAsync(context, default);

            // Assert
            Assert.Equal(new[] { "run", "--no-restore" }, context.ProcessSpec.Arguments);
        }
示例#2
0
        public async ValueTask ProcessAsync(DotNetWatchContext context, CancellationToken cancellationToken)
        {
            using var fileSetWatcher = new FileSetWatcher(context.FileSet, _reporter);
            while (!cancellationToken.IsCancellationRequested)
            {
                var arguments = context.RequiresMSBuildRevaluation ?
                                new[] { "msbuild", "/t:Build", "/restore", "/nologo" } :
                new[] { "msbuild", "/t:Build", "/nologo" };

                var processSpec = new ProcessSpec
                {
                    Executable       = _muxer,
                    Arguments        = arguments,
                    WorkingDirectory = context.ProcessSpec.WorkingDirectory,
                };

                _reporter.Output("Building...");
                var exitCode = await _processRunner.RunAsync(processSpec, cancellationToken);

                if (exitCode == 0)
                {
                    return;
                }

                // If the build fails, we'll retry until we have a successful build.
                context.ChangedFile = await fileSetWatcher.GetChangedFileAsync(cancellationToken, () => _reporter.Warn("Waiting for a file to change before restarting dotnet..."));
            }
        }
示例#3
0
        public async ValueTask TryHandleFileAction_CausesBrowserRefreshForNonCssFile()
        {
            // Arrange
            var server = new Mock <BrowserRefreshServer>(NullReporter.Singleton);

            byte[] writtenBytes = null;
            server.Setup(s => s.SendMessage(It.IsAny <byte[]>(), It.IsAny <CancellationToken>()))
            .Callback((byte[] bytes, CancellationToken cts) =>
            {
                writtenBytes = bytes;
            });
            var fileContentHandler = new FileChangeHandler(NullReporter.Singleton);
            var context            = new DotNetWatchContext
            {
                BrowserRefreshServer = server.Object,
            };
            var file = new FileItem {
                FilePath = "Test.js", IsStaticFile = true, StaticWebAssetPath = "Test.js"
            };

            // Act
            var result = await fileContentHandler.TryHandleFileAction(context, file, default);

            // Assert
            Assert.True(result);
            Assert.NotNull(writtenBytes);
            var deserialized = JsonSerializer.Deserialize <UpdateStaticFileMessage>(writtenBytes, new JsonSerializerOptions(JsonSerializerDefaults.Web));

            Assert.Equal("UpdateStaticFile", deserialized.Type);
            Assert.Equal("content/Test.js", deserialized.Path);
        }
示例#4
0
        public async ValueTask ProcessAsync(DotNetWatchContext context, CancellationToken cancellationToken)
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                var arguments = context.Iteration == 0 || (context.ChangedFile?.FilePath is string changedFile && changedFile.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase)) ?
                                new[] { "msbuild", "/t:Build", "/restore", "/nologo" } :
                new[] { "msbuild", "/t:Build", "/nologo" };

                var processSpec = new ProcessSpec
                {
                    Executable       = _muxer,
                    Arguments        = arguments,
                    WorkingDirectory = context.ProcessSpec.WorkingDirectory,
                };

                _reporter.Output("Building...");
                var exitCode = await _processRunner.RunAsync(processSpec, cancellationToken);

                context.FileSet = await _fileSetFactory.CreateAsync(cancellationToken);

                if (exitCode == 0)
                {
                    return;
                }

                // If the build fails, we'll retry until we have a successful build.
                using var fileSetWatcher = new FileSetWatcher(context.FileSet, _reporter);
                await fileSetWatcher.GetChangedFileAsync(cancellationToken, () => _reporter.Warn("Waiting for a file to change before restarting dotnet..."));
            }
        }
示例#5
0
        public async Task ProcessAsync_AddsNoRestoreSwitch_WithAdditionalArguments()
        {
            // Arrange
            var filter = new NoRestoreFilter();

            var context = new DotNetWatchContext
            {
                Iteration   = 0,
                ProcessSpec = new ProcessSpec
                {
                    Arguments = new[] { "run", "-f", ToolsetInfo.CurrentTargetFramework, "--", "foo=bar" },
                }
            };
            await filter.ProcessAsync(context, default);

            context.ChangedFile = new FileItem {
                FilePath = "Program.cs"
            };
            context.Iteration++;

            // Act
            await filter.ProcessAsync(context, default);

            // Assert
            Assert.Equal(new[] { "run", "--no-restore", "-f", ToolsetInfo.CurrentTargetFramework, "--", "foo=bar" }, context.ProcessSpec.Arguments);
        }
示例#6
0
 public async ValueTask <bool> TryHandleFileChange(DotNetWatchContext context, FileItem file, CancellationToken cancellationToken)
 {
     return
         (await _staticFileHandler.TryHandleFileChange(context, file, cancellationToken) ||
          await _scopedCssFileHandler.TryHandleFileChange(context, file, cancellationToken) ||
          await _compilationHandler.TryHandleFileChange(context, file, cancellationToken));
 }
示例#7
0
        private static bool CanLaunchBrowser(DotNetWatchContext context, out string launchUrl)
        {
            launchUrl = null;
            var reporter = context.Reporter;

            if (!context.FileSet.IsNetCoreApp31OrNewer)
            {
                // Browser refresh middleware supports 3.1 or newer
                reporter.Verbose("Browser refresh is only supported in .NET Core 3.1 or newer projects.");
                return(false);
            }

            var dotnetCommand = context.ProcessSpec.Arguments.FirstOrDefault();

            if (!string.Equals(dotnetCommand, "run", StringComparison.Ordinal))
            {
                reporter.Verbose("Browser refresh is only supported for run commands.");
                return(false);
            }

            // We're executing the run-command. Determine if the launchSettings allows it
            var launchSettingsPath = Path.Combine(context.ProcessSpec.WorkingDirectory, "Properties", "launchSettings.json");

            if (!File.Exists(launchSettingsPath))
            {
                reporter.Verbose($"No launchSettings.json file found at {launchSettingsPath}. Unable to determine if browser refresh is allowed.");
                return(false);
            }

            LaunchSettingsJson launchSettings;

            try
            {
                launchSettings = JsonSerializer.Deserialize <LaunchSettingsJson>(
                    File.ReadAllText(launchSettingsPath),
                    new JsonSerializerOptions(JsonSerializerDefaults.Web));
            }
            catch (Exception ex)
            {
                reporter.Verbose($"Error reading launchSettings.json: {ex}.");
                return(false);
            }

            var defaultProfile = launchSettings.Profiles.FirstOrDefault(f => f.Value.CommandName == "Project").Value;

            if (defaultProfile is null)
            {
                reporter.Verbose("Unable to find default launchSettings profile.");
                return(false);
            }

            if (!defaultProfile.LaunchBrowser)
            {
                reporter.Verbose("launchSettings does not allow launching browsers.");
                return(false);
            }

            launchUrl = defaultProfile.LaunchUrl;
            return(true);
        }
示例#8
0
        public async Task ProcessAsync_DoesNotModifyArgumentsForUnknownCommands()
        {
            // Arrange
            var filter    = new NoRestoreFilter();
            var arguments = new[] { "ef", "database", "update" };

            var context = new DotNetWatchContext
            {
                Iteration   = 0,
                ProcessSpec = new ProcessSpec
                {
                    Arguments = arguments,
                }
            };
            await filter.ProcessAsync(context, default);

            context.ChangedFile = new FileItem {
                FilePath = "Program.cs"
            };
            context.Iteration++;

            // Act
            await filter.ProcessAsync(context, default);

            // Assert
            Assert.Same(arguments, context.ProcessSpec.Arguments);
        }
示例#9
0
        public async Task InitializeAsync_ConfiguresEnvironmentVariables()
        {
            // Arrange
            var applier = new DefaultDeltaApplier(Mock.Of <IReporter>())
            {
                SuppressNamedPipeForTests = true
            };
            var process = new ProcessSpec();
            var fileSet = new FileSet(null, new[]
            {
                new FileItem {
                    FilePath = "Test.cs"
                },
            });
            var context = new DotNetWatchContext {
                ProcessSpec = process, FileSet = fileSet, Iteration = 0
            };

            // Act
            await applier.InitializeAsync(context, default);

            // Assert
            Assert.Equal("debug", process.EnvironmentVariables["DOTNET_MODIFIABLE_ASSEMBLIES"]);
            Assert.NotEmpty(process.EnvironmentVariables["DOTNET_HOTRELOAD_NAMEDPIPE_NAME"]);
            Assert.NotEmpty(process.EnvironmentVariables.DotNetStartupHooks);
        }
示例#10
0
        public async Task ProcessAsync_LeavesArgumentsUnchangedIfMsBuildRevaluationIsRequired()
        {
            // Arrange
            var filter = new NoRestoreFilter();

            var context = new DotNetWatchContext
            {
                Iteration   = 0,
                ProcessSpec = new ProcessSpec
                {
                    Arguments = _arguments,
                }
            };
            await filter.ProcessAsync(context, default);

            context.ChangedFile = new FileItem {
                FilePath = "Test.proj"
            };
            context.RequiresMSBuildRevaluation = true;
            context.Iteration++;

            // Act
            await filter.ProcessAsync(context, default);

            // Assert
            Assert.Same(_arguments, context.ProcessSpec.Arguments);
        }
示例#11
0
        public async Task ProcessAsync_LeavesArgumentsUnchangedIfOptimizationIsSuppressed()
        {
            // Arrange
            var filter = new NoRestoreFilter();

            var context = new DotNetWatchContext
            {
                Iteration   = 0,
                ProcessSpec = new ProcessSpec
                {
                    Arguments = _arguments,
                },
                SuppressMSBuildIncrementalism = true,
            };
            await filter.ProcessAsync(context, default);

            context.ChangedFile = new FileItem {
                FilePath = "Program.cs"
            };
            context.Iteration++;

            // Act
            await filter.ProcessAsync(context, default);

            // Assert
            Assert.Same(_arguments, context.ProcessSpec.Arguments);
        }
示例#12
0
        public async Task ProcessAsync_SetsEvaluationRequired_IfMSBuildFileChanges_ButIsNotChangedFile()
        {
            // There's a chance that the watcher does not correctly report edits to msbuild files on
            // concurrent edits. MSBuildEvaluationFilter uses timestamps to additionally track changes to these files.

            // Arrange
            var fileSet        = new FileSet(new[] { "Controlller.cs", "Proj.csproj" });
            var fileSetFactory = Mock.Of <IFileSetFactory>(f => f.CreateAsync(It.IsAny <CancellationToken>()) == Task.FromResult <IFileSet>(fileSet));

            var filter = new TestableMSBuildEvaluationFilter(fileSetFactory)
            {
                Timestamps =
                {
                    ["Controller.cs"] = new DateTime(1000),
                    ["Proj.csproj"]   = new DateTime(1000),
                }
            };
            var context = new DotNetWatchContext
            {
                Iteration = 0,
            };

            await filter.ProcessAsync(context, default);

            context.RequiresMSBuildRevaluation = false;
            context.ChangedFile = "Controller.cs";
            context.Iteration++;
            filter.Timestamps["Proj.csproj"] = new DateTime(1007);

            // Act
            await filter.ProcessAsync(context, default);

            // Assert
            Assert.True(context.RequiresMSBuildRevaluation);
        }
示例#13
0
        public async Task ProcessAsync_EvaluateFileSetOnEveryChangeIfOptimizationIsSuppressed()
        {
            // Arrange
            var filter  = new MSBuildEvaluationFilter(_fileSetFactory);
            var context = new DotNetWatchContext
            {
                Iteration = 0,
                SuppressMSBuildIncrementalism = true,
            };

            await filter.ProcessAsync(context, default);

            context.Iteration++;
            context.ChangedFile = new FileItem {
                FilePath = "Controller.cs"
            };
            context.RequiresMSBuildRevaluation = false;

            // Act
            await filter.ProcessAsync(context, default);

            // Assert
            Assert.True(context.RequiresMSBuildRevaluation);
            Mock.Get(_fileSetFactory).Verify(v => v.CreateAsync(It.IsAny <CancellationToken>()), Times.Exactly(2));
        }
示例#14
0
 public async ValueTask <bool> TryHandleFileChange(DotNetWatchContext context, FileItem file, CancellationToken cancellationToken)
 {
     HotReloadEventSource.Log.HotReloadStart(HotReloadEventSource.StartType.ScopedCssHandler);
     if (!file.FilePath.EndsWith(".razor.css", StringComparison.Ordinal) &&
         !file.FilePath.EndsWith(".cshtml.css", StringComparison.Ordinal))
     {
         HotReloadEventSource.Log.HotReloadEnd(HotReloadEventSource.StartType.ScopedCssHandler);
         return(default);
        public async Task <ImmutableArray <string> > GetApplyUpdateCapabilitiesAsync(DotNetWatchContext context, CancellationToken cancellationToken)
        {
            var result = await Task.WhenAll(
                _wasmApplier.GetApplyUpdateCapabilitiesAsync(context, cancellationToken),
                _hostApplier.GetApplyUpdateCapabilitiesAsync(context, cancellationToken));

            return(result[0].Intersect(result[1], StringComparer.OrdinalIgnoreCase).ToImmutableArray());
        }
示例#16
0
        public async ValueTask <bool> TryHandleFileChange(DotNetWatchContext context, FileItem file, CancellationToken cancellationToken)
        {
            HotReloadEventSource.Log.HotReloadStart(HotReloadEventSource.StartType.Main);
            var fileHandlerResult = await _staticFileHandler.TryHandleFileChange(context, file, cancellationToken) ||
                                    await _scopedCssFileHandler.TryHandleFileChange(context, file, cancellationToken) ||
                                    await _compilationHandler.TryHandleFileChange(context, file, cancellationToken);

            HotReloadEventSource.Log.HotReloadEnd(HotReloadEventSource.StartType.Main);
            return(fileHandlerResult);
        }
        public async ValueTask ReportDiagnosticsAsync(DotNetWatchContext context, IEnumerable <string> diagnostics, CancellationToken cancellationToken)
        {
            if (context.BrowserRefreshServer != null)
            {
                var message = new HotReloadDiagnostics
                {
                    Diagnostics = diagnostics
                };

                await context.BrowserRefreshServer.SendJsonSerlialized(message, cancellationToken);
            }
        }
示例#18
0
        public async ValueTask <bool> TryHandleFileChange(DotNetWatchContext context, FileItem file, CancellationToken cancellationToken)
        {
            if (await _staticFileHandler.TryHandleFileChange(context, file, cancellationToken))
            {
                return(true);
            }

            if (await _compilationHandler.TryHandleFileChange(context, file, cancellationToken)) // This needs to be 6.0
            {
                return(true);
            }

            return(false);
        }
示例#19
0
        public async ValueTask ProcessAsync(DotNetWatchContext context, CancellationToken cancellationToken)
        {
            tempContext = context;

            if (_suppressLaunchBrowser)
            {
                return;
            }

            if (context.Iteration == 0)
            {
                _reporter = context.Reporter;

                if (CanLaunchBrowser(context, out var launchPath))
                {
                    context.Reporter.Verbose("dotnet-watch is configured to launch a browser on ASP.NET Core application startup.");
                    _canLaunchBrowser  = true;
                    _launchPath        = launchPath;
                    _cancellationToken = cancellationToken;

                    // We've redirected the output, but want to ensure that it continues to appear in the user's console.
                    context.ProcessSpec.OnOutput += (_, eventArgs) => Console.WriteLine(eventArgs.Data);
                    context.ProcessSpec.OnOutput += OnOutput;

                    if (!_suppressBrowserRefresh)
                    {
                        _refreshServer = new BrowserRefreshServer(context.Reporter);
                        var serverUrl = await _refreshServer.StartAsync(cancellationToken);

                        context.Reporter.Verbose($"Refresh server running at {serverUrl}.");
                        context.ProcessSpec.EnvironmentVariables["ASPNETCORE_AUTO_RELOAD_WS_ENDPOINT"] = serverUrl;

                        var pathToMiddleware = Path.Combine(AppContext.BaseDirectory, "middleware", "Microsoft.AspNetCore.Watch.BrowserRefresh.dll");
                        context.ProcessSpec.EnvironmentVariables["DOTNET_STARTUP_HOOKS"] = pathToMiddleware;
                        context.ProcessSpec.EnvironmentVariables["ASPNETCORE_HOSTINGSTARTUPASSEMBLIES"] = "Microsoft.AspNetCore.Watch.BrowserRefresh";
                    }
                }
            }

            if (_canLaunchBrowser)
            {
                if (context.Iteration > 0)
                {
                    // We've detected a change. Notify the browser.
                    await SendMessage(WaitMessage, cancellationToken);
                }
            }
        }
示例#20
0
        public async Task ProcessAsync_LeavesArgumentsUnchangedOnFirstRun()
        {
            // Arrange
            var filter = new NoRestoreFilter();

            var context = new DotNetWatchContext
            {
                ProcessSpec = new ProcessSpec
                {
                    Arguments = _arguments,
                }
            };

            // Act
            await filter.ProcessAsync(context, default);

            // Assert
            Assert.Same(_arguments, context.ProcessSpec.Arguments);
        }
        public async ValueTask InitializeAsync(DotNetWatchContext context, CancellationToken cancellationToken)
        {
            if (_pipe is not null)
            {
                _pipe.Close();
                await _pipe.DisposeAsync();
            }

            _pipe = new NamedPipeServerStream("netcore-hot-reload", PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.CurrentUserOnly);
            _task = _pipe.WaitForConnectionAsync(cancellationToken);

            if (context.Iteration == 0)
            {
                var deltaApplier = Path.Combine(AppContext.BaseDirectory, "hotreload", "Microsoft.Extensions.AspNetCoreDeltaApplier.dll");
                context.ProcessSpec.EnvironmentVariables.DotNetStartupHooks.Add(deltaApplier);

                // Configure the app for EnC
                context.ProcessSpec.EnvironmentVariables["DOTNET_MODIFIABLE_ASSEMBLIES"] = "debug";
            }
        }
        public async ValueTask ProcessAsync(DotNetWatchContext context, CancellationToken cancellationToken)
        {
            if (_suppressLaunchBrowser)
            {
                return;
            }

            if (context.Iteration == 0)
            {
                _reporter = context.Reporter;

                if (CanLaunchBrowser(context, out var launchPath))
                {
                    context.Reporter.Verbose("dotnet-watch is configured to launch a browser on ASP.NET Core application startup.");
                    _launchPath        = launchPath;
                    _cancellationToken = cancellationToken;

                    // We've redirected the output, but want to ensure that it continues to appear in the user's console.
                    context.ProcessSpec.OnOutput += (_, eventArgs) => Console.WriteLine(eventArgs.Data);
                    context.ProcessSpec.OnOutput += OnOutput;

                    if (!_suppressBrowserRefresh)
                    {
                        _refreshServer = new BrowserRefreshServer(context.Reporter);
                        context.BrowserRefreshServer = _refreshServer;
                        var serverUrls = string.Join(',', await _refreshServer.StartAsync(cancellationToken));
                        context.Reporter.Verbose($"Refresh server running at {serverUrls}.");
                        context.ProcessSpec.EnvironmentVariables["ASPNETCORE_AUTO_RELOAD_WS_ENDPOINT"] = serverUrls;

                        var pathToMiddleware = Path.Combine(AppContext.BaseDirectory, "middleware", "Microsoft.AspNetCore.Watch.BrowserRefresh.dll");
                        context.ProcessSpec.EnvironmentVariables.DotNetStartupHooks.Add(pathToMiddleware);
                        context.ProcessSpec.EnvironmentVariables.AspNetCoreHostingStartupAssemblies.Add("Microsoft.AspNetCore.Watch.BrowserRefresh");
                    }
                }
            }
            else if (!_suppressBrowserRefresh)
            {
                // We've detected a change. Notify the browser.
                await(_refreshServer?.SendWaitMessageAsync(cancellationToken) ?? default);
            }
        }
示例#23
0
        public async ValueTask ProcessAsync(DotNetWatchContext context, CancellationToken cancellationToken)
        {
            if (_suppressBrowserRefresh)
            {
                return;
            }

            if (context.Iteration == 0)
            {
                if (context.ProjectGraph is null)
                {
                    _reporter.Verbose("Unable to determine if this project is a webapp.");
                    return;
                }
                else if (IsWebApp(context.ProjectGraph))
                {
                    _reporter.Verbose("Configuring the app to use browser-refresh middleware.");
                }
                else
                {
                    _reporter.Verbose("Skipping configuring browser-refresh middleware since this is not a webapp.");
                    return;
                }

                _refreshServer = new BrowserRefreshServer(context.Reporter);
                context.BrowserRefreshServer = _refreshServer;
                var serverUrls = string.Join(',', await _refreshServer.StartAsync(cancellationToken));
                context.Reporter.Verbose($"Refresh server running at {serverUrls}.");
                context.ProcessSpec.EnvironmentVariables["ASPNETCORE_AUTO_RELOAD_WS_ENDPOINT"] = serverUrls;
                context.ProcessSpec.EnvironmentVariables["ASPNETCORE_AUTO_RELOAD_WS_KEY"]      = _refreshServer.ServerKey;

                var pathToMiddleware = Path.Combine(AppContext.BaseDirectory, "middleware", "Microsoft.AspNetCore.Watch.BrowserRefresh.dll");
                context.ProcessSpec.EnvironmentVariables.DotNetStartupHooks.Add(pathToMiddleware);
                context.ProcessSpec.EnvironmentVariables.AspNetCoreHostingStartupAssemblies.Add("Microsoft.AspNetCore.Watch.BrowserRefresh");
            }
            else if (!_suppressBrowserRefresh)
            {
                // We've detected a change. Notify the browser.
                await(_refreshServer?.SendWaitMessageAsync(cancellationToken) ?? default);
            }
        }
示例#24
0
        public async Task ProcessAsync_EvaluatesFileSetIfProjFileChanges()
        {
            // Arrange
            var filter  = new MSBuildEvaluationFilter(_fileSetFactory);
            var context = new DotNetWatchContext
            {
                Iteration = 0,
            };

            await filter.ProcessAsync(context, default);

            context.Iteration++;
            context.ChangedFile = "Test.csproj";
            context.RequiresMSBuildRevaluation = false;

            // Act
            await filter.ProcessAsync(context, default);

            // Assert
            Assert.True(context.RequiresMSBuildRevaluation);
        }
示例#25
0
        public async ValueTask <bool> TryHandleFileChange(DotNetWatchContext context, FileItem[] files, CancellationToken cancellationToken)
        {
            HotReloadEventSource.Log.HotReloadStart(HotReloadEventSource.StartType.Main);

            var fileHandlerResult = false;

            for (var i = files.Length - 1; i >= 0; i--)
            {
                var file = files[i];
                if (await _staticFileHandler.TryHandleFileChange(context, file, cancellationToken) ||
                    await _scopedCssFileHandler.TryHandleFileChange(context, file, cancellationToken))
                {
                    fileHandlerResult = true;
                }
            }

            fileHandlerResult |= await _compilationHandler.TryHandleFileChange(context, files, cancellationToken);

            HotReloadEventSource.Log.HotReloadEnd(HotReloadEventSource.StartType.Main);
            return(fileHandlerResult);
        }
示例#26
0
        public async Task ProcessAsync_DoesNotEvaluateFileSetIfNonProjFileChanges()
        {
            // Arrange
            var filter  = new MSBuildEvaluationFilter(_fileSetFactory);
            var context = new DotNetWatchContext
            {
                Iteration = 0,
            };

            await filter.ProcessAsync(context, default);

            context.Iteration++;
            context.ChangedFile = "Controller.cs";
            context.RequiresMSBuildRevaluation = false;

            // Act
            await filter.ProcessAsync(context, default);

            // Assert
            Assert.False(context.RequiresMSBuildRevaluation);
            Mock.Get(_fileSetFactory).Verify(v => v.CreateAsync(It.IsAny <CancellationToken>()), Times.Once());
        }
        private static bool CanLaunchBrowser(DotNetWatchContext context, out string launchUrl)
        {
            launchUrl = null;
            var reporter = context.Reporter;

            if (!context.FileSet.Project.IsNetCoreApp31OrNewer())
            {
                // Browser refresh middleware supports 3.1 or newer
                reporter.Verbose("Browser refresh is only supported in .NET Core 3.1 or newer projects.");
                return(false);
            }

            var dotnetCommand = context.ProcessSpec.Arguments.FirstOrDefault();

            if (!string.Equals(dotnetCommand, "run", StringComparison.Ordinal))
            {
                reporter.Verbose("Browser refresh is only supported for run commands.");
                return(false);
            }

            if (context.DefaultLaunchSettingsProfile is not {
                LaunchBrowser : true
            })
示例#28
0
        public async ValueTask ProcessAsync(DotNetWatchContext context, CancellationToken cancellationToken)
        {
            if (_suppressLaunchBrowser)
            {
                return;
            }

            if (context.Iteration == 0)
            {
                _reporter = context.Reporter;

                if (CanLaunchBrowser(context, out var launchPath))
                {
                    context.Reporter.Verbose("dotnet-watch is configured to launch a browser on ASP.NET Core application startup.");
                    _canLaunchBrowser  = true;
                    _launchPath        = launchPath;
                    _cancellationToken = cancellationToken;

                    _refreshServer = new BrowserRefreshServer(context.Reporter);
                    var serverUrl = await _refreshServer.StartAsync(cancellationToken);

                    context.Reporter.Verbose($"Refresh server running at {serverUrl}.");
                    context.ProcessSpec.EnvironmentVariables["DOTNET_WATCH_REFRESH_URL"] = serverUrl;

                    context.ProcessSpec.OnOutput += OnOutput;
                }
            }

            if (_canLaunchBrowser)
            {
                if (context.Iteration > 0)
                {
                    // We've detected a change. Notify the browser.
                    await _refreshServer.SendMessage(WaitMessage, cancellationToken);
                }
            }
        }
示例#29
0
        public async Task ProcessAsync_AddsNoRestoreSwitch_ForTestCommand()
        {
            // Arrange
            var filter = new NoRestoreFilter();

            var context = new DotNetWatchContext
            {
                Iteration   = 0,
                ProcessSpec = new ProcessSpec
                {
                    Arguments = new[] { "test", "--filter SomeFilter" },
                }
            };
            await filter.ProcessAsync(context, default);

            context.ChangedFile = "Program.cs";
            context.Iteration++;

            // Act
            await filter.ProcessAsync(context, default);

            // Assert
            Assert.Equal(new[] { "test", "--no-restore", "--filter SomeFilter" }, context.ProcessSpec.Arguments);
        }
示例#30
0
        public ValueTask InitializeAsync(DotNetWatchContext context, CancellationToken cancellationToken)
        {
            if (!SuppressNamedPipeForTests)
            {
                _pipe           = new NamedPipeServerStream(_namedPipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.CurrentUserOnly);
                _connectionTask = _pipe.WaitForConnectionAsync(cancellationToken);

                _capabilities = Task.Run(async() =>
                {
                    try
                    {
                        await _connectionTask;
                        // When the client connects, the first payload it sends is the initialization payload which includes the apply capabilities.
                        var capabiltiies = ClientInitializationPayload.Read(_pipe).Capabilities;
                        _reporter.Verbose($"Application supports the following capabilities {capabiltiies}.");
                        return(capabiltiies.Split(' ').ToImmutableArray());
                    }
                    catch
                    {
                        // Do nothing. This is awaited by Apply which will surface the error.
                    }

                    return(ImmutableArray <string> .Empty);
                });
            }

            if (context.Iteration == 0)
            {
                var deltaApplier = Path.Combine(AppContext.BaseDirectory, "hotreload", "Microsoft.Extensions.DotNetDeltaApplier.dll");
                context.ProcessSpec.EnvironmentVariables.DotNetStartupHooks.Add(deltaApplier);

                // Configure the app for EnC
                context.ProcessSpec.EnvironmentVariables["DOTNET_MODIFIABLE_ASSEMBLIES"]    = "debug";
                context.ProcessSpec.EnvironmentVariables["DOTNET_HOTRELOAD_NAMEDPIPE_NAME"] = _namedPipeName;
            }
            return(default);