<commit_before>package api

import (
	"context"
	"errors"
	"fmt"
	"io"
	"strings"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/filters"
	"github.com/docker/docker/api/types/strslice"
	"github.com/docker/go-connections/nat"
)

func CreateContainer(ctx context.Context, cli MeliAPiClient, dc *DockerContainer) (bool, string, error) {
	// 1. make labels
	labelsMap := make(map[string]string)
	if len(dc.ComposeService.Labels) > 0 {
		for _, v := range dc.ComposeService.Labels {
			onelabel := FormatLabels(v)
			labelsMap[onelabel[0]] = onelabel[1]
		}
	}

	// reuse container if already running
	meliService := labelsMap["meli_service"]
	filters := filters.NewArgs()
	filters.Add("label", fmt.Sprintf("meli_service=%s", meliService))
	containers, err := cli.ContainerList(ctx, types.ContainerListOptions{
		Quiet:   true,
		All:     true,
		Filters: filters})
	if err != nil {
		fmt.Println(" :unable to list containers")
	}
	if len(containers) > 0 {
		dc.UpdateContainerID(containers[0].ID)
		return true, containers[0].ID, nil
	}

	// 2. make ports
	portsMap := make(map[nat.Port]struct{})
	portBindingMap := make(map[nat.Port][]nat.PortBinding)
	if len(dc.ComposeService.Ports) > 0 {
		for _, v := range dc.ComposeService.Ports {
			oneport := FormatPorts(v)
			hostport := oneport[0]
			containerport := oneport[1]
			port, err := nat.NewPort("tcp", containerport)
			myPortBinding := nat.PortBinding{HostPort: hostport}
			if err != nil {
				fmt.Println(err, " :unable to create a nat.Port")
			}
			portsMap[port] = EmptyStruct{}
			portBindingMap[port] = []nat.PortBinding{myPortBinding}
		}
	}
	// 3. create command
	cmd := strslice.StrSlice{}
	if dc.ComposeService.Command != "" {
		sliceCommand := strings.Fields(dc.ComposeService.Command)
		cmd = strslice.StrSlice(sliceCommand)
	}
	// 4. create restart policy
	restartPolicy := container.RestartPolicy{}
	if dc.ComposeService.Restart != "" {
		// You cannot set MaximumRetryCount for the following restart policies;
		// always, no, unless-stopped
		if dc.ComposeService.Restart == "on-failure" {
			restartPolicy = container.RestartPolicy{Name: dc.ComposeService.Restart, MaximumRetryCount: 3}
		} else {
			restartPolicy = container.RestartPolicy{Name: dc.ComposeService.Restart}
		}

	}
	// 5. build image
	imageNamePtr := &dc.ComposeService.Image
	if dc.ComposeService.Build != (Buildstruct{}) {
		imageName, err := BuildDockerImage(ctx, cli, dc)
		if err != nil {
			return false, "", &popagateError{originalErr: err}
		}
		// done this way so that we can manipulate the value of the
		// imageName inside this scope
		imageNamePtr = &imageName
	}
	imageName := *imageNamePtr

	// 6. add volumes
	volume := make(map[string]struct{})
	binds := []string{}
	if len(dc.ComposeService.Volumes) > 0 {
		for _, v := range dc.ComposeService.Volumes {
			vol := FormatServiceVolumes(v, dc.DockerComposeFile)
			volume[vol[1]] = EmptyStruct{}
			// TODO: handle other read/write modes
			whatToBind := vol[0] + ":" + vol[1] + ":rw"
			binds = append(binds, whatToBind)
		}
	}

	containerCreateResp, err := cli.ContainerCreate(
		ctx,
		&container.Config{
			Image:        imageName,
			Labels:       labelsMap,
			Env:          dc.ComposeService.Environment,
			ExposedPorts: portsMap,
			Cmd:          cmd,
			Volumes:      volume},
		&container.HostConfig{
			DNS: []string{
				"8.8.8.8",
				"8.8.4.4",
				"fd00:c2b6:b24b:be67:2827:688d:e6a1:6a3b",
				"fd00:a516:7c1b:17cd:6d81:2137:bd2a:2c5b"},
			DNSSearch: []string{
				"8.8.8.8",
				"8.8.4.4",
				"fd00:c2b6:b24b:be67:2827:688d:e6a1:6a3b",
				"fd00:a516:7c1b:17cd:6d81:2137:bd2a:2c5b"},
			PublishAllPorts: false,
			PortBindings:    portBindingMap,
			NetworkMode:     container.NetworkMode(dc.NetworkName),
			RestartPolicy:   restartPolicy,
			Binds:           binds,
			Links:           dc.ComposeService.Links},
		nil,
		FormatImageName(dc.ServiceName))
	if err != nil {
		return false, "", &popagateError{
			originalErr: err,
			newErr:      errors.New(" :unable to create container")}
	}

	dc.UpdateContainerID(containerCreateResp.ID)
	return false, containerCreateResp.ID, nil
}

