<commit_before>package docker

import (
	"bytes"
	"crypto/md5"
	"errors"
	"fmt"
	"io"
	"path"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/docker/distribution/reference"
	"github.com/fsouza/go-dockerclient"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/common"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/executors"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers"
	docker_helpers "gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers/docker"
)

type dockerOptions struct {
	Image    string   `json:"image"`
	Services []string `json:"services"`
}

type executor struct {
	executors.AbstractExecutor
	client      docker_helpers.Client
	failures    []*docker.Container
	builds      []*docker.Container
	services    []*docker.Container
	caches      []*docker.Container
	options     dockerOptions
	info        *docker.Env
	binds       []string
	volumesFrom []string
	devices     []docker.Device
	links       []string
}

func (s *executor) getServiceVariables() []string {
	return s.Build.GetAllVariables().PublicOrInternal().StringList()
}

func (s *executor) getUserAuthConfiguration(indexName string) *docker.AuthConfiguration {
	if s.Build == nil {
		return nil
	}

	authConfigString := s.Build.GetDockerAuthConfig()
	authConfigs, _ := docker.NewAuthConfigurations(bytes.NewBufferString(authConfigString))
	if authConfigs != nil {
		return docker_helpers.ResolveDockerAuthConfig(indexName, authConfigs)
	}
	return nil
}

func (s *executor) getBuildAuthConfiguration(indexName string) *docker.AuthConfiguration {
	if s.Build == nil {
		return nil
	}

	authConfigs := &docker.AuthConfigurations{
		Configs: make(map[string]docker.AuthConfiguration),
	}

	for _, credentials := range s.Build.Credentials {
		if credentials.Type != "registry" {
			continue
		}

		authConfigs.Configs[credentials.URL] = docker.AuthConfiguration{
			Username:      credentials.Username,
			Password:      <PASSWORD>,
			ServerAddress: credentials.URL,
		}
	}

	if authConfigs != nil {
		return docker_helpers.ResolveDockerAuthConfig(indexName, authConfigs)
	}
	return nil
}

func (s *executor) getHomeDirAuthConfiguration(indexName string) *docker.AuthConfiguration {
	authConfigs, _ := docker_helpers.ReadDockerAuthConfigsFromHomeDir(s.Shell().User)
	if authConfigs != nil {
		return docker_helpers.ResolveDockerAuthConfig(indexName, authConfigs)
	}
	return nil
}

func (s *executor) getAuthConfig(imageName string) docker.AuthConfiguration {
	indexName, _ := docker_helpers.SplitDockerImageName(imageName)

	authConfig := s.getUserAuthConfiguration(indexName)
	if authConfig == nil {
		authConfig = s.getHomeDirAuthConfiguration(indexName)
	}
	if authConfig == nil {
		authConfig = s.getBuildAuthConfiguration(indexName)
	}

	if authConfig != nil {
		s.Debugln("Using", authConfig.Username, "to connect to", authConfig.ServerAddress,
			"in order to resolve", imageName, "...")
		return *authConfig
	}

	s.Debugln(fmt.Sprintf("No credentials found for %v", indexName))
	return docker.AuthConfiguration{}
}

func (s *executor) pullDockerImage(imageName string, authConfig docker.AuthConfiguration) (image *docker.Image, err error) {
	s.Println("Pulling docker image", imageName, "...")
	pullImageOptions := docker.PullImageOptions{
		Repository: imageName,
	}

	// Add :latest to limit the download results
	if !strings.ContainsAny(pullImageOptions.Repository, ":@") {
		pullImageOptions.Repository += ":latest"
	}

	err = s.client.PullImage(pullImageOptions, authConfig)
	if err != nil {
		if strings.Contains(err.Error(), "not found") {
			return nil, &common.BuildError{Inner: err}
		}
		return nil, err
	}

	return s.client.InspectImage(imageName)
}

func (s *executor) getDockerImage(imageName string) (*docker.Image, error) {
	pullPolicy, err := s.Config.Docker.PullPolicy.Get()
	if err != nil {
		return nil, err
	}

	authConfig := s.getAuthConfig(imageName)

	s.Debugln("Looking for image", imageName, "...")
	image, err := s.client.InspectImage(imageName)

	// If never is specified then we return what inspect did return
	if pullPolicy == common.PullPolicyNever {
		return image, err
	}

	if err == nil {
		// Don't pull image that is passed by ID
		if image.ID == imageName {
			return image, nil
		}

		// If not-present is specified
		if pullPolicy == common.PullPolicyIfNotPresent {
			return image, err
		}
	}

	newImage, err := s.pullDockerImage(imageName, authConfig)
	if err != nil {
		return nil, err
	}
	return newImage, nil
}

