Skip to content

Commit 673e3c2

Browse files
committed
Fix invalid JSON and YAML outputs for outdated command
Fixes issue #2104 The code for `internal/cli/core` and `internal/cli/lib` has been refactored so that we can use only the `Get` functions from `internal/cli/outdated` package and compose there composited object. For regular text output, the new table will have some extra fields that either for platforms or for libraries will be blank. For JSON and YAML output, the resulting object will have the top-level keys `platforms` and `libraries` which contain, respectively, the array of outaded platforms and outdated libraries. Signed-off-by: Lluís Martínez <[email protected]>
1 parent d5eb0b7 commit 673e3c2

File tree

7 files changed

+168
-16
lines changed

7 files changed

+168
-16
lines changed

Diff for: docs/UPGRADING.md

+42
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,48 @@ Here you can find a list of migration guides to handle breaking changes between
77
Configuration file lookup in current working directory and its parents is dropped. The command line flag `--config-file`
88
must be specified to use an alternative configuration file from the one in the data directory.
99

10+
### Command `outdated` output change
11+
12+
For `text` format (default), the command prints now a single table for platforms and libraries instead of two separate
13+
tables.
14+
15+
Similarly, for JSON and YAML formats, the command prints now a single valid object, with `platform` and `libraries`
16+
top-level keys. For example, for JSON output:
17+
18+
```
19+
$ arduino-cli outdated --format json
20+
{
21+
"platforms": [
22+
{
23+
"id": "arduino:avr",
24+
"installed": "1.6.3",
25+
"latest": "1.8.6",
26+
"name": "Arduino AVR Boards",
27+
...
28+
}
29+
],
30+
"libraries": [
31+
{
32+
"library": {
33+
"name": "USBHost",
34+
"author": "Arduino",
35+
"maintainer": "Arduino \[email protected]\u003e",
36+
"category": "Device Control",
37+
"version": "1.0.0",
38+
...
39+
},
40+
"release": {
41+
"author": "Arduino",
42+
"version": "1.0.5",
43+
"maintainer": "Arduino \[email protected]\u003e",
44+
"category": "Device Control",
45+
...
46+
}
47+
}
48+
]
49+
}
50+
```
51+
1052
## 0.31.0
1153

1254
### Added `post_install` script support for tools

Diff for: internal/cli/core/list.go

+8-3
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,14 @@ func runListCommand(args []string, all bool, updatableOnly bool) {
5252
List(inst, all, updatableOnly)
5353
}
5454

