1 //go:build windows 2 3 package cmd 4 5 import ( 6 "context" 7 "io" 8 "net/url" 9 "time" 10 11 "github.com/pkg/errors" 12 "github.com/sirupsen/logrus" 13 ) 14 15 // UpstreamIO is an interface describing the IO to connect to above the shim. 16 // Depending on the callers settings there may be no opened IO. 17 type UpstreamIO interface { 18 // Close closes all open io. 19 // 20 // This call is idempotent and safe to call multiple times. 21 Close(ctx context.Context) 22 // CloseStdin closes just `Stdin()` if open. 23 // 24 // This call is idempotent and safe to call multiple times. 25 CloseStdin(ctx context.Context) 26 // Stdin returns the open `stdin` reader. If `stdin` was never opened this 27 // will return `nil`. 28 Stdin() io.Reader 29 // StdinPath returns the original path used to open the `Stdin()` reader. 30 StdinPath() string 31 // Stdout returns the open `stdout` writer. If `stdout` was never opened 32 // this will return `nil`. 33 Stdout() io.Writer 34 // StdoutPath returns the original path used to open the `Stdout()` writer. 35 StdoutPath() string 36 // Stderr returns the open `stderr` writer. If `stderr` was never opened 37 // this will return `nil`. 38 Stderr() io.Writer 39 // StderrPath returns the original path used to open the `Stderr()` writer. 40 StderrPath() string 41 // Terminal returns `true` if the connection is emulating a terminal. If 42 // `true` `Stderr()` will always return `nil` and `StderrPath()` will always 43 // return `""`. 44 Terminal() bool 45 } 46 47 // NewUpstreamIO returns an UpstreamIO instance. Currently we only support named pipes and binary 48 // logging driver for container IO. When using binary logger `stdout` and `stderr` are assumed to be 49 // the same and the value of `stderr` is completely ignored. 50 func NewUpstreamIO(ctx context.Context, id, stdout, stderr, stdin string, terminal bool, ioRetryTimeout time.Duration) (UpstreamIO, error) { 51 u, err := url.Parse(stdout) 52 53 // Create IO with named pipes. 54 if err != nil || u.Scheme == "" { 55 return NewNpipeIO(ctx, stdin, stdout, stderr, terminal, ioRetryTimeout) 56 } 57 58 // Create IO for binary logging driver. 59 if u.Scheme != "binary" { 60 return nil, errors.Errorf("scheme must be 'binary', got: '%s'", u.Scheme) 61 } 62 63 return NewBinaryIO(ctx, id, u) 64 } 65 66 // relayIO is a glorified io.Copy that also logs when the copy has completed. 67 func relayIO(w io.Writer, r io.Reader, log *logrus.Entry, name string) (int64, error) { 68 n, err := io.Copy(w, r) 69 if log != nil { 70 lvl := logrus.DebugLevel 71 log = log.WithFields(logrus.Fields{ 72 "file": name, 73 "bytes": n, 74 }) 75 if err != nil { 76 lvl = logrus.ErrorLevel 77 log = log.WithError(err) 78 } 79 log.Log(lvl, "Cmd IO relay complete") 80 } 81 return n, err 82 } 83