Skip to content

Fix invalid JSON and YAML outputs for outdated command #2111

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
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions docs/UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,48 @@ Here you can find a list of migration guides to handle breaking changes between
Configuration file lookup in current working directory and its parents is dropped. The command line flag `--config-file`
must be specified to use an alternative configuration file from the one in the data directory.

### Command `outdated` output change

For `text` format (default), the command prints now a single table for platforms and libraries instead of two separate
tables.

Similarly, for JSON and YAML formats, the command prints now a single valid object, with `platform` and `libraries`
top-level keys. For example, for JSON output:

```
$ arduino-cli outdated --format json
{
"platforms": [
{
"id": "arduino:avr",
"installed": "1.6.3",
"latest": "1.8.6",
"name": "Arduino AVR Boards",
...
}
],
"libraries": [
{
"library": {
"name": "USBHost",
"author": "Arduino",
"maintainer": "Arduino \[email protected]\u003e",
"category": "Device Control",
"version": "1.0.0",
...
},
"release": {
"author": "Arduino",
"version": "1.0.5",
"maintainer": "Arduino \[email protected]\u003e",
"category": "Device Control",
...
}
}
]
}
```

## 0.31.0

### Added `post_install` script support for tools
Expand Down
11 changes: 8 additions & 3 deletions internal/cli/core/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,14 @@ func runListCommand(args []string, all bool, updatableOnly bool) {
List(inst, all, updatableOnly)
}

// List print a list of installed platforms.
// List gets and prints a list of installed platforms.
func List(inst *rpc.Instance, all bool, updatableOnly bool) {
platforms := GetList(inst, all, updatableOnly)
feedback.PrintResult(installedResult{platforms})
}

