| // 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" |
| } |