blob: 61016de363e3261d1763003150ac224ba6817987 [file] [log] [blame]
// Copyright 2020 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.
// fvd generates a Fuchsia Virtual Device (.fvd) file for the current
// product x arch image being built. It is meant to be run during the build.
package main
// TODO(kjharland): Set QEMU metadata.
import (
"encoding/json"
"errors"
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"github.com/golang/protobuf/jsonpb"
fvdpb "go.fuchsia.dev/fuchsia/tools/virtual_device/proto"
)
// The names of images to write to the FVD.
//
// In the future these might be configurable but for now we use the same images
// for all emulator product x arch combinations.
const (
imageNameKernel = "qemu-kernel"
imageNameFVM = "storage-full"
imageNameInitialRamdisk = "zircon-a"
)
func main() {
if err := mainImpl(); err != nil {
fmt.Fprintf(os.Stderr, "fvd: %v\n", err)
os.Exit(1)
}
}
func mainImpl() error {
imagesJSONPath := flag.String("images_json", "", "The path to images.json")
outputPath := flag.String("output", "", "Where to write the .fvd file (Default: stdout)")
fvdName := flag.String("name", "default", "The virtual device name")
flag.Parse()
if *imagesJSONPath == "" {
return errors.New("missing --images_json")
}
if *fvdName == "" {
return errors.New("missing --name")
}
images, err := readImagesJSON(*imagesJSONPath)
if err != nil {
return err
}
fvd, err := generate(*fvdName, images)
var out io.Writer = os.Stdout
if *outputPath != "" {
fd, err := os.Create(*outputPath)
if err != nil {
return err
}
defer fd.Close()
out = fd
}
m := jsonpb.Marshaler{Indent: " "}
return m.Marshal(out, fvd)
}
func generate(name string, images imagesJSON) (*fvdpb.VirtualDevice, error) {
fvd := &fvdpb.VirtualDevice{Name: name}
// Ensure the image names written into the FVD are present in images.json.
for _, entry := range images {
switch entry.Name {
case imageNameKernel:
fvd.Kernel = entry.Name
case imageNameFVM:
fvd.Fvm = entry.Name
case imageNameInitialRamdisk:
fvd.Initrd = entry.Name
}
}
if fvd.Kernel == "" {
return nil, errors.New("kernel image not found")
}
if fvd.Fvm == "" {
return nil, errors.New("fvm image not found")
}
if fvd.Initrd == "" {
return nil, errors.New("initial ramdisk not found")
}
return fvd, nil
}
// scope represents a JSON object entry in images.json.
//
// See `build_api_module("images")` in /BUILD.gn for documentation on the full
// set of fields that may appear in the scope. This is only a subset needed to
// generate the FVD proto.
type scope struct {
Name string `json:"name"`
Path string `json:"path"`
}
type imagesJSON []scope
func readImagesJSON(filename string) (imagesJSON, error) {
bytes, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
var i imagesJSON
if err := json.Unmarshal(bytes, &i); err != nil {
return nil, err
}
return i, nil
}