Windows: Native ANSI console support

Signed-off-by: John Howard <jhoward@microsoft.com>
This commit is contained in:
John Howard 2015-10-15 11:40:14 -07:00
parent be7bdc5be2
commit 7b3e897b0b
2 changed files with 87 additions and 0 deletions

View file

@ -1,5 +1,34 @@
package system package system
import (
"fmt"
"syscall"
)
// OSVersion is a wrapper for Windows version information
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx
type OSVersion struct {
Version uint32
MajorVersion uint8
MinorVersion uint8
Build uint16
}
// GetOSVersion gets the operating system version on Windows. Note that
// docker.exe must be manifested to get the correct version information.
func GetOSVersion() (OSVersion, error) {
var err error
osv := OSVersion{}
osv.Version, err = syscall.GetVersion()
if err != nil {
return osv, fmt.Errorf("Failed to call GetVersion()")
}
osv.MajorVersion = uint8(osv.Version & 0xFF)
osv.MinorVersion = uint8(osv.Version >> 8 & 0xFF)
osv.Build = uint16(osv.Version >> 16)
return osv, nil
}
// Unmount is a platform-specific helper function to call // Unmount is a platform-specific helper function to call
// the unmount syscall. Not supported on Windows // the unmount syscall. Not supported on Windows
func Unmount(dest string) { func Unmount(dest string) {

View file

@ -7,9 +7,11 @@ import (
"io" "io"
"os" "os"
"os/signal" "os/signal"
"syscall"
"github.com/Azure/go-ansiterm/winterm" "github.com/Azure/go-ansiterm/winterm"
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/system"
"github.com/docker/docker/pkg/term/windows" "github.com/docker/docker/pkg/term/windows"
) )
@ -36,10 +38,66 @@ func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
// MSYS (mingw) does not emulate ANSI well. // MSYS (mingw) does not emulate ANSI well.
return windows.ConsoleStreams() return windows.ConsoleStreams()
default: default:
if useNativeConsole() {
return os.Stdin, os.Stdout, os.Stderr
}
return windows.ConsoleStreams() return windows.ConsoleStreams()
} }
} }
// useNativeConsole determines if the docker client should use the built-in
// console which supports ANSI emulation, or fall-back to the golang emulator
// (github.com/azure/go-ansiterm).
func useNativeConsole() bool {
osv, err := system.GetOSVersion()
if err != nil {
return false
}
// Native console is not available major version 10
if osv.MajorVersion < 10 {
return false
}
// Must have a late pre-release TP4 build of Windows Server 2016/Windows 10 TH2 or later
if osv.Build < 10578 {
return false
}
// Environment variable override
if e := os.Getenv("USE_NATIVE_CONSOLE"); e != "" {
if e == "1" {
return true
}
return false
}
// Get the handle to stdout
stdOutHandle, err := syscall.GetStdHandle(syscall.STD_OUTPUT_HANDLE)
if err != nil {
return false
}
// Get the console mode from the consoles stdout handle
var mode uint32
if err := syscall.GetConsoleMode(stdOutHandle, &mode); err != nil {
return false
}
// Legacy mode does not have native ANSI emulation.
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx
const enableVirtualTerminalProcessing = 0x0004
if mode&enableVirtualTerminalProcessing == 0 {
return false
}
// TODO Windows (Post TP4). The native emulator still has issues which
// mean it shouldn't be enabled for everyone. Change this next line to true
// to change the default to "enable if available". In the meantime, users
// can still try it out by using USE_NATIVE_CONSOLE env variable.
return false
}
// GetFdInfo returns the file descriptor for an os.File and indicates whether the file represents a terminal. // GetFdInfo returns the file descriptor for an os.File and indicates whether the file represents a terminal.
func GetFdInfo(in interface{}) (uintptr, bool) { func GetFdInfo(in interface{}) (uintptr, bool) {
return windows.GetHandleInfo(in) return windows.GetHandleInfo(in)