blob: 2732f98450d195f18b2f6816cafc2ce63d80f0af [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.
package main
import (
"errors"
"flag"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"go.fuchsia.dev/fuchsia/tools/sdk-tools/sdkcommon"
)
// ExecCommand exports exec.Command as a variable so it can be mocked.
var ExecCommand = exec.Command
type sdkProvider interface {
GetToolsDir() (string, error)
GetFuchsiaProperty(deviceName string, property string) (string, error)
ResolveTargetAddress(deviceIP string, deviceName string) (sdkcommon.DeviceConfig, error)
RunFFX(args []string, interactive bool) (string, error)
}
var osExit = os.Exit
func main() {
dataPathFlag := flag.String("data-path", "", "Specifies the data path for SDK tools. Defaults to $HOME/.fuchsia.")
helpFlag := flag.Bool("help", false, "Show the usage message")
verboseFlag := flag.Bool("verbose", false, "Print informational messages.")
deviceNameFlag := flag.String("device-name", "", `Specifies the device name to use to look up configuration information regarding the package repo location. If not specified, the default device configured using fconfig is used.`)
repoFlag := flag.String("repo-dir", "", "Specify the path to the package repository. If not specified, the default device configured using fconfig is used.")
flag.Parse()
sdk, err := sdkcommon.NewWithDataPath(*dataPathFlag)
if err != nil {
fmt.Fprintf(os.Stderr, "Could not initialize SDK %v", err)
osExit(1)
}
if *helpFlag {
usage()
osExit(0)
}
message, err := publish(sdk, *repoFlag, *deviceNameFlag, flag.Args(), *verboseFlag)
if err != nil {
var exitError *exec.ExitError
if errors.As(err, &exitError) {
log.Fatalf("%v: %v %v", string(exitError.Stderr), message, exitError)
osExit(exitError.ProcessState.ExitCode())
}
log.Fatalf("%v%v", err, message)
osExit(1)
}
fmt.Println(message)
registerSymbolIndex(sdk, flag.Args(), *verboseFlag)
osExit(0)
}
// Register the packages in the symbol index. Discard any failure.
func registerSymbolIndex(sdk sdkProvider, packages []string, verbose bool) {
for _, pkg := range packages {
// pkg should end with ".far", otherwise the publish function should fail.
symbolIndexJsonFile := pkg[:len(pkg)-4] + ".symbol-index.json"
if _, err := os.Stat(symbolIndexJsonFile); err != nil {
// File doesn't exist or is not readable.
continue
}
args := []string{"debug", "symbol-index", "add", symbolIndexJsonFile}
if verbose {
fmt.Printf("Running command: ffx %v\n", args)
}
// The command outputs nothing if succeeds, and outputs error messages if fails,
// which is sufficient for our users. Use interactive=true here allows the
// command to output.
sdk.RunFFX(args, true)
}
}
func publish(sdk sdkProvider, packageRepo string, deviceName string, packages []string, verbose bool) (string, error) {
var err error
repoPath := packageRepo
deviceConfig, err := sdk.ResolveTargetAddress("", deviceName)
if err != nil {
return "", fmt.Errorf("Could not resolve device: %v", err)
}
if repoPath == "" {
repoPath, err = sdk.GetFuchsiaProperty(deviceConfig.DeviceName, sdkcommon.PackageRepoKey)
if err != nil {
return "", fmt.Errorf("could not lookup package repo directory for %v: %v", deviceConfig, err)
}
}
if repoPath == "" {
return "", errors.New("could not determine package repo directory")
}
toolsDir, err := sdk.GetToolsDir()
if err != nil {
return "", fmt.Errorf("Could not determine tools directory %v", err)
}
cmd := filepath.Join(toolsDir, "pm")
args := []string{
"publish", "-n", "-a", "-r", repoPath, "-f"}
args = append(args, packages...)
if verbose {
args = append(args, "-v")
fmt.Printf("Running command: %v %v\n", cmd, args)
}
output, err := ExecCommand(cmd, args...).CombinedOutput()
return string(output), err
}
func usage() {
fmt.Printf("Usage: %s <far-file>\n", filepath.Base(os.Args[0]))
flag.PrintDefaults()
}