in executors/docker/executor_docker.go [872:931]
func (s *executor) watchContainer(ctx context.Context, id string, input io.Reader) (err error) {
options := types.ContainerAttachOptions{
Stream: true,
Stdin: true,
Stdout: true,
Stderr: true,
}
s.Debugln("Attaching to container", id, "...")
hijacked, err := s.client.ContainerAttach(ctx, id, options)
if err != nil {
return
}
defer hijacked.Close()
s.Debugln("Starting container", id, "...")
err = s.client.ContainerStart(ctx, id, types.ContainerStartOptions{})
if err != nil {
return
}
s.Debugln("Waiting for attach to finish", id, "...")
attachCh := make(chan error, 2)
// Copy any output to the build trace
go func() {
_, err := stdcopy.StdCopy(s.Trace, s.Trace, hijacked.Reader)
if err != nil {
attachCh <- err
}
}()
// Write the input to the container and close its STDIN to get it to finish
go func() {
_, err := io.Copy(hijacked.Conn, input)
hijacked.CloseWrite()
if err != nil {
attachCh <- err
}
}()
waitCh := make(chan error, 1)
go func() {
waitCh <- s.waitForContainer(id)
}()
select {
case <-ctx.Done():
s.killContainer(id, waitCh)
err = errors.New("Aborted")
case err = <-attachCh:
s.killContainer(id, waitCh)
s.Debugln("Container", id, "finished with", err)
case err = <-waitCh:
s.Debugln("Container", id, "finished with", err)
}
return
}