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
|
||||
{
|
||||
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; }
|
||||
|
|
@ -61,8 +62,16 @@ Examples:
|
|||
};
|
||||
|
||||
app.HelpOption("-?|-h|--help");
|
||||
var optProjects = app.Option("-p|--project", "The project to watch",
|
||||
CommandOptionType.SingleValue); // TODO multiple shouldn't be too hard to support
|
||||
// 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",
|
||||
CommandOptionType.NoValue);
|
||||
var optVerbose = app.VerboseOption();
|
||||
|
|
@ -92,6 +101,7 @@ Examples:
|
|||
return new CommandLineOptions
|
||||
{
|
||||
Project = optProjects.Value(),
|
||||
MSBuildProjectExtensionsPath = optMSBuildProjectExtensionsPath.Value(),
|
||||
IsQuiet = optQuiet.HasValue(),
|
||||
IsVerbose = optVerbose.HasValue(),
|
||||
RemainingArguments = app.RemainingArguments,
|
||||
|
|
|
|||
|
|
@ -21,19 +21,26 @@ namespace Microsoft.DotNet.Watcher.Internal
|
|||
private const string WatchTargetsFileName = "DotNetWatchCommon.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;
|
||||
|
||||
public MsBuildFileSetFactory(IReporter reporter, string projectFile, bool waitOnError)
|
||||
: this(reporter, projectFile, new OutputSink())
|
||||
public MsBuildFileSetFactory(IReporter reporter,
|
||||
string projectFile,
|
||||
string msBuildProjectExtensionsPath,
|
||||
bool waitOnError)
|
||||
: this(reporter, projectFile, msBuildProjectExtensionsPath, new OutputSink())
|
||||
{
|
||||
_waitOnError = waitOnError;
|
||||
}
|
||||
|
||||
// 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.NotNullOrEmpty(projectFile, nameof(projectFile));
|
||||
|
|
@ -44,6 +51,11 @@ namespace Microsoft.DotNet.Watcher.Internal
|
|||
_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;
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
var projectExtensionFile = Path.Combine(projectExtensionsPath,
|
||||
var projectExtensionFile = Path.Combine(_projectExtensionsPath,
|
||||
Path.GetFileName(_projectFile) + ProjectExtensionFileExtension);
|
||||
|
||||
if (!File.Exists(projectExtensionFile))
|
||||
|
|
|
|||
|
|
@ -81,12 +81,14 @@ 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);
|
||||
}
|
||||
|
|
@ -121,6 +123,7 @@ namespace Microsoft.DotNet.Watcher
|
|||
private async Task<int> MainInternalAsync(
|
||||
IReporter reporter,
|
||||
string project,
|
||||
string msbuildProjectExtensionsPath,
|
||||
ICollection<string> args,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
|
|
@ -136,7 +139,10 @@ namespace Microsoft.DotNet.Watcher
|
|||
return 1;
|
||||
}
|
||||
|
||||
var fileSetFactory = new MsBuildFileSetFactory(reporter, projectFile, waitOnError: true);
|
||||
var fileSetFactory = new MsBuildFileSetFactory(reporter,
|
||||
projectFile,
|
||||
NormalizePath(msbuildProjectExtensionsPath),
|
||||
waitOnError: true);
|
||||
var processInfo = new ProcessSpec
|
||||
{
|
||||
Executable = DotNetMuxer.MuxerPathOrDefault(),
|
||||
|
|
@ -157,6 +163,7 @@ 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
|
||||
|
|
@ -171,7 +178,10 @@ namespace Microsoft.DotNet.Watcher
|
|||
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);
|
||||
|
||||
if (files == null)
|
||||
|
|
@ -190,6 +200,22 @@ 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;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
|
@ -40,6 +41,11 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests
|
|||
: 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();
|
||||
}
|
||||
|
||||
var args = new[] { "run", "--" }.Concat(arguments);
|
||||
var args = GetDefaultArgs().Concat(arguments);
|
||||
Start(args, name);
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
protected virtual IEnumerable<string> GetDefaultArgs()
|
||||
{
|
||||
return new[] { "run", "--" };
|
||||
}
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
_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>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -238,7 +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, output)
|
||||
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" }
|
||||
|
|
@ -280,7 +280,7 @@ namespace Microsoft.DotNet.Watcher.Tools.Tests
|
|||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
@ -298,4 +298,4 @@ namespace Microsoft.DotNet.Watcher.Tools.Tests
|
|||
_tempDir.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue