Skip to content

[Console] Fix check of color support on Windows #26609

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 2, 2018

Conversation

mlocati
Copy link
Contributor

@mlocati mlocati commented Mar 20, 2018

Q A
Branch? 2.7
Bug fix? yes
New feature? no
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets
License MIT
Doc PR

If the stream is redirected, StreamOutput::hasColorSupport() returns false on POSIX systems.
On Windows, this is not always true. Before PHP 7.2 we can't say if the stream is redirected, but since PHP 7.2 we have the stream_isatty function that works on Windows too: let's use it.

Sure, sapi_windows_vt100_support should return false if the stream is redirected, but it's in or with the other conditions, so the logic was flawed.

If the stream is redirected, the script should behave the same on Windows
and on POSIX systems.
@mlocati mlocati force-pushed the fix-output-hascolorsupport branch from 61feb7d to f7f8189 Compare March 20, 2018 14:50
@mlocati
Copy link
Contributor Author

mlocati commented Mar 20, 2018

I have a doubt about this PR: sapi_windows_vt100_support is enabled by default (PHP sets it to true at startup), so it may be false only if the PHP code explicitly sets it to false.
So, an alternative to this PR would be:

if (function_exists('stream_isatty') && !@stream_isatty($this->stream)) {
    return false;
}
if (DIRECTORY_SEPARATOR === '\\') {
    if (function_exists('sapi_windows_vt100_support')) {
        return @sapi_windows_vt100_support($this->stream);
    }
    return
        '10.0.10586' === PHP_WINDOWS_VERSION_MAJOR.'.'.PHP_WINDOWS_VERSION_MINOR.'.'.PHP_WINDOWS_VERSION_BUILD
        || false !== getenv('ANSICON')
        || 'ON' === getenv('ConEmuANSI')
        || 'xterm' === getenv('TERM');
}
return function_exists('posix_isatty') && @posix_isatty($this->stream);

@fabpot
Copy link
Member

fabpot commented Apr 2, 2018

Thank you @mlocati.

@fabpot fabpot merged commit f7f8189 into symfony:2.7 Apr 2, 2018
fabpot added a commit that referenced this pull request Apr 2, 2018
This PR was merged into the 2.7 branch.

Discussion
----------

[Console] Fix check of color support on Windows

| Q             | A
| ------------- | ---
| Branch?       | 2.7
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets |
| License       | MIT
| Doc PR        |

If the stream is redirected, `StreamOutput::hasColorSupport()` returns `false` on POSIX systems.
On Windows, this is not always true. Before PHP 7.2 we can't say if the stream is redirected, but since PHP 7.2 we have the `stream_isatty` function that works on Windows too: let's use it.

Sure, `sapi_windows_vt100_support` should return `false` if the stream is redirected, but it's in `or` with the other conditions, so the logic was flawed.

Commits
-------

f7f8189 Fix check of color support on Windows
@mlocati mlocati deleted the fix-output-hascolorsupport branch April 2, 2018 14:00
This was referenced Apr 3, 2018
@mu4ddi3
Copy link

mu4ddi3 commented Apr 5, 2018

Hello, i use cygwin with mintty terminal on windows and up to 4.0.6 i have got colored output, but after update package to 4.0.7, the colors are lost. :/

@mlocati
Copy link
Contributor Author

mlocati commented Apr 5, 2018

@mu4ddi3 If seems that stream_isatty fails in your environment.
Could you post the result of this command?

php -r "var_export(stream_isatty(STDERR));"

@mu4ddi3
Copy link

mu4ddi3 commented Apr 5, 2018

@mlocati thx for answer.

its "false" in cygwin but i can write to STDERR:
php -r 'fwrite(STDERR, "stderr here\n");' shows "stderr here"

it's "true" in windows shell (cmd).

//edit
I also tried in git-bash shell, which is quite similar to cygwin, and still, there is no colors,
therefore php -r "var_export(stream_isatty(STDERR));" executed there returns "true"

@fabpot fabpot mentioned this pull request Apr 6, 2018
@mlocati
Copy link
Contributor Author

mlocati commented Apr 6, 2018

