Simplify the MSBuild targets in dotnet-watch

Use CustomAfterMicrosoftCommonTargets instead of MSBuildProjectExtensionsPath.
 - No more need to write to obj/$(Project).g.dotnetwatch.targets
 - Works on project that have changed default file locations via BaseIntermediateOutputPath

Simplify DotNetWatch targets
 - Condense to one targets file
 - Simplify dependency chain of targets
 - Build project references in a parallel
This commit is contained in:
Nate McMaster 2017-09-22 12:19:39 -07:00
parent aa93ce9299
commit 3dd029a8b5
17 changed files with 119 additions and 298 deletions

View File

@ -13,6 +13,8 @@
<!-- Binary compatiblity is not a goal for command-line tools. -->
<EnableApiCheck>false</EnableApiCheck>
<BaseIntermediateOutputPath>$(MSBuildThisFileDirectory)obj\$(MSBuildProjectName)\</BaseIntermediateOutputPath>
<BaseOutputPath>$(MSBuildThisFileDirectory)bin\$(MSBuildProjectName)\</BaseOutputPath>
</PropertyGroup>
</Project>

View File

@ -13,7 +13,6 @@ namespace Microsoft.DotNet.Watcher
internal class CommandLineOptions
{
public string Project { get; private set; }
public string MSBuildProjectExtensionsPath { get; private set; }
public bool IsHelp { get; private set; }
public bool IsQuiet { get; private set; }
public bool IsVerbose { get; private set; }
@ -78,12 +77,6 @@ Examples:
var optProjects = app.Option("-p|--project <PROJECT>", "The project to watch",
CommandOptionType.SingleValue);
var optMSBuildProjectExtensionsPath = app.Option("--msbuildprojectextensionspath <PATH>",
"The MSBuild project extensions path. Defaults to \"obj\".",
CommandOptionType.SingleValue);
// Hide from help text because this is an internal option that will hopefully go away when/if #244 is resolved.
optMSBuildProjectExtensionsPath.ShowInHelpText = false;
var optQuiet = app.Option("-q|--quiet", "Suppresses all output except warnings and errors",
CommandOptionType.NoValue);
var optVerbose = app.VerboseOption();
@ -113,7 +106,6 @@ Examples:
return new CommandLineOptions
{
Project = optProjects.Value(),
MSBuildProjectExtensionsPath = optMSBuildProjectExtensionsPath.Value(),
IsQuiet = optQuiet.HasValue(),
IsVerbose = optVerbose.HasValue(),
RemainingArguments = app.RemainingArguments,

View File

@ -17,21 +17,19 @@ namespace Microsoft.DotNet.Watcher.Internal
public class MsBuildFileSetFactory : IFileSetFactory
{
private const string TargetName = "GenerateWatchList";
private const string ProjectExtensionFileExtension = ".dotnetwatch.g.targets";
private const string WatchTargetsFileName = "DotNetWatchCommon.targets";
private const string WatchTargetsFileName = "DotNetWatch.targets";
private readonly IReporter _reporter;
private readonly string _projectFile;
private readonly string _projectExtensionsPath;
private readonly string _watchTargetsDir;
private readonly OutputSink _outputSink;
private readonly ProcessRunner _processRunner;
private readonly bool _waitOnError;
private readonly IReadOnlyList<string> _buildFlags;
public MsBuildFileSetFactory(IReporter reporter,
string projectFile,
string msBuildProjectExtensionsPath,
bool waitOnError)
: this(reporter, projectFile, msBuildProjectExtensionsPath, new OutputSink())
bool waitOnError,
bool trace)
: this(reporter, projectFile, new OutputSink(), trace)
{
_waitOnError = waitOnError;
}
@ -39,8 +37,8 @@ namespace Microsoft.DotNet.Watcher.Internal
// output sink is for testing
internal MsBuildFileSetFactory(IReporter reporter,
string projectFile,
string msBuildProjectExtensionsPath,
OutputSink outputSink)
OutputSink outputSink,
bool trace)
{
Ensure.NotNull(reporter, nameof(reporter));
Ensure.NotNullOrEmpty(projectFile, nameof(projectFile));
@ -48,29 +46,13 @@ namespace Microsoft.DotNet.Watcher.Internal
_reporter = reporter;
_projectFile = projectFile;
_watchTargetsDir = FindWatchTargetsDir();
_outputSink = outputSink;
_processRunner = new ProcessRunner(reporter);
// default value for MSBuildProjectExtensionsPath is $(BaseIntermediateOutputPath), which defaults to 'obj/'.
_projectExtensionsPath = string.IsNullOrEmpty(msBuildProjectExtensionsPath)
? Path.Combine(Path.GetDirectoryName(_projectFile), "obj")
: msBuildProjectExtensionsPath;
_buildFlags = InitializeArgs(FindTargetsFile(), trace);
}
internal List<string> BuildFlags { get; } = new List<string>
{
"/nologo",
"/v:n",
"/t:" + TargetName,
"/p:DotNetWatchBuild=true", // extensibility point for users
"/p:DesignTimeBuild=true", // don't do expensive things
};
public async Task<IFileSet> CreateAsync(CancellationToken cancellationToken)
{
EnsureInitialized();
var watchList = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
try
{
@ -91,9 +73,8 @@ namespace Microsoft.DotNet.Watcher.Internal
{
"msbuild",
_projectFile,
$"/p:_DotNetWatchTargetsLocation={_watchTargetsDir}", // add our dotnet-watch targets
$"/p:_DotNetWatchListFile={watchList}"
}.Concat(BuildFlags),
}.Concat(_buildFlags),
OutputCapture = capture
};
@ -162,29 +143,31 @@ namespace Microsoft.DotNet.Watcher.Internal
}
}
// Ensures file exists in $(MSBuildProjectExtensionsPath)/$(MSBuildProjectFile).dotnetwatch.targets
private void EnsureInitialized()
private IReadOnlyList<string> InitializeArgs(string watchTargetsFile, bool trace)
{
// see https://github.com/Microsoft/msbuild/blob/bf9b21cc7869b96ea2289ff31f6aaa5e1d525a26/src/XMakeTasks/Microsoft.Common.targets#L127
var projectExtensionFile = Path.Combine(_projectExtensionsPath,
Path.GetFileName(_projectFile) + ProjectExtensionFileExtension);
if (!File.Exists(projectExtensionFile))
var args = new List<string>
{
// ensure obj folder is available
Directory.CreateDirectory(Path.GetDirectoryName(projectExtensionFile));
"/nologo",
"/v:n",
"/t:" + TargetName,
"/p:DotNetWatchBuild=true", // extensibility point for users
"/p:DesignTimeBuild=true", // don't do expensive things
"/p:CustomAfterMicrosoftCommonTargets=" + watchTargetsFile,
"/p:CustomAfterMicrosoftCommonCrossTargetingTargets=" + watchTargetsFile,
};
using (var fileStream = new FileStream(projectExtensionFile, FileMode.Create))
using (var assemblyStream = GetType().GetTypeInfo().Assembly.GetManifestResourceStream("dotnetwatch.targets"))
{
assemblyStream.CopyTo(fileStream);
}
if (trace)
{
// enables capturing markers to know which projects have been visited
args.Add("/p:_DotNetWatchTraceOutput=true");
}
return args;
}
private string FindWatchTargetsDir()
private string FindTargetsFile()
{
var assemblyDir = Path.GetDirectoryName(GetType().GetTypeInfo().Assembly.Location);
var assemblyDir = Path.GetDirectoryName(typeof(MsBuildFileSetFactory).Assembly.Location);
var searchPaths = new[]
{
AppContext.BaseDirectory,
@ -194,8 +177,13 @@ namespace Microsoft.DotNet.Watcher.Internal
Path.Combine(AppContext.BaseDirectory, "../../toolassets"), // relative to packaged deps.json
};
var targetPath = searchPaths.Select(p => Path.Combine(p, WatchTargetsFileName)).First(File.Exists);
return Path.GetDirectoryName(targetPath);
var targetPath = searchPaths.Select(p => Path.Combine(p, WatchTargetsFileName)).FirstOrDefault(File.Exists);
if (targetPath == null)
{
_reporter.Error("Fatal error: could not find DotNetWatch.targets");
return null;
}
return targetPath;
}
}
}