func ContainerStart(ctx context.Context, cli MeliAPiClient, dc *DockerContainer) error {
	err := cli.ContainerStart(
		ctx,
		dc.ContainerID,
		types.ContainerStartOptions{})
	if err != nil {
		return &popagateError{
			originalErr: err,
			newErr:      fmt.Errorf(" :unable to start container %s", dc.ContainerID)}

	}
	return nil
}

func ContainerLogs(ctx context.Context, cli MeliAPiClient, dc *DockerContainer) error {
	containerLogResp, err := cli.ContainerLogs(
		ctx,
		dc.ContainerID,
		types.ContainerLogsOptions{
			ShowStdout: true,
			ShowStderr: true,
			Timestamps: true,
			Follow:     dc.FollowLogs,
			Details:    true,
			Tail:       "all"})

	if err != nil {
		if err != nil {
			return &popagateError{
				originalErr: err,
				newErr:      fmt.Errorf(" :unable to get container logs %s", dc.ContainerID)}
		}
	}
	io.Copy(dc.LogMedium, containerLogResp)

	containerLogResp.Close()
	return nil
}<commit_msg>pretty container logs<commit_after>package api

import (
	"bufio"
	"context"
	"errors"
	"fmt"
	"strings"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/filters"
	"github.com/docker/docker/api/types/strslice"
	"github.com/docker/go-connections/nat"
)