I asked two developers (@weltling and @johnstevenson) that have a deep knowledge of the PHP source code.
And the sad response is that we can't do anything about that, and here's why:
hasColorSupport tries to detect if the CLI command has a redirected output (for instance php.exe app.php > file.txt or php.exe app.php | more). If so, the output shouldn't have the colors control codes (users won't usually want those unprintable characters in their log files).
The problem is that mintty emulates pseudo terminals via named pipes, so it's like if php.exe was executed as php.exe app.php | more).
I noticed this problem on WLS in addition to mintty (but with Git Bash it seems to work well).

@fabpot fabpot mentioned this pull request Apr 6, 2018
@mu4ddi3
Copy link

mu4ddi3 commented Apr 6, 2018

I understand that the cygwin minnty is some kind of emulation and can not work (sad that before this fix it worked), but normal Git bash shell from windows instalation of git (which is btw also using mintty) didnt work with colors now as well (even if the command you requested to check returns true). I need to live with it.

@rtek
Copy link
Contributor

rtek commented Apr 7, 2018

Im running gitbash and recently ran into this issue that color support is not detected as true. Is there a way to detect gitbash and set OutputInterface::setDecorated(true)? I dont know enough about how these emulated terminals interact with PHP.

@johnstevenson
Copy link
Contributor

@fabpot Unfortunately, this is a BC break, because color output is now broken in Windows unixy terminals/bash, which were tested using an environment variable (because of the named pipes issue) and now they are not.

Please see https://github.com/composer/xdebug-handler/blob/master/src/Process.php#L111 which uses the new PHP 7.2 functionality without breaking bc.

@mlocati @mu4ddi3 Git Bash works fine, but it does depend on how you have set it up (using the native conhost or mintty) and how you are running it (standalone terminal, in Console/Console2, ConEmu etc) and on what version of Windows, ie. does it support vt100 natively (Windows 10 generally, or later than November 2015 if never updated).

Likewise with Cygwin. There is no problem if you invoke it using Cygwin.bat on Windows 10.

