Ver código fonte

Merge pull request #17089 from Microsoft/10662-ansi

Windows: Native ANSI console support
Alexander Morozov 9 anos atrás
pai
commit
28588efb47
3 arquivos alterados com 91 adições e 10 exclusões
  1. 4 10
      daemon/daemon_windows.go
  2. 29 0
      pkg/system/syscall_windows.go
  3. 58 0
      pkg/term/term_windows.go

+ 4 - 10
daemon/daemon_windows.go

@@ -3,13 +3,13 @@ package daemon
 import (
 	"fmt"
 	"os"
-	"syscall"
 
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/daemon/graphdriver"
 	// register the windows graph driver
 	_ "github.com/docker/docker/daemon/graphdriver/windows"
 	"github.com/docker/docker/pkg/parsers"
+	"github.com/docker/docker/pkg/system"
 	"github.com/docker/docker/runconfig"
 	"github.com/docker/libnetwork"
 )
@@ -62,21 +62,15 @@ func checkConfigOptions(config *Config) error {
 
 // checkSystem validates platform-specific requirements
 func checkSystem() error {
-	var dwVersion uint32
-
-	// TODO Windows. May need at some point to ensure have elevation and
-	// possibly LocalSystem.
-
 	// Validate the OS version. Note that docker.exe must be manifested for this
 	// call to return the correct version.
-	dwVersion, err := syscall.GetVersion()
+	osv, err := system.GetOSVersion()
 	if err != nil {
-		return fmt.Errorf("Failed to call GetVersion()")
+		return err
 	}
-	if int(dwVersion&0xFF) < 10 {
+	if osv.MajorVersion < 10 {
 		return fmt.Errorf("This version of Windows does not support the docker daemon")
 	}
-
 	return nil
 }
 

+ 29 - 0
pkg/system/syscall_windows.go

@@ -1,5 +1,34 @@
 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
 // the unmount syscall. Not supported on Windows
 func Unmount(dest string) error {

+ 58 - 0
pkg/term/term_windows.go

@@ -7,9 +7,11 @@ import (
 	"io"
 	"os"
 	"os/signal"
+	"syscall"
 
 	"github.com/Azure/go-ansiterm/winterm"
 	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/pkg/system"
 	"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.
 		return windows.ConsoleStreams()
 	default:
+		if useNativeConsole() {
+			return os.Stdin, os.Stdout, os.Stderr
+		}
 		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.
 func GetFdInfo(in interface{}) (uintptr, bool) {
 	return windows.GetHandleInfo(in)