package docker import ( "bytes" "context" "encoding/base64" "encoding/json" "fmt" "io" "sync" "time" fw "git.buran.team/main/fairwind" archive "github.com/moby/go-archive" mobyregistry "github.com/moby/moby/api/types/registry" moby "github.com/moby/moby/client" ) type Image struct { ctx context.Context log *fw.Log client *Docker registry *Registry tag string version string build bool push bool } func NewImage(ctx context.Context, log *fw.Log, client *Docker, registry *Registry, tag string, version string, build bool, push bool) *Image { return &Image{ ctx: ctx, log: log, client: client, registry: registry, tag: tag, version: version, build: build, push: push, } } func (this *Image) Name() string { return fmt.Sprintf("%s/%s:%s", this.registry.address, this.tag, this.version) } func (this *Image) Build(timeout int, path string) ([]byte, error) { if (!this.build) { return []byte{}, nil } ctx, cancel := context.WithTimeout(this.ctx, time.Duration(timeout)*time.Millisecond) defer cancel() stream, err := archive.TarWithOptions(path, &archive.TarOptions{}) if err != nil { return nil, fmt.Errorf("can't build image: %w", err) } defer stream.Close() response, err := this.client.Docker.ImageBuild( ctx, stream, moby.ImageBuildOptions{ Dockerfile: "Dockerfile", Tags: []string{ this.Name(), }, }, ) if err != nil { return nil, fmt.Errorf("can't build image: %w", err) } defer response.Body.Close() var stdout bytes.Buffer _, err = io.Copy(&stdout, response.Body) if err != nil { return nil, fmt.Errorf("can't build image: %w", err) } return stdout.Bytes(), nil } func (this *Image) Push(timeout int) ([]byte, error) { if (!this.push) { return []byte{}, nil } ctx, cancel := context.WithTimeout(this.ctx, time.Duration(timeout)*time.Millisecond) defer cancel() credentials, err := credentialsToString( this.registry.login, this.registry.password, ) if err != nil { return nil, fmt.Errorf("can't push image: %w", err) } response, err := this.client.Docker.ImagePush( ctx, this.Name(), moby.ImagePushOptions{ RegistryAuth: credentials, }, ) if err != nil { return nil, fmt.Errorf("can't push image: %w", err) } var stdout bytes.Buffer var waitGroup sync.WaitGroup waitGroup.Add(1) go func() { defer waitGroup.Done() _, err := io.Copy(&stdout, response) if err != nil { // ... } }() err = response.Wait(ctx) if err != nil { return nil, fmt.Errorf("can't push image: %w", err) } waitGroup.Wait() return stdout.Bytes(), nil } func credentialsToString(login string, password string) (string, error) { encodedJSON, err := json.Marshal( &mobyregistry.AuthConfig{ Username: login, Password: password, }, ) if err != nil { return "", fmt.Errorf("can't serialize credentials: %w", err) } authStr := base64.URLEncoding.EncodeToString(encodedJSON) return authStr, nil }