From 2cf99bc047f80c1cae7d9c79c8699af8e76be766 Mon Sep 17 00:00:00 2001 From: Massimiliano Pippi Date: Tue, 3 Sep 2019 16:23:10 +0200 Subject: [PATCH 01/15] make Print format gnostic --- cli/feedback/exported.go | 8 +++++--- cli/feedback/feedback.go | 20 +++++++++++--------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/cli/feedback/exported.go b/cli/feedback/exported.go index a3cc2a6f23d..c6468f59302 100644 --- a/cli/feedback/exported.go +++ b/cli/feedback/exported.go @@ -52,8 +52,8 @@ func Printf(format string, v ...interface{}) { } // Print behaves like fmt.Print but writes on the out writer and adds a newline. -func Print(v ...interface{}) { - fb.Print(v...) +func Print(v interface{}) { + fb.Print(v) } // Errorf behaves like fmt.Printf but writes on the error writer and adds a @@ -74,7 +74,9 @@ func PrintJSON(v interface{}) { fb.PrintJSON(v) } -// PrintResult is a convenient wrapper... +// PrintResult is a convenient wrapper to provide feedback for complex data, +// where the contents can't be just serialized to JSON but requires more +// structure. func PrintResult(res Result) { fb.PrintResult(res) } diff --git a/cli/feedback/feedback.go b/cli/feedback/feedback.go index 1f355c9f869..feb72ad5ac9 100644 --- a/cli/feedback/feedback.go +++ b/cli/feedback/feedback.go @@ -86,8 +86,12 @@ func (fb *Feedback) Printf(format string, v ...interface{}) { } // Print behaves like fmt.Print but writes on the out writer and adds a newline. -func (fb *Feedback) Print(v ...interface{}) { - fmt.Fprintln(fb.out, v...) +func (fb *Feedback) Print(v interface{}) { + if fb.format == JSON { + fb.PrintJSON(v) + } else { + fmt.Fprintln(fb.out, v) + } } // Errorf behaves like fmt.Printf but writes on the error writer and adds a @@ -109,18 +113,16 @@ func (fb *Feedback) PrintJSON(v interface{}) { if d, err := json.MarshalIndent(v, "", " "); err != nil { fb.Errorf("Error during JSON encoding of the output: %v", err) } else { - fb.Print(string(d)) + fmt.Fprint(fb.out, string(d)) } } -// PrintResult is a convenient wrapper... +// PrintResult is a convenient wrapper to provide feedback for complex data, +// where the contents can't be just serialized to JSON but requires more +// structure. func (fb *Feedback) PrintResult(res Result) { if fb.format == JSON { - if d, err := json.MarshalIndent(res.Data(), "", " "); err != nil { - fb.Errorf("Error during JSON encoding of the output: %v", err) - } else { - fb.Print(string(d)) - } + fb.PrintJSON(res.Data()) } else { fb.Print(fmt.Sprintf("%s", res)) } From 237994d75311c2f3acefa8cec1c8cb4e9432bfca Mon Sep 17 00:00:00 2001 From: Massimiliano Pippi Date: Tue, 3 Sep 2019 16:23:36 +0200 Subject: [PATCH 02/15] make version format agnostic --- cli/version/version.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cli/version/version.go b/cli/version/version.go index 15c90054b2c..6c083c20ed1 100644 --- a/cli/version/version.go +++ b/cli/version/version.go @@ -38,9 +38,5 @@ func NewCommand() *cobra.Command { } func run(cmd *cobra.Command, args []string) { - if globals.OutputFormat == "json" { - feedback.PrintJSON(globals.VersionInfo) - } else { - feedback.Print(globals.VersionInfo) - } + feedback.Print(globals.VersionInfo) } From 21da8f3f7b6e2443331fb5258b5d08bfa0a5cb80 Mon Sep 17 00:00:00 2001 From: Massimiliano Pippi Date: Tue, 3 Sep 2019 16:32:29 +0200 Subject: [PATCH 03/15] make config dump format agnostic --- cli/config/dump.go | 50 +++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/cli/config/dump.go b/cli/config/dump.go index a1f56e536e0..9b83325aa7c 100644 --- a/cli/config/dump.go +++ b/cli/config/dump.go @@ -58,6 +58,21 @@ var dumpCmd = &cobra.Command{ Run: runDumpCommand, } +// ouput 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`") @@ -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, @@ -98,8 +113,7 @@ func runDumpCommand(cmd *cobra.Command, args []string) { BoardsManager: &jsonBoardsManagerConfig{ AdditionalURLS: c.BoardManagerAdditionalUrls, }, - }) - } else { - feedback.Print(string(data)) - } + }, + plain: string(data), + }) } From ff42ff22a293dadbb7ef430026df5d1e3eb75290 Mon Sep 17 00:00:00 2001 From: Massimiliano Pippi Date: Tue, 3 Sep 2019 16:38:27 +0200 Subject: [PATCH 04/15] make board list format agnostic --- cli/board/list.go | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/cli/board/list.go b/cli/board/list.go index 8702e418a05..f7db6bbed87 100644 --- a/cli/board/list.go +++ b/cli/board/list.go @@ -18,15 +18,12 @@ package board import ( - "fmt" "os" "sort" "time" - "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" @@ -68,27 +65,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}) +} + +// ouput 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() @@ -123,5 +126,5 @@ func outputListResp(ports []*rpc.DetectedPort) { t.AddRow(address, protocol, board, fqbn, coreName) } } - feedback.Print(t.Render()) + return t.Render() } From dfb05c9fd53515e32e8a7530d7a6ed4cf3fcdd9d Mon Sep 17 00:00:00 2001 From: Massimiliano Pippi Date: Tue, 3 Sep 2019 16:42:37 +0200 Subject: [PATCH 05/15] make board listall format agnostic --- cli/board/listall.go | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/cli/board/listall.go b/cli/board/listall.go index 0034c6c6827..07856fb08de 100644 --- a/cli/board/listall.go +++ b/cli/board/listall.go @@ -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" @@ -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}) +} + +// ouput 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() } From a23b32ee7cb90017359b6718e7e9cb3faf346c50 Mon Sep 17 00:00:00 2001 From: Massimiliano Pippi Date: Tue, 3 Sep 2019 16:46:17 +0200 Subject: [PATCH 06/15] make lib list format agnostic --- cli/lib/list.go | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/cli/lib/list.go b/cli/lib/list.go index 0de750b4529..a0ce3104dee 100644 --- a/cli/lib/list.go +++ b/cli/lib/list.go @@ -22,7 +22,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/lib" rpc "github.com/arduino/arduino-cli/rpc/commands" @@ -66,27 +65,31 @@ func runListCommand(cmd *cobra.Command, args []string) { } libs := res.GetInstalledLibrary() - if libs != nil { - if globals.OutputFormat == "json" { - feedback.PrintJSON(libs) - } else { - outputListLibrary(libs) - } - } + feedback.PrintResult(installedResult{libs}) logrus.Info("Done") } -func outputListLibrary(il []*rpc.InstalledLibrary) { - if il == nil || len(il) == 0 { - return +// ouput from this command requires special formatting, let's create a dedicated +// feedback.Result implementation +type installedResult struct { + installedLibs []*rpc.InstalledLibrary +} + +func (ir installedResult) Data() interface{} { + return ir.installedLibs +} + +func (ir installedResult) String() string { + if ir.installedLibs == nil || len(ir.installedLibs) == 0 { + return "" } t := table.New() t.SetHeader("Name", "Installed", "Available", "Location") lastName := "" - for _, libMeta := range il { + for _, libMeta := range ir.installedLibs { lib := libMeta.GetLibrary() name := lib.Name if name == lastName { @@ -110,5 +113,5 @@ func outputListLibrary(il []*rpc.InstalledLibrary) { } } - feedback.Print(t.Render()) + return t.Render() } From 8ed20722448df157191be8ef5d3ce0613d4181f8 Mon Sep 17 00:00:00 2001 From: Massimiliano Pippi Date: Tue, 3 Sep 2019 17:18:35 +0200 Subject: [PATCH 07/15] make lib search format agnostic --- cli/lib/search.go | 105 +++++++++++++++++++++++++--------------------- 1 file changed, 58 insertions(+), 47 deletions(-) diff --git a/cli/lib/search.go b/cli/lib/search.go index 4014acc56fc..231df726641 100644 --- a/cli/lib/search.go +++ b/cli/lib/search.go @@ -26,7 +26,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/lib" rpc "github.com/arduino/arduino-cli/rpc/commands" @@ -64,63 +63,75 @@ func runSearchCommand(cmd *cobra.Command, args []string) { os.Exit(errorcodes.ErrGeneric) } - if globals.OutputFormat == "json" { - if searchFlags.namesOnly { - type LibName struct { - Name string `json:"name,required"` - } - - type NamesOnly struct { - Libraries []LibName `json:"libraries,required"` - } - - names := []LibName{} - results := searchResp.GetLibraries() - for _, lsr := range results { - names = append(names, LibName{lsr.Name}) - } - feedback.PrintJSON(NamesOnly{ - names, - }) - } else { - feedback.PrintJSON(searchResp) + // get a sorted slice of results + results := searchResp.GetLibraries() + sort.Slice(results, func(i, j int) bool { + return results[i].Name < results[j].Name + }) + + feedback.PrintResult(result{ + results: results, + namesOnly: searchFlags.namesOnly, + }) + + logrus.Info("Done") +} + +// ouput from this command requires special formatting, let's create a dedicated +// feedback.Result implementation +type result struct { + results []*rpc.SearchedLibrary + namesOnly bool +} + +func (res result) Data() interface{} { + if res.namesOnly { + type LibName struct { + Name string `json:"name,required"` + } + + type NamesOnly struct { + Libraries []LibName `json:"libraries,required"` + } + + names := []LibName{} + for _, lsr := range res.results { + names = append(names, LibName{lsr.Name}) + } + + return NamesOnly{ + names, } - } else { - // get a sorted slice of results - results := searchResp.GetLibraries() - sort.Slice(results, func(i, j int) bool { - return results[i].Name < results[j].Name - }) - - // print all the things - outputSearchedLibrary(results, searchFlags.namesOnly) } - logrus.Info("Done") + return res.results } -func outputSearchedLibrary(results []*rpc.SearchedLibrary, namesOnly bool) { - if len(results) == 0 { - feedback.Print("No libraries matching your search.") - return +func (res result) String() string { + if len(res.results) == 0 { + return "No libraries matching your search." } - for _, lsr := range results { - feedback.Printf(`Name: "%s"`, lsr.Name) - if namesOnly { + var out strings.Builder + + for _, lsr := range res.results { + out.WriteString(fmt.Sprintf("Name: \"%s\"\n", lsr.Name)) + if res.namesOnly { continue } - feedback.Printf(" Author: %s", lsr.GetLatest().Author) - feedback.Printf(" Maintainer: %s", lsr.GetLatest().Maintainer) - feedback.Printf(" Sentence: %s", lsr.GetLatest().Sentence) - feedback.Printf(" Paragraph: %s", lsr.GetLatest().Paragraph) - feedback.Printf(" Website: %s", lsr.GetLatest().Website) - feedback.Printf(" Category: %s", lsr.GetLatest().Category) - feedback.Printf(" Architecture: %s", strings.Join(lsr.GetLatest().Architectures, ", ")) - feedback.Printf(" Types: %s", strings.Join(lsr.GetLatest().Types, ", ")) - feedback.Printf(" Versions: %s", strings.Replace(fmt.Sprint(versionsFromSearchedLibrary(lsr)), " ", ", ", -1)) + out.WriteString(fmt.Sprintf(" Author: %s\n", lsr.GetLatest().Author)) + out.WriteString(fmt.Sprintf(" Maintainer: %s\n", lsr.GetLatest().Maintainer)) + out.WriteString(fmt.Sprintf(" Sentence: %s\n", lsr.GetLatest().Sentence)) + out.WriteString(fmt.Sprintf(" Paragraph: %s\n", lsr.GetLatest().Paragraph)) + out.WriteString(fmt.Sprintf(" Website: %s\n", lsr.GetLatest().Website)) + out.WriteString(fmt.Sprintf(" Category: %s\n", lsr.GetLatest().Category)) + out.WriteString(fmt.Sprintf(" Architecture: %s\n", strings.Join(lsr.GetLatest().Architectures, ", "))) + out.WriteString(fmt.Sprintf(" Types: %s\n", strings.Join(lsr.GetLatest().Types, ", "))) + out.WriteString(fmt.Sprintf(" Versions: %s\n", strings.Replace(fmt.Sprint(versionsFromSearchedLibrary(lsr)), " ", ", ", -1))) } + + return fmt.Sprintf("%s", out.String()) } func versionsFromSearchedLibrary(library *rpc.SearchedLibrary) []*semver.Version { From f40a71ddf018e588db867c8f0a2de25d85240ba3 Mon Sep 17 00:00:00 2001 From: Massimiliano Pippi Date: Tue, 3 Sep 2019 17:22:12 +0200 Subject: [PATCH 08/15] make core list format agnostic --- cli/core/list.go | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/cli/core/list.go b/cli/core/list.go index d45f1835f38..8a0dae0e81a 100644 --- a/cli/core/list.go +++ b/cli/core/list.go @@ -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" @@ -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}) +} + +// ouput 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() } From 9d00e2e34f181ed7561557beff6248b38ba5c113 Mon Sep 17 00:00:00 2001 From: Massimiliano Pippi Date: Tue, 3 Sep 2019 17:26:54 +0200 Subject: [PATCH 09/15] make core search format agnostic --- cli/core/search.go | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/cli/core/search.go b/cli/core/search.go index 419db357019..af4f30f8e4f 100644 --- a/cli/core/search.go +++ b/cli/core/search.go @@ -66,25 +66,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}) +} + +// ouput 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." } From 183a15914835242a3c471625623a0537edd53d19 Mon Sep 17 00:00:00 2001 From: Massimiliano Pippi Date: Tue, 3 Sep 2019 17:38:46 +0200 Subject: [PATCH 10/15] remove format from globals --- cli/cli.go | 20 ++++++++++++-------- cli/config/init.go | 9 --------- cli/core/search.go | 6 ------ cli/feedback/exported.go | 6 ------ cli/feedback/feedback.go | 8 ++++---- cli/globals/globals.go | 2 -- cli/output/rpc_progress.go | 8 +++++--- 7 files changed, 21 insertions(+), 38 deletions(-) diff --git a/cli/cli.go b/cli/cli.go index 4fb884f9b6b..63ddeb62069 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -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" @@ -52,9 +53,10 @@ var ( PersistentPreRun: preRun, } - verbose bool - logFile string - logFormat string + verbose bool + logFile string + logFormat string + outputFormat string ) const ( @@ -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 (default: warn).") 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.") } @@ -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? @@ -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) } @@ -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.") diff --git a/cli/config/init.go b/cli/config/init.go index 66998e02437..7d7efbc9eed 100644 --- a/cli/config/init.go +++ b/cli/config/init.go @@ -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 @@ -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() diff --git a/cli/core/search.go b/cli/core/search.go index af4f30f8e4f..fee7a8be9d4 100644 --- a/cli/core/search.go +++ b/cli/core/search.go @@ -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" @@ -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, diff --git a/cli/feedback/exported.go b/cli/feedback/exported.go index c6468f59302..aee07535dbd 100644 --- a/cli/feedback/exported.go +++ b/cli/feedback/exported.go @@ -68,12 +68,6 @@ func Error(v ...interface{}) { fb.Error(v...) } -// PrintJSON is a convenient wrapper to provide feedback by printing the -// desired output in a pretty JSON format. It adds a newline to the output. -func PrintJSON(v interface{}) { - fb.PrintJSON(v) -} - // PrintResult is a convenient wrapper to provide feedback for complex data, // where the contents can't be just serialized to JSON but requires more // structure. diff --git a/cli/feedback/feedback.go b/cli/feedback/feedback.go index feb72ad5ac9..9ccc5f4671d 100644 --- a/cli/feedback/feedback.go +++ b/cli/feedback/feedback.go @@ -88,7 +88,7 @@ func (fb *Feedback) Printf(format string, v ...interface{}) { // Print behaves like fmt.Print but writes on the out writer and adds a newline. func (fb *Feedback) Print(v interface{}) { if fb.format == JSON { - fb.PrintJSON(v) + fb.printJSON(v) } else { fmt.Fprintln(fb.out, v) } @@ -107,9 +107,9 @@ func (fb *Feedback) Error(v ...interface{}) { logrus.Error(fmt.Sprint(v...)) } -// PrintJSON is a convenient wrapper to provide feedback by printing the +// printJSON is a convenient wrapper to provide feedback by printing the // desired output in a pretty JSON format. It adds a newline to the output. -func (fb *Feedback) PrintJSON(v interface{}) { +func (fb *Feedback) printJSON(v interface{}) { if d, err := json.MarshalIndent(v, "", " "); err != nil { fb.Errorf("Error during JSON encoding of the output: %v", err) } else { @@ -122,7 +122,7 @@ func (fb *Feedback) PrintJSON(v interface{}) { // structure. func (fb *Feedback) PrintResult(res Result) { if fb.format == JSON { - fb.PrintJSON(res.Data()) + fb.printJSON(res.Data()) } else { fb.Print(fmt.Sprintf("%s", res)) } diff --git a/cli/globals/globals.go b/cli/globals/globals.go index 12863bc0b83..35ff4efcc57 100644 --- a/cli/globals/globals.go +++ b/cli/globals/globals.go @@ -29,8 +29,6 @@ import ( var ( // Debug determines whether to dump debug output to stderr or not Debug bool - // OutputFormat can be "text" or "json" - OutputFormat string // HTTPClientHeader is the object that will be propagated to configure the clients inside the downloaders HTTPClientHeader = getHTTPClientHeader() // VersionInfo contains all info injected during build diff --git a/cli/output/rpc_progress.go b/cli/output/rpc_progress.go index e6b61a2e1ea..ec47de305a3 100644 --- a/cli/output/rpc_progress.go +++ b/cli/output/rpc_progress.go @@ -20,16 +20,18 @@ package output import ( "fmt" - "github.com/arduino/arduino-cli/cli/globals" "github.com/arduino/arduino-cli/commands" rpc "github.com/arduino/arduino-cli/rpc/commands" "github.com/cmaglie/pb" ) +// OutputFormat can be "text" or "json" +var OutputFormat string + // ProgressBar returns a DownloadProgressCB that prints a progress bar. // If JSON output format has been selected, the callback outputs nothing. func ProgressBar() commands.DownloadProgressCB { - if globals.OutputFormat != "json" { + if OutputFormat != "json" { return NewDownloadProgressBarCB() } return func(curr *rpc.DownloadProgress) { @@ -40,7 +42,7 @@ func ProgressBar() commands.DownloadProgressCB { // TaskProgress returns a TaskProgressCB that prints the task progress. // If JSON output format has been selected, the callback outputs nothing. func TaskProgress() commands.TaskProgressCB { - if globals.OutputFormat != "json" { + if OutputFormat != "json" { return NewTaskProgressCB() } return func(curr *rpc.TaskProgress) { From 9f44678779ca7b20ac2cd0f4fd9b05f464eb449b Mon Sep 17 00:00:00 2001 From: Massimiliano Pippi Date: Tue, 3 Sep 2019 18:16:12 +0200 Subject: [PATCH 11/15] fix regression on search output --- cli/lib/search.go | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/cli/lib/search.go b/cli/lib/search.go index 231df726641..670d47e6ec5 100644 --- a/cli/lib/search.go +++ b/cli/lib/search.go @@ -63,14 +63,8 @@ func runSearchCommand(cmd *cobra.Command, args []string) { os.Exit(errorcodes.ErrGeneric) } - // get a sorted slice of results - results := searchResp.GetLibraries() - sort.Slice(results, func(i, j int) bool { - return results[i].Name < results[j].Name - }) - feedback.PrintResult(result{ - results: results, + results: searchResp, namesOnly: searchFlags.namesOnly, }) @@ -80,7 +74,7 @@ func runSearchCommand(cmd *cobra.Command, args []string) { // ouput from this command requires special formatting, let's create a dedicated // feedback.Result implementation type result struct { - results []*rpc.SearchedLibrary + results *rpc.LibrarySearchResp namesOnly bool } @@ -95,7 +89,8 @@ func (res result) Data() interface{} { } names := []LibName{} - for _, lsr := range res.results { + results := res.results.GetLibraries() + for _, lsr := range results { names = append(names, LibName{lsr.Name}) } @@ -108,13 +103,19 @@ func (res result) Data() interface{} { } func (res result) String() string { - if len(res.results) == 0 { + results := res.results.GetLibraries() + if len(results) == 0 { return "No libraries matching your search." } + // get a sorted slice of results + sort.Slice(results, func(i, j int) bool { + return results[i].Name < results[j].Name + }) + var out strings.Builder - for _, lsr := range res.results { + for _, lsr := range results { out.WriteString(fmt.Sprintf("Name: \"%s\"\n", lsr.Name)) if res.namesOnly { continue From 0da53d227fed5bab51d23496b31c1eed52df6003 Mon Sep 17 00:00:00 2001 From: Massimiliano Pippi Date: Tue, 3 Sep 2019 18:16:30 +0200 Subject: [PATCH 12/15] provide an output when nothing was found --- cli/lib/list.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/lib/list.go b/cli/lib/list.go index a0ce3104dee..7717bb06993 100644 --- a/cli/lib/list.go +++ b/cli/lib/list.go @@ -82,7 +82,7 @@ func (ir installedResult) Data() interface{} { func (ir installedResult) String() string { if ir.installedLibs == nil || len(ir.installedLibs) == 0 { - return "" + return "No libraries installed." } t := table.New() From 04752884d6a02f4eae6b432d357cad5f8088aba7 Mon Sep 17 00:00:00 2001 From: Massimiliano Pippi Date: Tue, 3 Sep 2019 18:16:54 +0200 Subject: [PATCH 13/15] adjusted tests for the new output --- test/test_lib.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_lib.py b/test/test_lib.py index a899275a1ad..8d16b88d4ac 100644 --- a/test/test_lib.py +++ b/test/test_lib.py @@ -23,11 +23,11 @@ def test_list(run_command): result = run_command("lib list") assert result.ok assert "" == result.stderr - assert "" == result.stdout + assert "No libraries installed." == result.stdout.strip() result = run_command("lib list --format json") assert result.ok assert "" == result.stderr - assert "" == result.stdout + assert "null" == result.stdout # Install something we can list at a version older than latest result = run_command("lib install ArduinoJson@6.11.0") @@ -83,7 +83,7 @@ def test_search(run_command): result = run_command("lib search --names") assert result.ok - out_lines = result.stdout.splitlines() + out_lines = result.stdout.strip().splitlines() # Create an array with just the name of the vars libs = [] for line in out_lines: From 7e6f0c520610263a11b4c2a65ee429fe4d2969e0 Mon Sep 17 00:00:00 2001 From: Massimiliano Pippi Date: Fri, 20 Sep 2019 15:58:53 +0200 Subject: [PATCH 14/15] gone missing --- cli/board/list.go | 2 ++ go.mod | 1 + 2 files changed, 3 insertions(+) diff --git a/cli/board/list.go b/cli/board/list.go index f7db6bbed87..170b85dc8aa 100644 --- a/cli/board/list.go +++ b/cli/board/list.go @@ -18,10 +18,12 @@ package board import ( + "fmt" "os" "sort" "time" + "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/instance" diff --git a/go.mod b/go.mod index 048f2ce8093..1b43191b677 100644 --- a/go.mod +++ b/go.mod @@ -43,6 +43,7 @@ require ( go.bug.st/serial.v1 v0.0.0-20180827123349-5f7892a7bb45 golang.org/x/net v0.0.0-20190311183353-d8887717615a golang.org/x/text v0.3.0 + google.golang.org/appengine v1.4.0 // indirect google.golang.org/genproto v0.0.0-20190327125643-d831d65fe17d // indirect google.golang.org/grpc v1.21.1 gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce // indirect From 31e9e8ecd534578d13368a2e45c1cbec5fe03e7a Mon Sep 17 00:00:00 2001 From: Massimiliano Pippi Date: Wed, 9 Oct 2019 12:26:38 +0200 Subject: [PATCH 15/15] s/ouput/output --- cli/board/details.go | 2 +- cli/board/list.go | 2 +- cli/board/listall.go | 2 +- cli/config/dump.go | 2 +- cli/core/list.go | 2 +- cli/core/search.go | 2 +- cli/lib/list.go | 2 +- cli/lib/search.go | 2 +- test/test_lib.py | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cli/board/details.go b/cli/board/details.go index 40ff23aeeb8..f34e9b7a6db 100644 --- a/cli/board/details.go +++ b/cli/board/details.go @@ -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 diff --git a/cli/board/list.go b/cli/board/list.go index 170b85dc8aa..a8f73929cf8 100644 --- a/cli/board/list.go +++ b/cli/board/list.go @@ -70,7 +70,7 @@ func runListCommand(cmd *cobra.Command, args []string) { feedback.PrintResult(result{ports}) } -// 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 result struct { ports []*rpc.DetectedPort diff --git a/cli/board/listall.go b/cli/board/listall.go index 07856fb08de..47472a69cc6 100644 --- a/cli/board/listall.go +++ b/cli/board/listall.go @@ -60,7 +60,7 @@ func runListAllCommand(cmd *cobra.Command, args []string) { feedback.PrintResult(resultAll{list}) } -// 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 resultAll struct { list *rpc.BoardListAllResp diff --git a/cli/config/dump.go b/cli/config/dump.go index 9b83325aa7c..8b8787c8192 100644 --- a/cli/config/dump.go +++ b/cli/config/dump.go @@ -58,7 +58,7 @@ var dumpCmd = &cobra.Command{ Run: runDumpCommand, } -// 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 dumpResult struct { structured *jsonConfig diff --git a/cli/core/list.go b/cli/core/list.go index 8a0dae0e81a..c85fa4b290c 100644 --- a/cli/core/list.go +++ b/cli/core/list.go @@ -61,7 +61,7 @@ func runListCommand(cmd *cobra.Command, args []string) { feedback.PrintResult(installedResult{platforms}) } -// 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 installedResult struct { platforms []*cores.PlatformRelease diff --git a/cli/core/search.go b/cli/core/search.go index fee7a8be9d4..4d38e41a14b 100644 --- a/cli/core/search.go +++ b/cli/core/search.go @@ -63,7 +63,7 @@ func runSearchCommand(cmd *cobra.Command, args []string) { feedback.PrintResult(searchResults{coreslist}) } -// 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 searchResults struct { platforms []*rpc.Platform diff --git a/cli/lib/list.go b/cli/lib/list.go index 7717bb06993..495174caf0f 100644 --- a/cli/lib/list.go +++ b/cli/lib/list.go @@ -70,7 +70,7 @@ func runListCommand(cmd *cobra.Command, args []string) { logrus.Info("Done") } -// 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 installedResult struct { installedLibs []*rpc.InstalledLibrary diff --git a/cli/lib/search.go b/cli/lib/search.go index 670d47e6ec5..5c47df9019d 100644 --- a/cli/lib/search.go +++ b/cli/lib/search.go @@ -71,7 +71,7 @@ func runSearchCommand(cmd *cobra.Command, args []string) { logrus.Info("Done") } -// 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 result struct { results *rpc.LibrarySearchResp diff --git a/test/test_lib.py b/test/test_lib.py index 8d16b88d4ac..22f7fbff525 100644 --- a/test/test_lib.py +++ b/test/test_lib.py @@ -19,7 +19,7 @@ def test_list(run_command): # Init the environment explicitly assert run_command("core update-index") - # When ouput is empty, nothing is printed out, no matter the output format + # When output is empty, nothing is printed out, no matter the output format result = run_command("lib list") assert result.ok assert "" == result.stderr