blob: d429f9924148cc66553ecb46744275588fa074cd [file] [log] [blame]
package main
import (
"context"
"fmt"
"path"
"strings"
"time"
"go.skia.org/infra/go/exec"
"go.skia.org/infra/go/gitauth"
"go.skia.org/infra/go/skerr"
"go.skia.org/infra/task_driver/go/lib/git_steps"
"go.skia.org/infra/task_driver/go/td"
"golang.org/x/sync/errgroup"
)
func build(ctx context.Context, commit, repo, workspace, username, email string, targets []string, rbe bool) error {
ctx = td.StartStep(ctx, td.Props("Build Images"))
defer td.EndStep(ctx)
// Initialize git authentication.
ts, err := git_steps.Init(ctx, true)
if err != nil {
return td.FailStep(ctx, err)
}
if _, err := gitauth.New(ts, "/tmp/.gitcookies", true, email); err != nil {
return td.FailStep(ctx, err)
}
bazelTargetToImagePath := make(map[string]string, len(targets))
for _, target := range targets {
targetSplit := strings.Split(target, ":")
if len(targetSplit) != 3 {
return td.FailStep(ctx, skerr.Fmt("Invalid target specification %q; expected \"//bazel-target:bazel-target:gcr.io/image/path\"", target))
}
bazelTarget := strings.Join(targetSplit[:2], ":")
imagePath := targetSplit[2]
bazelTargetToImagePath[bazelTarget] = imagePath
}
// Create a shallow clone of the repo.
checkoutDir, err := shallowClone(ctx, repo, commit)
if err != nil {
return td.FailStep(ctx, err)
}
// Create the timestamped Docker image tag.
timestamp := time.Now().UTC().Format("2006-01-02T15_04_05Z")
imageTag := fmt.Sprintf("%s-%s-%s-%s", timestamp, username, commit[:7], "clean")
// Perform the builds concurrently.
imageInfo := &buildImagesJSON{
Images: make([]*SingleImageInfo, 0, len(bazelTargetToImagePath)),
}
eg, ctx := errgroup.WithContext(ctx)
for bazelTarget, imagePath := range bazelTargetToImagePath {
// https://golang.org/doc/faq#closures_and_goroutines
bazelTarget := bazelTarget
louhiImageTag := fmt.Sprintf("louhi_ws/%s:%s", imagePath, imageTag)
imageInfo.Images = append(imageInfo.Images, &SingleImageInfo{
Image: imagePath,
Tag: imageTag,
})
eg.Go(func() error {
return bazelRun(ctx, checkoutDir, bazelTarget, louhiImageTag, rbe)
})
}
if err := eg.Wait(); err != nil {
return td.FailStep(ctx, err)
}
return writeBuildImagesJSON(ctx, workspace, imageInfo)
}
// bazelTargetToDockerTag converts a Bazel target specification to a Docker
// image tag which is applied to the image during the Bazel build.
func bazelTargetToDockerTag(target string) string {
return path.Join("bazel", target)
}
// bazelRun executes `bazel run` for the given target and applies the given tag
// to the resulting image.
func bazelRun(ctx context.Context, cwd, target, louhiImageTag string, rbe bool) error {
ctx = td.StartStep(ctx, td.Props(fmt.Sprintf("Build %s", target)))
defer td.EndStep(ctx)
cmd := []string{"bazelisk", "run"}
if rbe {
cmd = append(cmd, "--config=remote", "--google_default_credentials")
}
cmd = append(cmd, target)
if _, err := exec.RunCwd(ctx, cwd, cmd...); err != nil {
return td.FailStep(ctx, err)
}
if _, err := exec.RunCwd(ctx, cwd, "docker", "tag", bazelTargetToDockerTag(target), louhiImageTag); err != nil {
return td.FailStep(ctx, err)
}
return nil
}