Add --msbuildprojectextensionspath option to dotnet-watch
In the event someone wants to move the obj/ folder, MSBuild will not be able to locate dotnet-watch's generated targets. dotnet-watch cannot automatically find the obj folder (#244), so this command line switch allows users to point dotnet-watch to the right location.
This commit is contained in:
parent
e8ee83d216
commit
34ea52068a
|
|
@ -12,6 +12,7 @@ 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; }
|
||||||
|
|
@ -61,8 +62,16 @@ Examples:
|
||||||
};
|
};
|
||||||
|
|
||||||
app.HelpOption("-?|-h|--help");
|
app.HelpOption("-?|-h|--help");
|
||||||
var optProjects = app.Option("-p|--project", "The project to watch",
|
// TODO multiple shouldn't be too hard to support
|
||||||
CommandOptionType.SingleValue); // TODO multiple shouldn't be too hard to support
|
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",
|
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();
|
||||||
|
|
@ -92,6 +101,7 @@ 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,
|
||||||
|
|
|
||||||
|
|
@ -21,19 +21,26 @@ namespace Microsoft.DotNet.Watcher.Internal
|
||||||
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 _projectExtensionsPath;
|
||||||
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;
|
private readonly bool _waitOnError;
|
||||||
|
|
||||||
public MsBuildFileSetFactory(IReporter reporter, string projectFile, bool waitOnError)
|
public MsBuildFileSetFactory(IReporter reporter,
|
||||||
: this(reporter, projectFile, new OutputSink())
|
string projectFile,
|
||||||
|
string msBuildProjectExtensionsPath,
|
||||||
|
bool waitOnError)
|
||||||
|
: this(reporter, projectFile, msBuildProjectExtensionsPath, new OutputSink())
|
||||||
{
|
{
|
||||||
_waitOnError = waitOnError;
|
_waitOnError = waitOnError;
|
||||||
}
|
}
|
||||||
|
|
||||||
// output sink is for testing
|
// output sink is for testing
|
||||||
internal MsBuildFileSetFactory(IReporter reporter, string projectFile, OutputSink outputSink)
|
internal MsBuildFileSetFactory(IReporter reporter,
|
||||||
|
string projectFile,
|
||||||
|
string msBuildProjectExtensionsPath,
|
||||||
|
OutputSink outputSink)
|
||||||
{
|
{
|
||||||
Ensure.NotNull(reporter, nameof(reporter));
|
Ensure.NotNull(reporter, nameof(reporter));
|
||||||
Ensure.NotNullOrEmpty(projectFile, nameof(projectFile));
|
Ensure.NotNullOrEmpty(projectFile, nameof(projectFile));
|
||||||
|
|
@ -44,6 +51,11 @@ namespace Microsoft.DotNet.Watcher.Internal
|
||||||
_watchTargetsDir = FindWatchTargetsDir();
|
_watchTargetsDir = FindWatchTargetsDir();
|
||||||
_outputSink = outputSink;
|
_outputSink = outputSink;
|
||||||
_processRunner = new ProcessRunner(reporter);
|
_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;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal List<string> BuildFlags { get; } = new List<string>
|
internal List<string> BuildFlags { get; } = new List<string>
|
||||||
|
|
@ -153,11 +165,8 @@ namespace Microsoft.DotNet.Watcher.Internal
|
||||||
// Ensures file exists in $(MSBuildProjectExtensionsPath)/$(MSBuildProjectFile).dotnetwatch.targets
|
// Ensures file exists in $(MSBuildProjectExtensionsPath)/$(MSBuildProjectFile).dotnetwatch.targets
|
||||||
private void EnsureInitialized()
|
private void EnsureInitialized()
|
||||||
{
|
{
|
||||||
// default value for MSBuildProjectExtensionsPath.
|
|
||||||
var projectExtensionsPath = Path.Combine(Path.GetDirectoryName(_projectFile), "obj");
|
|
||||||
|
|
||||||
// see https://github.com/Microsoft/msbuild/blob/bf9b21cc7869b96ea2289ff31f6aaa5e1d525a26/src/XMakeTasks/Microsoft.Common.targets#L127
|
// see https://github.com/Microsoft/msbuild/blob/bf9b21cc7869b96ea2289ff31f6aaa5e1d525a26/src/XMakeTasks/Microsoft.Common.targets#L127
|
||||||
var projectExtensionFile = Path.Combine(projectExtensionsPath,
|
var projectExtensionFile = Path.Combine(_projectExtensionsPath,
|
||||||
Path.GetFileName(_projectFile) + ProjectExtensionFileExtension);
|
Path.GetFileName(_projectFile) + ProjectExtensionFileExtension);
|
||||||
|
|
||||||
if (!File.Exists(projectExtensionFile))
|
if (!File.Exists(projectExtensionFile))
|
||||||
|
|
|
||||||
|
|
@ -81,12 +81,14 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
@ -121,6 +123,7 @@ 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)
|
||||||
{
|
{
|
||||||
|
|
@ -136,7 +139,10 @@ namespace Microsoft.DotNet.Watcher
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileSetFactory = new MsBuildFileSetFactory(reporter, projectFile, waitOnError: true);
|
var fileSetFactory = new MsBuildFileSetFactory(reporter,
|
||||||
|
projectFile,
|
||||||
|
NormalizePath(msbuildProjectExtensionsPath),
|
||||||
|
waitOnError: true);
|
||||||
var processInfo = new ProcessSpec
|
var processInfo = new ProcessSpec
|
||||||
{
|
{
|
||||||
Executable = DotNetMuxer.MuxerPathOrDefault(),
|
Executable = DotNetMuxer.MuxerPathOrDefault(),
|
||||||
|
|
@ -157,6 +163,7 @@ 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
|
||||||
|
|
@ -171,7 +178,10 @@ namespace Microsoft.DotNet.Watcher
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileSetFactory = new MsBuildFileSetFactory(reporter, projectFile, waitOnError: false);
|
var fileSetFactory = new MsBuildFileSetFactory(reporter,
|
||||||
|
projectFile,
|
||||||
|
NormalizePath(msbuildProjectExtensionsPath),
|
||||||
|
waitOnError: false);
|
||||||
var files = await fileSetFactory.CreateAsync(cancellationToken);
|
var files = await fileSetFactory.CreateAsync(cancellationToken);
|
||||||
|
|
||||||
if (files == null)
|
if (files == null)
|
||||||
|
|
@ -190,6 +200,22 @@ 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;
|
||||||
|
|
|
||||||
|
|
@ -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.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
@ -40,6 +41,11 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
|
||||||
: base("KitchenSink", logger)
|
: base("KitchenSink", logger)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override IEnumerable<string> GetDefaultArgs()
|
||||||
|
{
|
||||||
|
return new[] { "--msbuildprojectextensionspath", ".net/obj", "run", "--" };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
|
||||||
await PrepareAsync();
|
await PrepareAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
var args = new[] { "run", "--" }.Concat(arguments);
|
var args = GetDefaultArgs().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.
|
||||||
|
|
@ -104,6 +104,11 @@ 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");
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,16 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<BaseIntermediateOutputPath>.net/obj</BaseIntermediateOutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -238,7 +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, output)
|
var filesetFactory = new MsBuildFileSetFactory(_reporter, graph.GetOrCreate("A").Path, null, output)
|
||||||
{
|
{
|
||||||
// enables capturing markers to know which projects have been visited
|
// enables capturing markers to know which projects have been visited
|
||||||
BuildFlags = { "/p:_DotNetWatchTraceOutput=true" }
|
BuildFlags = { "/p:_DotNetWatchTraceOutput=true" }
|
||||||
|
|
@ -280,7 +280,7 @@ namespace Microsoft.DotNet.Watcher.Tools.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task<IFileSet> GetFileSet(TemporaryCSharpProject target)
|
private Task<IFileSet> GetFileSet(TemporaryCSharpProject target)
|
||||||
=> GetFileSet(new MsBuildFileSetFactory(_reporter, target.Path, waitOnError: false));
|
=> GetFileSet(new MsBuildFileSetFactory(_reporter, target.Path, null, waitOnError: false));
|
||||||
|
|
||||||
private async Task<IFileSet> GetFileSet(MsBuildFileSetFactory filesetFactory)
|
private async Task<IFileSet> GetFileSet(MsBuildFileSetFactory filesetFactory)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue