Beispiel #1
0
            public ProcessState(Process process, IReporter reporter)
            {
                _reporter        = reporter;
                _process         = process;
                _process.Exited += OnExited;
                Task             = _tcs.Task.ContinueWith(_ =>
                {
                    try
                    {
                        // We need to use two WaitForExit calls to ensure that all of the output/events are processed. Previously
                        // this code used Process.Exited, which could result in us missing some output due to the ordering of
                        // events.
                        //
                        // See the remarks here: https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.process.waitforexit#System_Diagnostics_Process_WaitForExit_System_Int32_
                        if (!_process.WaitForExit(Int32.MaxValue))
                        {
                            throw new TimeoutException();
                        }

                        _process.WaitForExit();
                    }
                    catch (InvalidOperationException)
                    {
                        // suppress if this throws if no process is associated with this object anymore.
                    }
                });
            }
 public MsBuildFileSetFactory(
     IReporter reporter,
     string projectFile,
     bool waitOnError,
     bool trace)
     : this(new Muxer().MuxerPath, reporter, projectFile, new OutputSink(), waitOnError, trace)
 {
 }
Beispiel #3
0
 public MsBuildFileSetFactory(
     IReporter reporter,
     DotNetWatchOptions dotNetWatchOptions,
     string projectFile,
     bool waitOnError,
     bool trace)
     : this(dotNetWatchOptions, DotnetMuxer.MuxerPath, reporter, projectFile, new OutputSink(), waitOnError, trace)
 {
 }
Beispiel #4
0
        public Program(IConsole console, string workingDirectory)
        {
            Ensure.NotNull(console, nameof(console));
            Ensure.NotNullOrEmpty(workingDirectory, nameof(workingDirectory));

            _console          = console;
            _workingDirectory = workingDirectory;
            _cts = new CancellationTokenSource();
            console.CancelKeyPress += OnCancelKeyPress;
            _reporter = CreateReporter(verbose: true, quiet: false, console: _console);
        }
Beispiel #5
0
        public HotReloadDotNetWatcher(IReporter reporter, IFileSetFactory fileSetFactory, DotNetWatchOptions dotNetWatchOptions, IConsole console)
        {
            Ensure.NotNull(reporter, nameof(reporter));

            _reporter           = reporter;
            _processRunner      = new ProcessRunner(reporter);
            _dotNetWatchOptions = dotNetWatchOptions;
            _console            = console;

            _filters = new IWatchFilter[]
            {
                new MSBuildEvaluationFilter(fileSetFactory),
                new DotNetBuildFilter(_processRunner, _reporter),
                new LaunchBrowserFilter(_dotNetWatchOptions),
            };
        }
Beispiel #6
0
        private async Task <int> MainInternalAsync(
            IReporter reporter,
            string project,
            IReadOnlyCollection <string> args,
            CancellationToken cancellationToken)
        {
            // TODO multiple projects should be easy enough to add here
            string projectFile;

            try
            {
                projectFile = MsBuildProjectFinder.FindMsBuildProject(_workingDirectory, project);
            }
            catch (FileNotFoundException ex)
            {
                reporter.Error(ex.Message);
                return(1);
            }

            var watchOptions = DotNetWatchOptions.Default;

            var fileSetFactory = new MsBuildFileSetFactory(reporter,
                                                           watchOptions,
                                                           projectFile,
                                                           waitOnError: true,
                                                           trace: false);
            var processInfo = new ProcessSpec
            {
                Executable           = new Muxer().MuxerPath,
                WorkingDirectory     = Path.GetDirectoryName(projectFile),
                Arguments            = args,
                EnvironmentVariables =
                {
                    ["DOTNET_WATCH"] = "1"
                },
            };

            if (CommandLineOptions.IsPollingEnabled)
            {
                _reporter.Output("Polling file watcher is enabled");
            }

            await using var watcher = new DotNetWatcher(reporter, fileSetFactory, watchOptions);
            await watcher.WatchAsync(processInfo, cancellationToken);

            return(0);
        }
Beispiel #7
0
        public HotReloadDotNetWatcher(IReporter reporter, IFileSetFactory fileSetFactory, DotNetWatchOptions dotNetWatchOptions, IConsole console)
        {
            Ensure.NotNull(reporter, nameof(reporter));

            _reporter           = reporter;
            _processRunner      = new ProcessRunner(reporter);
            _dotNetWatchOptions = dotNetWatchOptions;
            _console            = console;

            _filters = new IWatchFilter[]
            {
                new DotNetBuildFilter(fileSetFactory, _processRunner, _reporter),
                new LaunchBrowserFilter(dotNetWatchOptions),
                new BrowserRefreshFilter(dotNetWatchOptions, _reporter),
            };
            _rudeEditDialog = new(reporter, _console);
        }
        // output sink is for testing
        internal MsBuildFileSetFactory(
            string muxerPath,
            IReporter reporter,
            string projectFile,
            OutputSink outputSink,
            bool waitOnError,
            bool trace)
        {
            Ensure.NotNull(reporter, nameof(reporter));
            Ensure.NotNullOrEmpty(projectFile, nameof(projectFile));
            Ensure.NotNull(outputSink, nameof(outputSink));

            _muxerPath     = muxerPath;
            _reporter      = reporter;
            _projectFile   = projectFile;
            _outputSink    = outputSink;
            _processRunner = new ProcessRunner(reporter);
            _buildFlags    = InitializeArgs(FindTargetsFile(), trace);
            _waitOnError   = waitOnError;
        }
