Skip to content

Enhance "board details" command #674

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 17 commits into from
Apr 24, 2020
5 changes: 4 additions & 1 deletion arduino/cores/packageindex/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type indexPackage struct {
Name string `json:"name,required"`
Maintainer string `json:"maintainer,required"`
WebsiteURL string `json:"websiteUrl"`
URL string `json:"Url"`
Email string `json:"email"`
Platforms []*indexPlatformRelease `json:"platforms,required"`
Tools []*indexToolRelease `json:"tools,required"`
Expand Down Expand Up @@ -94,7 +95,7 @@ type indexHelp struct {
}

// MergeIntoPackages converts the Index data into a cores.Packages and merge them
// with the existing conents of the cores.Packages passed as parameter.
// with the existing contents of the cores.Packages passed as parameter.
func (index Index) MergeIntoPackages(outPackages cores.Packages) {
for _, inPackage := range index.Packages {
inPackage.extractPackageIn(outPackages)
Expand All @@ -105,7 +106,9 @@ func (inPackage indexPackage) extractPackageIn(outPackages cores.Packages) {
outPackage := outPackages.GetOrCreatePackage(inPackage.Name)
outPackage.Maintainer = inPackage.Maintainer
outPackage.WebsiteURL = inPackage.WebsiteURL
outPackage.URL = inPackage.URL
outPackage.Email = inPackage.Email
outPackage.Help = cores.PackageHelp{Online: inPackage.Help.Online}

for _, inTool := range inPackage.Tools {
inTool.extractToolIn(outPackage)
Expand Down
14 changes: 12 additions & 2 deletions arduino/cores/packagemanager/package_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,18 @@ func (pm *PackageManager) ResolveFQBN(fqbn *cores.FQBN) (

// LoadPackageIndex loads a package index by looking up the local cached file from the specified URL
func (pm *PackageManager) LoadPackageIndex(URL *url.URL) error {
_, err := pm.LoadPackageIndexFromFile(pm.IndexDir.Join(path.Base(URL.Path)))
return err
indexPath := pm.IndexDir.Join(path.Base(URL.Path))
index, err := packageindex.LoadIndex(indexPath)
if err != nil {
return fmt.Errorf("loading json index file %s: %s", indexPath, err)
}

for _, p := range index.Packages {
p.URL = URL.String()
}

index.MergeIntoPackages(pm.Packages)
return nil
}

// LoadPackageIndexFromFile load a package index from the specified file
Expand Down
7 changes: 7 additions & 0 deletions arduino/cores/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,21 @@ func NewPackages() Packages {
return map[string]*Package{}
}

// PackageHelp contains info on how to reach maintainers for help
type PackageHelp struct {
Online string `json:"online,omitempty"`
}

// Package represents a package in the system.
type Package struct {
Name string // Name of the package.
Maintainer string // Name of the maintainer.
WebsiteURL string // Website of maintainer.
URL string // origin URL for package index json file.
Email string // Email of maintainer.
Platforms map[string]*Platform // The platforms in the system.
Tools map[string]*Tool // The tools in the system.
Help PackageHelp `json:"-"`
Packages Packages `json:"-"`
}

Expand Down
2 changes: 1 addition & 1 deletion cli/board/board.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func NewCommand() *cobra.Command {
}

boardCommand.AddCommand(initAttachCommand())
boardCommand.AddCommand(detailsCommand)
boardCommand.AddCommand(initDetailsCommand())
boardCommand.AddCommand(initListCommand())
boardCommand.AddCommand(listAllCommand)

Expand Down
74 changes: 61 additions & 13 deletions cli/board/details.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ package board

import (
"context"
"os"

"fmt"
"github.com/arduino/arduino-cli/cli/errorcodes"
"github.com/arduino/arduino-cli/cli/feedback"
"github.com/arduino/arduino-cli/cli/instance"
Expand All @@ -27,15 +26,24 @@ import (
"github.com/arduino/arduino-cli/table"
"github.com/fatih/color"
"github.com/spf13/cobra"
"os"
)

var detailsCommand = &cobra.Command{
Use: "details <FQBN>",
Short: "Print details about a board.",
Long: "Show information about a board, in particular if the board has options to be specified in the FQBN.",
Example: " " + os.Args[0] + " board details arduino:avr:nano",
Args: cobra.ExactArgs(1),
Run: runDetailsCommand,
var showFullDetails bool

func initDetailsCommand() *cobra.Command {
var detailsCommand = &cobra.Command{
Use: "details <FQBN>",
Short: "Print details about a board.",
Long: "Show information about a board, in particular if the board has options to be specified in the FQBN.",
Example: " " + os.Args[0] + " board details arduino:avr:nano",
Args: cobra.ExactArgs(1),
Run: runDetailsCommand,
}

detailsCommand.Flags().BoolVarP(&showFullDetails, "full", "f", false, "Include full details in text output")

return detailsCommand
}

func runDetailsCommand(cmd *cobra.Command, args []string) {
Expand Down Expand Up @@ -85,18 +93,58 @@ func (dr detailsResult) String() string {
t := table.New()
t.SetColumnWidthMode(1, table.Average)
t.AddRow("Board name:", details.Name)
t.AddRow("Board fqbn:", details.Fqbn)
t.AddRow("Board propertiesId:", details.PropertiesId)
t.AddRow("Board version:", details.Version)

if details.Official {
t.AddRow() // get some space from above
t.AddRow("Official Arduino board:",
table.NewCell("✔", color.New(color.FgGreen)))
}

for i, tool := range details.RequiredTools {
for i, idp := range details.IdentificationPref {
if i == 0 {
t.AddRow() // get some space from above
t.AddRow("Required tools:", tool.Packager+":"+tool.Name, "", tool.Version)
t.AddRow("Identification Preferences:", "VID:"+idp.UsbID.VID+" PID:"+idp.UsbID.PID)
continue
}
t.AddRow("", tool.Packager+":"+tool.Name, "", tool.Version)
t.AddRow("", "VID:"+idp.UsbID.VID+" PID:"+idp.UsbID.PID)
}

for _, option := range details.ConfigOptions {
t.AddRow() // get some space from above
t.AddRow("Package name:", details.Package.Name)
t.AddRow("Package maintainer:", details.Package.Maintainer)
t.AddRow("Package URL:", details.Package.Url)
t.AddRow("Package websiteURL:", details.Package.WebsiteURL)
t.AddRow("Package online help:", details.Package.Help.Online)

t.AddRow() // get some space from above
t.AddRow("Platform name:", details.Platform.Name)
t.AddRow("Platform category:", details.Platform.Category)
t.AddRow("Platform architecture:", details.Platform.Architecture)
t.AddRow("Platform URL:", details.Platform.Url)
t.AddRow("Platform file name:", details.Platform.ArchiveFileName)
t.AddRow("Platform size (bytes):", fmt.Sprint(details.Platform.Size))
t.AddRow("Platform checksum:", details.Platform.Checksum)

t.AddRow() // get some space from above
for _, tool := range details.ToolsDependencies {
t.AddRow("Required tools:", tool.Packager+":"+tool.Name, "", tool.Version)
if showFullDetails {
for _, sys := range tool.Systems {
t.AddRow("", "OS:", "", sys.Host)
t.AddRow("", "File:", "", sys.ArchiveFileName)
t.AddRow("", "Size (bytes):", "", fmt.Sprint(sys.Size))
t.AddRow("", "Checksum:", "", sys.Checksum)
t.AddRow("", "URL:", "", sys.Url)
t.AddRow() // get some space from above
}
}
t.AddRow() // get some space from above
}

for _, option := range details.ConfigOptions {
t.AddRow("Option:", option.OptionLabel, "", option.Option)
for _, value := range option.Values {
green := color.New(color.FgGreen)
Expand Down
66 changes: 57 additions & 9 deletions commands/board/details.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ import (
rpc "github.com/arduino/arduino-cli/rpc/commands"
)

// Details FIXMEDOC
// Details returns all details for a board including tools and HW identifiers.
// This command basically gather al the information and translates it into the required grpc struct properties
func Details(ctx context.Context, req *rpc.BoardDetailsReq) (*rpc.BoardDetailsResp, error) {
pm := commands.GetPackageManager(req.GetInstance().GetId())
if pm == nil {
Expand All @@ -37,13 +38,47 @@ func Details(ctx context.Context, req *rpc.BoardDetailsReq) (*rpc.BoardDetailsRe
return nil, fmt.Errorf("parsing fqbn: %s", err)
}

_, _, board, _, _, err := pm.ResolveFQBN(fqbn)
boardPackage, boardPlatform, board, _, _, err := pm.ResolveFQBN(fqbn)
if err != nil {
return nil, fmt.Errorf("loading board data: %s", err)
}

details := &rpc.BoardDetailsResp{}
details.Name = board.Name()
details.Fqbn = board.FQBN()
details.PropertiesId = board.BoardID
details.Official = fqbn.Package == "arduino"
details.Version = board.PlatformRelease.Version.String()

details.Package = &rpc.Package{
Name: boardPackage.Name,
Maintainer: boardPackage.Maintainer,
WebsiteURL: boardPackage.WebsiteURL,
Email: boardPackage.Email,
Help: &rpc.Help{Online: boardPackage.Help.Online},
Url: boardPackage.URL,
}

details.Platform = &rpc.BoardPlatform{
Architecture: boardPlatform.Platform.Architecture,
Category: boardPlatform.Platform.Category,
Url: boardPlatform.Resource.URL,
ArchiveFileName: boardPlatform.Resource.ArchiveFileName,
Checksum: boardPlatform.Resource.Checksum,
Size: boardPlatform.Resource.Size,
Name: boardPlatform.Platform.Name,
}

details.IdentificationPref = []*rpc.IdentificationPref{}
vids := board.Properties.SubTree("vid")
pids := board.Properties.SubTree("pid")
for id, vid := range vids.AsMap() {
if pid, ok := pids.GetOk(id); ok {
idPref := rpc.IdentificationPref{UsbID: &rpc.USBID{VID: vid, PID: pid}}
details.IdentificationPref = append(details.IdentificationPref, &idPref)
}
}

details.ConfigOptions = []*rpc.ConfigOption{}
options := board.GetConfigOptions()
for _, option := range options.Keys() {
Expand All @@ -60,7 +95,6 @@ func Details(ctx context.Context, req *rpc.BoardDetailsReq) (*rpc.BoardDetailsRe
} else if !hasSelected && i == 0 {
configValue.Selected = true
}

configValue.Value = value
configValue.ValueLabel = values.Get(value)
configOption.Values = append(configOption.Values, configValue)
Expand All @@ -69,12 +103,26 @@ func Details(ctx context.Context, req *rpc.BoardDetailsReq) (*rpc.BoardDetailsRe
details.ConfigOptions = append(details.ConfigOptions, configOption)
}

details.RequiredTools = []*rpc.RequiredTool{}
for _, reqTool := range board.PlatformRelease.Dependencies {
details.RequiredTools = append(details.RequiredTools, &rpc.RequiredTool{
Name: reqTool.ToolName,
Packager: reqTool.ToolPackager,
Version: reqTool.ToolVersion.String(),
details.ToolsDependencies = []*rpc.ToolsDependencies{}
for _, tool := range boardPlatform.Dependencies {
toolRelease := pm.FindToolDependency(tool)
var systems []*rpc.Systems
if toolRelease != nil {
for _, f := range toolRelease.Flavors {
systems = append(systems, &rpc.Systems{
Checksum: f.Resource.Checksum,
Size: f.Resource.Size,
Host: f.OS,
ArchiveFileName: f.Resource.ArchiveFileName,
Url: f.Resource.URL,
})
}
}
details.ToolsDependencies = append(details.ToolsDependencies, &rpc.ToolsDependencies{
Name: tool.ToolName,
Packager: tool.ToolPackager,
Version: tool.ToolVersion.String(),
Systems: systems,
})
}

Expand Down
Loading