github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/docker/run.go (about) 1 package docker 2 3 import ( 4 "fmt" 5 "io" 6 7 "github.com/distribution/reference" 8 mobycontainer "github.com/docker/docker/api/types/container" 9 "github.com/docker/docker/api/types/mount" 10 ) 11 12 // RunConfig defines the container to create and start. 13 type RunConfig struct { 14 // Image to execute. 15 // 16 // If Pull is true, this must be a reference.Named. 17 Image reference.Reference 18 // Pull will ensure the image exists locally before running. 19 // 20 // If an image will only be used once, this is a convenience to avoid calling ImagePull first. 21 // If an image will be used multiple times (across containers), prefer explicitly calling ImagePull 22 // to avoid the overhead of calling the registry API to check if the image is up-to-date every time. 23 Pull bool 24 // ContainerName is a unique name for the container. If not specified, Docker will generate a random name. 25 ContainerName string 26 // Stdout from the container will be written here if non-nil. 27 // 28 // Errors copying the container output are logged but not propagated. 29 Stdout io.Writer 30 // Stderr from the container will be written here if non-nil. 31 // 32 // Errors copying the container output are logged but not propagated. 33 Stderr io.Writer 34 // Cmd to run when starting the container. 35 Cmd []string 36 // Mounts to attach to the container. 37 Mounts []mount.Mount 38 } 39 40 // RunResult contains information about a container execution. 41 type RunResult struct { 42 ContainerID string 43 44 logsErrCh <-chan error 45 statusRespCh <-chan mobycontainer.WaitResponse 46 statusErrCh <-chan error 47 tearDown func(containerID string) error 48 } 49 50 // Wait blocks until stdout and stderr have been fully consumed (if writers were passed via RunConfig) and the 51 // container has exited. If there is any error consuming stdout/stderr or monitoring the container execution, an 52 // error will be returned. 53 func (r *RunResult) Wait() (int64, error) { 54 select { 55 case err := <-r.statusErrCh: 56 return -1, err 57 case statusResp := <-r.statusRespCh: 58 if statusResp.Error != nil { 59 return -1, fmt.Errorf("error waiting on container: %s", statusResp.Error.Message) 60 } 61 logsErr := <-r.logsErrCh 62 if logsErr != nil { 63 // error is 64 return statusResp.StatusCode, fmt.Errorf("error reading container logs: %w", logsErr) 65 } 66 return statusResp.StatusCode, nil 67 } 68 } 69 70 // Close removes the container (forcibly if it's still running). 71 func (r *RunResult) Close() error { 72 if r.tearDown == nil { 73 return nil 74 } 75 err := r.tearDown(r.ContainerID) 76 if err != nil { 77 return err 78 } 79 r.tearDown = nil 80 return nil 81 }