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  }