<commit_before>package docker

import (
	"fmt"
	"strconv"
	"strings"

	"golang.org/x/net/context"

	"github.com/Sirupsen/logrus"
	"github.com/docker/engine-api/client"
	"github.com/docker/engine-api/types"
	eventtypes "github.com/docker/engine-api/types/events"
	"github.com/docker/engine-api/types/filters"
	"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"
	dockerevents "github.com/vdemeester/docker-events"
)

// Service is a project.Service implementations.
type Service struct {
	name          string
	project       *project.Project
	serviceConfig *config.ServiceConfig
	clientFactory project.ClientFactory
	authLookup    AuthLookup

	// FIXME(vdemeester) remove this at some point
	context *Context
}

// NewService creates a service
func NewService(name string, serviceConfig *config.ServiceConfig, context *Context) *Service {
	return &Service{
		name:          name,
		project:       context.Project,
		serviceConfig: serviceConfig,
		clientFactory: context.ClientFactory,
		authLookup:    context.AuthLookup,
		context:       context,
	}
}

// Name returns the service name.
func (s *Service) Name() string {
	return s.name
}

// Config returns the configuration of the service (config.ServiceConfig).
func (s *Service) Config() *config.ServiceConfig {
	return s.serviceConfig
}

// DependentServices returns the dependent services (as an array of ServiceRelationship) of the service.
func (s *Service) DependentServices() []project.ServiceRelationship {
	return project.DefaultDependentServices(s.project, s)
}

// Create implements Service.Create. It ensures the image exists or build it
// if it can and then create a container.
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.clientFactory.Create(s)
	containers, err := GetContainersByFilter(ctx, client, labels.SERVICE.Eq(s.name), labels.PROJECT.Eq(s.project.Name))
	if err != nil {
		return nil, err
	}

	result := []*Container{}

	for _, container := range containers {
		containerNumber, err := strconv.Atoi(container.Labels[labels.NUMBER.Str()])
		if err != nil {
			return nil, err
		}
		// Compose add "/" before name, so Name[1] will store actaul name.
		name := strings.SplitAfter(container.Names[0], "/")
		result = append(result, NewContainer(client, 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.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.project.Name, s.Name())
}

// Build implements Service.Build. If an imageName is specified or if the context has
// no build to work with it will do nothing. Otherwise it will try to build
// the image and returns an error if any.
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.clientFactory.Create(s),
		ContextDirectory: s.Config().Build.Context,
		Dockerfile:       s.Config().Build.Dockerfile,
		BuildArgs:        s.Config().Build.Args.ToMap(),
		AuthConfigs:      s.authLookup.All(),<commit_msg>Expose ImageExists in docker.Service<commit_after>package docker

import (
	"fmt"
	"strconv"
	"strings"

	"golang.org/x/net/context"

	"github.com/Sirupsen/logrus"
	"github.com/docker/engine-api/client"
	"github.com/docker/engine-api/types"
	eventtypes "github.com/docker/engine-api/types/events"
	"github.com/docker/engine-api/types/filters"
	"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"
	dockerevents "github.com/vdemeester/docker-events"
)

// Service is a project.Service implementations.
type Service struct {
	name          string
	project       *project.Project
	serviceConfig *config.ServiceConfig
	clientFactory project.ClientFactory
	authLookup    AuthLookup

	// FIXME(vdemeester) remove this at some point
	context *Context
}

// NewService creates a service
func NewService(name string, serviceConfig *config.ServiceConfig, context *Context) *Service {
	return &Service{
		name:          name,
		project:       context.Project,
		serviceConfig: serviceConfig,
		clientFactory: context.ClientFactory,
		authLookup:    context.AuthLookup,
		context:       context,
	}
}

// Name returns the service name.
func (s *Service) Name() string {
	return s.name
}

// Config returns the configuration of the service (config.ServiceConfig).
func (s *Service) Config() *config.ServiceConfig {
	return s.serviceConfig
}

// DependentServices returns the dependent services (as an array of ServiceRelationship) of the service.
func (s *Service) DependentServices() []project.ServiceRelationship {
	return project.DefaultDependentServices(s.project, s)
}

// Create implements Service.Create. It ensures the image exists or build it
// if it can and then create a container.
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.clientFactory.Create(s)
	containers, err := GetContainersByFilter(ctx, client, labels.SERVICE.Eq(s.name), labels.PROJECT.Eq(s.project.Name))
	if err != nil {
		return nil, err
	}

	result := []*Container{}

	for _, container := range containers {
		containerNumber, err := strconv.Atoi(container.Labels[labels.NUMBER.Str()])
		if err != nil {
			return nil, err
		}
		// Compose add "/" before name, so Name[1] will store actaul name.
		name := strings.SplitAfter(container.Names[0], "/")
		result = append(result, NewContainer(client, 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) {
	exists, err := s.ImageExists(ctx)
	if err != nil {
		return "", err
	}
	if exists {
		return s.imageName(), nil
	}

	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)
}

// ImageExists returns whether or not the service image already exists
func (s *Service) ImageExists(ctx context.Context) (bool, error) {
	dockerClient := s.clientFactory.Create(s)

	_, _, err := dockerClient.ImageInspectWithRaw(ctx, s.imageName(), false)
	if err == nil {
		return true, nil
	}
	if err != nil && client.IsErrImageNotFound(err) {
		return false, nil
	}

	return false, err
}

func (s *Service) imageName() string {
	if s.Config().Image != "" {
		return s.Config().Image
	}
	return fmt.Sprintf("%s_%s", s.project.Name, s.Name())
}

// Build implements Service.Build. If an imageName is specified or if the context has
// no build to work with it will do nothing. Otherwise it will try to build
// the image and returns an error if any.
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.clientFactory.Create(s),
		ContextDirectory: s.Config().Build.Context,
		Dockerfile:       s.Config().Build.Dockerfile,
		BuildArgs:        s.Config().Build.Args.ToMap(),
		AuthConfigs:      s.authLookup.All(),
{'fraction_non_alphanumeric': 0.12957998212689903, 'fraction_numerical': 0.0011915400655347036, 'mean_word_length': 4.0843008581524485, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3779577', 'n_tokens_mistral': 3357, 'n_tokens_neox': 3210, 'n_words': 865}