// +build !windows package main import ( "fmt" "io" "io/ioutil" "log" "net" "os" "sync" "syscall" "time" gocontext "context" "github.com/pkg/errors" "github.com/tonistiigi/fifo" "github.com/urfave/cli" "google.golang.org/grpc" "google.golang.org/grpc/grpclog" ) func prepareStdio(stdin, stdout, stderr string, console bool) (*sync.WaitGroup, error) { var wg sync.WaitGroup ctx := gocontext.Background() f, err := fifo.OpenFifo(ctx, stdin, syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700) if err != nil { return nil, err } defer func(c io.Closer) { if err != nil { c.Close() } }(f) go func(w io.WriteCloser) { io.Copy(w, os.Stdin) w.Close() }(f) f, err = fifo.OpenFifo(ctx, stdout, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700) if err != nil { return nil, err } defer func(c io.Closer) { if err != nil { c.Close() } }(f) wg.Add(1) go func(r io.ReadCloser) { io.Copy(os.Stdout, r) r.Close() wg.Done() }(f) f, err = fifo.OpenFifo(ctx, stderr, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700) if err != nil { return nil, err } defer func(c io.Closer) { if err != nil { c.Close() } }(f) if !console { wg.Add(1) go func(r io.ReadCloser) { io.Copy(os.Stderr, r) r.Close() wg.Done() }(f) } return &wg, nil } func getGRPCConnection(context *cli.Context) (*grpc.ClientConn, error) { if grpcConn != nil { return grpcConn, nil } bindSocket := context.GlobalString("address") // reset the logger for grpc to log to dev/null so that it does not mess with our stdio grpclog.SetLogger(log.New(ioutil.Discard, "", log.LstdFlags)) dialOpts := []grpc.DialOption{grpc.WithInsecure(), grpc.WithTimeout(100 * time.Second)} dialOpts = append(dialOpts, grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) { return net.DialTimeout("unix", bindSocket, timeout) }, )) conn, err := grpc.Dial(fmt.Sprintf("unix://%s", bindSocket), dialOpts...) if err != nil { return nil, errors.Wrapf(err, "failed to dial %q", bindSocket) } grpcConn = conn return grpcConn, nil }