Skip to content
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

Added msys2/cygwin terminal detection support #485

Merged
merged 1 commit into from
Mar 24, 2017

Conversation

ereOn
Copy link

@ereOn ereOn commented Mar 6, 2017

This PR adds support for MSYS/Cygwin terminal support detection on Windows (#484).

The strategy for the regular terminal is still to use GetConsoleMode to detect the classic cmd.exe console.

If that fails, instead of failing directly, we now fallback to the following sequence:

  1. If the io.Writer's handle is a pipe handle, we move to 2.
  2. If the pipe's name matches \\(cygwin|msys)-\w+-pty\d?-(to|from)-master, MSYS/Cygwin terminal is detected and we return true.

If any of the two points above fails, we return false like the previous implementation.

The exact same check is done in Vim, the popular UNIX text-editor.

I also added a test that validates (on Windows only) that STDOUT is detected as a terminal.

}

func TestIsTerminal(t *testing.T) {
handle, err := windows.GetStdHandle(windows.STD_OUTPUT_HANDLE)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test directly fetches STDOUT using GetStdHandle because go test redirects its output (and so fails) but only if not run with -v which makes for a surprising behavior otherwise !

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add this as a comment in the code.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

"syscall"
"unsafe"

"golang.org/x/sys/windows"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather avoid this enormous dependency since we're only using a few of its functions and they are not difficult to implement locally.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this come with Go itself ?

I mainly used that instead of reinventing the wheel but I guess I can reimplement those in there if you think it is better form.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it requires using go get to retrieve and would need to be vendored by those that vendor their dependencies.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I removed all the reference to external modules. I discovered that syscall actually already has a lot of useful stuff we needed, including for handling UTF16 names (on which Windows heavily relies).

}

func TestIsTerminal(t *testing.T) {
handle, err := windows.GetStdHandle(windows.STD_OUTPUT_HANDLE)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add this as a comment in the code.

@ereOn ereOn force-pushed the isterminal_msys2_support branch from 0ef6cea to c7967ca Compare March 22, 2017 23:46
@ChrisHines
Copy link
Member

ChrisHines commented Mar 22, 2017

I have verified that this PR fixes IsTerminal for git bash on Windows. I discovered, however, that NewColorWriter does not work correctly for a git bash terminal anymore. It turns out that git bash handles ANSI color codes natively, and all of the syscalls in colorwriter_windows.go that are enabled when IsTerminal works properly for git bash break NewColorWriter. So we should address the logic in NewColorWriter to make sure it works properly on MSYS2/Cygwin in combination with the IsTerminal fix here.

@ereOn ereOn force-pushed the isterminal_msys2_support branch 5 times, most recently from b11d065 to 4c2de73 Compare March 23, 2017 18:14
@ereOn
Copy link
Author

ereOn commented Mar 23, 2017

@ChrisHines I changed everything you mentionned except for your last comment about Git bash. I will look at this right now.

I noticed a weird behavior of go test: whenever it is launched without -v or ran indirectly (like go test ./...), os.Stdout is not a terminal. I had to explicitely open CONOUT$ (which directly points at the console output) to write a reliable test.

All the code now uses only syscall which avoid a useless dependency (thanks for the advice on this).

Let me know what you think of this.

@ereOn ereOn force-pushed the isterminal_msys2_support branch from 2dbbb85 to ef721fa Compare March 23, 2017 18:38
@ereOn
Copy link
Author

ereOn commented Mar 23, 2017

Updated the PR to restore the behavior.

I manually tested it with: https://gist.github.com/ereOn/32aafdf41c34b9749a90f464b2c96498.

image
image

Copy link
Member

@ChrisHines ChrisHines left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks really nice. I'm glad you broke out IsConsole and IsMSYSTerminal because I thought that would be a good approach to make NewColorWriter work well.

I've tested it in all three types of terminals and they all work great. I just have a few nits about the comments I'd like you to address and then we can merge this PR.

r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fw.Fd(), uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0

// If the terminal is a Windows console, succeed right away.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment seems obsolete. I would say it's not needed anymore.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. I had to push in a hurry, forgot about those comments. Fixed.

// If the terminal is a Windows console, succeed right away.
err := syscall.GetConsoleMode(handle, &st)

return (err == nil && st != 0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to see a comment explaining st and the significance of comparing it to 0.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

return false
}

// The terminal is not a cmd.exe terminal, let's try to detect MSYS2 terminals.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear to me how we know it's not a cmd.exe terminal at this point.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep indeed. That was a leftover too. Removed.

@ereOn ereOn force-pushed the isterminal_msys2_support branch from ef721fa to a62210c Compare March 24, 2017 12:22
@ereOn
Copy link
Author

ereOn commented Mar 24, 2017

@ChrisHines I addressed all the remaining comment issues. Thanks for the feedback !

@ChrisHines
Copy link
Member

Thanks for the contribution. Good work!

@ChrisHines ChrisHines merged commit 5d93a23 into go-kit:master Mar 24, 2017
@ereOn ereOn deleted the isterminal_msys2_support branch March 24, 2017 23:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants