in internal/pkg/cli/deploy/workload.go [486:556]
func buildContainerImagesInParallel(in *ImageActionInput, uri string, buildArgsPerContainer map[string]*dockerengine.BuildArguments, buildFunc func(ctx context.Context, args *dockerengine.BuildArguments, w io.Writer) (string, error), out *UploadArtifactsOutput) error {
var digestsMu sync.Mutex
out.ImageDigests = make(map[string]ContainerImageIdentifier, len(buildArgsPerContainer))
var labeledBuffers []*syncbuffer.LabeledSyncBuffer
g, ctx := errgroup.WithContext(context.Background())
cursor := cursor.New()
cursor.Hide()
for name, buildArgs := range buildArgsPerContainer {
// create a copy of loop variables to avoid data race.
name := name
buildArgs := buildArgs
buildArgs.URI = uri
buildArgsList, err := buildArgs.GenerateDockerBuildArgs(dockerengine.New(exec.NewCmd()))
if err != nil {
return fmt.Errorf("generate docker build args for %q: %w", name, err)
}
buf := syncbuffer.New()
labeledBuffers = append(labeledBuffers, buf.WithLabel(fmt.Sprintf("Building your container image %q: docker %s", name, strings.Join(buildArgsList, " "))))
pr, pw := io.Pipe()
g.Go(func() error {
defer pw.Close()
digest, err := buildFunc(ctx, buildArgs, pw)
if err != nil {
return fmt.Errorf("build and push the image %q: %w", name, err)
}
id := ContainerImageIdentifier{
Digest: digest,
CustomTag: in.CustomTag,
GitShortCommitTag: in.GitShortCommitTag,
}
for _, tag := range buildArgs.Tags {
id.RepoTags = append(id.RepoTags, fmt.Sprintf("%s:%s", uri, tag))
}
sort.Strings(id.RepoTags)
digestsMu.Lock()
defer digestsMu.Unlock()
out.ImageDigests[name] = id
return nil
})
g.Go(func() error {
if err := buf.Copy(pr); err != nil {
return fmt.Errorf("copy build and push output for %q: %w", name, err)
}
return nil
})
}
opts := []syncbuffer.LabeledTermPrinterOption{syncbuffer.WithPadding(paddingInSpacesForBuildAndPush)}
if os.Getenv("CI") != "true" {
opts = append(opts, syncbuffer.WithNumLines(defaultNumLinesForBuildAndPush))
}
ltp := in.LabeledTermPrinter(os.Stderr, labeledBuffers, opts...)
g.Go(func() error {
for {
ltp.Print()
if ltp.IsDone() {
return nil
}
select {
case <-ctx.Done():
return nil
case <-time.After(pollIntervalForBuildAndPush):
}
}
})
if err := g.Wait(); err != nil {
return err
}
return nil
}