diff --git a/src/RoslynCodeTaskFactory.UnitTests/RoslynCodeTaskFactory.UnitTests.csproj b/src/RoslynCodeTaskFactory.UnitTests/RoslynCodeTaskFactory.UnitTests.csproj index bddb5a5..1294de0 100644 --- a/src/RoslynCodeTaskFactory.UnitTests/RoslynCodeTaskFactory.UnitTests.csproj +++ b/src/RoslynCodeTaskFactory.UnitTests/RoslynCodeTaskFactory.UnitTests.csproj @@ -19,4 +19,8 @@ + + + + diff --git a/src/RoslynCodeTaskFactory/CodeTaskFactory.cs b/src/RoslynCodeTaskFactory/CodeTaskFactory.cs index 691aa37..7c4491a 100644 --- a/src/RoslynCodeTaskFactory/CodeTaskFactory.cs +++ b/src/RoslynCodeTaskFactory/CodeTaskFactory.cs @@ -4,9 +4,11 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; +using System.Threading; using System.Xml; using System.Xml.Linq; @@ -160,6 +162,8 @@ public TaskPropertyInfo[] GetTaskParameters() /// public bool Initialize(string taskName, IDictionary parameterGroup, string taskBody, IBuildEngine taskFactoryLoggingHost) { + WaitForDebuggerIfConfigured(); + _log = new TaskLoggingHelper(taskFactoryLoggingHost, taskName) { TaskResources = Strings.ResourceManager, @@ -807,5 +811,27 @@ private bool TryCompileInMemoryAssembly(IBuildEngine buildEngine, TaskInfo taskI } } } + + /// + /// Waits for a user to attach a debugger. + /// + private void WaitForDebuggerIfConfigured() + { + if (!String.Equals(Environment.GetEnvironmentVariable("ROSLYNCODETASKFACTORY_DEBUG"), "1")) + { + return; + } + + Process currentProcess = Process.GetCurrentProcess(); + + Console.WriteLine(Strings.CodeTaskFactory_WaitingForDebugger, currentProcess.MainModule.FileName, currentProcess.Id); + + while (!Debugger.IsAttached) + { + Thread.Sleep(200); + } + + Debugger.Break(); + } } } \ No newline at end of file diff --git a/src/RoslynCodeTaskFactory/Internal/ManagedCompiler.cs b/src/RoslynCodeTaskFactory/Internal/ManagedCompiler.cs index ad78ab7..12bdabf 100644 --- a/src/RoslynCodeTaskFactory/Internal/ManagedCompiler.cs +++ b/src/RoslynCodeTaskFactory/Internal/ManagedCompiler.cs @@ -1,13 +1,38 @@ -using System; -using System.IO; -using Microsoft.Build.Framework; +using Microsoft.Build.Framework; using Microsoft.Build.Tasks; using Microsoft.Build.Utilities; +using System; +using System.IO; +using System.Linq; namespace RoslynCodeTaskFactory.Internal { internal abstract class ManagedCompiler : ToolTask { + private static readonly string DotnetCliPath = Environment.GetEnvironmentVariable("DOTNET_HOST_PATH"); + + private readonly Lazy _executablePath; + + protected ManagedCompiler() + { + _executablePath = new Lazy(() => + { + string pathToBuildTools = ToolLocationHelper.GetPathToBuildTools(ToolLocationHelper.CurrentToolsVersion, DotNetFrameworkArchitecture.Bitness32); + + Func[] possibleLocations = + { + // Standard MSBuild and legacy .NET Core + () => Path.Combine(pathToBuildTools, "Roslyn", ToolName), + // Legacy .NET Core + () => Path.Combine(pathToBuildTools, "Roslyn", Path.ChangeExtension(ToolName, ".dll")), + // .NET Core 2.0 + () => Path.Combine(pathToBuildTools, "Roslyn", "bincore", Path.ChangeExtension(ToolName, ".dll")), + }; + + return possibleLocations.Select(possibleLocation => possibleLocation()).FirstOrDefault(File.Exists); + }, isThreadSafe: true); + } + public bool? Deterministic { get; set; } public bool? NoConfig { get; set; } @@ -26,6 +51,8 @@ internal abstract class ManagedCompiler : ToolTask public bool? UseSharedCompilation { get; set; } + protected bool IsDotnetCli => !String.IsNullOrWhiteSpace(DotnetCliPath); + protected internal virtual void AddResponseFileCommands(CommandLineBuilderExtension commandLine) { commandLine.AppendPlusOrMinusSwitch("/deterministic", Deterministic); @@ -45,6 +72,13 @@ protected override string GenerateCommandLineCommands() { CommandLineBuilderExtension commandLineBuilder = new CommandLineBuilderExtension(); + if (IsDotnetCli) + { + commandLineBuilder.AppendFileNameIfNotNull(_executablePath.Value); + + commandLineBuilder.AppendTextUnquoted(" "); + } + AddCommandLineCommands(commandLineBuilder); return commandLineBuilder.ToString(); @@ -57,19 +91,12 @@ protected override string GenerateFullPathToTool() return ToolExe; } - string pathToBuildTools = ToolLocationHelper.GetPathToBuildTools(ToolLocationHelper.CurrentToolsVersion, DotNetFrameworkArchitecture.Bitness32); - - if (pathToBuildTools != null) + if (IsDotnetCli) { - string toolMSBuildLocation = Path.Combine(pathToBuildTools, "Roslyn", ToolName); - - if (File.Exists(toolMSBuildLocation)) - { - return toolMSBuildLocation; - } + return DotnetCliPath; } - return null; + return _executablePath.Value; } protected override string GenerateResponseFileCommands() diff --git a/src/RoslynCodeTaskFactory/Strings.Designer.cs b/src/RoslynCodeTaskFactory/Strings.Designer.cs index 8cf1d94..e7ad8a5 100644 --- a/src/RoslynCodeTaskFactory/Strings.Designer.cs +++ b/src/RoslynCodeTaskFactory/Strings.Designer.cs @@ -160,5 +160,14 @@ internal static string CodeTaskFactory_NoSourceCode { return ResourceManager.GetString("CodeTaskFactory_NoSourceCode", resourceCulture); } } + + /// + /// Looks up a localized string similar to Waiting for debugger to attach ({0} PID {1}). Press enter to continue.... + /// + internal static string CodeTaskFactory_WaitingForDebugger { + get { + return ResourceManager.GetString("CodeTaskFactory_WaitingForDebugger", resourceCulture); + } + } } } diff --git a/src/RoslynCodeTaskFactory/Strings.resx b/src/RoslynCodeTaskFactory/Strings.resx index 52d55f4..f9e148b 100644 --- a/src/RoslynCodeTaskFactory/Strings.resx +++ b/src/RoslynCodeTaskFactory/Strings.resx @@ -159,4 +159,7 @@ MSB3428: You must specify source code within the Code element or a path to a file containing source code. {StrBegin="MSB3428: "} + + Waiting for debugger to attach ({0} PID {1}). Press enter to continue... + \ No newline at end of file