func (c *Container) Up(ctx context.Context, imageName string) error {
	var err error
	container, err := c.Create(ctx, imageName)
	if err != nil {
		return err
	}
	if !container.State.Running {
		c.Start(container)
	}
	return nil
}
Up creates and start the container based on the image name and send an event
to notify the container has been created. If the container exists but is stopped
it tries to start it.
package docker
import (
	"fmt"
	"io"
	"math"
	"os"
	"strings"
	"golang.org/x/net/context"
	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/pkg/promise"
	"github.com/docker/docker/pkg/stdcopy"
	"github.com/docker/docker/pkg/term"
	"github.com/docker/engine-api/client"
	"github.com/docker/engine-api/types"
	"github.com/docker/engine-api/types/container"
	"github.com/docker/go-connections/nat"
	"github.com/docker/libcompose/config"
	"github.com/docker/libcompose/labels"
	"github.com/docker/libcompose/logger"
	"github.com/docker/libcompose/project"
	"github.com/docker/libcompose/project/events"
	"github.com/docker/engine-api/types/network"
	util "github.com/docker/libcompose/utils"
)
type Container struct {
	name            string
	serviceName     string
	projectName     string
	containerNumber int
	oneOff          bool
	eventNotifier   events.Notifier
	loggerFactory   logger.Factory
	client          client.APIClient
	service *Service
}
func NewContainer(client client.APIClient, name string, containerNumber int, service *Service) *Container {
	return &Container{
		client:          client,
		name:            name,
		containerNumber: containerNumber,
		serviceName:   service.name,
		projectName:   service.context.Project.Name,
		eventNotifier: service.context.Project,
		loggerFactory: service.context.LoggerFactory,
		service: service,
	}
}
func NewOneOffContainer(client client.APIClient, name string, containerNumber int, service *Service) *Container {
	c := NewContainer(client, name, containerNumber, service)
	c.oneOff = true
	return c
}
func (c *Container) findExisting(ctx context.Context) (*types.ContainerJSON, error) {
	return GetContainer(ctx, c.client, c.name)
}
func (c *Container) Info(ctx context.Context, qFlag bool) (project.Info, error) {
	container, err := c.findExisting(ctx)
	if err != nil || container == nil {
		return nil, err
	}
	infos, err := GetContainersByFilter(ctx, c.client, map[string][]string{
		"name": {container.Name},
	})
	if err != nil || len(infos) == 0 {
		return nil, err
	}
	info := infos[0]
	result := project.Info{}
	if qFlag {
		result = append(result, project.InfoPart{Key: "Id", Value: container.ID})
	} else {
		result = append(result, project.InfoPart{Key: "Name", Value: name(info.Names)})
		result = append(result, project.InfoPart{Key: "Command", Value: info.Command})
		result = append(result, project.InfoPart{Key: "State", Value: info.Status})
		result = append(result, project.InfoPart{Key: "Ports", Value: portString(info.Ports)})
	}
	return result, nil
}
func portString(ports []types.Port) string {
	result := []string{}
	for _, port := range ports {
		if port.PublicPort > 0 {
			result = append(result, fmt.Sprintf("%s:%d->%d/%s", port.IP, port.PublicPort, port.PrivatePort, port.Type))
		} else {
			result = append(result, fmt.Sprintf("%d/%s", port.PrivatePort, port.Type))
		}
	}
	return strings.Join(result, ", ")
}
func name(names []string) string {
	max := math.MaxInt32
	var current string
	for _, v := range names {
		if len(v) < max {
			max = len(v)
			current = v
		}
	}
	return current[1:]
}
func (c *Container) Recreate(ctx context.Context, imageName string) (*types.ContainerJSON, error) {
	container, err := c.findExisting(ctx)
	if err != nil || container == nil {
		return nil, err
	}
	hash := container.Config.Labels[labels.HASH.Str()]
	legacyHash := container.Config.Labels[labels.HASH_LEGACY.Str()]
	if hash == "" && legacyHash != "" {
		hash = legacyHash
	}
	if hash == "" {
		return nil, fmt.Errorf("Failed to find hash on old container: %s", container.Name)
	}
	name := container.Name[1:]
	newName := fmt.Sprintf("%s_%s", name, container.ID[:12])
	logrus.Debugf("Renaming %s => %s", name, newName)
	if err := c.client.ContainerRename(ctx, container.ID, newName); err != nil {
		logrus.Errorf("Failed to rename old container %s", c.name)
		return nil, err
	}
	newContainer, err := c.createContainer(ctx, imageName, container.ID, nil)
	if err != nil {
		return nil, err
	}
	logrus.Debugf("Created replacement container %s", newContainer.ID)
	if err := c.client.ContainerRemove(ctx, types.ContainerRemoveOptions{
		ContainerID:   container.ID,
		Force:         true,
		RemoveVolumes: false,
	}); err != nil {
		logrus.Errorf("Failed to remove old container %s", c.name)
		return nil, err
	}
	logrus.Debugf("Removed old container %s %s", c.name, container.ID)
	return newContainer, nil
}
func (c *Container) Create(ctx context.Context, imageName string) (*types.ContainerJSON, error) {
	return c.CreateWithOverride(ctx, imageName, nil)
}
func (c *Container) CreateWithOverride(ctx context.Context, imageName string, configOverride *config.ServiceConfig) (*types.ContainerJSON, error) {
	container, err := c.findExisting(ctx)
	if err != nil {
		return nil, err
	}
	if container == nil {
		container, err = c.createContainer(ctx, imageName, "", configOverride)
		if err != nil {
			return nil, err
		}
		c.eventNotifier.Notify(events.ContainerCreated, c.serviceName, map[string]string{
			"name": c.Name(),
		})
	}
	return container, err
}
func (c *Container) Stop(ctx context.Context, timeout int) error {
	return c.withContainer(ctx, func(container *types.ContainerJSON) error {
		return c.client.ContainerStop(ctx, container.ID, timeout)
	})
}
func (c *Container) Pause(ctx context.Context) error {
	return c.withContainer(ctx, func(container *types.ContainerJSON) error {
		if !container.State.Paused {
			return c.client.ContainerPause(ctx, container.ID)
		}
		return nil
	})
}
func (c *Container) Unpause(ctx context.Context) error {
	return c.withContainer(ctx, func(container *types.ContainerJSON) error {
		if container.State.Paused {
			return c.client.ContainerUnpause(ctx, container.ID)
		}
		return nil
	})
}
func (c *Container) Kill(ctx context.Context, signal string) error {
	return c.withContainer(ctx, func(container *types.ContainerJSON) error {
		return c.client.ContainerKill(ctx, container.ID, signal)
	})
}
func (c *Container) Delete(ctx context.Context, removeVolume bool) error {
	container, err := c.findExisting(ctx)
	if err != nil || container == nil {
		return err
	}
	info, err := c.client.ContainerInspect(ctx, container.ID)
	if err != nil {
		return err
	}
	if !info.State.Running {
		return c.client.ContainerRemove(ctx, types.ContainerRemoveOptions{
			ContainerID:   container.ID,
			Force:         true,
			RemoveVolumes: removeVolume,
		})
	}
	return nil
}
func (c *Container) IsRunning(ctx context.Context) (bool, error) {
	container, err := c.findExisting(ctx)
	if err != nil || container == nil {
		return false, err
	}
	info, err := c.client.ContainerInspect(ctx, container.ID)
	if err != nil {
		return false, err
	}
	return info.State.Running, nil
}
func (c *Container) Run(ctx context.Context, imageName string, configOverride *config.ServiceConfig) (int, error) {
	var (
		errCh       chan error
		out, stderr io.Writer
		in          io.ReadCloser
	)
	container, err := c.createContainer(ctx, imageName, "", configOverride)
	if err != nil {
		return -1, err
	}
	if configOverride.StdinOpen {
		in = os.Stdin
	}
	if configOverride.Tty {
		out = os.Stdout
	}
	if configOverride.Tty {
		stderr = os.Stderr
	}
	options := types.ContainerAttachOptions{
		ContainerID: container.ID,
		Stream:      true,
		Stdin:       configOverride.StdinOpen,
		Stdout:      configOverride.Tty,
		Stderr:      configOverride.Tty,
	}
	resp, err := c.client.ContainerAttach(ctx, options)
	if err != nil {
		return -1, err
	}
	inFd, _ := term.GetFdInfo(in)
	state, err := term.SetRawTerminal(inFd)
	if err != nil {
		return -1, err
	}
	defer term.RestoreTerminal(inFd, state)
	errCh = promise.Go(func() error {
		return holdHijackedConnection(configOverride.Tty, in, out, stderr, resp)
	})
	if err := c.client.ContainerStart(ctx, container.ID); err != nil {
		return -1, err
	}
	if err := <-errCh; err != nil {
		logrus.Debugf("Error hijack: %s", err)
		return -1, err
	}
	exitedContainer, err := c.client.ContainerInspect(ctx, container.ID)
	if err != nil {
		return -1, err
	}
	return exitedContainer.State.ExitCode, nil
}
func holdHijackedConnection(tty bool, inputStream io.ReadCloser, outputStream, errorStream io.Writer, resp types.HijackedResponse) error {
	var err error
	receiveStdout := make(chan error, 1)
	if outputStream != nil || errorStream != nil {
		go func() {
			if tty && outputStream != nil {
				_, err = io.Copy(outputStream, resp.Reader)
			} else {
				_, err = stdcopy.StdCopy(outputStream, errorStream, resp.Reader)
			}
			logrus.Debugf("[hijack] End of stdout")
			receiveStdout <- err
		}()
	}
	stdinDone := make(chan struct{})
	go func() {
		if inputStream != nil {
			io.Copy(resp.Conn, inputStream)
			logrus.Debugf("[hijack] End of stdin")
		}
		if err := resp.CloseWrite(); err != nil {
			logrus.Debugf("Couldn't send EOF: %s", err)
		}
		close(stdinDone)
	}()
	select {
	case err := <-receiveStdout:
		if err != nil {
			logrus.Debugf("Error receiveStdout: %s", err)
			return err
		}
	case <-stdinDone:
		if outputStream != nil || errorStream != nil {
			if err := <-receiveStdout; err != nil {
				logrus.Debugf("Error receiveStdout: %s", err)
				return err
			}
		}
	}
	return nil
}