func (s *executor) getArchitecture() string {
	architecture := s.info.Get("Architecture")
	switch architecture {
	case "armv7l", "aarch64":
		architecture = "arm"
	case "amd64":
		architecture = "x86_64"
	}

	if architecture != "" {
		return architecture
	}

	switch runtime.GOARCH {
	case "amd64":
		return "x86_64"
	default:<commit_msg>Add logging for specific cases<commit_after>package docker

import (
	"bytes"
	"crypto/md5"
	"errors"
	"fmt"
	"io"
	"path"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/docker/distribution/reference"
	"github.com/fsouza/go-dockerclient"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/common"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/executors"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers"
	docker_helpers "gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers/docker"
)

type dockerOptions struct {
	Image    string   `json:"image"`
	Services []string `json:"services"`
}

type executor struct {
	executors.AbstractExecutor
	client      docker_helpers.Client
	failures    []*docker.Container
	builds      []*docker.Container
	services    []*docker.Container
	caches      []*docker.Container
	options     dockerOptions
	info        *docker.Env
	binds       []string
	volumesFrom []string
	devices     []docker.Device
	links       []string
}

func (s *executor) getServiceVariables() []string {
	return s.Build.GetAllVariables().PublicOrInternal().StringList()
}

func (s *executor) getUserAuthConfiguration(indexName string) *docker.AuthConfiguration {
	if s.Build == nil {
		return nil
	}

	authConfigString := s.Build.GetDockerAuthConfig()
	authConfigs, _ := docker.NewAuthConfigurations(bytes.NewBufferString(authConfigString))
	if authConfigs != nil {
		return docker_helpers.ResolveDockerAuthConfig(indexName, authConfigs)
	}
	return nil
}

func (s *executor) getBuildAuthConfiguration(indexName string) *docker.AuthConfiguration {
	if s.Build == nil {
		return nil
	}

	authConfigs := &docker.AuthConfigurations{
		Configs: make(map[string]docker.AuthConfiguration),
	}

	for _, credentials := range s.Build.Credentials {
		if credentials.Type != "registry" {
			continue
		}

		authConfigs.Configs[credentials.URL] = docker.AuthConfiguration{
			Username:      credentials.Username,
			Password:      <PASSWORD>,
			ServerAddress: credentials.URL,
		}
	}

	if authConfigs != nil {
		return docker_helpers.ResolveDockerAuthConfig(indexName, authConfigs)
	}
	return nil
}

func (s *executor) getHomeDirAuthConfiguration(indexName string) *docker.AuthConfiguration {
	authConfigs, _ := docker_helpers.ReadDockerAuthConfigsFromHomeDir(s.Shell().User)
	if authConfigs != nil {
		return docker_helpers.ResolveDockerAuthConfig(indexName, authConfigs)
	}
	return nil
}

func (s *executor) getAuthConfig(imageName string) docker.AuthConfiguration {
	indexName, _ := docker_helpers.SplitDockerImageName(imageName)

	authConfig := s.getUserAuthConfiguration(indexName)
	if authConfig == nil {
		authConfig = s.getHomeDirAuthConfiguration(indexName)
	}
	if authConfig == nil {
		authConfig = s.getBuildAuthConfiguration(indexName)
	}

	if authConfig != nil {
		s.Debugln("Using", authConfig.Username, "to connect to", authConfig.ServerAddress,
			"in order to resolve", imageName, "...")
		return *authConfig
	}

	s.Debugln(fmt.Sprintf("No credentials found for %v", indexName))
	return docker.AuthConfiguration{}
}

func (s *executor) pullDockerImage(imageName string, authConfig docker.AuthConfiguration) (image *docker.Image, err error) {
	s.Println("Pulling docker image", imageName, "...")
	pullImageOptions := docker.PullImageOptions{
		Repository: imageName,
	}

	// Add :latest to limit the download results
	if !strings.ContainsAny(pullImageOptions.Repository, ":@") {
		pullImageOptions.Repository += ":latest"
	}

	err = s.client.PullImage(pullImageOptions, authConfig)
	if err != nil {
		if strings.Contains(err.Error(), "not found") {
			return nil, &common.BuildError{Inner: err}
		}
		return nil, err
	}

	return s.client.InspectImage(imageName)
}

func (s *executor) getDockerImage(imageName string) (*docker.Image, error) {
	pullPolicy, err := s.Config.Docker.PullPolicy.Get()
	if err != nil {
		return nil, err
	}

	authConfig := s.getAuthConfig(imageName)

	s.Debugln("Looking for image", imageName, "...")
	image, err := s.client.InspectImage(imageName)

	// If never is specified then we return what inspect did return
	if pullPolicy == common.PullPolicyNever {
		return image, err
	}

	if err == nil {
		// Don't pull image that is passed by ID
		if image.ID == imageName {
			s.Println("Using locally found image version with exactly the same ID")
			return image, nil
		}

		// If not-present is specified
		if pullPolicy == common.PullPolicyIfNotPresent {
			s.Println("Using locally found image version due to if-not-present pull policy")
			return image, err
		}
	}

	newImage, err := s.pullDockerImage(imageName, authConfig)
	if err != nil {
		return nil, err
	}
	return newImage, nil
}

func (s *executor) getArchitecture() string {
	architecture := s.info.Get("Architecture")
	switch architecture {
	case "armv7l", "aarch64":
		architecture = "arm"
	case "amd64":
		architecture = "x86_64"
	}

	if architecture != "" {
		return architecture
	}

	switch runtime.GOARCH {
	case "amd64":
		return "x86_64"
	default:
{'fraction_non_alphanumeric': 0.11939690301548492, 'fraction_numerical': 0.0032599837000814994, 'mean_word_length': 4.4508606329816764, 'pattern_counts': {'":': 10, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7301866', 'n_tokens_mistral': 3447, 'n_tokens_neox': 3226, 'n_words': 717}