View File

@ -12,9 +12,8 @@
<ItemGroup>
<Compile Include="..\..\shared\**\*.cs" />
<EmbeddedResource Include="dotnetwatch.targets" LogicalName="dotnetwatch.targets" />
<None Include="prefercliruntime" Pack="true" PackagePath="\prefercliruntime" />
<None Include="toolassets\*.targets" Pack="true" CopyToOutputDirectory="PreserveNewest" PackagePath="%(Identity)" />
<Content Include="prefercliruntime" PackagePath="\prefercliruntime" />
<Content Include="toolassets\DotNetWatch.targets" CopyToOutputDirectory="PreserveNewest" PackagePath="%(Identity)" />
</ItemGroup>
<ItemGroup>

View File

@ -87,14 +87,12 @@ namespace Microsoft.DotNet.Watcher
{
return await ListFilesAsync(_reporter,
options.Project,
options.MSBuildProjectExtensionsPath,
_cts.Token);
}
else
{
return await MainInternalAsync(_reporter,
options.Project,
options.MSBuildProjectExtensionsPath,
options.RemainingArguments,
_cts.Token);
}
@ -129,7 +127,6 @@ namespace Microsoft.DotNet.Watcher
private async Task<int> MainInternalAsync(
IReporter reporter,
string project,
string msbuildProjectExtensionsPath,
ICollection<string> args,
CancellationToken cancellationToken)
{
@ -147,8 +144,8 @@ namespace Microsoft.DotNet.Watcher
var fileSetFactory = new MsBuildFileSetFactory(reporter,
projectFile,
NormalizePath(msbuildProjectExtensionsPath),
waitOnError: true);
waitOnError: true,
trace: false);
var processInfo = new ProcessSpec
{
Executable = DotNetMuxer.MuxerPathOrDefault(),
@ -174,7 +171,6 @@ namespace Microsoft.DotNet.Watcher
private async Task<int> ListFilesAsync(
IReporter reporter,
string project,
string msbuildProjectExtensionsPath,
CancellationToken cancellationToken)
{
// TODO multiple projects should be easy enough to add here
@ -191,8 +187,8 @@ namespace Microsoft.DotNet.Watcher
var fileSetFactory = new MsBuildFileSetFactory(reporter,
projectFile,
NormalizePath(msbuildProjectExtensionsPath),
waitOnError: false);
waitOnError: false,
trace: false);
var files = await fileSetFactory.CreateAsync(cancellationToken);
if (files == null)
@ -211,21 +207,6 @@ namespace Microsoft.DotNet.Watcher
private static IReporter CreateReporter(bool verbose, bool quiet, IConsole console)
=> new PrefixConsoleReporter(console, verbose || CliContext.IsGlobalVerbose(), quiet);
private string NormalizePath(string path)
{
if (path == null || Path.IsPathRooted(path))
{
return path;
}
if (string.IsNullOrWhiteSpace(path))
{
return _workingDir;
}
return Path.Combine(_workingDir, path);
}
public void Dispose()
{
_console.CancelKeyPress -= OnCancelKeyPress;

View File

@ -1,18 +0,0 @@
<!-- This file is autogenerated by dotnet-watch. -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<_DotNetWatchTargetsFile Condition="'$(_DotNetWatchTargetsFile)' == ''">$(MSBuildThisFileFullPath)</_DotNetWatchTargetsFile>
</PropertyGroup>
<Import Project="$(_DotNetWatchTargetsLocation)\DotNetWatchCommon.targets"
Condition="Exists('$(_DotNetWatchTargetsLocation)\DotNetWatchCommon.targets')" />
<ImportGroup Condition="'$(TargetFramework)'==''">
<Import Project="$(_DotNetWatchTargetsLocation)\DotNetWatchOuter.targets"
Condition="Exists('$(_DotNetWatchTargetsLocation)\DotNetWatchOuter.targets')" />
</ImportGroup>
<ImportGroup Condition="'$(TargetFramework)'!=''">
<Import Project="$(_DotNetWatchTargetsLocation)\DotNetWatchInner.targets"
Condition="Exists('$(_DotNetWatchTargetsLocation)\DotNetWatchInner.targets')" />
</ImportGroup>
</Project>

View File

@ -0,0 +1,68 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!--
=========================================================================
GenerateWatchList
Main target called by dotnet-watch. It gathers MSBuild items and writes
them to a file.
=========================================================================
-->
<Target Name="GenerateWatchList"
DependsOnTargets="_CollectWatchItems">
<WriteLinesToFile Overwrite="true"
File="$(_DotNetWatchListFile)"
Lines="@(Watch -> '%(FullPath)')" />
</Target>
<!--
=========================================================================
_CollectWatchItems
Gathers all files to be watched.
Returns: @(Watch)
=========================================================================
-->
<PropertyGroup>
<_CollectWatchItemsDependsOn Condition=" '$(TargetFrameworks)' != '' AND '$(TargetFramework)' == '' ">
_CollectWatchItemsPerFramework;
</_CollectWatchItemsDependsOn>
<_CollectWatchItemsDependsOn Condition=" '$(TargetFramework)' != '' ">
_CoreCollectWatchItems;
</_CollectWatchItemsDependsOn>
</PropertyGroup>
<Target Name="_CollectWatchItems" DependsOnTargets="$(_CollectWatchItemsDependsOn)" Returns="@(Watch)" />
<Target Name="_CollectWatchItemsPerFramework">
<ItemGroup>
<_TargetFramework Include="$(TargetFrameworks)" />
</ItemGroup>
<MSBuild Projects="$(MSBuildProjectFullPath)"
Targets="_CoreCollectWatchItems"
Properties="TargetFramework=%(_TargetFramework.Identity)">
<Output TaskParameter="TargetOutputs" ItemName="Watch" />
</MSBuild>
</Target>
<Target Name="_CoreCollectWatchItems" Returns="@(Watch)">
<!-- message used to debug -->
<Message Importance="High" Text="Collecting watch items from '$(MSBuildProjectName)'" Condition="'$(_DotNetWatchTraceOutput)'=='true'" />
<Error Text="TargetFramework should be set" Condition="'$(TargetFramework)' == '' "/>
<ItemGroup>
<Watch Include="%(Compile.FullPath)" Condition="'%(Compile.Watch)' != 'false'" />
<Watch Include="%(EmbeddedResource.FullPath)" Condition="'%(EmbeddedResource.Watch)' != 'false'"/>
<Watch Include="$(MSBuildProjectFullPath)" />
<_WatchProjects Include="%(ProjectReference.Identity)" Condition="'%(ProjectReference.Watch)' != 'false'" />
</ItemGroup>
<MSBuild Projects="@(_WatchProjects)"
Targets="_CollectWatchItems"
BuildInParallel="true">
<Output TaskParameter="TargetOutputs" ItemName="Watch" />
</MSBuild>
</Target>
</Project>

View File

@ -1,28 +0,0 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="_WriteGeneratedWatchList" >
<WriteLinesToFile Overwrite="true"
File="$(_DotNetWatchListFile)"
Lines="@(Watch -> '%(FullPath)')" />
</Target>
<!--
=========================================================================
_CollectWatchItems
Invokes _CoreCollectWatchItems on each distinct project in _DotNetWatchProjects.
Returns: @(Watch)
=========================================================================
-->
<Target Name="_CollectWatchItems">
<RemoveDuplicates Inputs="@(_DotNetWatchProjects)">
<Output TaskParameter="Filtered" ItemName="_DotNetWatchProjectsFiltered" />
</RemoveDuplicates>
<MSBuild
Targets="_CoreCollectWatchItems"
Projects="%(_DotNetWatchProjectsFiltered.FullPath)">
<Output TaskParameter="TargetOutputs" ItemName="Watch"/>
</MSBuild>
</Target>
</Project>

View File

@ -1,70 +0,0 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!--
=========================================================================
GenerateWatchList
Main target called by dotnet-watch. This is the single-tfm version.
For multi-tfm version, see the Outer.targets file for description of the
design of this target.
=========================================================================
-->
<Target Name="GenerateWatchList"
DependsOnTargets="_CollectWatchProjects;_CollectWatchItems;_WriteGeneratedWatchList" />
<!--
=========================================================================
_CoreCollectWatchItems
Creates item group with default set of files to watch.
Returns: @(Watch)
=========================================================================
-->
<Target Name="_CoreCollectWatchItems" Returns="@(Watch)">
<!-- message used to debug -->
<Message Importance="High" Text="Collecting watch items from '$(MSBuildProjectName)'" Condition="'$(_DotNetWatchTraceOutput)'=='true'" />
<ItemGroup>
<Watch Include="@(Compile->'%(FullPath)')" Condition="'%(Compile.Watch)' != 'false'" />
<Watch Include="@(EmbeddedResource->'%(FullPath)')" Condition="'%(EmbeddedResource.Watch)' != 'false'"/>
<Watch Include="$(MSBuildProjectFullPath)" />
</ItemGroup>
</Target>
<!--
=========================================================================
_CollectWatchProjects
Adds all ProjectReference items to _DotNetWatchProjects.
Copies the project file extension file to all project references.
Invokes '_CollectWatchProjects' on all referenced projects.
Returns: @(_DotNetWatchProjects)
=========================================================================
-->
<Target Name="_CollectWatchProjects"
Returns="@(_DotNetWatchProjects)">
<!-- message used to debug -->
<Message Importance="High" Text="Collecting referenced projects from '$(MSBuildProjectName)'" Condition="'$(_DotNetWatchTraceOutput)'=='true'" />
<ItemGroup>
<_DotNetWatchProjects Include="@(ProjectReference->'%(FullPath)')" Condition="'%(ProjectReference.Watch)' != 'false'" />
<_DotNetWatchImportsTargets Include="@(_DotNetWatchProjects->'%(RelativeDir)obj\%(FileName)%(Extension).dotnetwatch.targets')">
<TargetsFile>$(_DotNetWatchTargetsFile)</TargetsFile>
</_DotNetWatchImportsTargets>
</ItemGroup>
<Copy SourceFiles="@(_DotNetWatchImportsTargets->'%(TargetsFile)')"
DestinationFiles="@(_DotNetWatchImportsTargets)"
SkipUnchangedFiles="true" />
<MSBuild
Targets="_CollectWatchProjects"
Projects="%(_DotNetWatchProjects.FullPath)">
<Output TaskParameter="TargetOutputs" ItemName="_DotNetWatchProjects"/>
</MSBuild>
<ItemGroup>
<_DotNetWatchProjects Include="$(MSBuildProjectFullPath)"/>
</ItemGroup>
</Target>
</Project>

View File

@ -1,69 +0,0 @@
<Project
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!--
=========================================================================
GenerateWatchList
Main target called by dotnet-watch. This is the cross-targetting version.
For single-tfm, the 'GenerateWatchList' in Inner.targets is the main target.
Phase 1: _CollectWatchProjects:
traverses the project-to-project graph to resolve all projects referenced.
Phase 2: _CollectWatchItems:
for each unique project file from phase 1, extracts all 'Watch' items and
collects into a single item group. All values should be a fullpath.
Phase 3: _WriteGeneratedWatchList:
write all files to a file that can be read by dotnet-watch
=========================================================================
-->
<Target Name="GenerateWatchList"
DependsOnTargets="_CollectWatchProjects;_CollectWatchItems;_WriteGeneratedWatchList"
/>
<!--
=========================================================================
_CoreCollectWatchItems
Shim for cross-targetting builds to run _CoreCollectWatchItems for each target
framework.
Returns: @(Watch)
=========================================================================
-->
<Target Name="_CoreCollectWatchItems"
Returns="@(Watch)">
<ItemGroup>
<_TargetFramework Include="$(TargetFrameworks)" />
</ItemGroup>
<MSBuild Projects="$(MSBuildProjectFile)"
Condition="'$(TargetFrameworks)' != '' "
Targets="_CoreCollectWatchItems"
Properties="TargetFramework=%(_TargetFramework.Identity)">
<Output ItemName="Watch" TaskParameter="TargetOutputs" />
</MSBuild>
</Target>
<!--
=========================================================================
_CollectWatchProjects
Shim for cross-targetting builds to run _CollectWatchProjects for each target
framework.
Returns: @(_DotNetWatchProjects)
=========================================================================
-->
<Target Name="_CollectWatchProjects" Returns="@(_DotNetWatchProjects)">
<ItemGroup>
<_TargetFramework Include="$(TargetFrameworks)" />
</ItemGroup>
<MSBuild Projects="$(MSBuildProjectFile)"
Condition="'$(TargetFrameworks)' != '' "
Targets="_CollectWatchProjects"
Properties="TargetFramework=%(_TargetFramework.Identity)">
<Output ItemName="_DotNetWatchProjects" TaskParameter="TargetOutputs" />
</MSBuild>
</Target>
</Project>

View File

@ -41,11 +41,6 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
: base("KitchenSink", logger)
{
}
protected override IEnumerable<string> GetDefaultArgs()
{
return new[] { "--msbuildprojectextensionspath", ".net/obj", "run", "--" };
}
}
}
}

