func (s *Service) Info(ctx context.Context, qFlag bool) (project.InfoSet, error) {
	result := project.InfoSet{}
	containers, err := s.collectContainers(ctx)
	if err != nil {
		return nil, err
	}
	for _, c := range containers {
		info, err := c.Info(ctx, qFlag)
		if err != nil {
			return nil, err
		}
		result = append(result, info)
	}
	return result, nil
}
Info implements Service.Info. It returns an project.InfoSet with the containers
related to this service (can be multiple if using the scale command).
package docker
import (
	"fmt"
	"strconv"
	"strings"
	"github.com/docker/engine-api/types/network"
	"golang.org/x/net/context"
	"github.com/Sirupsen/logrus"
	"github.com/docker/engine-api/client"
	"github.com/docker/go-connections/nat"
	"github.com/docker/libcompose/config"
	"github.com/docker/libcompose/docker/builder"
	"github.com/docker/libcompose/labels"
	"github.com/docker/libcompose/project"
	"github.com/docker/libcompose/project/options"
	"github.com/docker/libcompose/utils"
)
type Service struct {
	name          string
	serviceConfig *config.ServiceConfig
	context       *Context
}
func NewService(name string, serviceConfig *config.ServiceConfig, context *Context) *Service {
	return &Service{
		name:          name,
		serviceConfig: serviceConfig,
		context:       context,
	}
}
func (s *Service) Name() string {
	return s.name
}
func (s *Service) Config() *config.ServiceConfig {
	return s.serviceConfig
}
func (s *Service) DependentServices() []project.ServiceRelationship {
	return project.DefaultDependentServices(s.context.Project, s)
}
func (s *Service) Create(ctx context.Context, options options.Create) error {
	containers, err := s.collectContainers(ctx)
	if err != nil {
		return err
	}
	imageName, err := s.ensureImageExists(ctx, options.NoBuild)
	if err != nil {
		return err
	}
	if len(containers) != 0 {
		return s.eachContainer(ctx, func(c *Container) error {
			return s.recreateIfNeeded(ctx, imageName, c, options.NoRecreate, options.ForceRecreate)
		})
	}
	_, err = s.createOne(ctx, imageName)
	return err
}
func (s *Service) collectContainers(ctx context.Context) ([]*Container, error) {
	client := s.context.ClientFactory.Create(s)
	containers, err := GetContainersByFilter(ctx, client, labels.SERVICE.Eq(s.name), labels.PROJECT.Eq(s.context.Project.Name))
	if err != nil {
		return nil, err
	}
	legacyContainers, err := GetContainersByFilter(ctx, client, labels.SERVICE_LEGACY.Eq(s.name), labels.PROJECT_LEGACY.Eq(s.context.Project.Name))
	if err != nil {
		return nil, err
	}
	if len(containers) == 0 && len(legacyContainers) > 0 {
		containers = legacyContainers
	}
	result := []*Container{}
	for _, container := range containers {
		numberLabel := container.Labels[labels.NUMBER.Str()]
		name := strings.SplitAfter(container.Names[0], "/")
		if numberLabel == "" {
			result = append(result, NewContainer(client, name[len(name)-1], 1, s))
			return result, nil
		}
		containerNumber, err := strconv.Atoi(numberLabel)
		if err != nil {
			return nil, err
		}
		result = append(result, NewContainer(client, name[len(name)-1], containerNumber, s))
	}
	return result, nil
}
func (s *Service) createOne(ctx context.Context, imageName string) (*Container, error) {
	containers, err := s.constructContainers(ctx, imageName, 1)
	if err != nil {
		return nil, err
	}
	return containers[0], err
}
func (s *Service) ensureImageExists(ctx context.Context, noBuild bool) (string, error) {
	err := s.imageExists()
	if err == nil {
		return s.imageName(), nil
	}
	if err != nil && !client.IsErrImageNotFound(err) {
		return "", err
	}
	if s.Config().Build.Context != "" {
		if noBuild {
			return "", fmt.Errorf("Service %q needs to be built, but no-build was specified", s.name)
		}
		return s.imageName(), s.build(ctx, options.Build{})
	}
	return s.imageName(), s.Pull(ctx)
}
func (s *Service) imageExists() error {
	client := s.context.ClientFactory.Create(s)
	_, _, err := client.ImageInspectWithRaw(context.Background(), s.imageName(), false)
	return err
}
func (s *Service) imageName() string {
	if s.Config().Image != "" {
		return s.Config().Image
	}
	return fmt.Sprintf("%s_%s", s.context.ProjectName, s.Name())
}
func (s *Service) Build(ctx context.Context, buildOptions options.Build) error {
	if s.Config().Image != "" {
		return nil
	}
	return s.build(ctx, buildOptions)
}
func (s *Service) build(ctx context.Context, buildOptions options.Build) error {
	if s.Config().Build.Context == "" {
		return fmt.Errorf("Specified service does not have a build section")
	}
	builder := &builder.DaemonBuilder{
		Client:           s.context.ClientFactory.Create(s),
		ContextDirectory: s.Config().Build.Context,
		Dockerfile:       s.Config().Build.Dockerfile,
		AuthConfigs:      s.context.AuthLookup.All(),
		NoCache:          buildOptions.NoCache,
		ForceRemove:      buildOptions.ForceRemove,
		Pull:             buildOptions.Pull,
	}
	return builder.Build(ctx, s.imageName())
}
func (s *Service) constructContainers(ctx context.Context, imageName string, count int) ([]*Container, error) {
	result, err := s.collectContainers(ctx)
	if err != nil {
		return nil, err
	}
	client := s.context.ClientFactory.Create(s)
	var namer Namer
	if s.serviceConfig.ContainerName != "" {
		if count > 1 {
			logrus.Warnf(`The "%s" service is using the custom container name "%s". Docker requires each container to have a unique name. Remove the custom name to scale the service.`, s.name, s.serviceConfig.ContainerName)
		}
		namer = NewSingleNamer(s.serviceConfig.ContainerName)
	} else {
		namer, err = NewNamer(ctx, client, s.context.Project.Name, s.name, false)
		if err != nil {
			return nil, err
		}
	}
	for i := len(result); i < count; i++ {
		containerName, containerNumber := namer.Next()
		c := NewContainer(client, containerName, containerNumber, s)
		dockerContainer, err := c.Create(ctx, imageName)
		if err != nil {
			return nil, err
		}
		logrus.Debugf("Created container %s: %v", dockerContainer.ID, dockerContainer.Name)
		result = append(result, NewContainer(client, containerName, containerNumber, s))
	}
	return result, nil
}
func (s *Service) Up(ctx context.Context, options options.Up) error {
	containers, err := s.collectContainers(ctx)
	if err != nil {
		return err
	}
	var imageName = s.imageName()
	if len(containers) == 0 || !options.NoRecreate {
		imageName, err = s.ensureImageExists(ctx, options.NoBuild)
		if err != nil {
			return err
		}
	}
	return s.up(ctx, imageName, true, options)
}
func (s *Service) Run(ctx context.Context, commandParts []string) (int, error) {
	imageName, err := s.ensureImageExists(ctx, false)
	if err != nil {
		return -1, err
	}
	client := s.context.ClientFactory.Create(s)
	namer, err := NewNamer(ctx, client, s.context.Project.Name, s.name, true)
	if err != nil {
		return -1, err
	}
	containerName, containerNumber := namer.Next()
	c := NewOneOffContainer(client, containerName, containerNumber, s)
	if err := s.connectContainerToNetworks(ctx, c, true); err != nil {
		return -1, err
	}
	return c.Run(ctx, imageName, &config.ServiceConfig{Command: commandParts, Tty: true, StdinOpen: true})
}