func CreateContainer(ctx context.Context, cli MeliAPiClient, dc *DockerContainer) (bool, string, error) {
	// 1. make labels
	labelsMap := make(map[string]string)
	if len(dc.ComposeService.Labels) > 0 {
		for _, v := range dc.ComposeService.Labels {
			onelabel := FormatLabels(v)
			labelsMap[onelabel[0]] = onelabel[1]
		}
	}

	// reuse container if already running
	meliService := labelsMap["meli_service"]
	filters := filters.NewArgs()
	filters.Add("label", fmt.Sprintf("meli_service=%s", meliService))
	containers, err := cli.ContainerList(ctx, types.ContainerListOptions{
		Quiet:   true,
		All:     true,
		Filters: filters})
	if err != nil {
		fmt.Println(" :unable to list containers")
	}
	if len(containers) > 0 {
		dc.UpdateContainerID(containers[0].ID)
		return true, containers[0].ID, nil
	}

	// 2. make ports
	portsMap := make(map[nat.Port]struct{})
	portBindingMap := make(map[nat.Port][]nat.PortBinding)
	if len(dc.ComposeService.Ports) > 0 {
		for _, v := range dc.ComposeService.Ports {
			oneport := FormatPorts(v)
			hostport := oneport[0]
			containerport := oneport[1]
			port, err := nat.NewPort("tcp", containerport)
			myPortBinding := nat.PortBinding{HostPort: hostport}
			if err != nil {
				fmt.Println(err, " :unable to create a nat.Port")
			}
			portsMap[port] = EmptyStruct{}
			portBindingMap[port] = []nat.PortBinding{myPortBinding}
		}
	}
	// 3. create command
	cmd := strslice.StrSlice{}
	if dc.ComposeService.Command != "" {
		sliceCommand := strings.Fields(dc.ComposeService.Command)
		cmd = strslice.StrSlice(sliceCommand)
	}
	// 4. create restart policy
	restartPolicy := container.RestartPolicy{}
	if dc.ComposeService.Restart != "" {
		// You cannot set MaximumRetryCount for the following restart policies;
		// always, no, unless-stopped
		if dc.ComposeService.Restart == "on-failure" {
			restartPolicy = container.RestartPolicy{Name: dc.ComposeService.Restart, MaximumRetryCount: 3}
		} else {
			restartPolicy = container.RestartPolicy{Name: dc.ComposeService.Restart}
		}

	}
	// 5. build image
	imageNamePtr := &dc.ComposeService.Image
	if dc.ComposeService.Build != (Buildstruct{}) {
		imageName, err := BuildDockerImage(ctx, cli, dc)
		if err != nil {
			return false, "", &popagateError{originalErr: err}
		}
		// done this way so that we can manipulate the value of the
		// imageName inside this scope
		imageNamePtr = &imageName
	}
	imageName := *imageNamePtr

	// 6. add volumes
	volume := make(map[string]struct{})
	binds := []string{}
	if len(dc.ComposeService.Volumes) > 0 {
		for _, v := range dc.ComposeService.Volumes {
			vol := FormatServiceVolumes(v, dc.DockerComposeFile)
			volume[vol[1]] = EmptyStruct{}
			// TODO: handle other read/write modes
			whatToBind := vol[0] + ":" + vol[1] + ":rw"
			binds = append(binds, whatToBind)
		}
	}

	containerCreateResp, err := cli.ContainerCreate(
		ctx,
		&container.Config{
			Image:        imageName,
			Labels:       labelsMap,
			Env:          dc.ComposeService.Environment,
			ExposedPorts: portsMap,
			Cmd:          cmd,
			Volumes:      volume},
		&container.HostConfig{
			DNS: []string{
				"8.8.8.8",
				"8.8.4.4",
				"fd00:c2b6:b24b:be67:2827:688d:e6a1:6a3b",
				"fd00:a516:7c1b:17cd:6d81:2137:bd2a:2c5b"},
			DNSSearch: []string{
				"8.8.8.8",
				"8.8.4.4",
				"fd00:c2b6:b24b:be67:2827:688d:e6a1:6a3b",
				"fd00:a516:7c1b:17cd:6d81:2137:bd2a:2c5b"},
			PublishAllPorts: false,
			PortBindings:    portBindingMap,
			NetworkMode:     container.NetworkMode(dc.NetworkName),
			RestartPolicy:   restartPolicy,
			Binds:           binds,
			Links:           dc.ComposeService.Links},
		nil,
		FormatImageName(dc.ServiceName))
	if err != nil {
		return false, "", &popagateError{
			originalErr: err,
			newErr:      errors.New(" :unable to create container")}
	}

	dc.UpdateContainerID(containerCreateResp.ID)
	return false, containerCreateResp.ID, nil
}

func ContainerStart(ctx context.Context, cli MeliAPiClient, dc *DockerContainer) error {
	err := cli.ContainerStart(
		ctx,
		dc.ContainerID,
		types.ContainerStartOptions{})
	if err != nil {
		return &popagateError{
			originalErr: err,
			newErr:      fmt.Errorf(" :unable to start container %s", dc.ContainerID)}

	}
	return nil
}

func ContainerLogs(ctx context.Context, cli MeliAPiClient, dc *DockerContainer) error {
	containerLogResp, err := cli.ContainerLogs(
		ctx,
		dc.ContainerID,
		types.ContainerLogsOptions{
			ShowStdout: true,
			ShowStderr: true,
			Timestamps: true,
			Follow:     dc.FollowLogs,
			Details:    true,
			Tail:       "all"})

	if err != nil {
		if err != nil {
			return &popagateError{
				originalErr: err,
				newErr:      fmt.Errorf(" :unable to get container logs %s", dc.ContainerID)}
		}
	}

	scanner := bufio.NewScanner(containerLogResp)
	for scanner.Scan() {
		fmt.Fprintln(dc.LogMedium, dc.ServiceName, "::", scanner.Text())
	}
	if err := scanner.Err(); err != nil {
		fmt.Println(" :unable to log output for container", dc.ContainerID, err)
	}

	containerLogResp.Close()
	return nil
}
{'fraction_non_alphanumeric': 0.13780242899493161, 'fraction_numerical': 0.021421057664722194, 'mean_word_length': 3.7364130434782608, 'pattern_counts': {'":': 5, '<': 3, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 8, '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': '4070330', 'n_tokens_mistral': 4230, 'n_tokens_neox': 3765, 'n_words': 771}