55-
// List print a list of installed platforms.
55+
// List gets and prints a list of installed platforms.
5656
func List(inst *rpc.Instance, all bool, updatableOnly bool) {
57+
platforms := GetList(inst, all, updatableOnly)
58+
feedback.PrintResult(installedResult{platforms})
59+
}
60+
61+
// GetList returns a list of installed platforms.
62+
func GetList(inst *rpc.Instance, all bool, updatableOnly bool) []*rpc.Platform {
5763
platforms, err := core.GetPlatforms(&rpc.PlatformListRequest{
5864
Instance: inst,
5965
UpdatableOnly: updatableOnly,
@@ -62,8 +68,7 @@ func List(inst *rpc.Instance, all bool, updatableOnly bool) {
6268
if err != nil {
6369
feedback.Fatal(tr("Error listing platforms: %v", err), feedback.ErrGeneric)
6470
}
65-
66-
feedback.PrintResult(installedResult{platforms})
71+
return platforms
6772
}
6873

6974
// output from this command requires special formatting, let's create a dedicated

Diff for: internal/cli/lib/list.go

+17-6
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,23 @@ func runListCommand(args []string, all bool, updatable bool) {
6060
List(instance, args, all, updatable)
6161
}
6262

63-
// List lists all the installed libraries.
63+
// List gets and prints a list of installed libraries.
6464
func List(instance *rpc.Instance, args []string, all bool, updatable bool) {
65+
installedLibs := GetList(instance, args, all, updatable)
66+
feedback.PrintResult(installedResult{
67+
onlyUpdates: updatable,
68+
installedLibs: installedLibs,
69+
})
70+
logrus.Info("Done")
71+
}
72+
73+
// GetList returns a list of installed libraries.
74+
func GetList(
75+
instance *rpc.Instance,
76+
args []string,
77+
all bool,
78+
updatable bool,
79+
) []*rpc.InstalledLibrary {
6580
name := ""
6681
if len(args) > 0 {
6782
name = args[0]
@@ -95,11 +110,7 @@ func List(instance *rpc.Instance, args []string, all bool, updatable bool) {
95110
libs = []*rpc.InstalledLibrary{}
96111
}
97112

98-
feedback.PrintResult(installedResult{
99-
onlyUpdates: updatable,
100-
installedLibs: libs,
101-
})
102-
logrus.Info("Done")
113+
return libs
103114
}
104115

105116
// output from this command requires special formatting, let's create a dedicated

Diff for: internal/cli/outdated/outdated.go

+97-3
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,18 @@
1616
package outdated
1717

1818
import (
19+
"fmt"
1920
"os"
21+
"sort"
22+
"strings"
2023

2124
"github.com/arduino/arduino-cli/i18n"
2225
"github.com/arduino/arduino-cli/internal/cli/core"
26+
"github.com/arduino/arduino-cli/internal/cli/feedback"
2327
"github.com/arduino/arduino-cli/internal/cli/instance"
2428
"github.com/arduino/arduino-cli/internal/cli/lib"
2529
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
30+
"github.com/arduino/arduino-cli/table"
2631
"github.com/sirupsen/logrus"
2732
"github.com/spf13/cobra"
2833
)
@@ -49,8 +54,97 @@ func runOutdatedCommand(cmd *cobra.Command, args []string) {
4954
Outdated(inst)
5055
}
5156

52-
// Outdated returns a list of outdated platforms and libraries
57+
// Outdated prints a list of outdated platforms and libraries
5358
func Outdated(inst *rpc.Instance) {
54-
core.List(inst, false, true)
55-
lib.List(inst, []string{}, false, true)
59+
feedback.PrintResult(
60+
outdatedResult{core.GetList(inst, false, true), lib.GetList(inst, []string{}, false, true)},
61+
)
62+
}
63+
64+
// output from this command requires special formatting, let's create a dedicated
65+
// feedback.Result implementation
66+
type outdatedResult struct {
67+
Platforms []*rpc.Platform `json:"platforms,omitempty"`
68+
InstalledLibs []*rpc.InstalledLibrary `json:"libraries,omitempty"`
69+
}
70+
71+
func (ir outdatedResult) Data() interface{} {
72+
return &ir
73+
}
74+
75+
func (ir outdatedResult) String() string {
76+
if len(ir.Platforms) == 0 && len(ir.InstalledLibs) == 0 {
77+
return tr("No outdated platforms or libraries found.")
78+
}
79+
80+
// A table useful both for platforms and libraries, where some of the fields will be blank.
81+
t := table.New()
82+
t.SetHeader(
83+
tr("ID"),
84+
tr("Name"),
85+
tr("Installed"),
86+
tr("Latest"),
87+
tr("Location"),
88+
tr("Description"),
89+
)
90+
t.SetColumnWidthMode(2, table.Average)
91+
t.SetColumnWidthMode(3, table.Average)
92+
t.SetColumnWidthMode(5, table.Average)
93+
94+
// Based on internal/cli/core/list.go
95+
for _, p := range ir.Platforms {
96+
name := p.Name
97+
if p.Deprecated {
98+
name = fmt.Sprintf("[%s] %s", tr("DEPRECATED"), name)
99+
}
100+
t.AddRow(p.Id, name, p.Installed, p.Latest, "", "")
101+
}
102+
103+
// Based on internal/cli/lib/list.go
104+
sort.Slice(ir.InstalledLibs, func(i, j int) bool {
105+
return strings.ToLower(
106+
ir.InstalledLibs[i].Library.Name,
107+
) < strings.ToLower(
108+
ir.InstalledLibs[j].Library.Name,
109+
) ||
110+
strings.ToLower(
111+
ir.InstalledLibs[i].Library.ContainerPlatform,
112+
) < strings.ToLower(
113+
ir.InstalledLibs[j].Library.ContainerPlatform,
114+
)
115+
})
116+
lastName := ""
117+
for _, libMeta := range ir.InstalledLibs {
118+
lib := libMeta.GetLibrary()
119+
name := lib.Name
120+
if name == lastName {
121+
name = ` "`
122+
} else {
123+
lastName = name
124+
}
125+
126+
location := lib.GetLocation().String()
127+
if lib.ContainerPlatform != "" {
128+
location = lib.GetContainerPlatform()
129+
}
130+
131+
available := ""
132+
sentence := ""
133+
if libMeta.GetRelease() != nil {
134+
available = libMeta.GetRelease().GetVersion()
135+
sentence = lib.Sentence
136+
}
137+
138+
if available == "" {
139+
available = "-"
140+
}
141+
if sentence == "" {
142+
sentence = "-"
143+
} else if len(sentence) > 40 {
144+
sentence = sentence[:37] + "..."
145+
}
146+
t.AddRow("", name, lib.Version, available, location, sentence)
147+
}
148+
149+
return t.Render()
56150
}

Diff for: internal/integrationtest/outdated/outdated_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ func TestOutdated(t *testing.T) {
5353
lines[i] = strings.TrimSpace(lines[i])
5454
}
5555
require.Contains(t, lines[1], "Arduino AVR Boards")
56-
require.Contains(t, lines[4], "USBHost")
56+
require.Contains(t, lines[2], "USBHost")
5757
}
5858

5959
func TestOutdatedUsingLibraryWithInvalidVersion(t *testing.T) {

Diff for: internal/integrationtest/update/update_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ func TestUpdateShowingOutdated(t *testing.T) {
6767
require.Contains(t, lines[0], "Downloading index: library_index.tar.bz2 downloaded")
6868
require.Contains(t, lines[1], "Downloading index: package_index.tar.bz2 downloaded")
6969
require.Contains(t, lines[3], "Arduino AVR Boards")
70-
require.Contains(t, lines[6], "USBHost")
70+
require.Contains(t, lines[4], "USBHost")
7171
}
7272

7373
func TestUpdateWithUrlNotFound(t *testing.T) {

Diff for: internal/integrationtest/upgrade/upgrade_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,15 @@ func TestUpgrade(t *testing.T) {
5050
require.NoError(t, err)
5151
lines := strings.Split(string(stdout), "\n")
5252
require.Contains(t, lines[1], "Arduino AVR Boards")
53-
require.Contains(t, lines[4], "USBHost")
53+
require.Contains(t, lines[2], "USBHost")
5454

5555
_, _, err = cli.Run("upgrade")
5656
require.NoError(t, err)
5757

5858
// Verifies cores and libraries have been updated
5959
stdout, _, err = cli.Run("outdated")
6060
require.NoError(t, err)
61-
require.Contains(t, string(stdout), "No libraries update is available.")
61+
require.Contains(t, string(stdout), "No outdated platforms or libraries found.")
6262
}
6363

6464
func TestUpgradeUsingLibraryWithInvalidVersion(t *testing.T) {

0 commit comments

Comments
 (0)