blob: c16eadadb5e43f3df8dd8ea72b8ed2613b0bce1f [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package testsharder
import (
"context"
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"go.fuchsia.dev/fuchsia/tools/build"
"go.fuchsia.dev/fuchsia/tools/lib/ffxutil"
"go.fuchsia.dev/fuchsia/tools/lib/logger"
)
// for testability
type FFXInterface interface {
Run(context.Context, ...string) error
GetPBArtifacts(context.Context, string, string) ([]string, error)
Stop() error
}
var GetFFX = func(ctx context.Context, ffxPath, outputsDir string) (FFXInterface, error) {
return ffxutil.NewFFXInstance(ctx, ffxPath, "", []string{}, "", "", outputsDir)
}
// AddImageDeps selects and adds the subset of images needed by a shard to
// that shard's list of dependencies.
func AddImageDeps(ctx context.Context, s *Shard, buildDir string, images []build.Image, pave bool, pbPath, ffxPath string) error {
// Host-test only shards do not require any image deps because they are not running
// against a Fuchsia target.
if s.Env.Dimensions.DeviceType() == "" {
return nil
}
imageDeps := []string{"images.json"}
// GCE test shards do not require any image deps as the build creates a
// compute image with all the deps baked in.
if s.Env.Dimensions.DeviceType() == "GCE" {
s.AddDeps(imageDeps)
return nil
}
// TODO(https://fxbug.dev/42083611): Remove these images when product bundles are used as soon
// as ffx emu and flash are enabled by default. Otherwise we need to provide
// images from both images.json and product_bundles.json since either can be used
// depending on what ffx experiment level is being run and whether the device that's
// being targeted is idling in fastboot or not.
for _, image := range images {
if isUsedForTesting(s, image, pave) {
if _, err := os.Stat(filepath.Join(buildDir, image.Path)); err != nil {
if !errors.Is(err, os.ErrNotExist) {
return err
}
} else {
imageDeps = append(imageDeps, image.Path)
}
}
}
// Add product bundle related artifacts.
imageDeps = append(imageDeps, "product_bundles.json")
tmp, err := os.MkdirTemp("", "wt")
if err != nil {
return err
}
defer os.RemoveAll(tmp)
ffxOutputsDir := filepath.Join(tmp, "ffx_outputs")
ffx, err := GetFFX(ctx, ffxPath, ffxOutputsDir)
if err != nil {
return err
}
if ffx == nil {
return fmt.Errorf("failed to initialize an ffx instance")
}
defer func() {
if err := ffx.Stop(); err != nil {
logger.Debugf(ctx, "failed to stop ffx: %s", err)
}
}()
if err := ffx.Run(ctx, "config", "set", "daemon.autostart", "false", "-l", "global"); err != nil {
return err
}
artifactsGroup := "flash"
if s.Env.TargetsEmulator() {
artifactsGroup = "emu"
}
artifacts, err := ffx.GetPBArtifacts(ctx, filepath.Join(buildDir, pbPath), artifactsGroup)
if err != nil {
return err
}
for _, a := range artifacts {
imageDeps = append(imageDeps, filepath.Join(pbPath, a))
}
bootloaderArtifacts, err := ffx.GetPBArtifacts(ctx, filepath.Join(buildDir, pbPath), "bootloader")
if err != nil {
return err
}
for _, a := range bootloaderArtifacts {
parts := strings.SplitN(a, ":", 2)
if parts[0] == "firmware_fat" {
imageDeps = append(imageDeps, filepath.Join(pbPath, parts[1]))
}
}
s.AddDeps(imageDeps)
return nil
}
func isUsedForTesting(s *Shard, image build.Image, pave bool) bool {
if s.Env.TargetsEmulator() {
// All EMU targets in botanist are using product bundles, so we don't
// need to get any deps from the images.json.
return false
}
if isFlashingDep(image) {
return true
}
// TODO(https://fxbug.dev/42124288): Remove zedboot/paving images once we switch to flashing.
return ((pave && len(image.PaveArgs) != 0) ||
(!pave && len(image.NetbootArgs) != 0) ||
(len(image.PaveZedbootArgs) != 0) ||
(pave && len(image.FastbootFlashArgs) != 0) ||
(!pave && len(image.FastbootBootArgs) != 0))
}
func isFlashingDep(image build.Image) bool {
return image.Name == "fastboot"
}