|  | // 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/lib/color" | 
|  | "go.fuchsia.dev/fuchsia/tools/lib/logger" | 
|  | "go.fuchsia.dev/fuchsia/tools/sdk-tools/sdkcommon" | 
|  | ) | 
|  |  | 
|  | var ( | 
|  | // ExecCommand exports exec.Command as a variable so it can be mocked. | 
|  | ExecCommand = exec.Command | 
|  | // Logger level. | 
|  | level = logger.InfoLevel | 
|  | ) | 
|  |  | 
|  | const logFlags = log.Ltime | 
|  |  | 
|  | type sdkProvider interface { | 
|  | RunSSHShell(targetAddress string, sshConfig string, privateKey string, verbose bool, sshArgs []string) error | 
|  | } | 
|  |  | 
|  | func main() { | 
|  | var err error | 
|  |  | 
|  | sdk, err := sdkcommon.New() | 
|  | if err != nil { | 
|  | fmt.Fprintf(os.Stderr, "Could not initialize SDK %v", err) | 
|  | os.Exit(1) | 
|  | } | 
|  |  | 
|  | helpFlag := flag.Bool("help", false, "Show the usage message") | 
|  | verboseFlag := flag.Bool("verbose", false, "Print informational messages.") | 
|  |  | 
|  | // target related options | 
|  | privateKeyFlag := flag.String("private-key", "", "Uses additional private key when using ssh to access the device.") | 
|  | deviceNameFlag := flag.String("device-name", "", `Serves packages to a device with the given device hostname. Cannot be used with --device-ip." | 
|  | If neither --device-name nor --device-ip are specified, the device-name configured using fconfig.sh is used.`) | 
|  | deviceIPFlag := flag.String("device-ip", "", `Serves packages to a device with the given device ip address. Cannot be used with --device-name." | 
|  | If neither --device-name nor --device-ip are specified, the device-name configured using fconfig.sh is used.`) | 
|  | sshConfigFlag := flag.String("sshconfig", "", "Use the specified sshconfig file instead of fssh's version.") | 
|  | flag.Var(&level, "level", "Output verbosity, can be fatal, error, warning, info, debug or trace.") | 
|  |  | 
|  | flag.Parse() | 
|  |  | 
|  | log := logger.NewLogger(level, color.NewColor(color.ColorAuto), os.Stdout, os.Stderr, "fserve ") | 
|  | log.SetFlags(logFlags) | 
|  |  | 
|  | if *helpFlag { | 
|  | usage() | 
|  | os.Exit(0) | 
|  | } | 
|  |  | 
|  | targetAddress, err := sdk.ResolveTargetAddress(*deviceIPFlag, *deviceNameFlag) | 
|  | if err != nil { | 
|  | log.Fatalf("Could not determine target address with specified device-ip: %v, device-name: %v: %v", *deviceIPFlag, *deviceNameFlag, err) | 
|  | } | 
|  | log.Debugf("Using target address: %v", targetAddress) | 
|  |  | 
|  | if err := ssh(sdk, *verboseFlag, targetAddress, *sshConfigFlag, *privateKeyFlag, flag.Args()); err != nil { | 
|  | var exitError *exec.ExitError | 
|  | if errors.As(err, &exitError) { | 
|  | os.Exit(exitError.ExitCode()) | 
|  | } else { | 
|  | log.Fatalf("Error running ssh: %v", err) | 
|  | } | 
|  | } | 
|  | os.Exit(0) | 
|  | } | 
|  |  | 
|  | func usage() { | 
|  | fmt.Printf("Usage: %s [options] [args]", filepath.Base(os.Args[0])) | 
|  | flag.PrintDefaults() | 
|  | } | 
|  |  | 
|  | // ssh wraps sdk.RunSSHShell to enable testing by injecting an sdkProvider | 
|  | func ssh(sdk sdkProvider, verbose bool, targetAddress string, sshConfig string, privateKey string, args []string) error { | 
|  | return sdk.RunSSHShell(targetAddress, sshConfig, privateKey, verbose, args) | 
|  | } |