View File

@ -8,9 +8,7 @@
<ItemGroup>
<Compile Include="..\Shared\**\*.cs" />
<Content Include="TestProjects\**\*" CopyToOutputDirectory="PreserveNewest" />
<Content Include="..\..\src\Microsoft.DotNet.Watcher.Tools\toolassets\DotNetWatchInner.targets" Link="toolassets\DotNetWatchInner.targets" CopyToOutputDirectory="PreserveNewest" />
<Content Include="..\..\src\Microsoft.DotNet.Watcher.Tools\toolassets\DotNetWatchOuter.targets" Link="toolassets\DotNetWatchOuter.targets" CopyToOutputDirectory="PreserveNewest" />
<Content Include="..\..\src\Microsoft.DotNet.Watcher.Tools\toolassets\DotNetWatchCommon.targets" Link="toolassets\DotNetWatchCommon.targets" CopyToOutputDirectory="PreserveNewest" />
<Content Include="..\..\src\Microsoft.DotNet.Watcher.Tools\toolassets\DotNetWatch.targets" Link="toolassets\DotNetWatch.targets" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup>

View File

@ -99,7 +99,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
await PrepareAsync();
}
var args = GetDefaultArgs().Concat(arguments);
var args = new[] { "run", "--" }.Concat(arguments);
Start(args, name);
// Make this timeout long because it depends much on the MSBuild compilation speed.
@ -107,11 +107,6 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
await Process.GetOutputLineAsync(StartedMessage).TimeoutAfter(TimeSpan.FromMinutes(2));
}
protected virtual IEnumerable<string> GetDefaultArgs()
{
return new[] { "run", "--" };
}
public virtual void Dispose()
{
_logger?.WriteLine("Disposing WatchableApp");

View File

@ -2,6 +2,7 @@
<PropertyGroup>
<BaseIntermediateOutputPath>.net/obj</BaseIntermediateOutputPath>
<BaseOutputPath>.net/bin</BaseOutputPath>
</PropertyGroup>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />

View File

@ -20,14 +20,14 @@ namespace Microsoft.DotNet.Watcher.Tools.Tests
public static void EqualFileList(IEnumerable<string> expectedFiles, IEnumerable<string> actualFiles)
{
Func<string, string> normalize = p => p.Replace('\\', '/');
string normalize(string p) => p.Replace('\\', '/');
var expected = new HashSet<string>(expectedFiles.Select(normalize));
var actual = new HashSet<string>(actualFiles.Where(p => !string.IsNullOrEmpty(p)).Select(normalize));
if (!expected.SetEquals(actual))
{
throw new AssertActualExpectedException(
expected: string.Join("\n", expected),
actual: string.Join("\n", actual),
expected: "\n" + string.Join("\n", expected),
actual: "\n" + string.Join("\n", actual),
userMessage: "File sets should be equal");
}
}

View File

@ -6,9 +6,7 @@
<ItemGroup>
<Compile Include="..\Shared\**\*.cs" />
<Content Include="..\..\src\Microsoft.DotNet.Watcher.Tools\toolassets\DotNetWatchInner.targets" Link="toolassets\DotNetWatchInner.targets" CopyToOutputDirectory="PreserveNewest" />
<Content Include="..\..\src\Microsoft.DotNet.Watcher.Tools\toolassets\DotNetWatchOuter.targets" Link="toolassets\DotNetWatchOuter.targets" CopyToOutputDirectory="PreserveNewest" />
<Content Include="..\..\src\Microsoft.DotNet.Watcher.Tools\toolassets\DotNetWatchCommon.targets" Link="toolassets\DotNetWatchCommon.targets" CopyToOutputDirectory="PreserveNewest" />
<Content Include="..\..\src\Microsoft.DotNet.Watcher.Tools\toolassets\DotNetWatch.targets" Link="toolassets\DotNetWatch.targets" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup>

View File

@ -238,11 +238,7 @@ namespace Microsoft.DotNet.Watcher.Tools.Tests
graph.Find("A").WithProjectReference(graph.Find("W"), watch: false);
var output = new OutputSink();
var filesetFactory = new MsBuildFileSetFactory(_reporter, graph.GetOrCreate("A").Path, null, output)
{
// enables capturing markers to know which projects have been visited
BuildFlags = { "/p:_DotNetWatchTraceOutput=true" }
};
var filesetFactory = new MsBuildFileSetFactory(_reporter, graph.GetOrCreate("A").Path, output, trace: true);
var fileset = await GetFileSet(filesetFactory);
@ -270,17 +266,10 @@ namespace Microsoft.DotNet.Watcher.Tools.Tests
Assert.Single(output.Current.Lines,
line => line.Contains($"Collecting watch items from '{projectName}'"))
);
// ensure each project is only visited once to collect project references
Assert.All(includedProjects,
projectName =>
Assert.Single(output.Current.Lines,
line => line.Contains($"Collecting referenced projects from '{projectName}'"))
);
}
private Task<IFileSet> GetFileSet(TemporaryCSharpProject target)
=> GetFileSet(new MsBuildFileSetFactory(_reporter, target.Path, null, waitOnError: false));
=> GetFileSet(new MsBuildFileSetFactory(_reporter, target.Path, waitOnError: false, trace: false));
private async Task<IFileSet> GetFileSet(MsBuildFileSetFactory filesetFactory)
{