Beispiel #9
0
        private async Task <int> HandleWatch(CommandLineOptions options)
        {
            // update reporter as configured by options
            _reporter = CreateReporter(options.Verbose, options.Quiet, _console);

            try
            {
                if (_cts.IsCancellationRequested)
                {
                    return(1);
                }

                if (options.List)
                {
                    return(await ListFilesAsync(_reporter,
                                                options.Project,
                                                _cts.Token));
                }
                else
                {
                    return(await MainInternalAsync(_reporter,
                                                   options.Project,
                                                   options.RemainingArguments,
                                                   _cts.Token));
                }
            }
            catch (Exception ex)
            {
                if (ex is TaskCanceledException || ex is OperationCanceledException)
                {
                    // swallow when only exception is the CTRL+C forced an exit
                    return(0);
                }

                _reporter.Error(ex.ToString());
                _reporter.Error("An unexpected error occurred");
                return(1);
            }
        }
Beispiel #10
0
        private async Task <int> ListFilesAsync(
            IReporter reporter,
            string project,
            CancellationToken cancellationToken)
        {
            // TODO multiple projects should be easy enough to add here
            string projectFile;

            try
            {
                projectFile = MsBuildProjectFinder.FindMsBuildProject(_workingDirectory, project);
            }
            catch (FileNotFoundException ex)
            {
                reporter.Error(ex.Message);
                return(1);
            }

            var fileSetFactory = new MsBuildFileSetFactory(
                reporter,
                DotNetWatchOptions.Default,
                projectFile,
                waitOnError: false,
                trace: false);
            var files = await fileSetFactory.CreateAsync(cancellationToken);

            if (files == null)
            {
                return(1);
            }

            foreach (var file in files)
            {
                _console.Out.WriteLine(file.FilePath);
            }

            return(0);
        }
Beispiel #11
0
        public HotReloadDotNetWatcher(IReporter reporter, IRequester requester, IFileSetFactory fileSetFactory, DotNetWatchOptions dotNetWatchOptions, IConsole console, string workingDirectory)
        {
            Ensure.NotNull(reporter, nameof(reporter));
            Ensure.NotNull(requester, nameof(requester));
            Ensure.NotNullOrEmpty(workingDirectory, nameof(workingDirectory));

            _reporter           = reporter;
            _processRunner      = new ProcessRunner(reporter);
            _dotNetWatchOptions = dotNetWatchOptions;
            _console            = console;
            _workingDirectory   = workingDirectory;

            _filters = new IWatchFilter[]
            {
                new DotNetBuildFilter(fileSetFactory, _processRunner, _reporter),
                new LaunchBrowserFilter(dotNetWatchOptions),
                new BrowserRefreshFilter(dotNetWatchOptions, _reporter),
            };

            if (!dotNetWatchOptions.NonInteractive)
            {
                _rudeEditDialog = new(reporter, requester, _console);
            }
        }
Beispiel #12
0
        private async Task <int> MainInternalAsync(
            IReporter reporter,
            string project,
            IReadOnlyList <string> args,
            CancellationToken cancellationToken)
        {
            // TODO multiple projects should be easy enough to add here
            string projectFile;

            try
            {
                projectFile = MsBuildProjectFinder.FindMsBuildProject(_workingDirectory, project);
            }
            catch (FileNotFoundException ex)
            {
                reporter.Error(ex.Message);
                return(1);
            }

            var isDefaultRunCommand = false;

            if (args.Count == 1 && args[0] == "run")
            {
                isDefaultRunCommand = true;
            }
            else if (args.Count == 0)
            {
                isDefaultRunCommand = true;
                args = new[] { "run" };
            }

            var watchOptions = DotNetWatchOptions.Default;

            var fileSetFactory = new MsBuildFileSetFactory(reporter,
                                                           watchOptions,
                                                           projectFile,
                                                           waitOnError: true,
                                                           trace: false);
            var processInfo = new ProcessSpec
            {
                Executable           = new Muxer().MuxerPath,
                WorkingDirectory     = Path.GetDirectoryName(projectFile),
                Arguments            = args,
                EnvironmentVariables =
                {
                    ["DOTNET_WATCH"] = "1"
                },
            };

            if (CommandLineOptions.IsPollingEnabled)
            {
                _reporter.Output("Polling file watcher is enabled");
            }

            var defaultProfile = LaunchSettingsProfile.ReadDefaultProfile(_workingDirectory, reporter);

            var context = new DotNetWatchContext
            {
                ProcessSpec = processInfo,
                Reporter    = _reporter,
                SuppressMSBuildIncrementalism = watchOptions.SuppressMSBuildIncrementalism,
                DefaultLaunchSettingsProfile  = defaultProfile,
            };

            if (isDefaultRunCommand && !string.IsNullOrEmpty(defaultProfile?.HotReloadProfile))
            {
                _reporter.Verbose($"Found HotReloadProfile={defaultProfile.HotReloadProfile}. Watching with hot-reload");

                // We'll sue hot-reload based watching if
                // a) watch was invoked with no args or with exactly one arg - the run command e.g. `dotnet watch` or `dotnet watch run`
                // b) The launch profile supports hot-reload based watching.
                // The watcher will complain if users configure this for runtimes that would not support it.
                await using var watcher = new HotReloadDotNetWatcher(reporter, fileSetFactory, watchOptions, _console);
                await watcher.WatchAsync(context, cancellationToken);
            }
            else
            {
                _reporter.Verbose("Did not find a HotReloadProfile or running a non-default command. Watching with legacy behavior.");

                // We'll use the presence of a profile to decide if we're going to use the hot-reload based watching.
                // The watcher will complain if users configure this for runtimes that would not support it.
                await using var watcher = new DotNetWatcher(reporter, fileSetFactory, watchOptions);
                await watcher.WatchAsync(context, cancellationToken);
            }

            return(0);
        }
Beispiel #13
0
        public ProcessRunner(IReporter reporter)
        {
            Ensure.NotNull(reporter, nameof(reporter));

            _reporter = reporter;
        }