Skip to content

Make commands output agnostic #391

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Oct 9, 2019
2 changes: 1 addition & 1 deletion cli/board/details.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func runDetailsCommand(cmd *cobra.Command, args []string) {
feedback.PrintResult(detailsResult{details: res})
}

// ouput from this command requires special formatting, let's create a dedicated
// output from this command requires special formatting, let's create a dedicated
// feedback.Result implementation
type detailsResult struct {
details *rpc.BoardDetailsResp
Expand Down
33 changes: 19 additions & 14 deletions cli/board/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import (
"github.com/arduino/arduino-cli/arduino/cores"
"github.com/arduino/arduino-cli/cli/errorcodes"
"github.com/arduino/arduino-cli/cli/feedback"
"github.com/arduino/arduino-cli/cli/globals"
"github.com/arduino/arduino-cli/cli/instance"
"github.com/arduino/arduino-cli/commands/board"
rpc "github.com/arduino/arduino-cli/rpc/commands"
Expand Down Expand Up @@ -68,27 +67,33 @@ func runListCommand(cmd *cobra.Command, args []string) {
os.Exit(errorcodes.ErrNetwork)
}

if globals.OutputFormat == "json" {
feedback.PrintJSON(ports)
} else {
outputListResp(ports)
}
feedback.PrintResult(result{ports})
}

// output from this command requires special formatting, let's create a dedicated
// feedback.Result implementation
type result struct {
ports []*rpc.DetectedPort
}

func outputListResp(ports []*rpc.DetectedPort) {
if len(ports) == 0 {
feedback.Print("No boards found.")
return
func (dr result) Data() interface{} {
return dr.ports
}

func (dr result) String() string {
if len(dr.ports) == 0 {
return "No boards found."
}
sort.Slice(ports, func(i, j int) bool {
x, y := ports[i], ports[j]

sort.Slice(dr.ports, func(i, j int) bool {
x, y := dr.ports[i], dr.ports[j]
return x.GetProtocol() < y.GetProtocol() ||
(x.GetProtocol() == y.GetProtocol() && x.GetAddress() < y.GetAddress())
})

t := table.New()
t.SetHeader("Port", "Type", "Board Name", "FQBN", "Core")
for _, port := range ports {
for _, port := range dr.ports {
address := port.GetProtocol() + "://" + port.GetAddress()
if port.GetProtocol() == "serial" {
address = port.GetAddress()
Expand Down Expand Up @@ -123,5 +128,5 @@ func outputListResp(ports []*rpc.DetectedPort) {
t.AddRow(address, protocol, board, fqbn, coreName)
}
}
feedback.Print(t.Render())
return t.Render()
}
27 changes: 16 additions & 11 deletions cli/board/listall.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (

"github.com/arduino/arduino-cli/cli/errorcodes"
"github.com/arduino/arduino-cli/cli/feedback"
"github.com/arduino/arduino-cli/cli/globals"
"github.com/arduino/arduino-cli/cli/instance"
"github.com/arduino/arduino-cli/commands/board"
rpc "github.com/arduino/arduino-cli/rpc/commands"
Expand Down Expand Up @@ -58,22 +57,28 @@ func runListAllCommand(cmd *cobra.Command, args []string) {
os.Exit(errorcodes.ErrGeneric)
}

if globals.OutputFormat == "json" {
feedback.PrintJSON(list)
} else {
outputBoardListAll(list)
}
feedback.PrintResult(resultAll{list})
}

// output from this command requires special formatting, let's create a dedicated
// feedback.Result implementation
type resultAll struct {
list *rpc.BoardListAllResp
}

func (dr resultAll) Data() interface{} {
return dr.list
}

func outputBoardListAll(list *rpc.BoardListAllResp) {
sort.Slice(list.Boards, func(i, j int) bool {
return list.Boards[i].GetName() < list.Boards[j].GetName()
func (dr resultAll) String() string {
sort.Slice(dr.list.Boards, func(i, j int) bool {
return dr.list.Boards[i].GetName() < dr.list.Boards[j].GetName()
})

t := table.New()
t.SetHeader("Board Name", "FQBN")
for _, item := range list.GetBoards() {
for _, item := range dr.list.GetBoards() {
t.AddRow(item.GetName(), item.GetFQBN())
}
feedback.Print(t.Render())
return t.Render()
}
20 changes: 12 additions & 8 deletions cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/arduino/arduino-cli/cli/generatedocs"
"github.com/arduino/arduino-cli/cli/globals"
"github.com/arduino/arduino-cli/cli/lib"
"github.com/arduino/arduino-cli/cli/output"
"github.com/arduino/arduino-cli/cli/sketch"
"github.com/arduino/arduino-cli/cli/upload"
"github.com/arduino/arduino-cli/cli/version"
Expand All @@ -52,9 +53,10 @@ var (
PersistentPreRun: preRun,
}

verbose bool
logFile string
logFormat string
verbose bool
logFile string
logFormat string
outputFormat string
)

const (
Expand Down Expand Up @@ -83,7 +85,7 @@ func createCliCommandTree(cmd *cobra.Command) {
cmd.PersistentFlags().StringVar(&globals.LogLevel, "log-level", defaultLogLevel, "Messages with this level and above will be logged.")
cmd.PersistentFlags().StringVar(&logFile, "log-file", "", "Path to the file where logs will be written.")
cmd.PersistentFlags().StringVar(&logFormat, "log-format", "text", "The output format for the logs, can be [text|json].")
cmd.PersistentFlags().StringVar(&globals.OutputFormat, "format", "text", "The output format, can be [text|json].")
cmd.PersistentFlags().StringVar(&outputFormat, "format", "text", "The output format, can be [text|json].")
cmd.PersistentFlags().StringVar(&globals.YAMLConfigFile, "config-file", "", "The custom config file (if not specified the default will be used).")
cmd.PersistentFlags().StringSliceVar(&globals.AdditionalUrls, "additional-urls", []string{}, "Additional URLs for the board manager.")
}
Expand Down Expand Up @@ -115,7 +117,9 @@ func parseFormatString(arg string) (feedback.OutputFormat, bool) {

func preRun(cmd *cobra.Command, args []string) {
// normalize the format strings
globals.OutputFormat = strings.ToLower(globals.OutputFormat)
outputFormat = strings.ToLower(outputFormat)
// configure the output package
output.OutputFormat = outputFormat
logFormat = strings.ToLower(logFormat)

// should we log to file?
Expand Down Expand Up @@ -159,9 +163,9 @@ func preRun(cmd *cobra.Command, args []string) {
}

// check the right output format was passed
format, found := parseFormatString(globals.OutputFormat)
format, found := parseFormatString(outputFormat)
if !found {
feedback.Error("Invalid output format: " + globals.OutputFormat)
feedback.Error("Invalid output format: " + outputFormat)
os.Exit(errorcodes.ErrBadCall)
}

Expand All @@ -174,7 +178,7 @@ func preRun(cmd *cobra.Command, args []string) {
logrus.Info("Starting root command preparation (`arduino`)")

logrus.Info("Formatter set")
if globals.OutputFormat != "text" {
if outputFormat != "text" {
cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
logrus.Warn("Calling help on JSON format")
feedback.Error("Invalid Call : should show Help, but it is available only in TEXT mode.")
Expand Down
50 changes: 32 additions & 18 deletions cli/config/dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,21 @@ var dumpCmd = &cobra.Command{
Run: runDumpCommand,
}

// output from this command requires special formatting, let's create a dedicated
// feedback.Result implementation
type dumpResult struct {
structured *jsonConfig
plain string
}

func (dr dumpResult) Data() interface{} {
return dr.structured
}

func (dr dumpResult) String() string {
return dr.plain
}

func runDumpCommand(cmd *cobra.Command, args []string) {
logrus.Info("Executing `arduino config dump`")

Expand All @@ -69,23 +84,23 @@ func runDumpCommand(cmd *cobra.Command, args []string) {

c := globals.Config

if globals.OutputFormat == "json" {
sketchbookDir := ""
if c.SketchbookDir != nil {
sketchbookDir = c.SketchbookDir.String()
}
sketchbookDir := ""
if c.SketchbookDir != nil {
sketchbookDir = c.SketchbookDir.String()
}

arduinoDataDir := ""
if c.DataDir != nil {
arduinoDataDir = c.DataDir.String()
}
arduinoDataDir := ""
if c.DataDir != nil {
arduinoDataDir = c.DataDir.String()
}

arduinoDownloadsDir := ""
if c.ArduinoDownloadsDir != nil {
arduinoDownloadsDir = c.ArduinoDownloadsDir.String()
}
arduinoDownloadsDir := ""
if c.ArduinoDownloadsDir != nil {
arduinoDownloadsDir = c.ArduinoDownloadsDir.String()
}

feedback.PrintJSON(jsonConfig{
feedback.PrintResult(&dumpResult{
structured: &jsonConfig{
ProxyType: c.ProxyType,
ProxyManualConfig: &jsonProxyConfig{
Hostname: c.ProxyHostname,
Expand All @@ -98,8 +113,7 @@ func runDumpCommand(cmd *cobra.Command, args []string) {
BoardsManager: &jsonBoardsManagerConfig{
AdditionalURLS: c.BoardManagerAdditionalUrls,
},
})
} else {
feedback.Print(string(data))
}
},
plain: string(data),
})
}
9 changes: 0 additions & 9 deletions cli/config/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ func initInitCommand() *cobra.Command {
Args: cobra.NoArgs,
Run: runInitCommand,
}
initCommand.Flags().BoolVar(&initFlags._default, "default", false,
"If omitted, ask questions to the user about setting configuration properties, otherwise use default configuration.")
initCommand.Flags().StringVar(&initFlags.location, "save-as", "",
"Sets where to save the configuration file [default is ./arduino-cli.yaml].")
return initCommand
Expand All @@ -55,13 +53,6 @@ var initFlags struct {
func runInitCommand(cmd *cobra.Command, args []string) {
logrus.Info("Executing `arduino config init`")

if !initFlags._default {
if globals.OutputFormat != "text" {
feedback.Error("The interactive mode is supported only in text mode.")
os.Exit(errorcodes.ErrBadCall)
}
}

filepath := initFlags.location
if filepath == "" {
filepath = globals.Config.ConfigFile.String()
Expand Down
31 changes: 18 additions & 13 deletions cli/core/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"github.com/arduino/arduino-cli/arduino/cores"
"github.com/arduino/arduino-cli/cli/errorcodes"
"github.com/arduino/arduino-cli/cli/feedback"
"github.com/arduino/arduino-cli/cli/globals"
"github.com/arduino/arduino-cli/cli/instance"
"github.com/arduino/arduino-cli/commands/core"
"github.com/arduino/arduino-cli/table"
Expand Down Expand Up @@ -59,26 +58,32 @@ func runListCommand(cmd *cobra.Command, args []string) {
os.Exit(errorcodes.ErrGeneric)
}

if globals.OutputFormat == "json" {
feedback.PrintJSON(platforms)
} else {
outputInstalledCores(platforms)
}
feedback.PrintResult(installedResult{platforms})
}

// output from this command requires special formatting, let's create a dedicated
// feedback.Result implementation
type installedResult struct {
platforms []*cores.PlatformRelease
}

func (ir installedResult) Data() interface{} {
return ir.platforms
}

func outputInstalledCores(platforms []*cores.PlatformRelease) {
if platforms == nil || len(platforms) == 0 {
return
func (ir installedResult) String() string {
if ir.platforms == nil || len(ir.platforms) == 0 {
return ""
}

t := table.New()
t.SetHeader("ID", "Installed", "Latest", "Name")
sort.Slice(platforms, func(i, j int) bool {
return platforms[i].Platform.String() < platforms[j].Platform.String()
sort.Slice(ir.platforms, func(i, j int) bool {
return ir.platforms[i].Platform.String() < ir.platforms[j].Platform.String()
})
for _, p := range platforms {
for _, p := range ir.platforms {
t.AddRow(p.Platform.String(), p.Version.String(), p.Platform.GetLatestRelease().Version.String(), p.Platform.Name)
}

feedback.Print(t.Render())
return t.Render()
}
37 changes: 18 additions & 19 deletions cli/core/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import (

"github.com/arduino/arduino-cli/cli/errorcodes"
"github.com/arduino/arduino-cli/cli/feedback"
"github.com/arduino/arduino-cli/cli/globals"
"github.com/arduino/arduino-cli/cli/instance"
"github.com/arduino/arduino-cli/commands/core"
rpc "github.com/arduino/arduino-cli/rpc/commands"
Expand All @@ -51,11 +50,6 @@ func runSearchCommand(cmd *cobra.Command, args []string) {
logrus.Info("Executing `arduino core search`")

arguments := strings.ToLower(strings.Join(args, " "))

if globals.OutputFormat != "json" {
feedback.Printf("Searching for platforms matching '%s'", arguments)
}

resp, err := core.PlatformSearch(context.Background(), &rpc.PlatformSearchReq{
Instance: instance,
SearchArgs: arguments,
Expand All @@ -66,25 +60,30 @@ func runSearchCommand(cmd *cobra.Command, args []string) {
}

coreslist := resp.GetSearchOutput()
if globals.OutputFormat == "json" {
feedback.PrintJSON(coreslist)
} else {
outputSearchCores(coreslist)
}
feedback.PrintResult(searchResults{coreslist})
}

// output from this command requires special formatting, let's create a dedicated
// feedback.Result implementation
type searchResults struct {
platforms []*rpc.Platform
}

func (sr searchResults) Data() interface{} {
return sr.platforms
}

func outputSearchCores(cores []*rpc.Platform) {
if len(cores) > 0 {
func (sr searchResults) String() string {
if len(sr.platforms) > 0 {
t := table.New()
t.SetHeader("ID", "Version", "Name")
sort.Slice(cores, func(i, j int) bool {
return cores[i].ID < cores[j].ID
sort.Slice(sr.platforms, func(i, j int) bool {
return sr.platforms[i].ID < sr.platforms[j].ID
})
for _, item := range cores {
for _, item := range sr.platforms {
t.AddRow(item.GetID(), item.GetLatest(), item.GetName())
}
feedback.Print(t.Render())
} else {
feedback.Print("No platforms matching your search.")
return t.Render()
}
return "No platforms matching your search."
}
Loading