Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 94a5eeb

Browse files
author
Massimiliano Pippi
authoredOct 9, 2019
Make commands output agnostic (#391)
1 parent 63da3d8 commit 94a5eeb

File tree

16 files changed

+217
-185
lines changed

16 files changed

+217
-185
lines changed
 

‎cli/board/details.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func runDetailsCommand(cmd *cobra.Command, args []string) {
5454
feedback.PrintResult(detailsResult{details: res})
5555
}
5656

57-
// ouput from this command requires special formatting, let's create a dedicated
57+
// output from this command requires special formatting, let's create a dedicated
5858
// feedback.Result implementation
5959
type detailsResult struct {
6060
details *rpc.BoardDetailsResp

‎cli/board/list.go

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import (
2626
"github.com/arduino/arduino-cli/arduino/cores"
2727
"github.com/arduino/arduino-cli/cli/errorcodes"
2828
"github.com/arduino/arduino-cli/cli/feedback"
29-
"github.com/arduino/arduino-cli/cli/globals"
3029
"github.com/arduino/arduino-cli/cli/instance"
3130
"github.com/arduino/arduino-cli/commands/board"
3231
rpc "github.com/arduino/arduino-cli/rpc/commands"
@@ -68,27 +67,33 @@ func runListCommand(cmd *cobra.Command, args []string) {
6867
os.Exit(errorcodes.ErrNetwork)
6968
}
7069

71-
if globals.OutputFormat == "json" {
72-
feedback.PrintJSON(ports)
73-
} else {
74-
outputListResp(ports)
75-
}
70+
feedback.PrintResult(result{ports})
71+
}
72+
73+
// output from this command requires special formatting, let's create a dedicated
74+
// feedback.Result implementation
75+
type result struct {
76+
ports []*rpc.DetectedPort
7677
}
7778

78-
func outputListResp(ports []*rpc.DetectedPort) {
79-
if len(ports) == 0 {
80-
feedback.Print("No boards found.")
81-
return
79+
func (dr result) Data() interface{} {
80+
return dr.ports
81+
}
82+
83+
func (dr result) String() string {
84+
if len(dr.ports) == 0 {
85+
return "No boards found."
8286
}
83-
sort.Slice(ports, func(i, j int) bool {
84-
x, y := ports[i], ports[j]
87+
88+
sort.Slice(dr.ports, func(i, j int) bool {
89+
x, y := dr.ports[i], dr.ports[j]
8590
return x.GetProtocol() < y.GetProtocol() ||
8691
(x.GetProtocol() == y.GetProtocol() && x.GetAddress() < y.GetAddress())
8792
})
8893

8994
t := table.New()
9095
t.SetHeader("Port", "Type", "Board Name", "FQBN", "Core")
91-
for _, port := range ports {
96+
for _, port := range dr.ports {
9297
address := port.GetProtocol() + "://" + port.GetAddress()
9398
if port.GetProtocol() == "serial" {
9499
address = port.GetAddress()
@@ -123,5 +128,5 @@ func outputListResp(ports []*rpc.DetectedPort) {
123128
t.AddRow(address, protocol, board, fqbn, coreName)
124129
}
125130
}
126-
feedback.Print(t.Render())
131+
return t.Render()
127132
}

‎cli/board/listall.go

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import (
2424

2525
"github.com/arduino/arduino-cli/cli/errorcodes"
2626
"github.com/arduino/arduino-cli/cli/feedback"
27-
"github.com/arduino/arduino-cli/cli/globals"
2827
"github.com/arduino/arduino-cli/cli/instance"
2928
"github.com/arduino/arduino-cli/commands/board"
3029
rpc "github.com/arduino/arduino-cli/rpc/commands"
@@ -58,22 +57,28 @@ func runListAllCommand(cmd *cobra.Command, args []string) {
5857
os.Exit(errorcodes.ErrGeneric)
5958
}
6059

61-
if globals.OutputFormat == "json" {
62-
feedback.PrintJSON(list)
63-
} else {
64-
outputBoardListAll(list)
65-
}
60+
feedback.PrintResult(resultAll{list})
61+
}
62+
63+
// output from this command requires special formatting, let's create a dedicated
64+
// feedback.Result implementation
65+
type resultAll struct {
66+
list *rpc.BoardListAllResp
67+
}
68+
69+
func (dr resultAll) Data() interface{} {
70+
return dr.list
6671
}
6772

68-
func outputBoardListAll(list *rpc.BoardListAllResp) {
69-
sort.Slice(list.Boards, func(i, j int) bool {
70-
return list.Boards[i].GetName() < list.Boards[j].GetName()
73+
func (dr resultAll) String() string {
74+
sort.Slice(dr.list.Boards, func(i, j int) bool {
75+
return dr.list.Boards[i].GetName() < dr.list.Boards[j].GetName()
7176
})
7277

7378
t := table.New()
7479
t.SetHeader("Board Name", "FQBN")
75-
for _, item := range list.GetBoards() {
80+
for _, item := range dr.list.GetBoards() {
7681
t.AddRow(item.GetName(), item.GetFQBN())
7782
}
78-
feedback.Print(t.Render())
83+
return t.Render()
7984
}

‎cli/cli.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
"github.com/arduino/arduino-cli/cli/generatedocs"
3434
"github.com/arduino/arduino-cli/cli/globals"
3535
"github.com/arduino/arduino-cli/cli/lib"
36+
"github.com/arduino/arduino-cli/cli/output"
3637
"github.com/arduino/arduino-cli/cli/sketch"
3738
"github.com/arduino/arduino-cli/cli/upload"
3839
"github.com/arduino/arduino-cli/cli/version"
@@ -52,9 +53,10 @@ var (
5253
PersistentPreRun: preRun,
5354
}
5455

55-
verbose bool
56-
logFile string
57-
logFormat string
56+
verbose bool
57+
logFile string
58+
logFormat string
59+
outputFormat string
5860
)
5961

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

116118
func preRun(cmd *cobra.Command, args []string) {
117119
// normalize the format strings
118-
globals.OutputFormat = strings.ToLower(globals.OutputFormat)
120+
outputFormat = strings.ToLower(outputFormat)
121+
// configure the output package
122+
output.OutputFormat = outputFormat
119123
logFormat = strings.ToLower(logFormat)
120124

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

161165
// check the right output format was passed
162-
format, found := parseFormatString(globals.OutputFormat)
166+
format, found := parseFormatString(outputFormat)
163167
if !found {
164-
feedback.Error("Invalid output format: " + globals.OutputFormat)
168+
feedback.Error("Invalid output format: " + outputFormat)
165169
os.Exit(errorcodes.ErrBadCall)
166170
}
167171

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

176180
logrus.Info("Formatter set")
177-
if globals.OutputFormat != "text" {
181+
if outputFormat != "text" {
178182
cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
179183
logrus.Warn("Calling help on JSON format")
180184
feedback.Error("Invalid Call : should show Help, but it is available only in TEXT mode.")

‎cli/config/dump.go

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,21 @@ var dumpCmd = &cobra.Command{
5858
Run: runDumpCommand,
5959
}
6060

61+
// output from this command requires special formatting, let's create a dedicated
62+
// feedback.Result implementation
63+
type dumpResult struct {
64+
structured *jsonConfig
65+
plain string
66+
}
67+
68+
func (dr dumpResult) Data() interface{} {
69+
return dr.structured
70+
}
71+
72+
func (dr dumpResult) String() string {
73+
return dr.plain
74+
}
75+
6176
func runDumpCommand(cmd *cobra.Command, args []string) {
6277
logrus.Info("Executing `arduino config dump`")
6378

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

7085
c := globals.Config
7186

72-
if globals.OutputFormat == "json" {
73-
sketchbookDir := ""
74-
if c.SketchbookDir != nil {
75-
sketchbookDir = c.SketchbookDir.String()
76-
}
87+
sketchbookDir := ""
88+
if c.SketchbookDir != nil {
89+
sketchbookDir = c.SketchbookDir.String()
90+
}
7791

78-
arduinoDataDir := ""
79-
if c.DataDir != nil {
80-
arduinoDataDir = c.DataDir.String()
81-
}
92+
arduinoDataDir := ""
93+
if c.DataDir != nil {
94+
arduinoDataDir = c.DataDir.String()
95+
}
8296

83-
arduinoDownloadsDir := ""
84-
if c.ArduinoDownloadsDir != nil {
85-
arduinoDownloadsDir = c.ArduinoDownloadsDir.String()
86-
}
97+
arduinoDownloadsDir := ""
98+
if c.ArduinoDownloadsDir != nil {
99+
arduinoDownloadsDir = c.ArduinoDownloadsDir.String()
100+
}
87101

88-
feedback.PrintJSON(jsonConfig{
102+
feedback.PrintResult(&dumpResult{
103+
structured: &jsonConfig{
89104
ProxyType: c.ProxyType,
90105
ProxyManualConfig: &jsonProxyConfig{
91106
Hostname: c.ProxyHostname,
@@ -98,8 +113,7 @@ func runDumpCommand(cmd *cobra.Command, args []string) {
98113
BoardsManager: &jsonBoardsManagerConfig{
99114
AdditionalURLS: c.BoardManagerAdditionalUrls,
100115
},
101-
})
102-
} else {
103-
feedback.Print(string(data))
104-
}
116+
},
117+
plain: string(data),
118+
})
105119
}

‎cli/config/init.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ func initInitCommand() *cobra.Command {
4040
Args: cobra.NoArgs,
4141
Run: runInitCommand,
4242
}
43-
initCommand.Flags().BoolVar(&initFlags._default, "default", false,
44-
"If omitted, ask questions to the user about setting configuration properties, otherwise use default configuration.")
4543
initCommand.Flags().StringVar(&initFlags.location, "save-as", "",
4644
"Sets where to save the configuration file [default is ./arduino-cli.yaml].")
4745
return initCommand
@@ -55,13 +53,6 @@ var initFlags struct {
5553
func runInitCommand(cmd *cobra.Command, args []string) {
5654
logrus.Info("Executing `arduino config init`")
5755

58-
if !initFlags._default {
59-
if globals.OutputFormat != "text" {
60-
feedback.Error("The interactive mode is supported only in text mode.")
61-
os.Exit(errorcodes.ErrBadCall)
62-
}
63-
}
64-
6556
filepath := initFlags.location
6657
if filepath == "" {
6758
filepath = globals.Config.ConfigFile.String()

‎cli/core/list.go

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import (
2424
"github.com/arduino/arduino-cli/arduino/cores"
2525
"github.com/arduino/arduino-cli/cli/errorcodes"
2626
"github.com/arduino/arduino-cli/cli/feedback"
27-
"github.com/arduino/arduino-cli/cli/globals"
2827
"github.com/arduino/arduino-cli/cli/instance"
2928
"github.com/arduino/arduino-cli/commands/core"
3029
"github.com/arduino/arduino-cli/table"
@@ -59,26 +58,32 @@ func runListCommand(cmd *cobra.Command, args []string) {
5958
os.Exit(errorcodes.ErrGeneric)
6059
}
6160

62-
if globals.OutputFormat == "json" {
63-
feedback.PrintJSON(platforms)
64-
} else {
65-
outputInstalledCores(platforms)
66-
}
61+
feedback.PrintResult(installedResult{platforms})
62+
}
63+
64+
// output from this command requires special formatting, let's create a dedicated
65+
// feedback.Result implementation
66+
type installedResult struct {
67+
platforms []*cores.PlatformRelease
68+
}
69+
70+
func (ir installedResult) Data() interface{} {
71+
return ir.platforms
6772
}
6873

69-
func outputInstalledCores(platforms []*cores.PlatformRelease) {
70-
if platforms == nil || len(platforms) == 0 {
71-
return
74+
func (ir installedResult) String() string {
75+
if ir.platforms == nil || len(ir.platforms) == 0 {
76+
return ""
7277
}
7378

7479
t := table.New()
7580
t.SetHeader("ID", "Installed", "Latest", "Name")
76-
sort.Slice(platforms, func(i, j int) bool {
77-
return platforms[i].Platform.String() < platforms[j].Platform.String()
81+
sort.Slice(ir.platforms, func(i, j int) bool {
82+
return ir.platforms[i].Platform.String() < ir.platforms[j].Platform.String()
7883
})
79-
for _, p := range platforms {
84+
for _, p := range ir.platforms {
8085
t.AddRow(p.Platform.String(), p.Version.String(), p.Platform.GetLatestRelease().Version.String(), p.Platform.Name)
8186
}
8287

83-
feedback.Print(t.Render())
88+
return t.Render()
8489
}

‎cli/core/search.go

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import (
2525

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

5352
arguments := strings.ToLower(strings.Join(args, " "))
54-
55-
if globals.OutputFormat != "json" {
56-
feedback.Printf("Searching for platforms matching '%s'", arguments)
57-
}
58-
5953
resp, err := core.PlatformSearch(context.Background(), &rpc.PlatformSearchReq{
6054
Instance: instance,
6155
SearchArgs: arguments,
@@ -66,25 +60,30 @@ func runSearchCommand(cmd *cobra.Command, args []string) {
6660
}
6761

6862
coreslist := resp.GetSearchOutput()
69-
if globals.OutputFormat == "json" {
70-
feedback.PrintJSON(coreslist)
71-
} else {
72-
outputSearchCores(coreslist)
73-
}
63+
feedback.PrintResult(searchResults{coreslist})
64+
}
65+
66+
// output from this command requires special formatting, let's create a dedicated
67+
// feedback.Result implementation
68+
type searchResults struct {
69+
platforms []*rpc.Platform
70+
}
71+
72+
func (sr searchResults) Data() interface{} {
73+
return sr.platforms
7474
}
7575

76-
func outputSearchCores(cores []*rpc.Platform) {
77-
if len(cores) > 0 {
76+
func (sr searchResults) String() string {
77+
if len(sr.platforms) > 0 {
7878
t := table.New()
7979
t.SetHeader("ID", "Version", "Name")
80-
sort.Slice(cores, func(i, j int) bool {
81-
return cores[i].ID < cores[j].ID
80+
sort.Slice(sr.platforms, func(i, j int) bool {
81+
return sr.platforms[i].ID < sr.platforms[j].ID
8282
})
83-
for _, item := range cores {
83+
for _, item := range sr.platforms {
8484
t.AddRow(item.GetID(), item.GetLatest(), item.GetName())
8585
}
86-
feedback.Print(t.Render())
87-
} else {
88-
feedback.Print("No platforms matching your search.")
86+
return t.Render()
8987
}
88+
return "No platforms matching your search."
9089
}

‎cli/feedback/exported.go

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ func Printf(format string, v ...interface{}) {
5252
}
5353

5454
// Print behaves like fmt.Print but writes on the out writer and adds a newline.
55-
func Print(v ...interface{}) {
56-
fb.Print(v...)
55+
func Print(v interface{}) {
56+
fb.Print(v)
5757
}
5858

5959
// Errorf behaves like fmt.Printf but writes on the error writer and adds a
@@ -68,13 +68,9 @@ func Error(v ...interface{}) {
6868
fb.Error(v...)
6969
}
7070

71-
// PrintJSON is a convenient wrapper to provide feedback by printing the
72-
// desired output in a pretty JSON format. It adds a newline to the output.
73-
func PrintJSON(v interface{}) {
74-
fb.PrintJSON(v)
75-
}
76-
77-
// PrintResult is a convenient wrapper...
71+
// PrintResult is a convenient wrapper to provide feedback for complex data,
72+
// where the contents can't be just serialized to JSON but requires more
73+
// structure.
7874
func PrintResult(res Result) {
7975
fb.PrintResult(res)
8076
}

‎cli/feedback/feedback.go

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,12 @@ func (fb *Feedback) Printf(format string, v ...interface{}) {
8686
}
8787

8888
// Print behaves like fmt.Print but writes on the out writer and adds a newline.
89-
func (fb *Feedback) Print(v ...interface{}) {
90-
fmt.Fprintln(fb.out, v...)
89+
func (fb *Feedback) Print(v interface{}) {
90+
if fb.format == JSON {
91+
fb.printJSON(v)
92+
} else {
93+
fmt.Fprintln(fb.out, v)
94+
}
9195
}
9296

9397
// Errorf behaves like fmt.Printf but writes on the error writer and adds a
@@ -103,24 +107,22 @@ func (fb *Feedback) Error(v ...interface{}) {
103107
logrus.Error(fmt.Sprint(v...))
104108
}
105109

106-
// PrintJSON is a convenient wrapper to provide feedback by printing the
110+
// printJSON is a convenient wrapper to provide feedback by printing the
107111
// desired output in a pretty JSON format. It adds a newline to the output.
108-
func (fb *Feedback) PrintJSON(v interface{}) {
112+
func (fb *Feedback) printJSON(v interface{}) {
109113
if d, err := json.MarshalIndent(v, "", " "); err != nil {
110114
fb.Errorf("Error during JSON encoding of the output: %v", err)
111115
} else {
112-
fb.Print(string(d))
116+
fmt.Fprint(fb.out, string(d))
113117
}
114118
}
115119

116-
// PrintResult is a convenient wrapper...
120+
// PrintResult is a convenient wrapper to provide feedback for complex data,
121+
// where the contents can't be just serialized to JSON but requires more
122+
// structure.
117123
func (fb *Feedback) PrintResult(res Result) {
118124
if fb.format == JSON {
119-
if d, err := json.MarshalIndent(res.Data(), "", " "); err != nil {
120-
fb.Errorf("Error during JSON encoding of the output: %v", err)
121-
} else {
122-
fb.Print(string(d))
123-
}
125+
fb.printJSON(res.Data())
124126
} else {
125127
fb.Print(fmt.Sprintf("%s", res))
126128
}

‎cli/globals/globals.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ import (
2929
var (
3030
// Debug determines whether to dump debug output to stderr or not
3131
Debug bool
32-
// OutputFormat can be "text" or "json"
33-
OutputFormat string
3432
// VersionInfo contains all info injected during build
3533
VersionInfo = version.NewInfo(filepath.Base(os.Args[0]))
3634
// Config FIXMEDOC

‎cli/lib/list.go

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222

2323
"github.com/arduino/arduino-cli/cli/errorcodes"
2424
"github.com/arduino/arduino-cli/cli/feedback"
25-
"github.com/arduino/arduino-cli/cli/globals"
2625
"github.com/arduino/arduino-cli/cli/instance"
2726
"github.com/arduino/arduino-cli/commands/lib"
2827
rpc "github.com/arduino/arduino-cli/rpc/commands"
@@ -66,27 +65,31 @@ func runListCommand(cmd *cobra.Command, args []string) {
6665
}
6766

6867
libs := res.GetInstalledLibrary()
69-
if libs != nil {
70-
if globals.OutputFormat == "json" {
71-
feedback.PrintJSON(libs)
72-
} else {
73-
outputListLibrary(libs)
74-
}
75-
}
68+
feedback.PrintResult(installedResult{libs})
7669

7770
logrus.Info("Done")
7871
}
7972

80-
func outputListLibrary(il []*rpc.InstalledLibrary) {
81-
if il == nil || len(il) == 0 {
82-
return
73+
// output from this command requires special formatting, let's create a dedicated
74+
// feedback.Result implementation
75+
type installedResult struct {
76+
installedLibs []*rpc.InstalledLibrary
77+
}
78+
79+
func (ir installedResult) Data() interface{} {
80+
return ir.installedLibs
81+
}
82+
83+
func (ir installedResult) String() string {
84+
if ir.installedLibs == nil || len(ir.installedLibs) == 0 {
85+
return "No libraries installed."
8386
}
8487

8588
t := table.New()
8689
t.SetHeader("Name", "Installed", "Available", "Location")
8790

8891
lastName := ""
89-
for _, libMeta := range il {
92+
for _, libMeta := range ir.installedLibs {
9093
lib := libMeta.GetLibrary()
9194
name := lib.Name
9295
if name == lastName {
@@ -110,5 +113,5 @@ func outputListLibrary(il []*rpc.InstalledLibrary) {
110113
}
111114
}
112115

113-
feedback.Print(t.Render())
116+
return t.Render()
114117
}

‎cli/lib/search.go

Lines changed: 57 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import (
2626

2727
"github.com/arduino/arduino-cli/cli/errorcodes"
2828
"github.com/arduino/arduino-cli/cli/feedback"
29-
"github.com/arduino/arduino-cli/cli/globals"
3029
"github.com/arduino/arduino-cli/cli/instance"
3130
"github.com/arduino/arduino-cli/commands/lib"
3231
rpc "github.com/arduino/arduino-cli/rpc/commands"
@@ -64,63 +63,76 @@ func runSearchCommand(cmd *cobra.Command, args []string) {
6463
os.Exit(errorcodes.ErrGeneric)
6564
}
6665

67-
if globals.OutputFormat == "json" {
68-
if searchFlags.namesOnly {
69-
type LibName struct {
70-
Name string `json:"name,required"`
71-
}
72-
73-
type NamesOnly struct {
74-
Libraries []LibName `json:"libraries,required"`
75-
}
76-
77-
names := []LibName{}
78-
results := searchResp.GetLibraries()
79-
for _, lsr := range results {
80-
names = append(names, LibName{lsr.Name})
81-
}
82-
feedback.PrintJSON(NamesOnly{
83-
names,
84-
})
85-
} else {
86-
feedback.PrintJSON(searchResp)
66+
feedback.PrintResult(result{
67+
results: searchResp,
68+
namesOnly: searchFlags.namesOnly,
69+
})
70+
71+
logrus.Info("Done")
72+
}
73+
74+
// output from this command requires special formatting, let's create a dedicated
75+
// feedback.Result implementation
76+
type result struct {
77+
results *rpc.LibrarySearchResp
78+
namesOnly bool
79+
}
80+
81+
func (res result) Data() interface{} {
82+
if res.namesOnly {
83+
type LibName struct {
84+
Name string `json:"name,required"`
85+
}
86+
87+
type NamesOnly struct {
88+
Libraries []LibName `json:"libraries,required"`
89+
}
90+
91+
names := []LibName{}
92+
results := res.results.GetLibraries()
93+
for _, lsr := range results {
94+
names = append(names, LibName{lsr.Name})
95+
}
96+
97+
return NamesOnly{
98+
names,
8799
}
88-
} else {
89-
// get a sorted slice of results
90-
results := searchResp.GetLibraries()
91-
sort.Slice(results, func(i, j int) bool {
92-
return results[i].Name < results[j].Name
93-
})
94-
95-
// print all the things
96-
outputSearchedLibrary(results, searchFlags.namesOnly)
97100
}
98101

99-
logrus.Info("Done")
102+
return res.results
100103
}
101104

102-
func outputSearchedLibrary(results []*rpc.SearchedLibrary, namesOnly bool) {
105+
func (res result) String() string {
106+
results := res.results.GetLibraries()
103107
if len(results) == 0 {
104-
feedback.Print("No libraries matching your search.")
105-
return
108+
return "No libraries matching your search."
106109
}
107110

111+
// get a sorted slice of results
112+
sort.Slice(results, func(i, j int) bool {
113+
return results[i].Name < results[j].Name
114+
})
115+
116+
var out strings.Builder
117+
108118
for _, lsr := range results {
109-
feedback.Printf(`Name: "%s"`, lsr.Name)
110-
if namesOnly {
119+
out.WriteString(fmt.Sprintf("Name: \"%s\"\n", lsr.Name))
120+
if res.namesOnly {
111121
continue
112122
}
113123

114-
feedback.Printf(" Author: %s", lsr.GetLatest().Author)
115-
feedback.Printf(" Maintainer: %s", lsr.GetLatest().Maintainer)
116-
feedback.Printf(" Sentence: %s", lsr.GetLatest().Sentence)
117-
feedback.Printf(" Paragraph: %s", lsr.GetLatest().Paragraph)
118-
feedback.Printf(" Website: %s", lsr.GetLatest().Website)
119-
feedback.Printf(" Category: %s", lsr.GetLatest().Category)
120-
feedback.Printf(" Architecture: %s", strings.Join(lsr.GetLatest().Architectures, ", "))
121-
feedback.Printf(" Types: %s", strings.Join(lsr.GetLatest().Types, ", "))
122-
feedback.Printf(" Versions: %s", strings.Replace(fmt.Sprint(versionsFromSearchedLibrary(lsr)), " ", ", ", -1))
124+
out.WriteString(fmt.Sprintf(" Author: %s\n", lsr.GetLatest().Author))
125+
out.WriteString(fmt.Sprintf(" Maintainer: %s\n", lsr.GetLatest().Maintainer))
126+
out.WriteString(fmt.Sprintf(" Sentence: %s\n", lsr.GetLatest().Sentence))
127+
out.WriteString(fmt.Sprintf(" Paragraph: %s\n", lsr.GetLatest().Paragraph))
128+
out.WriteString(fmt.Sprintf(" Website: %s\n", lsr.GetLatest().Website))
129+
out.WriteString(fmt.Sprintf(" Category: %s\n", lsr.GetLatest().Category))
130+
out.WriteString(fmt.Sprintf(" Architecture: %s\n", strings.Join(lsr.GetLatest().Architectures, ", ")))
131+
out.WriteString(fmt.Sprintf(" Types: %s\n", strings.Join(lsr.GetLatest().Types, ", ")))
132+
out.WriteString(fmt.Sprintf(" Versions: %s\n", strings.Replace(fmt.Sprint(versionsFromSearchedLibrary(lsr)), " ", ", ", -1)))
123133
}
134+
135+
return fmt.Sprintf("%s", out.String())
124136
}
125137

126138
func versionsFromSearchedLibrary(library *rpc.SearchedLibrary) []*semver.Version {

‎cli/output/rpc_progress.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,18 @@ package output
2020
import (
2121
"fmt"
2222

23-
"github.com/arduino/arduino-cli/cli/globals"
2423
"github.com/arduino/arduino-cli/commands"
2524
rpc "github.com/arduino/arduino-cli/rpc/commands"
2625
"github.com/cmaglie/pb"
2726
)
2827

28+
// OutputFormat can be "text" or "json"
29+
var OutputFormat string
30+
2931
// ProgressBar returns a DownloadProgressCB that prints a progress bar.
3032
// If JSON output format has been selected, the callback outputs nothing.
3133
func ProgressBar() commands.DownloadProgressCB {
32-
if globals.OutputFormat != "json" {
34+
if OutputFormat != "json" {
3335
return NewDownloadProgressBarCB()
3436
}
3537
return func(curr *rpc.DownloadProgress) {
@@ -40,7 +42,7 @@ func ProgressBar() commands.DownloadProgressCB {
4042
// TaskProgress returns a TaskProgressCB that prints the task progress.
4143
// If JSON output format has been selected, the callback outputs nothing.
4244
func TaskProgress() commands.TaskProgressCB {
43-
if globals.OutputFormat != "json" {
45+
if OutputFormat != "json" {
4446
return NewTaskProgressCB()
4547
}
4648
return func(curr *rpc.TaskProgress) {

‎cli/version/version.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,5 @@ func NewCommand() *cobra.Command {
3838
}
3939

4040
func run(cmd *cobra.Command, args []string) {
41-
if globals.OutputFormat == "json" {
42-
feedback.PrintJSON(globals.VersionInfo)
43-
} else {
44-
feedback.Print(globals.VersionInfo)
45-
}
41+
feedback.Print(globals.VersionInfo)
4642
}

‎test/test_lib.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@ def test_list(run_command):
1919
# Init the environment explicitly
2020
assert run_command("core update-index")
2121

22-
# When ouput is empty, nothing is printed out, no matter the output format
22+
# When output is empty, nothing is printed out, no matter the output format
2323
result = run_command("lib list")
2424
assert result.ok
2525
assert "" == result.stderr
26-
assert "" == result.stdout
26+
assert "No libraries installed." == result.stdout.strip()
2727
result = run_command("lib list --format json")
2828
assert result.ok
2929
assert "" == result.stderr
30-
assert "" == result.stdout
30+
assert "null" == result.stdout
3131

3232
# Install something we can list at a version older than latest
3333
result = run_command("lib install ArduinoJson@6.11.0")
@@ -83,7 +83,7 @@ def test_search(run_command):
8383

8484
result = run_command("lib search --names")
8585
assert result.ok
86-
out_lines = result.stdout.splitlines()
86+
out_lines = result.stdout.strip().splitlines()
8787
# Create an array with just the name of the vars
8888
libs = []
8989
for line in out_lines:

0 commit comments

Comments
 (0)
Please sign in to comment.