package containers import ( "archive/tar" "context" "errors" "fmt" "sync" "github.com/docker/docker/api/types" "github.com/docker/go-connections/nat" ) var ( _ Container = (*containerRef)(nil) ErrNoMappedPort = errors.New("no mapped port found") ) type containerRef struct { info types.ContainerJSON shutdowner Shutdowner client Client resourceName string containerID string networkID string inspectOnce sync.Once } func (c *containerRef) CopyFileFromContainer(ctx context.Context, path string, f CopyContainerFileHandler) (err error) { reader, _, err := c.client.CopyFromContainer(ctx, c.containerID, path) if err != nil { return err } defer func() { err = errors.Join(err, reader.Close()) }() tarReader := tar.NewReader(reader) var header *tar.Header for header, err = tarReader.Next(); err == nil; header, err = tarReader.Next() { if err := f(header, tarReader); err != nil { return err } } return nil } func (c *containerRef) NetworkID() string { return c.networkID } func (c *containerRef) ID() string { return c.containerID } func (c *containerRef) MappedPort(ctx context.Context, port nat.Port) (hostIP, hostPort string, err error) { c.inspectOnce.Do(func() { c.info, err = c.client.ContainerInspect(ctx, c.containerID) }) if err != nil { return "", "", err } binding, ok := c.info.NetworkSettings.Ports[port] if !ok || len(binding) == 0 { return "", "", fmt.Errorf("%w: %s", ErrNoMappedPort, port.Port()) } return binding[0].HostIP, binding[0].HostPort, nil } func (c *containerRef) Shutdown(ctx context.Context) error { return c.shutdowner.ShutdownContainer(ctx, c) }