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:
parent
aa93ce9299
commit
3dd029a8b5
|
|
@ -13,6 +13,8 @@
|
||||||
|
|
||||||
<!-- Binary compatiblity is not a goal for command-line tools. -->
|
<!-- Binary compatiblity is not a goal for command-line tools. -->
|
||||||
<EnableApiCheck>false</EnableApiCheck>
|
<EnableApiCheck>false</EnableApiCheck>
|
||||||
|
<BaseIntermediateOutputPath>$(MSBuildThisFileDirectory)obj\$(MSBuildProjectName)\</BaseIntermediateOutputPath>
|
||||||
|
<BaseOutputPath>$(MSBuildThisFileDirectory)bin\$(MSBuildProjectName)\</BaseOutputPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ namespace Microsoft.DotNet.Watcher
|
||||||
internal class CommandLineOptions
|
internal class CommandLineOptions
|
||||||
{
|
{
|
||||||
public string Project { get; private set; }
|
public string Project { get; private set; }
|
||||||
public string MSBuildProjectExtensionsPath { get; private set; }
|
|
||||||
public bool IsHelp { get; private set; }
|
public bool IsHelp { get; private set; }
|
||||||
public bool IsQuiet { get; private set; }
|
public bool IsQuiet { get; private set; }
|
||||||
public bool IsVerbose { 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",
|
var optProjects = app.Option("-p|--project <PROJECT>", "The project to watch",
|
||||||
CommandOptionType.SingleValue);
|
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",
|
var optQuiet = app.Option("-q|--quiet", "Suppresses all output except warnings and errors",
|
||||||
CommandOptionType.NoValue);
|
CommandOptionType.NoValue);
|
||||||
var optVerbose = app.VerboseOption();
|
var optVerbose = app.VerboseOption();
|
||||||
|
|
@ -113,7 +106,6 @@ Examples:
|
||||||
return new CommandLineOptions
|
return new CommandLineOptions
|
||||||
{
|
{
|
||||||
Project = optProjects.Value(),
|
Project = optProjects.Value(),
|
||||||
MSBuildProjectExtensionsPath = optMSBuildProjectExtensionsPath.Value(),
|
|
||||||
IsQuiet = optQuiet.HasValue(),
|
IsQuiet = optQuiet.HasValue(),
|
||||||
IsVerbose = optVerbose.HasValue(),
|
IsVerbose = optVerbose.HasValue(),
|
||||||
RemainingArguments = app.RemainingArguments,
|
RemainingArguments = app.RemainingArguments,
|
||||||
|
|
|
||||||
|
|
@ -17,21 +17,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.g.targets";
|
private const string WatchTargetsFileName = "DotNetWatch.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 _projectExtensionsPath;
|
|
||||||
private readonly string _watchTargetsDir;
|
|
||||||
private readonly OutputSink _outputSink;
|
private readonly OutputSink _outputSink;
|
||||||
private readonly ProcessRunner _processRunner;
|
private readonly ProcessRunner _processRunner;
|
||||||
private readonly bool _waitOnError;
|
private readonly bool _waitOnError;
|
||||||
|
private readonly IReadOnlyList<string> _buildFlags;
|
||||||
|
|
||||||
public MsBuildFileSetFactory(IReporter reporter,
|
public MsBuildFileSetFactory(IReporter reporter,
|
||||||
string projectFile,
|
string projectFile,
|
||||||
string msBuildProjectExtensionsPath,
|
bool waitOnError,
|
||||||
bool waitOnError)
|
bool trace)
|
||||||
: this(reporter, projectFile, msBuildProjectExtensionsPath, new OutputSink())
|
: this(reporter, projectFile, new OutputSink(), trace)
|
||||||
{
|
{
|
||||||
_waitOnError = waitOnError;
|
_waitOnError = waitOnError;
|
||||||
}
|
}
|
||||||
|
|
@ -39,8 +37,8 @@ namespace Microsoft.DotNet.Watcher.Internal
|
||||||
// output sink is for testing
|
// output sink is for testing
|
||||||
internal MsBuildFileSetFactory(IReporter reporter,
|
internal MsBuildFileSetFactory(IReporter reporter,
|
||||||
string projectFile,
|
string projectFile,
|
||||||
string msBuildProjectExtensionsPath,
|
OutputSink outputSink,
|
||||||
OutputSink outputSink)
|
bool trace)
|
||||||
{
|
{
|
||||||
Ensure.NotNull(reporter, nameof(reporter));
|
Ensure.NotNull(reporter, nameof(reporter));
|
||||||
Ensure.NotNullOrEmpty(projectFile, nameof(projectFile));
|
Ensure.NotNullOrEmpty(projectFile, nameof(projectFile));
|
||||||
|
|
@ -48,29 +46,13 @@ namespace Microsoft.DotNet.Watcher.Internal
|
||||||
|
|
||||||
_reporter = reporter;
|
_reporter = reporter;
|
||||||
_projectFile = projectFile;
|
_projectFile = projectFile;
|
||||||
_watchTargetsDir = FindWatchTargetsDir();
|
|
||||||
_outputSink = outputSink;
|
_outputSink = outputSink;
|
||||||
_processRunner = new ProcessRunner(reporter);
|
_processRunner = new ProcessRunner(reporter);
|
||||||
|
_buildFlags = InitializeArgs(FindTargetsFile(), trace);
|
||||||
// default value for MSBuildProjectExtensionsPath is $(BaseIntermediateOutputPath), which defaults to 'obj/'.
|
|
||||||
_projectExtensionsPath = string.IsNullOrEmpty(msBuildProjectExtensionsPath)
|
|
||||||
? Path.Combine(Path.GetDirectoryName(_projectFile), "obj")
|
|
||||||
: msBuildProjectExtensionsPath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
public async Task<IFileSet> CreateAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
EnsureInitialized();
|
|
||||||
|
|
||||||
var watchList = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
|
var watchList = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -91,9 +73,8 @@ namespace Microsoft.DotNet.Watcher.Internal
|
||||||
{
|
{
|
||||||
"msbuild",
|
"msbuild",
|
||||||
_projectFile,
|
_projectFile,
|
||||||
$"/p:_DotNetWatchTargetsLocation={_watchTargetsDir}", // add our dotnet-watch targets
|
|
||||||
$"/p:_DotNetWatchListFile={watchList}"
|
$"/p:_DotNetWatchListFile={watchList}"
|
||||||
}.Concat(BuildFlags),
|
}.Concat(_buildFlags),
|
||||||
OutputCapture = capture
|
OutputCapture = capture
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -162,29 +143,31 @@ namespace Microsoft.DotNet.Watcher.Internal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensures file exists in $(MSBuildProjectExtensionsPath)/$(MSBuildProjectFile).dotnetwatch.targets
|
private IReadOnlyList<string> InitializeArgs(string watchTargetsFile, bool trace)
|
||||||
private void EnsureInitialized()
|
|
||||||
{
|
{
|
||||||
// see https://github.com/Microsoft/msbuild/blob/bf9b21cc7869b96ea2289ff31f6aaa5e1d525a26/src/XMakeTasks/Microsoft.Common.targets#L127
|
var args = new List<string>
|
||||||
var projectExtensionFile = Path.Combine(_projectExtensionsPath,
|
|
||||||
Path.GetFileName(_projectFile) + ProjectExtensionFileExtension);
|
|
||||||
|
|
||||||
if (!File.Exists(projectExtensionFile))
|
|
||||||
{
|
{
|
||||||
// ensure obj folder is available
|
"/nologo",
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(projectExtensionFile));
|
"/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))
|
if (trace)
|
||||||
using (var assemblyStream = GetType().GetTypeInfo().Assembly.GetManifestResourceStream("dotnetwatch.targets"))
|
{
|
||||||
{
|
// enables capturing markers to know which projects have been visited
|
||||||
assemblyStream.CopyTo(fileStream);
|
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[]
|
var searchPaths = new[]
|
||||||
{
|
{
|
||||||
AppContext.BaseDirectory,
|
AppContext.BaseDirectory,
|
||||||
|
|
@ -194,8 +177,13 @@ namespace Microsoft.DotNet.Watcher.Internal
|
||||||
Path.Combine(AppContext.BaseDirectory, "../../toolassets"), // relative to packaged deps.json
|
Path.Combine(AppContext.BaseDirectory, "../../toolassets"), // relative to packaged deps.json
|
||||||
};
|
};
|
||||||
|
|
||||||
var targetPath = searchPaths.Select(p => Path.Combine(p, WatchTargetsFileName)).First(File.Exists);
|
var targetPath = searchPaths.Select(p => Path.Combine(p, WatchTargetsFileName)).FirstOrDefault(File.Exists);
|
||||||
return Path.GetDirectoryName(targetPath);
|
if (targetPath == null)
|
||||||
|
{
|
||||||
|
_reporter.Error("Fatal error: could not find DotNetWatch.targets");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return targetPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,8 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="..\..\shared\**\*.cs" />
|
<Compile Include="..\..\shared\**\*.cs" />
|
||||||
<EmbeddedResource Include="dotnetwatch.targets" LogicalName="dotnetwatch.targets" />
|
<Content Include="prefercliruntime" PackagePath="\prefercliruntime" />
|
||||||
<None Include="prefercliruntime" Pack="true" PackagePath="\prefercliruntime" />
|
<Content Include="toolassets\DotNetWatch.targets" CopyToOutputDirectory="PreserveNewest" PackagePath="%(Identity)" />
|
||||||
<None Include="toolassets\*.targets" Pack="true" CopyToOutputDirectory="PreserveNewest" PackagePath="%(Identity)" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -87,14 +87,12 @@ namespace Microsoft.DotNet.Watcher
|
||||||
{
|
{
|
||||||
return await ListFilesAsync(_reporter,
|
return await ListFilesAsync(_reporter,
|
||||||
options.Project,
|
options.Project,
|
||||||
options.MSBuildProjectExtensionsPath,
|
|
||||||
_cts.Token);
|
_cts.Token);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return await MainInternalAsync(_reporter,
|
return await MainInternalAsync(_reporter,
|
||||||
options.Project,
|
options.Project,
|
||||||
options.MSBuildProjectExtensionsPath,
|
|
||||||
options.RemainingArguments,
|
options.RemainingArguments,
|
||||||
_cts.Token);
|
_cts.Token);
|
||||||
}
|
}
|
||||||
|
|
@ -129,7 +127,6 @@ namespace Microsoft.DotNet.Watcher
|
||||||
private async Task<int> MainInternalAsync(
|
private async Task<int> MainInternalAsync(
|
||||||
IReporter reporter,
|
IReporter reporter,
|
||||||
string project,
|
string project,
|
||||||
string msbuildProjectExtensionsPath,
|
|
||||||
ICollection<string> args,
|
ICollection<string> args,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
|
@ -147,8 +144,8 @@ namespace Microsoft.DotNet.Watcher
|
||||||
|
|
||||||
var fileSetFactory = new MsBuildFileSetFactory(reporter,
|
var fileSetFactory = new MsBuildFileSetFactory(reporter,
|
||||||
projectFile,
|
projectFile,
|
||||||
NormalizePath(msbuildProjectExtensionsPath),
|
waitOnError: true,
|
||||||
waitOnError: true);
|
trace: false);
|
||||||
var processInfo = new ProcessSpec
|
var processInfo = new ProcessSpec
|
||||||
{
|
{
|
||||||
Executable = DotNetMuxer.MuxerPathOrDefault(),
|
Executable = DotNetMuxer.MuxerPathOrDefault(),
|
||||||
|
|
@ -174,7 +171,6 @@ namespace Microsoft.DotNet.Watcher
|
||||||
private async Task<int> ListFilesAsync(
|
private async Task<int> ListFilesAsync(
|
||||||
IReporter reporter,
|
IReporter reporter,
|
||||||
string project,
|
string project,
|
||||||
string msbuildProjectExtensionsPath,
|
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
// TODO multiple projects should be easy enough to add here
|
// TODO multiple projects should be easy enough to add here
|
||||||
|
|
@ -191,8 +187,8 @@ namespace Microsoft.DotNet.Watcher
|
||||||
|
|
||||||
var fileSetFactory = new MsBuildFileSetFactory(reporter,
|
var fileSetFactory = new MsBuildFileSetFactory(reporter,
|
||||||
projectFile,
|
projectFile,
|
||||||
NormalizePath(msbuildProjectExtensionsPath),
|
waitOnError: false,
|
||||||
waitOnError: false);
|
trace: false);
|
||||||
var files = await fileSetFactory.CreateAsync(cancellationToken);
|
var files = await fileSetFactory.CreateAsync(cancellationToken);
|
||||||
|
|
||||||
if (files == null)
|
if (files == null)
|
||||||
|
|
@ -211,21 +207,6 @@ namespace Microsoft.DotNet.Watcher
|
||||||
private static IReporter CreateReporter(bool verbose, bool quiet, IConsole console)
|
private static IReporter CreateReporter(bool verbose, bool quiet, IConsole console)
|
||||||
=> new PrefixConsoleReporter(console, verbose || CliContext.IsGlobalVerbose(), quiet);
|
=> 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()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_console.CancelKeyPress -= OnCancelKeyPress;
|
_console.CancelKeyPress -= OnCancelKeyPress;
|
||||||
|
|
|
||||||
|
|
@ -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>
|
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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>
|
|
||||||
|
|
@ -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>
|
|
||||||
|
|
@ -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>
|
|
||||||
|
|
@ -41,11 +41,6 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
|
||||||
: base("KitchenSink", logger)
|
: base("KitchenSink", logger)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IEnumerable<string> GetDefaultArgs()
|
|
||||||
{
|
|
||||||
return new[] { "--msbuildprojectextensionspath", ".net/obj", "run", "--" };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="..\Shared\**\*.cs" />
|
<Compile Include="..\Shared\**\*.cs" />
|
||||||
<Content Include="TestProjects\**\*" CopyToOutputDirectory="PreserveNewest" />
|
<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\DotNetWatch.targets" Link="toolassets\DotNetWatch.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" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
|
||||||
await PrepareAsync();
|
await PrepareAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
var args = GetDefaultArgs().Concat(arguments);
|
var args = new[] { "run", "--" }.Concat(arguments);
|
||||||
Start(args, name);
|
Start(args, name);
|
||||||
|
|
||||||
// Make this timeout long because it depends much on the MSBuild compilation speed.
|
// 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));
|
await Process.GetOutputLineAsync(StartedMessage).TimeoutAfter(TimeSpan.FromMinutes(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual IEnumerable<string> GetDefaultArgs()
|
|
||||||
{
|
|
||||||
return new[] { "run", "--" };
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Dispose()
|
public virtual void Dispose()
|
||||||
{
|
{
|
||||||
_logger?.WriteLine("Disposing WatchableApp");
|
_logger?.WriteLine("Disposing WatchableApp");
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<BaseIntermediateOutputPath>.net/obj</BaseIntermediateOutputPath>
|
<BaseIntermediateOutputPath>.net/obj</BaseIntermediateOutputPath>
|
||||||
|
<BaseOutputPath>.net/bin</BaseOutputPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
|
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
|
||||||
|
|
|
||||||
|
|
@ -20,14 +20,14 @@ namespace Microsoft.DotNet.Watcher.Tools.Tests
|
||||||
|
|
||||||
public static void EqualFileList(IEnumerable<string> expectedFiles, IEnumerable<string> actualFiles)
|
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 expected = new HashSet<string>(expectedFiles.Select(normalize));
|
||||||
var actual = new HashSet<string>(actualFiles.Where(p => !string.IsNullOrEmpty(p)).Select(normalize));
|
var actual = new HashSet<string>(actualFiles.Where(p => !string.IsNullOrEmpty(p)).Select(normalize));
|
||||||
if (!expected.SetEquals(actual))
|
if (!expected.SetEquals(actual))
|
||||||
{
|
{
|
||||||
throw new AssertActualExpectedException(
|
throw new AssertActualExpectedException(
|
||||||
expected: string.Join("\n", expected),
|
expected: "\n" + string.Join("\n", expected),
|
||||||
actual: string.Join("\n", actual),
|
actual: "\n" + string.Join("\n", actual),
|
||||||
userMessage: "File sets should be equal");
|
userMessage: "File sets should be equal");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="..\Shared\**\*.cs" />
|
<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\DotNetWatch.targets" Link="toolassets\DotNetWatch.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" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -238,11 +238,7 @@ namespace Microsoft.DotNet.Watcher.Tools.Tests
|
||||||
graph.Find("A").WithProjectReference(graph.Find("W"), watch: false);
|
graph.Find("A").WithProjectReference(graph.Find("W"), watch: false);
|
||||||
|
|
||||||
var output = new OutputSink();
|
var output = new OutputSink();
|
||||||
var filesetFactory = new MsBuildFileSetFactory(_reporter, graph.GetOrCreate("A").Path, null, output)
|
var filesetFactory = new MsBuildFileSetFactory(_reporter, graph.GetOrCreate("A").Path, output, trace: true);
|
||||||
{
|
|
||||||
// enables capturing markers to know which projects have been visited
|
|
||||||
BuildFlags = { "/p:_DotNetWatchTraceOutput=true" }
|
|
||||||
};
|
|
||||||
|
|
||||||
var fileset = await GetFileSet(filesetFactory);
|
var fileset = await GetFileSet(filesetFactory);
|
||||||
|
|
||||||
|
|
@ -270,17 +266,10 @@ namespace Microsoft.DotNet.Watcher.Tools.Tests
|
||||||
Assert.Single(output.Current.Lines,
|
Assert.Single(output.Current.Lines,
|
||||||
line => line.Contains($"Collecting watch items from '{projectName}'"))
|
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)
|
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)
|
private async Task<IFileSet> GetFileSet(MsBuildFileSetFactory filesetFactory)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue