msbuild: Exec ConsoleToMSBuild=true doesn't preserve colors
@rainersigwald I’ve spent some time pondering some deep, Confucious stuff lately regarding my build toolchain, and started asking:
“How can I run a .NET Core CLI Tool in an MSBuild Exec Task AND preserve the color output?”
Oh, boy.
Along the way, I found that MSBuild output itself can emit ANSI Escape Codes to processes like Travis CI… so it got me wondering, why can’t MSBuild parse ANSI Escape Codes rather than generate them? Searching StackOverflow, I don’t see any good answers. People seem to think fundamentally there is no way to capture color, it’s drastically impractical, because color is a property of the console, not the standard output and error streams. I say, let there be color. Pastel, maybe.
Here is a sample repro of the issue:
build.targets
<?xml version="1.0" encoding="utf-8" ?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="PowershellColoredOutput">
<Target Name="PowershellColoredOutput">
<!-- Clear your mind with this zen action: -->
<Exec Command="pwsh.exe -Command "Write-Host 'hi' -ForegroundColor red"" ConsoleToMSBuild="true">
<Output TaskParameter="ConsoleOutput" ItemName="OutputOfExec" />
</Exec>
</Target>
</Project>
Expected Output
“hi” in red.
Actual Output
“hi” in console default foreground color and default background color
Deep Thoughts
“I for one believe that if you give people a thorough understanding of what confronts them and the basic causes that produce it, they’ll create their own program, and when the people create a program, you get action.” — Malcolm X
About this issue
- Original URL
- State: open
- Created 5 years ago
- Reactions: 2
- Comments: 29 (2 by maintainers)
Thanks for filing this; I’ve been thinking about it for a long time, too. Unfortunately, I haven’t found a good solution either. There are a few problems:
ConDrv-awareExecinto core MSBuild just for colorization.This came up in the context of
dotnet test, which runs inside MSBuild but wants to control its output completely, which currently requires various workarounds.Hey so lemme chime in real quick before we get off the rails on ConPty.
Conpty exists to enable applications to act as terminal emulators on Windows. It acts as the console host, servicing console API calls in the same way the console normally does, but then “renders” the side effects of the API calls to a stream of VT sequences. This means that client applications (like cmd.exe, msbuild.exe, etc) can use the same old Console API’s they’ve been using since Windows 3.1, but now instead being forced to use conhost as the terminal window, another application could step in as the terminal instead, and the new terminal application could be written just the same as a terminal emulator on linux.
We (the console team) certainly haven’t done any work to expose ConPTY in any sort of managed sense. The sample you linked is community code, but there’s no official support currently.
Conpty is not a new magic commandline client API. It will not magically make your client app emit output as VT.
For commandline-client application developers targeting Win10+, our general recommendation is to use VT sequences always, and enable VT processing with SetConsoleMode. We’re expanding our support for VT sequences, but we’re leaving the console API as it is, for compatibility reasons. As noted here, the Console API isn’t really portable to other platforms.
And a footnote to this is that the mechanism by which this query is performed is also the directive syntax I mentioned earlier, e.g.:
@jonsequitur - Got it, thanks. Though one suggestion: You may want to rename ANSI to VT since ANSI stopped standardizing escape codes and VT sequences in the '80s, deferring instead to industry standards. ISO/IEC and ECMA both maintain standards, but haven’t really kept up with industry’s advancements to support, for example, 24-bit color, etc.
And perhaps
nonansicould be replaced withlegacyor similar?System.CommandLine.Renderingwill include VT if[output:ansi]is set, it will attempt to render usingSystem.ConsoleAPIs if[output:nonansi]is set, and it will render plain text (no VT, table layouts via whitespace) if[output:plaintext]is set.We typically try to detect the terminal capabilities and set this for you, so these are explicit overrides to that behavior.
LOLZ. Sorry if I dove deep, but I wanted to be sure that people realize that the command-line today is LITERALLY a mirror of the command-line as it was in 1960: It’s chars out and chars in. That’s it; everything else is just details! 😜
It’s for this very reason that I wrote this multi-part series on the command-line and how it evolved, and how Windows differs from *NIX, etc.
Yes there are. For .NET Core, we live in https://github.com/dotnet/corefx