handleEOF handles io.EOF errors while reading or writing from the underlying command pipes. When we've received an EOF we expect that the command will be terminated soon. As such, we call Wait() on the command and return EOF or the error depending on whether the command exited with an error. If Wa
(err error)
| 127 | // |
| 128 | // If Wait() does not return within 10s, an error is returned |
| 129 | func (c *commandConn) handleEOF(err error) error { |
| 130 | if err != io.EOF { |
| 131 | return err |
| 132 | } |
| 133 | |
| 134 | c.cmdMutex.Lock() |
| 135 | defer c.cmdMutex.Unlock() |
| 136 | |
| 137 | var werr error |
| 138 | if c.cmdExited.Load() { |
| 139 | werr = c.cmdWaitErr |
| 140 | } else { |
| 141 | werrCh := make(chan error) |
| 142 | go func() { werrCh <- c.cmd.Wait() }() |
| 143 | select { |
| 144 | case werr = <-werrCh: |
| 145 | c.cmdWaitErr = werr |
| 146 | c.cmdExited.Store(true) |
| 147 | case <-time.After(10 * time.Second): |
| 148 | c.stderrMu.Lock() |
| 149 | stderr := c.stderr.String() |
| 150 | c.stderrMu.Unlock() |
| 151 | return fmt.Errorf("command %v did not exit after %v: stderr=%q", c.cmd.Args, err, stderr) |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | if werr == nil { |
| 156 | return err |
| 157 | } |
| 158 | c.stderrMu.Lock() |
| 159 | stderr := c.stderr.String() |
| 160 | c.stderrMu.Unlock() |
| 161 | return fmt.Errorf("command %v has exited with %v, make sure the URL is valid, and Docker 18.09 or later is installed on the remote host: stderr=%s", c.cmd.Args, werr, stderr) |
| 162 | } |
| 163 | |
| 164 | func ignorableCloseError(err error) bool { |
| 165 | return strings.Contains(err.Error(), os.ErrClosed.Error()) |