The bottom line is that this has been a known feature/issue for years (mintty/mintty#56) and there are many ways to solve it, but no one-size fits all solution.

I think that the symfony approach (as was) provides a clean solution for the majority of developers. If output contains unwanted vt100 sequences then there is the option to either use the --no-ansi flag, or learn how to set things up correctly for your environment (or use a program like ConEmu that does this for you).

@nicolas-grekas
Copy link
Member

@mlocati would you like to send a PR that would fix the behavior change?

@mlocati
Copy link
Contributor Author

mlocati commented Apr 7, 2018

I can't see a way to understand when the output is redirected (ie > file.txt) and when the console is mintty... in the first case we'd need to turn off colors, in the second one no...

@nicolas-grekas
Copy link
Member

nicolas-grekas commented Apr 7, 2018

We don't need to make the difference: since years, we didn't, and nobody complained (on Windows).

@johnstevenson
Copy link
Contributor

Just nick my code (perhaps credit it so that we can keep it in sync?).

@johnstevenson
Copy link
Contributor

@mlocati

and when the console is mintty...

Thing is, you have no way of knowing what is happening outside mintty (whether a program has a hidden console window to get round the pseudo-terminal stuff, or whether it is doing cunning tricks like Git that use bash to access /dev/tty. In fact Git seems to change quite frequently, as more problems/issues come up with various setups and WSL. I see that it is now setting the TERM variable to xterm (rather than cygwin) so our code picks it up.

That's why I think that the previous symfony solution is the best. If there are problems then the user will have to find out what the current solution is, because these implementations are going to change (especially as the native conhost.exe improves and gets more unixy functionality ).

@mlocati
Copy link
Contributor Author

mlocati commented Apr 7, 2018

We don't need to make the difference

So, the solution is to simply remove these lines from the method:

if (function_exists('stream_isatty') && !@stream_isatty($this->stream)) {
    return false;
}

@nicolas-grekas
Copy link
Member

remove these lines from the method

actually, I'd suggest to move them after the Windows checks, like the Process class does.
https://github.com/composer/xdebug-handler/blob/master/src/Process.php#L121

@mlocati
Copy link
Contributor Author

mlocati commented Apr 7, 2018

posix_isatty has not been deprecated, so having both stream_isatty and posix_isatty is quite useless...

@johnstevenson
Copy link
Contributor

johnstevenson commented Apr 7, 2018

If this helps, this is why my code is as it is:

        if (defined('PHP_WINDOWS_VERSION_BUILD')) {
            return (function_exists('sapi_windows_vt100_support')
                && sapi_windows_vt100_support($output))
                || false !== getenv('ANSICON')
                || 'ON' === getenv('ConEmuANSI')
                || 'xterm' === getenv('TERM');
        }

There is no need to check for a specific build of Windows from Nov 2015 that accidentally enabled vt100 by default, because it will have been replaced by (automatic updates). Also, as this was obviously a Windows bug (it was never documented to do this) this functionality may have been removed in an intermediate fix - we don't know.

        if (function_exists('stream_isatty')) {
            return stream_isatty($output);
        } elseif (function_exists('posix_isatty')) {
            return posix_isatty($output);
        }

        $stat = fstat($output);
        // Check if formatted mode is S_IFCHR
        return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;

The new stream_isatty function (which @mlocati authored) additionally allows for other builds that might not have posix_isatty like s390x. The fstat trick then mimics the source for non PHP 7.2 builds on this platform (or others)

@johnstevenson
Copy link
Contributor

having both stream_isatty and posix_isatty is quite useless...

Please read my explanation above (I think both our posts arrived at the same time!)

@mlocati
Copy link
Contributor Author

mlocati commented Apr 7, 2018

The new stream_isatty allows for other builds that might not have posix_isatty like s390x. The fstat trick then mimics the source for non PHP 7.2 builds on this platform (or others)

You are right (as always ;) )

@johnstevenson
Copy link
Contributor

Ha ha. You wrote it in PHP source!

@rtek
Copy link
Contributor

rtek commented Apr 7, 2018

+1 for @johnstevenson code inspecting the env first since thereisnt a way to get colors w/o downgrading in gitbash/windows.

Edit - passing the --ansi argument will force color output.

@mu4ddi3
Copy link

mu4ddi3 commented Apr 8, 2018

@johnstevenson

@mlocati @mu4ddi3 Git Bash works fine, but it does depend on how you have set it up (using the native conhost or mintty) and how you are running it (standalone terminal, in Console/Console2, ConEmu etc) and on what version of Windows, ie. does it support vt100 natively (Windows 10 generally, or later than November 2015 if never updated).

I'm using bash with standard after-install settings (mintty in standalone terminal) and i'm currently using windows 7 (business pc).

Likewise with Cygwin. There is no problem if you invoke it using Cygwin.bat on Windows 10.

When i invoke it in my env it just starts in standard windows terminal and also without colors.

So, guys what is the conclusion? Is there something to be done to make it work again as is suppose to work?

@mlocati
Copy link
Contributor Author

mlocati commented Apr 8, 2018

I think that the code from @johnstevenson implements the best solution we can have so far. I don't want to steal code or credits, so I'd let him create another pull request with his own code...

@johnstevenson
Copy link
Contributor

@mlocati Ah okay, I'll do that if that's what you want

Seldaek added a commit to composer/composer that referenced this pull request Apr 13, 2018
Workaround for issues caused by symfony/symfony#26609

Fixes #7264
fabpot added a commit that referenced this pull request Apr 22, 2018
This PR was squashed before being merged into the 2.7 branch (closes #26910).

Discussion
----------

Use new PHP7.2 functions in hasColorSupport

| Q             | A
| ------------- | ---
| Branch?       |  2.7
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets |
| License       | MIT
| Doc PR        |

Fixes bc break in #26609
Reference: https://github.com/composer/xdebug-handler/blob/master/src/Process.php#L111

Commits
-------

b0c9225 Use new PHP7.2 functions in hasColorSupport
@artemdigi
Copy link
Contributor

Lost colors in MinTTY from default Git distribution for Windows. How to fix it?

@mu4ddi3
Copy link

mu4ddi3 commented Apr 24, 2018

@artemdigi Problem is known and fix is also ready. You need to wait for upcoming version.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants