Add better errors, fix help output text, and add 'dotnet watch --list' to help us diagnose issues

Fixes #252 - help output shown twice in dotnet-watch
Fixes #250 - add dotnet-watch --list. Prints a list of all files discovered
Fixes #249 - better error message when GenerateWatchList fails
This commit is contained in:
Nate McMaster 2017-01-13 09:52:32 -08:00
parent 7ee45afed4
commit e481df3d49
14 changed files with 207 additions and 61 deletions

28
.editorconfig Normal file
View File

@ -0,0 +1,28 @@
; EditorConfig to support per-solution formatting.
; Use the EditorConfig VS add-in to make this work.
; http://editorconfig.org/
; This is the default for the codeline.
root = true
[*]
indent_style = space
charset = utf-8
trim_trailing_whitespace = true
[*.{cs}]
indent_size = 4
insert_final_newline = true
; All XML-based file formats
[*.{config,csproj,nuspec,props,resx,targets,xml}]
indent_size = 2
[*.{json}]
indent_size = 2
[*.{ps1}]
indent_size = 4
[*.{sh}]
indent_size = 4

View File

@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio 15
VisualStudioVersion = 15.0.25807.0 VisualStudioVersion = 15.0.26020.0
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{66517987-2A5A-4330-B130-207039378FD4}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{66517987-2A5A-4330-B130-207039378FD4}"
EndProject EndProject
@ -8,6 +8,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.Watcher.To
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8321E0D1-9A47-4D2F-AED8-3AE636D44E35}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8321E0D1-9A47-4D2F-AED8-3AE636D44E35}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
NuGet.Config = NuGet.Config NuGet.Config = NuGet.Config
EndProjectSection EndProjectSection
EndProject EndProject
@ -43,10 +44,6 @@ Global
{8730E848-CA0F-4E0A-9A2F-BC22AD0B2C4E}.Debug|Any CPU.Build.0 = Debug|Any CPU {8730E848-CA0F-4E0A-9A2F-BC22AD0B2C4E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8730E848-CA0F-4E0A-9A2F-BC22AD0B2C4E}.Release|Any CPU.ActiveCfg = Debug|Any CPU {8730E848-CA0F-4E0A-9A2F-BC22AD0B2C4E}.Release|Any CPU.ActiveCfg = Debug|Any CPU
{8730E848-CA0F-4E0A-9A2F-BC22AD0B2C4E}.Release|Any CPU.Build.0 = Debug|Any CPU {8730E848-CA0F-4E0A-9A2F-BC22AD0B2C4E}.Release|Any CPU.Build.0 = Debug|Any CPU
{9295E811-FF0F-E40A-2F9A-0B2C4EBC22AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9295E811-FF0F-E40A-2F9A-0B2C4EBC22AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9295E811-FF0F-E40A-2F9A-0B2C4EBC22AD}.Release|Any CPU.ActiveCfg = Debug|Any CPU
{9295E811-FF0F-E40A-2F9A-0B2C4EBC22AD}.Release|Any CPU.Build.0 = Debug|Any CPU
{7B331122-83B1-4F08-A119-DC846959844C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7B331122-83B1-4F08-A119-DC846959844C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7B331122-83B1-4F08-A119-DC846959844C}.Debug|Any CPU.Build.0 = Debug|Any CPU {7B331122-83B1-4F08-A119-DC846959844C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7B331122-83B1-4F08-A119-DC846959844C}.Release|Any CPU.ActiveCfg = Debug|Any CPU {7B331122-83B1-4F08-A119-DC846959844C}.Release|Any CPU.ActiveCfg = Debug|Any CPU
@ -59,6 +56,10 @@ Global
{53F3B53D-303A-4DAA-9C38-4F55195FA5B9}.Debug|Any CPU.Build.0 = Debug|Any CPU {53F3B53D-303A-4DAA-9C38-4F55195FA5B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{53F3B53D-303A-4DAA-9C38-4F55195FA5B9}.Release|Any CPU.ActiveCfg = Debug|Any CPU {53F3B53D-303A-4DAA-9C38-4F55195FA5B9}.Release|Any CPU.ActiveCfg = Debug|Any CPU
{53F3B53D-303A-4DAA-9C38-4F55195FA5B9}.Release|Any CPU.Build.0 = Debug|Any CPU {53F3B53D-303A-4DAA-9C38-4F55195FA5B9}.Release|Any CPU.Build.0 = Debug|Any CPU
{9295E811-FF0F-E40A-2F9A-0B2C4EBC22AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9295E811-FF0F-E40A-2F9A-0B2C4EBC22AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9295E811-FF0F-E40A-2F9A-0B2C4EBC22AD}.Release|Any CPU.ActiveCfg = Debug|Any CPU
{9295E811-FF0F-E40A-2F9A-0B2C4EBC22AD}.Release|Any CPU.Build.0 = Debug|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -67,9 +68,9 @@ Global
{8A8CEABC-AC47-43FF-A5DF-69224F7E1F46} = {66517987-2A5A-4330-B130-207039378FD4} {8A8CEABC-AC47-43FF-A5DF-69224F7E1F46} = {66517987-2A5A-4330-B130-207039378FD4}
{16BADE2F-1184-4518-8A70-B68A19D0805B} = {F5B382BC-258F-46E1-AC3D-10E5CCD55134} {16BADE2F-1184-4518-8A70-B68A19D0805B} = {F5B382BC-258F-46E1-AC3D-10E5CCD55134}
{8730E848-CA0F-4E0A-9A2F-BC22AD0B2C4E} = {66517987-2A5A-4330-B130-207039378FD4} {8730E848-CA0F-4E0A-9A2F-BC22AD0B2C4E} = {66517987-2A5A-4330-B130-207039378FD4}
{9295E811-FF0F-E40A-2F9A-0B2C4EBC22AD} = {F5B382BC-258F-46E1-AC3D-10E5CCD55134}
{7B331122-83B1-4F08-A119-DC846959844C} = {F5B382BC-258F-46E1-AC3D-10E5CCD55134} {7B331122-83B1-4F08-A119-DC846959844C} = {F5B382BC-258F-46E1-AC3D-10E5CCD55134}
{8A2E6961-6B12-4A8E-8215-3E7301D52EAC} = {F5B382BC-258F-46E1-AC3D-10E5CCD55134} {8A2E6961-6B12-4A8E-8215-3E7301D52EAC} = {F5B382BC-258F-46E1-AC3D-10E5CCD55134}
{53F3B53D-303A-4DAA-9C38-4F55195FA5B9} = {66517987-2A5A-4330-B130-207039378FD4} {53F3B53D-303A-4DAA-9C38-4F55195FA5B9} = {66517987-2A5A-4330-B130-207039378FD4}
{9295E811-FF0F-E40A-2F9A-0B2C4EBC22AD} = {F5B382BC-258F-46E1-AC3D-10E5CCD55134}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View File

@ -16,6 +16,7 @@ namespace Microsoft.DotNet.Watcher
public bool IsQuiet { get; private set; } public bool IsQuiet { get; private set; }
public bool IsVerbose { get; private set; } public bool IsVerbose { get; private set; }
public IList<string> RemainingArguments { get; private set; } public IList<string> RemainingArguments { get; private set; }
public bool ListFiles { get; private set; }
public static CommandLineOptions Parse(string[] args, IConsole console) public static CommandLineOptions Parse(string[] args, IConsole console)
{ {
@ -63,6 +64,9 @@ Examples:
CommandOptionType.NoValue); CommandOptionType.NoValue);
var optVerbose = app.VerboseOption(); var optVerbose = app.VerboseOption();
var optList = app.Option("--list", "Lists all discovered files without starting the watcher",
CommandOptionType.NoValue);
app.VersionOptionFromAssemblyAttributes(typeof(Program).GetTypeInfo().Assembly); app.VersionOptionFromAssemblyAttributes(typeof(Program).GetTypeInfo().Assembly);
if (app.Execute(args) != 0) if (app.Execute(args) != 0)
@ -75,7 +79,9 @@ Examples:
throw new CommandParsingException(app, Resources.Error_QuietAndVerboseSpecified); throw new CommandParsingException(app, Resources.Error_QuietAndVerboseSpecified);
} }
if (app.RemainingArguments.Count == 0) if (app.RemainingArguments.Count == 0
&& !app.IsShowingInformation
&& !optList.HasValue())
{ {
app.ShowHelp(); app.ShowHelp();
} }
@ -86,8 +92,9 @@ Examples:
IsQuiet = optQuiet.HasValue(), IsQuiet = optQuiet.HasValue(),
IsVerbose = optVerbose.HasValue(), IsVerbose = optVerbose.HasValue(),
RemainingArguments = app.RemainingArguments, RemainingArguments = app.RemainingArguments,
IsHelp = app.IsShowingInformation IsHelp = app.IsShowingInformation,
ListFiles = optList.HasValue(),
}; };
} }
} }
} }

View File

@ -34,6 +34,13 @@ namespace Microsoft.DotNet.Watcher
while (true) while (true)
{ {
var fileSet = await fileSetFactory.CreateAsync(cancellationToken); var fileSet = await fileSetFactory.CreateAsync(cancellationToken);
if (fileSet == null)
{
_reporter.Error("Failed to find a list of files to watch");
return;
}
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
return; return;
@ -91,4 +98,4 @@ namespace Microsoft.DotNet.Watcher
} }
} }
} }
} }

View File

@ -16,17 +16,19 @@ namespace Microsoft.DotNet.Watcher.Internal
public class MsBuildFileSetFactory : IFileSetFactory public class MsBuildFileSetFactory : IFileSetFactory
{ {
private const string TargetName = "GenerateWatchList"; private const string TargetName = "GenerateWatchList";
private const string ProjectExtensionFileExtension = ".dotnetwatch.targets"; private const string ProjectExtensionFileExtension = ".dotnetwatch.g.targets";
private const string WatchTargetsFileName = "DotNetWatchCommon.targets"; private const string WatchTargetsFileName = "DotNetWatchCommon.targets";
private readonly IReporter _reporter; private readonly IReporter _reporter;
private readonly string _projectFile; private readonly string _projectFile;
private readonly string _watchTargetsDir; private readonly string _watchTargetsDir;
private readonly OutputSink _outputSink; private readonly OutputSink _outputSink;
private readonly ProcessRunner _processRunner; private readonly ProcessRunner _processRunner;
private readonly bool _waitOnError;
public MsBuildFileSetFactory(IReporter reporter, string projectFile) public MsBuildFileSetFactory(IReporter reporter, string projectFile, bool waitOnError)
: this(reporter, projectFile, new OutputSink()) : this(reporter, projectFile, new OutputSink())
{ {
_waitOnError = waitOnError;
} }
// output sink is for testing // output sink is for testing
@ -86,7 +88,7 @@ namespace Microsoft.DotNet.Watcher.Internal
var exitCode = await _processRunner.RunAsync(processSpec, cancellationToken); var exitCode = await _processRunner.RunAsync(processSpec, cancellationToken);
if (exitCode == 0) if (exitCode == 0 && File.Exists(watchList))
{ {
var fileset = new FileSet( var fileset = new FileSet(
File.ReadAllLines(watchList) File.ReadAllLines(watchList)
@ -109,28 +111,41 @@ namespace Microsoft.DotNet.Watcher.Internal
_reporter.Error($"Error(s) finding watch items project file '{Path.GetFileName(_projectFile)}'"); _reporter.Error($"Error(s) finding watch items project file '{Path.GetFileName(_projectFile)}'");
_reporter.Output($"MSBuild output from target '{TargetName}'"); _reporter.Output($"MSBuild output from target '{TargetName}':");
_reporter.Output(string.Empty);
foreach (var line in capture.Lines) foreach (var line in capture.Lines)
{ {
_reporter.Output($" [MSBUILD] : {line}"); _reporter.Output($" {line}");
} }
_reporter.Warn("Fix the error to continue or press Ctrl+C to exit."); _reporter.Output(string.Empty);
var fileSet = new FileSet(new[] {_projectFile}); if (!_waitOnError)
using (var watcher = new FileSetWatcher(fileSet))
{ {
await watcher.GetChangedFileAsync(cancellationToken); return null;
}
else
{
_reporter.Warn("Fix the error to continue or press Ctrl+C to exit.");
_reporter.Output($"File changed: {_projectFile}"); var fileSet = new FileSet(new[] { _projectFile });
using (var watcher = new FileSetWatcher(fileSet))
{
await watcher.GetChangedFileAsync(cancellationToken);
_reporter.Output($"File changed: {_projectFile}");
}
} }
} }
} }
finally finally
{ {
File.Delete(watchList); if (File.Exists(watchList))
{
File.Delete(watchList);
}
} }
} }
@ -173,4 +188,4 @@ namespace Microsoft.DotNet.Watcher.Internal
return Path.GetDirectoryName(targetPath); return Path.GetDirectoryName(targetPath);
} }
} }
} }

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
@ -80,7 +80,20 @@ namespace Microsoft.DotNet.Watcher
try try
{ {
return await MainInternalAsync(reporter, options.Project, options.RemainingArguments, ctrlCTokenSource.Token); if (options.ListFiles)
{
return await ListFilesAsync(reporter,
options.Project,
ctrlCTokenSource.Token);
}
else
{
return await MainInternalAsync(reporter,
options.Project,
options.RemainingArguments,
ctrlCTokenSource.Token);
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -115,8 +128,7 @@ namespace Microsoft.DotNet.Watcher
return 1; return 1;
} }
var fileSetFactory = new MsBuildFileSetFactory(reporter, projectFile); var fileSetFactory = new MsBuildFileSetFactory(reporter, projectFile, waitOnError: true);
var processInfo = new ProcessSpec var processInfo = new ProcessSpec
{ {
Executable = DotNetMuxer.MuxerPathOrDefault(), Executable = DotNetMuxer.MuxerPathOrDefault(),
@ -130,6 +142,39 @@ namespace Microsoft.DotNet.Watcher
return 0; return 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(_workingDir, project);
}
catch (FileNotFoundException ex)
{
reporter.Error(ex.Message);
return 1;
}
var fileSetFactory = new MsBuildFileSetFactory(reporter, projectFile, waitOnError: false);
var files = await fileSetFactory.CreateAsync(cancellationToken);
if (files == null)
{
return 1;
}
foreach (var file in files)
{
_console.Out.WriteLine(file);
}
return 0;
}
private static IReporter CreateReporter(bool verbose, bool quiet, IConsole console) private static IReporter CreateReporter(bool verbose, bool quiet, IConsole console)
{ {
const string prefix = "watch : "; const string prefix = "watch : ";
@ -178,4 +223,4 @@ namespace Microsoft.DotNet.Watcher
.Build(); .Build();
} }
} }
} }

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
@ -98,9 +98,7 @@ namespace Microsoft.Extensions.SecretManager.Tools.Internal
// running tool // running tool
using (var resource = GetType().GetTypeInfo().Assembly.GetManifestResourceStream("ProjectIdResolverTargets.xml")) using (var resource = GetType().GetTypeInfo().Assembly.GetManifestResourceStream("ProjectIdResolverTargets.xml"))
using (var stream = new FileStream(projectExtensionsPath, FileMode.Create)) using (var stream = new FileStream(projectExtensionsPath, FileMode.Create))
using (var writer = new StreamWriter(stream))
{ {
writer.WriteLine("<!-- Auto-generated by dotnet-user-secrets. This file can be deleted and should not be commited to source control. -->");
resource.CopyTo(stream); resource.CopyTo(stream);
} }
} }
@ -120,4 +118,4 @@ namespace Microsoft.Extensions.SecretManager.Tools.Internal
} }
} }
} }
} }

View File

@ -22,7 +22,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
[Fact] [Fact]
public async Task ChangeFileInDependency() public async Task ChangeFileInDependency()
{ {
await _app.StartWatcher().OrTimeout(); await _app.StartWatcherAsync().OrTimeout();
var fileToChange = Path.Combine(_app.DependencyFolder, "Foo.cs"); var fileToChange = Path.Combine(_app.DependencyFolder, "Foo.cs");
var programCs = File.ReadAllText(fileToChange); var programCs = File.ReadAllText(fileToChange);

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Text; using System.Text;
@ -9,8 +10,8 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow; using System.Threading.Tasks.Dataflow;
using Microsoft.Extensions.Internal; using Microsoft.Extensions.Internal;
using Xunit.Abstractions;
using Microsoft.Extensions.Tools.Internal; using Microsoft.Extensions.Tools.Internal;
using Xunit.Abstractions;
namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
{ {
@ -71,6 +72,21 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
return null; return null;
} }
public async Task<IList<string>> GetAllOutputLines()
{
var lines = new List<string>();
while (!_source.Completion.IsCompleted)
{
while (await _source.OutputAvailableAsync())
{
var next = await _source.ReceiveAsync();
_logger.WriteLine($"{DateTime.Now}: recv: '{next}'");
lines.Add(next);
}
}
return lines;
}
private void StartProcessingOutput(StreamReader streamReader) private void StartProcessingOutput(StreamReader streamReader)
{ {
_source = _source ?? new BufferBlock<string>(); _source = _source ?? new BufferBlock<string>();
@ -80,7 +96,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
string line; string line;
while ((line = streamReader.ReadLine()) != null) while ((line = streamReader.ReadLine()) != null)
{ {
_logger.WriteLine($"{DateTime.Now} post: {line}"); _logger.WriteLine($"{DateTime.Now}: post: '{line}'");
_source.Post(line); _source.Post(line);
} }

View File

@ -5,6 +5,7 @@ using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.DotNet.Watcher.Tools.Tests;
using Xunit; using Xunit;
using Xunit.Abstractions; using Xunit.Abstractions;
@ -24,7 +25,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
[InlineData(false)] [InlineData(false)]
public async Task ChangeCompiledFile(bool usePollingWatcher) public async Task ChangeCompiledFile(bool usePollingWatcher)
{ {
await _app.StartWatcher().OrTimeout(); await _app.StartWatcherAsync().OrTimeout();
var types = await _app.GetCompiledAppDefinedTypes().OrTimeout(); var types = await _app.GetCompiledAppDefinedTypes().OrTimeout();
Assert.Equal(2, types); Assert.Equal(2, types);
@ -41,7 +42,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
[Fact(Skip = "Broken. See https://github.com/aspnet/DotNetTools/issues/212")] [Fact(Skip = "Broken. See https://github.com/aspnet/DotNetTools/issues/212")]
public async Task AddCompiledFile() public async Task AddCompiledFile()
{ {
await _app.StartWatcher().OrTimeout(); await _app.StartWatcherAsync().OrTimeout();
var types = await _app.GetCompiledAppDefinedTypes().OrTimeout(); var types = await _app.GetCompiledAppDefinedTypes().OrTimeout();
Assert.Equal(2, types); Assert.Equal(2, types);
@ -57,7 +58,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
[Fact] [Fact]
public async Task DeleteCompiledFile() public async Task DeleteCompiledFile()
{ {
await _app.StartWatcher().OrTimeout(); await _app.StartWatcherAsync().OrTimeout();
var types = await _app.GetCompiledAppDefinedTypes().OrTimeout(); var types = await _app.GetCompiledAppDefinedTypes().OrTimeout();
Assert.Equal(2, types); Assert.Equal(2, types);
@ -73,7 +74,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
[Fact] [Fact]
public async Task DeleteSourceFolder() public async Task DeleteSourceFolder()
{ {
await _app.StartWatcher().OrTimeout(); await _app.StartWatcherAsync().OrTimeout();
var types = await _app.GetCompiledAppDefinedTypes().OrTimeout(); var types = await _app.GetCompiledAppDefinedTypes().OrTimeout();
Assert.Equal(2, types); Assert.Equal(2, types);
@ -89,7 +90,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
[Fact] [Fact]
public async Task RenameCompiledFile() public async Task RenameCompiledFile()
{ {
await _app.StartWatcher().OrTimeout(); await _app.StartWatcherAsync().OrTimeout();
var oldFile = Path.Combine(_app.SourceDirectory, "include", "Foo.cs"); var oldFile = Path.Combine(_app.SourceDirectory, "include", "Foo.cs");
var newFile = Path.Combine(_app.SourceDirectory, "include", "Foo_new.cs"); var newFile = Path.Combine(_app.SourceDirectory, "include", "Foo_new.cs");
@ -101,7 +102,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
[Fact] [Fact]
public async Task ChangeExcludedFile() public async Task ChangeExcludedFile()
{ {
await _app.StartWatcher().OrTimeout(); await _app.StartWatcherAsync().OrTimeout();
var changedFile = Path.Combine(_app.SourceDirectory, "exclude", "Baz.cs"); var changedFile = Path.Combine(_app.SourceDirectory, "exclude", "Baz.cs");
File.WriteAllText(changedFile, ""); File.WriteAllText(changedFile, "");
@ -111,6 +112,23 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
Assert.NotSame(restart, finished); Assert.NotSame(restart, finished);
} }
[Fact]
public async Task ListsFiles()
{
_app.Start(new [] { "--list" });
var lines = await _app.Process.GetAllOutputLines();
AssertEx.EqualFileList(
_app.Scenario.WorkFolder,
new[]
{
"GlobbingApp/Program.cs",
"GlobbingApp/include/Foo.cs",
"GlobbingApp/GlobbingApp.csproj",
},
lines);
}
public void Dispose() public void Dispose()
{ {
_app.Dispose(); _app.Dispose();

View File

@ -23,7 +23,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
[Fact] [Fact]
public async Task RestartProcessOnFileChange() public async Task RestartProcessOnFileChange()
{ {
await _app.StartWatcher(new[] { "--no-exit" }).OrTimeout(); await _app.StartWatcherAsync(new[] { "--no-exit" }).OrTimeout();
var pid = await _app.GetProcessId().OrTimeout(); var pid = await _app.GetProcessId().OrTimeout();
// Then wait for it to restart when we change a file // Then wait for it to restart when we change a file
@ -42,7 +42,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
[Fact] [Fact]
public async Task RestartProcessThatTerminatesAfterFileChange() public async Task RestartProcessThatTerminatesAfterFileChange()
{ {
await _app.StartWatcher().OrTimeout(); await _app.StartWatcherAsync().OrTimeout();
var pid = await _app.GetProcessId().OrTimeout(); var pid = await _app.GetProcessId().OrTimeout();
await _app.HasExited().OrTimeout(); // process should exit after run await _app.HasExited().OrTimeout(); // process should exit after run

View File

@ -118,17 +118,17 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
// this launches a new .NET Core process using the runtime of the current test app // this launches a new .NET Core process using the runtime of the current test app
// and the version of dotnet-watch that this test app is compiled against // and the version of dotnet-watch that this test app is compiled against
var thisAssembly = Path.GetFileNameWithoutExtension(GetType().GetTypeInfo().Assembly.Location); var thisAssembly = Path.GetFileNameWithoutExtension(GetType().GetTypeInfo().Assembly.Location);
var args = new List<string>();
args.Add("exec");
args.Add("--depsfile"); var args = new List<string>
args.Add(Path.Combine(AppContext.BaseDirectory, thisAssembly + ".deps.json")); {
"exec",
"--depsfile",
Path.Combine(AppContext.BaseDirectory, thisAssembly + ".deps.json"),
"--runtimeconfig",
Path.Combine(AppContext.BaseDirectory, thisAssembly + ".runtimeconfig.json")
};
args.Add("--runtimeconfig"); if (AppContext.GetData("FX_DEPS_FILE") is string currentFxVersion)
args.Add(Path.Combine(AppContext.BaseDirectory, thisAssembly + ".runtimeconfig.json"));
var currentFxVersion = AppContext.GetData("FX_DEPS_FILE") as string;
if (currentFxVersion != null)
{ {
// This overrides the version of shared fx in the runtimeconfig.json file. // This overrides the version of shared fx in the runtimeconfig.json file.
// Tests do this to ensure dotnet-watch is executing on the version of Microsoft.NETCore.App // Tests do this to ensure dotnet-watch is executing on the version of Microsoft.NETCore.App

View File

@ -1,12 +1,13 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.Extensions.Tools.Internal;
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Tools.Internal;
using Xunit.Abstractions; using Xunit.Abstractions;
namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
@ -16,12 +17,11 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
private const string StartedMessage = "Started"; private const string StartedMessage = "Started";
private const string ExitingMessage = "Exiting"; private const string ExitingMessage = "Exiting";
protected ProjectToolScenario Scenario { get; }
private readonly ITestOutputHelper _logger; private readonly ITestOutputHelper _logger;
protected AwaitableProcess Process { get; set; }
private string _appName; private string _appName;
private bool _prepared; private bool _prepared;
public WatchableApp(string appName, ITestOutputHelper logger) public WatchableApp(string appName, ITestOutputHelper logger)
{ {
_logger = logger; _logger = logger;
@ -31,6 +31,10 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
SourceDirectory = Path.Combine(Scenario.WorkFolder, appName); SourceDirectory = Path.Combine(Scenario.WorkFolder, appName);
} }
public ProjectToolScenario Scenario { get; }
public AwaitableProcess Process { get; protected set; }
public string SourceDirectory { get; } public string SourceDirectory { get; }
public Task HasRestarted() public Task HasRestarted()
@ -41,9 +45,6 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
public bool UsePollingWatcher { get; set; } public bool UsePollingWatcher { get; set; }
public Task StartWatcher([CallerMemberName] string name = null)
=> StartWatcher(Array.Empty<string>(), name);
public async Task<int> GetProcessId() public async Task<int> GetProcessId()
{ {
var line = await Process.GetOutputLineAsync(l => l.StartsWith("PID =")); var line = await Process.GetOutputLineAsync(l => l.StartsWith("PID ="));
@ -58,7 +59,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
_prepared = true; _prepared = true;
} }
public async Task StartWatcher(string[] arguments, [CallerMemberName] string name = null) public void Start(IEnumerable<string> arguments, [CallerMemberName] string name = null)
{ {
if (!_prepared) if (!_prepared)
{ {
@ -67,7 +68,6 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
var args = Scenario var args = Scenario
.GetDotnetWatchArguments() .GetDotnetWatchArguments()
.Concat(new[] { "run", "--" })
.Concat(arguments); .Concat(arguments);
var spec = new ProcessSpec var spec = new ProcessSpec
@ -79,6 +79,15 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
Process = new AwaitableProcess(spec, _logger); Process = new AwaitableProcess(spec, _logger);
Process.Start(); Process.Start();
}
public Task StartWatcherAsync([CallerMemberName] string name = null)
=> StartWatcherAsync(Array.Empty<string>(), name);
public async Task StartWatcherAsync(string[] arguments, [CallerMemberName] string name = null)
{
var args = new[] { "run", "--" }.Concat(arguments);
Start(args, name);
await Process.GetOutputLineAsync(StartedMessage); await Process.GetOutputLineAsync(StartedMessage);
} }

View File

@ -297,7 +297,8 @@ namespace Microsoft.DotNet.Watcher.Tools.Tests
} }
private Task<IFileSet> GetFileSet(TemporaryCSharpProject target) private Task<IFileSet> GetFileSet(TemporaryCSharpProject target)
=> GetFileSet(new MsBuildFileSetFactory(_reporter, target.Path)); => GetFileSet(new MsBuildFileSetFactory(_reporter, target.Path, waitOnError: false));
private async Task<IFileSet> GetFileSet(MsBuildFileSetFactory filesetFactory) private async Task<IFileSet> GetFileSet(MsBuildFileSetFactory filesetFactory)
{ {
_tempDir.Create(); _tempDir.Create();
@ -305,6 +306,7 @@ namespace Microsoft.DotNet.Watcher.Tools.Tests
var finished = await Task.WhenAny(createTask, Task.Delay(TimeSpan.FromSeconds(10))); var finished = await Task.WhenAny(createTask, Task.Delay(TimeSpan.FromSeconds(10)));
Assert.Same(createTask, finished); Assert.Same(createTask, finished);
Assert.NotNull(createTask.Result);
return createTask.Result; return createTask.Result;
} }