Windows: Native ANSI console support
| ... | ... |
@@ -3,13 +3,13 @@ package daemon |
| 3 | 3 |
import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
"os" |
| 6 |
- "syscall" |
|
| 7 | 6 |
|
| 8 | 7 |
"github.com/Sirupsen/logrus" |
| 9 | 8 |
"github.com/docker/docker/daemon/graphdriver" |
| 10 | 9 |
// register the windows graph driver |
| 11 | 10 |
_ "github.com/docker/docker/daemon/graphdriver/windows" |
| 12 | 11 |
"github.com/docker/docker/pkg/parsers" |
| 12 |
+ "github.com/docker/docker/pkg/system" |
|
| 13 | 13 |
"github.com/docker/docker/runconfig" |
| 14 | 14 |
"github.com/docker/libnetwork" |
| 15 | 15 |
) |
| ... | ... |
@@ -62,21 +62,15 @@ func checkConfigOptions(config *Config) error {
|
| 62 | 62 |
|
| 63 | 63 |
// checkSystem validates platform-specific requirements |
| 64 | 64 |
func checkSystem() error {
|
| 65 |
- var dwVersion uint32 |
|
| 66 |
- |
|
| 67 |
- // TODO Windows. May need at some point to ensure have elevation and |
|
| 68 |
- // possibly LocalSystem. |
|
| 69 |
- |
|
| 70 | 65 |
// Validate the OS version. Note that docker.exe must be manifested for this |
| 71 | 66 |
// call to return the correct version. |
| 72 |
- dwVersion, err := syscall.GetVersion() |
|
| 67 |
+ osv, err := system.GetOSVersion() |
|
| 73 | 68 |
if err != nil {
|
| 74 |
- return fmt.Errorf("Failed to call GetVersion()")
|
|
| 69 |
+ return err |
|
| 75 | 70 |
} |
| 76 |
- if int(dwVersion&0xFF) < 10 {
|
|
| 71 |
+ if osv.MajorVersion < 10 {
|
|
| 77 | 72 |
return fmt.Errorf("This version of Windows does not support the docker daemon")
|
| 78 | 73 |
} |
| 79 |
- |
|
| 80 | 74 |
return nil |
| 81 | 75 |
} |
| 82 | 76 |
|
| ... | ... |
@@ -1,5 +1,34 @@ |
| 1 | 1 |
package system |
| 2 | 2 |
|
| 3 |
+import ( |
|
| 4 |
+ "fmt" |
|
| 5 |
+ "syscall" |
|
| 6 |
+) |
|
| 7 |
+ |
|
| 8 |
+// OSVersion is a wrapper for Windows version information |
|
| 9 |
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx |
|
| 10 |
+type OSVersion struct {
|
|
| 11 |
+ Version uint32 |
|
| 12 |
+ MajorVersion uint8 |
|
| 13 |
+ MinorVersion uint8 |
|
| 14 |
+ Build uint16 |
|
| 15 |
+} |
|
| 16 |
+ |
|
| 17 |
+// GetOSVersion gets the operating system version on Windows. Note that |
|
| 18 |
+// docker.exe must be manifested to get the correct version information. |
|
| 19 |
+func GetOSVersion() (OSVersion, error) {
|
|
| 20 |
+ var err error |
|
| 21 |
+ osv := OSVersion{}
|
|
| 22 |
+ osv.Version, err = syscall.GetVersion() |
|
| 23 |
+ if err != nil {
|
|
| 24 |
+ return osv, fmt.Errorf("Failed to call GetVersion()")
|
|
| 25 |
+ } |
|
| 26 |
+ osv.MajorVersion = uint8(osv.Version & 0xFF) |
|
| 27 |
+ osv.MinorVersion = uint8(osv.Version >> 8 & 0xFF) |
|
| 28 |
+ osv.Build = uint16(osv.Version >> 16) |
|
| 29 |
+ return osv, nil |
|
| 30 |
+} |
|
| 31 |
+ |
|
| 3 | 32 |
// Unmount is a platform-specific helper function to call |
| 4 | 33 |
// the unmount syscall. Not supported on Windows |
| 5 | 34 |
func Unmount(dest string) error {
|
| ... | ... |
@@ -7,9 +7,11 @@ import ( |
| 7 | 7 |
"io" |
| 8 | 8 |
"os" |
| 9 | 9 |
"os/signal" |
| 10 |
+ "syscall" |
|
| 10 | 11 |
|
| 11 | 12 |
"github.com/Azure/go-ansiterm/winterm" |
| 12 | 13 |
"github.com/Sirupsen/logrus" |
| 14 |
+ "github.com/docker/docker/pkg/system" |
|
| 13 | 15 |
"github.com/docker/docker/pkg/term/windows" |
| 14 | 16 |
) |
| 15 | 17 |
|
| ... | ... |
@@ -36,10 +38,66 @@ func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
|
| 36 | 36 |
// MSYS (mingw) does not emulate ANSI well. |
| 37 | 37 |
return windows.ConsoleStreams() |
| 38 | 38 |
default: |
| 39 |
+ if useNativeConsole() {
|
|
| 40 |
+ return os.Stdin, os.Stdout, os.Stderr |
|
| 41 |
+ } |
|
| 39 | 42 |
return windows.ConsoleStreams() |
| 40 | 43 |
} |
| 41 | 44 |
} |
| 42 | 45 |
|
| 46 |
+// useNativeConsole determines if the docker client should use the built-in |
|
| 47 |
+// console which supports ANSI emulation, or fall-back to the golang emulator |
|
| 48 |
+// (github.com/azure/go-ansiterm). |
|
| 49 |
+func useNativeConsole() bool {
|
|
| 50 |
+ osv, err := system.GetOSVersion() |
|
| 51 |
+ if err != nil {
|
|
| 52 |
+ return false |
|
| 53 |
+ } |
|
| 54 |
+ |
|
| 55 |
+ // Native console is not available major version 10 |
|
| 56 |
+ if osv.MajorVersion < 10 {
|
|
| 57 |
+ return false |
|
| 58 |
+ } |
|
| 59 |
+ |
|
| 60 |
+ // Must have a late pre-release TP4 build of Windows Server 2016/Windows 10 TH2 or later |
|
| 61 |
+ if osv.Build < 10578 {
|
|
| 62 |
+ return false |
|
| 63 |
+ } |
|
| 64 |
+ |
|
| 65 |
+ // Environment variable override |
|
| 66 |
+ if e := os.Getenv("USE_NATIVE_CONSOLE"); e != "" {
|
|
| 67 |
+ if e == "1" {
|
|
| 68 |
+ return true |
|
| 69 |
+ } |
|
| 70 |
+ return false |
|
| 71 |
+ } |
|
| 72 |
+ |
|
| 73 |
+ // Get the handle to stdout |
|
| 74 |
+ stdOutHandle, err := syscall.GetStdHandle(syscall.STD_OUTPUT_HANDLE) |
|
| 75 |
+ if err != nil {
|
|
| 76 |
+ return false |
|
| 77 |
+ } |
|
| 78 |
+ |
|
| 79 |
+ // Get the console mode from the consoles stdout handle |
|
| 80 |
+ var mode uint32 |
|
| 81 |
+ if err := syscall.GetConsoleMode(stdOutHandle, &mode); err != nil {
|
|
| 82 |
+ return false |
|
| 83 |
+ } |
|
| 84 |
+ |
|
| 85 |
+ // Legacy mode does not have native ANSI emulation. |
|
| 86 |
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx |
|
| 87 |
+ const enableVirtualTerminalProcessing = 0x0004 |
|
| 88 |
+ if mode&enableVirtualTerminalProcessing == 0 {
|
|
| 89 |
+ return false |
|
| 90 |
+ } |
|
| 91 |
+ |
|
| 92 |
+ // TODO Windows (Post TP4). The native emulator still has issues which |
|
| 93 |
+ // mean it shouldn't be enabled for everyone. Change this next line to true |
|
| 94 |
+ // to change the default to "enable if available". In the meantime, users |
|
| 95 |
+ // can still try it out by using USE_NATIVE_CONSOLE env variable. |
|
| 96 |
+ return false |
|
| 97 |
+} |
|
| 98 |
+ |
|
| 43 | 99 |
// GetFdInfo returns the file descriptor for an os.File and indicates whether the file represents a terminal. |
| 44 | 100 |
func GetFdInfo(in interface{}) (uintptr, bool) {
|
| 45 | 101 |
return windows.GetHandleInfo(in) |