func (d *stiDocker) UploadToContainer(fs fs.FileSystem, src, dest, container string) error {
	makeWorldWritable := func(writer io.Writer) s2itar.Writer {
		return s2itar.ChmodAdapter{Writer: tar.NewWriter(writer), NewFileMode: 0666, NewExecFileMode: 0666, NewDirMode: 0777}
	}
	return d.UploadToContainerWithTarWriter(fs, src, dest, container, makeWorldWritable)
}
UploadToContainer uploads artifacts to the container.
package docker
import (
	"archive/tar"
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"strings"
	"syscall"
	"time"
	dockertypes "github.com/docker/docker/api/types"
	dockercontainer "github.com/docker/docker/api/types/container"
	dockernetwork "github.com/docker/docker/api/types/network"
	dockerapi "github.com/docker/docker/client"
	dockermessage "github.com/docker/docker/pkg/jsonmessage"
	dockerstdcopy "github.com/docker/docker/pkg/stdcopy"
	"github.com/docker/go-connections/tlsconfig"
	"golang.org/x/net/context"
	"github.com/openshift/source-to-image/pkg/api"
	"github.com/openshift/source-to-image/pkg/api/constants"
	s2ierr "github.com/openshift/source-to-image/pkg/errors"
	s2itar "github.com/openshift/source-to-image/pkg/tar"
	"github.com/openshift/source-to-image/pkg/util"
	"github.com/openshift/source-to-image/pkg/util/fs"
	"github.com/openshift/source-to-image/pkg/util/interrupt"
)
const (
	DefaultDestination = "/tmp"
	DefaultTag = "latest"
	DefaultDockerTimeout = 2 * time.Minute
	DefaultShmSize = int64(1024 * 1024 * 64)
	DefaultPullRetryDelay = 5 * time.Second
	DefaultPullRetryCount = 6
)
var (
	RetriableErrors = []string{
		"ping attempt failed with error",
		"is already in progress",
		"connection reset by peer",
		"transport closed before response was received",
		"connection refused",
	}
)
const containerNamePrefix = "s2i"
func containerName(image string) string {
	rand.Seed(time.Now().UnixNano())
	uid := fmt.Sprintf("%08x", rand.Uint32())
	image = strings.Map(func(r rune) rune {
		if ('0' <= r && r <= '9') || ('A' <= r && r <= 'Z') || ('a' <= r && r <= 'z') {
			return r
		}
		return '_'
	}, image)
	return fmt.Sprintf("%s_%s_%s", containerNamePrefix, image, uid)
}
type Docker interface {
	IsImageInLocalRegistry(name string) (bool, error)
	IsImageOnBuild(string) bool
	GetOnBuild(string) ([]string, error)
	RemoveContainer(id string) error
	GetScriptsURL(name string) (string, error)
	GetAssembleInputFiles(string) (string, error)
	GetAssembleRuntimeUser(string) (string, error)
	RunContainer(opts RunContainerOptions) error
	GetImageID(name string) (string, error)
	GetImageWorkdir(name string) (string, error)
	CommitContainer(opts CommitContainerOptions) (string, error)
	RemoveImage(name string) error
	CheckImage(name string) (*api.Image, error)
	PullImage(name string) (*api.Image, error)
	CheckAndPullImage(name string) (*api.Image, error)
	BuildImage(opts BuildImageOptions) error
	GetImageUser(name string) (string, error)
	GetImageEntrypoint(name string) ([]string, error)
	GetLabels(name string) (map[string]string, error)
	UploadToContainer(fs fs.FileSystem, srcPath, destPath, container string) error
	UploadToContainerWithTarWriter(fs fs.FileSystem, srcPath, destPath, container string, makeTarWriter func(io.Writer) s2itar.Writer) error
	DownloadFromContainer(containerPath string, w io.Writer, container string) error
	Version() (dockertypes.Version, error)
	CheckReachable() error
}
type Client interface {
	ContainerAttach(ctx context.Context, container string, options dockertypes.ContainerAttachOptions) (dockertypes.HijackedResponse, error)
	ContainerCommit(ctx context.Context, container string, options dockertypes.ContainerCommitOptions) (dockertypes.IDResponse, error)
	ContainerCreate(ctx context.Context, config *dockercontainer.Config, hostConfig *dockercontainer.HostConfig, networkingConfig *dockernetwork.NetworkingConfig, containerName string) (dockercontainer.ContainerCreateCreatedBody, error)
	ContainerInspect(ctx context.Context, container string) (dockertypes.ContainerJSON, error)
	ContainerRemove(ctx context.Context, container string, options dockertypes.ContainerRemoveOptions) error
	ContainerStart(ctx context.Context, container string, options dockertypes.ContainerStartOptions) error
	ContainerKill(ctx context.Context, container, signal string) error
	ContainerWait(ctx context.Context, container string, condition dockercontainer.WaitCondition) (<-chan dockercontainer.ContainerWaitOKBody, <-chan error)
	CopyToContainer(ctx context.Context, container, path string, content io.Reader, opts dockertypes.CopyToContainerOptions) error
	CopyFromContainer(ctx context.Context, container, srcPath string) (io.ReadCloser, dockertypes.ContainerPathStat, error)
	ImageBuild(ctx context.Context, buildContext io.Reader, options dockertypes.ImageBuildOptions) (dockertypes.ImageBuildResponse, error)
	ImageInspectWithRaw(ctx context.Context, image string) (dockertypes.ImageInspect, []byte, error)
	ImagePull(ctx context.Context, ref string, options dockertypes.ImagePullOptions) (io.ReadCloser, error)
	ImageRemove(ctx context.Context, image string, options dockertypes.ImageRemoveOptions) ([]dockertypes.ImageDeleteResponseItem, error)
	ServerVersion(ctx context.Context) (dockertypes.Version, error)
}
type stiDocker struct {
	client   Client
	pullAuth dockertypes.AuthConfig
}
func (d stiDocker) InspectImage(name string) (*dockertypes.ImageInspect, error) {
	ctx, cancel := getDefaultContext()
	defer cancel()
	resp, _, err := d.client.ImageInspectWithRaw(ctx, name)
	if err != nil {
		return nil, err
	}
	return &resp, nil
}
type PostExecutor interface {
	PostExecute(containerID, destination string) error
}
type PullResult struct {
	OnBuild bool
	Image   *api.Image
}
type RunContainerOptions struct {
	Image           string
	PullImage       bool
	PullAuth        api.AuthConfig
	ExternalScripts bool
	ScriptsURL      string
	Destination     string
	Env             []string
	AddHost         []string
	Entrypoint       []string
	Stdin            io.ReadCloser
	Stdout           io.WriteCloser
	Stderr           io.WriteCloser
	OnStart          func(containerID string) error
	PostExec         PostExecutor
	TargetImage      bool
	NetworkMode      string
	User             string
	CGroupLimits     *api.CGroupLimits
	CapDrop          []string
	Binds            []string
	Command          string
	CommandOverrides func(originalCmd string) string
	CommandExplicit []string
	SecurityOpt []string
}
func (rco RunContainerOptions) asDockerConfig() dockercontainer.Config {
	return dockercontainer.Config{
		Image:        getImageName(rco.Image),
		User:         rco.User,
		Env:          rco.Env,
		Entrypoint:   rco.Entrypoint,
		OpenStdin:    rco.Stdin != nil,
		StdinOnce:    rco.Stdin != nil,
		AttachStdout: rco.Stdout != nil,
	}
}
func (rco RunContainerOptions) asDockerHostConfig() dockercontainer.HostConfig {
	hostConfig := dockercontainer.HostConfig{
		CapDrop:         rco.CapDrop,
		PublishAllPorts: rco.TargetImage,
		NetworkMode:     dockercontainer.NetworkMode(rco.NetworkMode),
		Binds:           rco.Binds,
		ExtraHosts:      rco.AddHost,
		SecurityOpt:     rco.SecurityOpt,
	}
	if rco.CGroupLimits != nil {
		hostConfig.Resources.Memory = rco.CGroupLimits.MemoryLimitBytes
		hostConfig.Resources.MemorySwap = rco.CGroupLimits.MemorySwap
		hostConfig.Resources.CgroupParent = rco.CGroupLimits.Parent
	}
	return hostConfig
}
func (rco RunContainerOptions) asDockerCreateContainerOptions() dockertypes.ContainerCreateConfig {
	config := rco.asDockerConfig()
	hostConfig := rco.asDockerHostConfig()
	return dockertypes.ContainerCreateConfig{
		Name:       containerName(rco.Image),
		Config:     &config,
		HostConfig: &hostConfig,
	}
}
func (rco RunContainerOptions) asDockerAttachToContainerOptions() dockertypes.ContainerAttachOptions {
	return dockertypes.ContainerAttachOptions{
		Stdin:  rco.Stdin != nil,
		Stdout: rco.Stdout != nil,
		Stderr: rco.Stderr != nil,
		Stream: rco.Stdout != nil,
	}
}
type CommitContainerOptions struct {
	ContainerID string
	Repository  string
	User        string
	Command     []string
	Env         []string
	Entrypoint  []string
	Labels      map[string]string
}
type BuildImageOptions struct {
	Name         string
	Stdin        io.Reader
	Stdout       io.WriteCloser
	CGroupLimits *api.CGroupLimits
}
func NewEngineAPIClient(config *api.DockerConfig) (*dockerapi.Client, error) {
	var httpClient *http.Client
	if config.UseTLS || config.TLSVerify {
		tlscOptions := tlsconfig.Options{
			InsecureSkipVerify: !config.TLSVerify,
		}
		if _, err := os.Stat(config.CAFile); !os.IsNotExist(err) {
			tlscOptions.CAFile = config.CAFile
		}
		if _, err := os.Stat(config.CertFile); !os.IsNotExist(err) {
			tlscOptions.CertFile = config.CertFile
		}
		if _, err := os.Stat(config.KeyFile); !os.IsNotExist(err) {
			tlscOptions.KeyFile = config.KeyFile
		}
		tlsc, err := tlsconfig.Client(tlscOptions)
		if err != nil {
			return nil, err
		}
		httpClient = &http.Client{
			Transport: &http.Transport{
				TLSClientConfig: tlsc,
			},
		}
	}
	return dockerapi.NewClient(config.Endpoint, os.Getenv("DOCKER_API_VERSION"), httpClient, nil)
}
func New(client Client, auth api.AuthConfig) Docker {
	return &stiDocker{
		client: client,
		pullAuth: dockertypes.AuthConfig{
			Username:      auth.Username,
			Password:      auth.Password,
			Email:         auth.Email,
			ServerAddress: auth.ServerAddress,
		},
	}
}
func getDefaultContext() (context.Context, context.CancelFunc) {
	return context.WithTimeout(context.Background(), DefaultDockerTimeout)
}
func (d *stiDocker) GetImageWorkdir(name string) (string, error) {
	resp, err := d.InspectImage(name)
	if err != nil {
		return "", err
	}
	workdir := resp.Config.WorkingDir
	if len(workdir) == 0 {
		workdir = "/"
	}
	return workdir, nil
}
func (d *stiDocker) GetImageEntrypoint(name string) ([]string, error) {
	image, err := d.InspectImage(name)
	if err != nil {
		return nil, err
	}
	return image.Config.Entrypoint, nil
}