// GetList returns a list of installed platforms.
func GetList(inst *rpc.Instance, all bool, updatableOnly bool) []*rpc.Platform {
platforms, err := core.GetPlatforms(&rpc.PlatformListRequest{
Instance: inst,
UpdatableOnly: updatableOnly,
Expand All @@ -62,8 +68,7 @@ func List(inst *rpc.Instance, all bool, updatableOnly bool) {
if err != nil {
feedback.Fatal(tr("Error listing platforms: %v", err), feedback.ErrGeneric)
}

feedback.PrintResult(installedResult{platforms})
return platforms
}

// output from this command requires special formatting, let's create a dedicated
Expand Down
23 changes: 17 additions & 6 deletions internal/cli/lib/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,23 @@ func runListCommand(args []string, all bool, updatable bool) {
List(instance, args, all, updatable)
}

// List lists all the installed libraries.
// List gets and prints a list of installed libraries.
func List(instance *rpc.Instance, args []string, all bool, updatable bool) {
installedLibs := GetList(instance, args, all, updatable)
feedback.PrintResult(installedResult{
onlyUpdates: updatable,
installedLibs: installedLibs,
})
logrus.Info("Done")
}

// GetList returns a list of installed libraries.
func GetList(
instance *rpc.Instance,
args []string,
all bool,
updatable bool,
) []*rpc.InstalledLibrary {
name := ""
if len(args) > 0 {
name = args[0]
Expand Down Expand Up @@ -95,11 +110,7 @@ func List(instance *rpc.Instance, args []string, all bool, updatable bool) {
libs = []*rpc.InstalledLibrary{}
}

feedback.PrintResult(installedResult{
onlyUpdates: updatable,
installedLibs: libs,
})
logrus.Info("Done")
return libs
}

// output from this command requires special formatting, let's create a dedicated
Expand Down
100 changes: 97 additions & 3 deletions internal/cli/outdated/outdated.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,18 @@
package outdated

import (
"fmt"
"os"
"sort"
"strings"

"github.com/arduino/arduino-cli/i18n"
"github.com/arduino/arduino-cli/internal/cli/core"
"github.com/arduino/arduino-cli/internal/cli/feedback"
"github.com/arduino/arduino-cli/internal/cli/instance"
"github.com/arduino/arduino-cli/internal/cli/lib"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
"github.com/arduino/arduino-cli/table"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
Expand All @@ -49,8 +54,97 @@ func runOutdatedCommand(cmd *cobra.Command, args []string) {
Outdated(inst)
}

// Outdated returns a list of outdated platforms and libraries
// Outdated prints a list of outdated platforms and libraries
func Outdated(inst *rpc.Instance) {
core.List(inst, false, true)
lib.List(inst, []string{}, false, true)
feedback.PrintResult(
outdatedResult{core.GetList(inst, false, true), lib.GetList(inst, []string{}, false, true)},
)
}

// output from this command requires special formatting, let's create a dedicated
// feedback.Result implementation
type outdatedResult struct {
Platforms []*rpc.Platform `json:"platforms,omitempty"`
InstalledLibs []*rpc.InstalledLibrary `json:"libraries,omitempty"`
}

func (ir outdatedResult) Data() interface{} {
return &ir
}

func (ir outdatedResult) String() string {
if len(ir.Platforms) == 0 && len(ir.InstalledLibs) == 0 {
return tr("No outdated platforms or libraries found.")
}

// A table useful both for platforms and libraries, where some of the fields will be blank.
t := table.New()
t.SetHeader(
tr("ID"),
tr("Name"),
tr("Installed"),
tr("Latest"),
tr("Location"),
tr("Description"),
)
t.SetColumnWidthMode(2, table.Average)
t.SetColumnWidthMode(3, table.Average)
t.SetColumnWidthMode(5, table.Average)

// Based on internal/cli/core/list.go
for _, p := range ir.Platforms {
name := p.Name
if p.Deprecated {
name = fmt.Sprintf("[%s] %s", tr("DEPRECATED"), name)
}
t.AddRow(p.Id, name, p.Installed, p.Latest, "", "")
}

// Based on internal/cli/lib/list.go
sort.Slice(ir.InstalledLibs, func(i, j int) bool {
return strings.ToLower(
ir.InstalledLibs[i].Library.Name,
) < strings.ToLower(
ir.InstalledLibs[j].Library.Name,
) ||
strings.ToLower(
ir.InstalledLibs[i].Library.ContainerPlatform,
) < strings.ToLower(
ir.InstalledLibs[j].Library.ContainerPlatform,
)
})
lastName := ""
for _, libMeta := range ir.InstalledLibs {
lib := libMeta.GetLibrary()
name := lib.Name
if name == lastName {
name = ` "`
} else {
lastName = name
}

location := lib.GetLocation().String()
if lib.ContainerPlatform != "" {
location = lib.GetContainerPlatform()
}

available := ""
sentence := ""
if libMeta.GetRelease() != nil {
available = libMeta.GetRelease().GetVersion()
sentence = lib.Sentence
}

if available == "" {
available = "-"
}
if sentence == "" {
sentence = "-"
} else if len(sentence) > 40 {
sentence = sentence[:37] + "..."
}
t.AddRow("", name, lib.Version, available, location, sentence)
}

return t.Render()
}
2 changes: 1 addition & 1 deletion internal/integrationtest/outdated/outdated_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func TestOutdated(t *testing.T) {
lines[i] = strings.TrimSpace(lines[i])
}
require.Contains(t, lines[1], "Arduino AVR Boards")
require.Contains(t, lines[4], "USBHost")
require.Contains(t, lines[2], "USBHost")
}

func TestOutdatedUsingLibraryWithInvalidVersion(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion internal/integrationtest/update/update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func TestUpdateShowingOutdated(t *testing.T) {
require.Contains(t, lines[0], "Downloading index: library_index.tar.bz2 downloaded")
require.Contains(t, lines[1], "Downloading index: package_index.tar.bz2 downloaded")
require.Contains(t, lines[3], "Arduino AVR Boards")
require.Contains(t, lines[6], "USBHost")
require.Contains(t, lines[4], "USBHost")
}

func TestUpdateWithUrlNotFound(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions internal/integrationtest/upgrade/upgrade_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ func TestUpgrade(t *testing.T) {
require.NoError(t, err)
lines := strings.Split(string(stdout), "\n")
require.Contains(t, lines[1], "Arduino AVR Boards")
require.Contains(t, lines[4], "USBHost")
require.Contains(t, lines[2], "USBHost")

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

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

func TestUpgradeUsingLibraryWithInvalidVersion(t *testing.T) {
Expand Down