From 321174668d95ce7cbbeb7df4997badb22118e74a Mon Sep 17 00:00:00 2001 From: Massimiliano Pippi Date: Mon, 22 Jul 2019 15:32:36 +0200 Subject: [PATCH 1/2] consolidate argument parsing --- arduino/libraries/librariesindex/reference.go | 23 ---- cli/core/args.go | 74 ------------- cli/core/args_test.go | 49 --------- cli/core/download.go | 9 +- cli/core/install.go | 8 +- cli/core/uninstall.go | 9 +- cli/core/upgrade.go | 9 +- cli/globals/args.go | 74 +++++++++++++ cli/globals/args_test.go | 101 ++++++++++++++++++ cli/globals/configs.go | 94 ++++++++++++++++ cli/globals/globals.go | 86 +++------------ cli/lib/download.go | 12 +-- cli/lib/install.go | 8 +- cli/lib/uninstall.go | 12 +-- 14 files changed, 327 insertions(+), 241 deletions(-) delete mode 100644 cli/core/args.go delete mode 100644 cli/core/args_test.go create mode 100644 cli/globals/args.go create mode 100644 cli/globals/args_test.go create mode 100644 cli/globals/configs.go diff --git a/arduino/libraries/librariesindex/reference.go b/arduino/libraries/librariesindex/reference.go index 9a6f80718b1..ce8822b01cd 100644 --- a/arduino/libraries/librariesindex/reference.go +++ b/arduino/libraries/librariesindex/reference.go @@ -18,9 +18,6 @@ package librariesindex import ( - "fmt" - "strings" - semver "go.bug.st/relaxed-semver" ) @@ -36,23 +33,3 @@ func (r *Reference) String() string { } return r.Name + "@" + r.Version.String() } - -// ParseArgs parses a sequence of "item@version" tokens and returns a Name-Version slice. -// -// If version is not present it is assumed as "latest" version. -func ParseArgs(args []string) ([]*Reference, error) { - res := []*Reference{} - for _, item := range args { - tokens := strings.SplitN(item, "@", 2) - if len(tokens) == 2 { - version, err := semver.Parse(tokens[1]) - if err != nil { - return nil, fmt.Errorf("invalid version %s: %s", version, err) - } - res = append(res, &Reference{Name: tokens[0], Version: version}) - } else { - res = append(res, &Reference{Name: tokens[0]}) - } - } - return res, nil -} diff --git a/cli/core/args.go b/cli/core/args.go deleted file mode 100644 index 2f00602a945..00000000000 --- a/cli/core/args.go +++ /dev/null @@ -1,74 +0,0 @@ -/* - * This file is part of arduino-cli. - * - * Copyright 2018 ARDUINO SA (http://www.arduino.cc/) - * - * This software is released under the GNU General Public License version 3, - * which covers the main part of arduino-cli. - * The terms of this license can be found at: - * https://www.gnu.org/licenses/gpl-3.0.en.html - * - * You can be released from the requirements of the above licenses by purchasing - * a commercial license. Buying such a license is mandatory if you want to modify or - * otherwise use the software for commercial activities involving the Arduino - * software without disclosing the source code of your own applications. To purchase - * a commercial license, send an email to license@arduino.cc. - */ - -package core - -import ( - "fmt" - "os" - "strings" - - "github.com/arduino/arduino-cli/cli/errorcodes" - "github.com/arduino/arduino-cli/common/formatter" -) - -type platformReferenceArg struct { - Package string - Architecture string - Version string -} - -func (pl *platformReferenceArg) String() string { - if pl.Version != "" { - return pl.Package + ":" + pl.Architecture + "@" + pl.Version - } - return pl.Package + ":" + pl.Architecture -} - -// parsePlatformReferenceArgs parses a sequence of "packager:arch@version" tokens and -// returns a platformReferenceArg slice. -func parsePlatformReferenceArgs(args []string) []*platformReferenceArg { - ret := []*platformReferenceArg{} - for _, arg := range args { - reference, err := parsePlatformReferenceArg(arg) - if err != nil { - formatter.PrintError(err, "Invalid item "+arg) - os.Exit(errorcodes.ErrBadArgument) - } - ret = append(ret, reference) - } - return ret -} - -func parsePlatformReferenceArg(arg string) (*platformReferenceArg, error) { - split := strings.SplitN(arg, "@", 2) - arg = split[0] - version := "" - if len(split) > 1 { - version = split[1] - } - - split = strings.Split(arg, ":") - if len(split) != 2 { - return nil, fmt.Errorf("invalid item %s", arg) - } - return &platformReferenceArg{ - Package: split[0], - Architecture: split[1], - Version: version, - }, nil -} diff --git a/cli/core/args_test.go b/cli/core/args_test.go deleted file mode 100644 index 4f6f34959de..00000000000 --- a/cli/core/args_test.go +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is part of arduino-cli. - * - * Copyright 2018 ARDUINO SA (http://www.arduino.cc/) - * - * This software is released under the GNU General Public License version 3, - * which covers the main part of arduino-cli. - * The terms of this license can be found at: - * https://www.gnu.org/licenses/gpl-3.0.en.html - * - * You can be released from the requirements of the above licenses by purchasing - * a commercial license. Buying such a license is mandatory if you want to modify or - * otherwise use the software for commercial activities involving the Arduino - * software without disclosing the source code of your own applications. To purchase - * a commercial license, send an email to license@arduino.cc. - */ - -package core - -import ( - "testing" - - "github.com/stretchr/testify/require" - semver "go.bug.st/relaxed-semver" -) - -func TestParsePlatformReferenceArgs(t *testing.T) { - valid := func(arg, pack, arch, ver string) { - version, _ := semver.Parse(ver) // use nil in case of error - - ref, err := parsePlatformReferenceArg(arg) - require.NoError(t, err) - require.Equal(t, pack, ref.Package) - require.Equal(t, arch, ref.Architecture) - require.Equal(t, version.String(), ref.Version) - } - invalid := func(arg string) { - _, err := parsePlatformReferenceArg(arg) - require.Error(t, err) - } - valid("arduino:avr", "arduino", "avr", "-") - valid("arduino:avr@1.6.20", "arduino", "avr", "1.6.20") - valid("arduino:avr@", "arduino", "avr", "") - invalid("avr") - invalid("arduino:avr:avr") - invalid("arduino@1.6.20:avr") - invalid("avr@1.6.20") - invalid("arduino:avr:avr@1.6.20") -} diff --git a/cli/core/download.go b/cli/core/download.go index 1dba6a738fc..46ddef40fbf 100644 --- a/cli/core/download.go +++ b/cli/core/download.go @@ -50,11 +50,16 @@ func runDownloadCommand(cmd *cobra.Command, args []string) { instance := instance.CreateInstance() logrus.Info("Executing `arduino core download`") - platformsRefs := parsePlatformReferenceArgs(args) + platformsRefs, err := globals.ParseReferenceArgs(args, true) + if err != nil { + formatter.PrintError(err, "Invalid argument passed") + os.Exit(errorcodes.ErrBadArgument) + } + for i, platformRef := range platformsRefs { platformDownloadreq := &rpc.PlatformDownloadReq{ Instance: instance, - PlatformPackage: platformRef.Package, + PlatformPackage: platformRef.PackageName, Architecture: platformRef.Architecture, Version: platformRef.Version, } diff --git a/cli/core/install.go b/cli/core/install.go index d4e5b8152da..25d18eea835 100644 --- a/cli/core/install.go +++ b/cli/core/install.go @@ -51,12 +51,16 @@ func runInstallCommand(cmd *cobra.Command, args []string) { instance := instance.CreateInstance() logrus.Info("Executing `arduino core install`") - platformsRefs := parsePlatformReferenceArgs(args) + platformsRefs, err := globals.ParseReferenceArgs(args, true) + if err != nil { + formatter.PrintError(err, "Invalid argument passed") + os.Exit(errorcodes.ErrBadArgument) + } for _, platformRef := range platformsRefs { plattformInstallReq := &rpc.PlatformInstallReq{ Instance: instance, - PlatformPackage: platformRef.Package, + PlatformPackage: platformRef.PackageName, Architecture: platformRef.Architecture, Version: platformRef.Version, } diff --git a/cli/core/uninstall.go b/cli/core/uninstall.go index f15fa801e08..f057de7b7f2 100644 --- a/cli/core/uninstall.go +++ b/cli/core/uninstall.go @@ -22,6 +22,7 @@ import ( "os" "github.com/arduino/arduino-cli/cli/errorcodes" + "github.com/arduino/arduino-cli/cli/globals" "github.com/arduino/arduino-cli/cli/instance" "github.com/arduino/arduino-cli/cli/output" "github.com/arduino/arduino-cli/commands/core" @@ -46,7 +47,11 @@ func runUninstallCommand(cmd *cobra.Command, args []string) { instance := instance.CreateInstance() logrus.Info("Executing `arduino core uninstall`") - platformsRefs := parsePlatformReferenceArgs(args) + platformsRefs, err := globals.ParseReferenceArgs(args, true) + if err != nil { + formatter.PrintError(err, "Invalid argument passed") + os.Exit(errorcodes.ErrBadArgument) + } for _, platformRef := range platformsRefs { if platformRef.Version != "" { @@ -57,7 +62,7 @@ func runUninstallCommand(cmd *cobra.Command, args []string) { for _, platformRef := range platformsRefs { _, err := core.PlatformUninstall(context.Background(), &rpc.PlatformUninstallReq{ Instance: instance, - PlatformPackage: platformRef.Package, + PlatformPackage: platformRef.PackageName, Architecture: platformRef.Architecture, }, output.NewTaskProgressCB()) if err != nil { diff --git a/cli/core/upgrade.go b/cli/core/upgrade.go index 47a3d7a56d9..8727461c55a 100644 --- a/cli/core/upgrade.go +++ b/cli/core/upgrade.go @@ -72,7 +72,12 @@ func runUpgradeCommand(cmd *cobra.Command, args []string) { // proceed upgrading, if anything is upgradable exitErr := false - platformsRefs := parsePlatformReferenceArgs(args) + platformsRefs, err := globals.ParseReferenceArgs(args, true) + if err != nil { + formatter.PrintError(err, "Invalid argument passed") + os.Exit(errorcodes.ErrBadArgument) + } + for i, platformRef := range platformsRefs { if platformRef.Version != "" { formatter.PrintErrorMessage(("Invalid item " + args[i])) @@ -82,7 +87,7 @@ func runUpgradeCommand(cmd *cobra.Command, args []string) { r := &rpc.PlatformUpgradeReq{ Instance: instance, - PlatformPackage: platformRef.Package, + PlatformPackage: platformRef.PackageName, Architecture: platformRef.Architecture, } diff --git a/cli/globals/args.go b/cli/globals/args.go new file mode 100644 index 00000000000..ff15022c5a2 --- /dev/null +++ b/cli/globals/args.go @@ -0,0 +1,74 @@ +// This file is part of arduino-cli. +// +// Copyright 2019 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to modify or +// otherwise use the software for commercial activities involving the Arduino +// software without disclosing the source code of your own applications. To purchase +// a commercial license, send an email to license@arduino.cc. + +package globals + +import ( + "fmt" + "strings" +) + +// ReferenceArg represents a reference item (core or library) passed to the CLI +// interface +type ReferenceArg struct { + PackageName string + Architecture string + Version string +} + +func (r *ReferenceArg) String() string { + if r.Version != "" { + return r.PackageName + ":" + r.Architecture + "@" + r.Version + } + return r.PackageName + ":" + r.Architecture +} + +// ParseReferenceArgs is a convenient wrapper that operates on a slice of strings and +// calls ParseReferenceArg for each of them. It returns at the first invalid argument. +func ParseReferenceArgs(args []string, parseArch bool) ([]*ReferenceArg, error) { + ret := []*ReferenceArg{} + for _, arg := range args { + reference, err := ParseReferenceArg(arg, parseArch) + if err != nil { + return nil, err + } + ret = append(ret, reference) + } + return ret, nil +} + +// ParseReferenceArg parses a string and return a ReferenceArg object. If `parseArch` is passed, +// the method also tries to parse the architecture bit, i.e. string must be in the form +// "packager:arch@version", useful to represent a platform (or core) name. +func ParseReferenceArg(arg string, parseArch bool) (*ReferenceArg, error) { + ret := &ReferenceArg{} + + toks := strings.SplitN(arg, "@", 2) + ret.PackageName = toks[0] + if len(toks) > 1 { + ret.Version = toks[1] + } + + if parseArch { + toks = strings.Split(ret.PackageName, ":") + if len(toks) != 2 { + return nil, fmt.Errorf("invalid item %s", arg) + } + ret.PackageName = toks[0] + ret.Architecture = toks[1] + } + + return ret, nil +} diff --git a/cli/globals/args_test.go b/cli/globals/args_test.go new file mode 100644 index 00000000000..6db34377425 --- /dev/null +++ b/cli/globals/args_test.go @@ -0,0 +1,101 @@ +/* + * This file is part of arduino-cli. + * + * Copyright 2018 ARDUINO SA (http://www.arduino.cc/) + * + * This software is released under the GNU General Public License version 3, + * which covers the main part of arduino-cli. + * The terms of this license can be found at: + * https://www.gnu.org/licenses/gpl-3.0.en.html + * + * You can be released from the requirements of the above licenses by purchasing + * a commercial license. Buying such a license is mandatory if you want to modify or + * otherwise use the software for commercial activities involving the Arduino + * software without disclosing the source code of your own applications. To purchase + * a commercial license, send an email to license@arduino.cc. + */ + +package globals_test + +import ( + "testing" + + "github.com/arduino/arduino-cli/cli/globals" + "github.com/stretchr/testify/assert" +) + +var goodCores = []struct { + in string + expected *globals.ReferenceArg +}{ + {"arduino:avr", &globals.ReferenceArg{"arduino", "avr", ""}}, + {"arduino:avr@1.6.20", &globals.ReferenceArg{"arduino", "avr", "1.6.20"}}, + {"arduino:avr@", &globals.ReferenceArg{"arduino", "avr", ""}}, +} + +var goodLibs = []struct { + in string + expected *globals.ReferenceArg +}{ + {"mylib", &globals.ReferenceArg{"mylib", "", ""}}, + {"mylib@1.0", &globals.ReferenceArg{"mylib", "", "1.0"}}, + {"mylib@", &globals.ReferenceArg{"mylib", "", ""}}, +} + +var badCores = []struct { + in string + expected *globals.ReferenceArg +}{ + {"arduino:avr:avr", nil}, + {"arduino@1.6.20:avr", nil}, + {"arduino:avr:avr@1.6.20", nil}, +} + +func TestParseReferenceArgCores(t *testing.T) { + for _, tt := range goodCores { + actual, err := globals.ParseReferenceArg(tt.in, true) + assert.Nil(t, err) + assert.Equal(t, tt.expected, actual) + } + + for _, tt := range badCores { + actual, err := globals.ParseReferenceArg(tt.in, true) + assert.NotNil(t, err) + assert.Equal(t, tt.expected, actual) + } + + // library refs are not good as core's + for _, tt := range goodLibs { + _, err := globals.ParseReferenceArg(tt.in, true) + assert.NotNil(t, err) + } +} + +func TestParseReferenceArgLibs(t *testing.T) { + for _, tt := range goodLibs { + actual, err := globals.ParseReferenceArg(tt.in, false) + assert.Nil(t, err) + assert.Equal(t, tt.expected, actual) + } + + // good libs are bad when requiring Arch to be present + for _, tt := range goodLibs { + _, err := globals.ParseReferenceArg(tt.in, true) + assert.NotNil(t, err) + } +} + +func TestParseArgs(t *testing.T) { + input := []string{} + for _, tt := range goodCores { + input = append(input, tt.in) + } + + refs, err := globals.ParseReferenceArgs(input, true) + assert.Nil(t, err) + assert.Equal(t, len(goodCores), len(refs)) + + for i, tt := range goodCores { + assert.Equal(t, tt.expected, refs[i]) + } +} diff --git a/cli/globals/configs.go b/cli/globals/configs.go new file mode 100644 index 00000000000..f8362b5ac20 --- /dev/null +++ b/cli/globals/configs.go @@ -0,0 +1,94 @@ +// This file is part of arduino-cli. +// +// Copyright 2019 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to modify or +// otherwise use the software for commercial activities involving the Arduino +// software without disclosing the source code of your own applications. To purchase +// a commercial license, send an email to license@arduino.cc. + +package globals + +import ( + "fmt" + "os" + + "github.com/arduino/arduino-cli/cli/errorcodes" + "github.com/arduino/arduino-cli/common/formatter" + "github.com/arduino/arduino-cli/configs" + "github.com/arduino/go-paths-helper" + "github.com/sirupsen/logrus" +) + +// InitConfigs initializes the configuration from the specified file. +func InitConfigs() { + // Start with default configuration + if conf, err := configs.NewConfiguration(); err != nil { + logrus.WithError(err).Error("Error creating default configuration") + formatter.PrintError(err, "Error creating default configuration") + os.Exit(errorcodes.ErrGeneric) + } else { + Config = conf + } + + // Read configuration from global config file + logrus.Info("Checking for config file in: " + Config.ConfigFile.String()) + if Config.ConfigFile.Exist() { + readConfigFrom(Config.ConfigFile) + } + + if Config.IsBundledInDesktopIDE() { + logrus.Info("CLI is bundled into the IDE") + err := Config.LoadFromDesktopIDEPreferences() + if err != nil { + logrus.WithError(err).Warn("Did not manage to get config file of IDE, using default configuration") + } + } else { + logrus.Info("CLI is not bundled into the IDE") + } + + // Read configuration from parent folders (project config) + if pwd, err := paths.Getwd(); err != nil { + logrus.WithError(err).Warn("Did not manage to find current path") + if path := paths.New("arduino-yaml"); path.Exist() { + readConfigFrom(path) + } + } else { + Config.Navigate(pwd) + } + + // Read configuration from old configuration file if found, but output a warning. + if old := paths.New(".cli-config.yml"); old.Exist() { + logrus.Errorf("Old configuration file detected: %s.", old) + logrus.Info("The name of this file has been changed to `arduino-yaml`, please rename the file fix it.") + formatter.PrintError( + fmt.Errorf("WARNING: Old configuration file detected: %s", old), + "The name of this file has been changed to `arduino-yaml`, in a future release we will not support"+ + "the old name `.cli-config.yml` anymore. Please rename the file to `arduino-yaml` to silence this warning.") + readConfigFrom(old) + } + + // Read configuration from environment vars + Config.LoadFromEnv() + + // Read configuration from user specified file + if YAMLConfigFile != "" { + Config.ConfigFile = paths.New(YAMLConfigFile) + readConfigFrom(Config.ConfigFile) + } + + logrus.Info("Configuration set") +} + +func readConfigFrom(path *paths.Path) { + logrus.Infof("Reading configuration from %s", path) + if err := Config.LoadFromYAML(path); err != nil { + logrus.WithError(err).Warnf("Could not read configuration from %s", path) + } +} diff --git a/cli/globals/globals.go b/cli/globals/globals.go index 058fc290e5b..30974f637e2 100644 --- a/cli/globals/globals.go +++ b/cli/globals/globals.go @@ -1,3 +1,18 @@ +// This file is part of arduino-cli. +// +// Copyright 2019 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to modify or +// otherwise use the software for commercial activities involving the Arduino +// software without disclosing the source code of your own applications. To purchase +// a commercial license, send an email to license@arduino.cc. + package globals import ( @@ -7,12 +22,8 @@ import ( "path/filepath" "runtime" - "github.com/arduino/arduino-cli/cli/errorcodes" - "github.com/arduino/arduino-cli/common/formatter" "github.com/arduino/arduino-cli/configs" "github.com/arduino/arduino-cli/version" - "github.com/arduino/go-paths-helper" - "github.com/sirupsen/logrus" ) var ( @@ -36,70 +47,3 @@ func getHTTPClientHeader() http.Header { downloaderHeaders := http.Header{"User-Agent": []string{userAgentValue}} return downloaderHeaders } - -// InitConfigs initializes the configuration from the specified file. -func InitConfigs() { - // Start with default configuration - if conf, err := configs.NewConfiguration(); err != nil { - logrus.WithError(err).Error("Error creating default configuration") - formatter.PrintError(err, "Error creating default configuration") - os.Exit(errorcodes.ErrGeneric) - } else { - Config = conf - } - - // Read configuration from global config file - logrus.Info("Checking for config file in: " + Config.ConfigFile.String()) - if Config.ConfigFile.Exist() { - readConfigFrom(Config.ConfigFile) - } - - if Config.IsBundledInDesktopIDE() { - logrus.Info("CLI is bundled into the IDE") - err := Config.LoadFromDesktopIDEPreferences() - if err != nil { - logrus.WithError(err).Warn("Did not manage to get config file of IDE, using default configuration") - } - } else { - logrus.Info("CLI is not bundled into the IDE") - } - - // Read configuration from parent folders (project config) - if pwd, err := paths.Getwd(); err != nil { - logrus.WithError(err).Warn("Did not manage to find current path") - if path := paths.New("arduino-yaml"); path.Exist() { - readConfigFrom(path) - } - } else { - Config.Navigate(pwd) - } - - // Read configuration from old configuration file if found, but output a warning. - if old := paths.New(".cli-config.yml"); old.Exist() { - logrus.Errorf("Old configuration file detected: %s.", old) - logrus.Info("The name of this file has been changed to `arduino-yaml`, please rename the file fix it.") - formatter.PrintError( - fmt.Errorf("WARNING: Old configuration file detected: %s", old), - "The name of this file has been changed to `arduino-yaml`, in a future release we will not support"+ - "the old name `.cli-config.yml` anymore. Please rename the file to `arduino-yaml` to silence this warning.") - readConfigFrom(old) - } - - // Read configuration from environment vars - Config.LoadFromEnv() - - // Read configuration from user specified file - if YAMLConfigFile != "" { - Config.ConfigFile = paths.New(YAMLConfigFile) - readConfigFrom(Config.ConfigFile) - } - - logrus.Info("Configuration set") -} - -func readConfigFrom(path *paths.Path) { - logrus.Infof("Reading configuration from %s", path) - if err := Config.LoadFromYAML(path); err != nil { - logrus.WithError(err).Warnf("Could not read configuration from %s", path) - } -} diff --git a/cli/lib/download.go b/cli/lib/download.go index 8787338c7ef..af0661fbc34 100644 --- a/cli/lib/download.go +++ b/cli/lib/download.go @@ -21,7 +21,6 @@ import ( "context" "os" - "github.com/arduino/arduino-cli/arduino/libraries/librariesindex" "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/globals" "github.com/arduino/arduino-cli/cli/instance" @@ -48,16 +47,17 @@ func initDownloadCommand() *cobra.Command { func runDownloadCommand(cmd *cobra.Command, args []string) { instance := instance.CreateInstaceIgnorePlatformIndexErrors() - pairs, err := librariesindex.ParseArgs(args) + refs, err := globals.ParseReferenceArgs(args, false) if err != nil { - formatter.PrintError(err, "Arguments error") + formatter.PrintError(err, "Invalid argument passed") os.Exit(errorcodes.ErrBadArgument) } - for _, library := range pairs { + + for _, library := range refs { libraryDownloadReq := &rpc.LibraryDownloadReq{ Instance: instance, - Name: library.Name, - Version: library.Version.String(), + Name: library.PackageName, + Version: library.Version, } _, err := lib.LibraryDownload(context.Background(), libraryDownloadReq, output.ProgressBar(), globals.HTTPClientHeader) diff --git a/cli/lib/install.go b/cli/lib/install.go index 70bbf50bd59..bf3a6f8c671 100644 --- a/cli/lib/install.go +++ b/cli/lib/install.go @@ -21,7 +21,6 @@ import ( "context" "os" - "github.com/arduino/arduino-cli/arduino/libraries/librariesindex" "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/globals" "github.com/arduino/arduino-cli/cli/instance" @@ -48,16 +47,17 @@ func initInstallCommand() *cobra.Command { func runInstallCommand(cmd *cobra.Command, args []string) { instance := instance.CreateInstaceIgnorePlatformIndexErrors() - refs, err := librariesindex.ParseArgs(args) + refs, err := globals.ParseReferenceArgs(args, false) if err != nil { formatter.PrintError(err, "Arguments error") os.Exit(errorcodes.ErrBadArgument) } + for _, library := range refs { libraryInstallReq := &rpc.LibraryInstallReq{ Instance: instance, - Name: library.Name, - Version: library.Version.String(), + Name: library.PackageName, + Version: library.Version, } err := lib.LibraryInstall(context.Background(), libraryInstallReq, output.ProgressBar(), output.TaskProgress(), globals.HTTPClientHeader) diff --git a/cli/lib/uninstall.go b/cli/lib/uninstall.go index f398addc7f8..8beb84fe463 100644 --- a/cli/lib/uninstall.go +++ b/cli/lib/uninstall.go @@ -21,8 +21,8 @@ import ( "context" "os" - "github.com/arduino/arduino-cli/arduino/libraries/librariesindex" "github.com/arduino/arduino-cli/cli/errorcodes" + "github.com/arduino/arduino-cli/cli/globals" "github.com/arduino/arduino-cli/cli/instance" "github.com/arduino/arduino-cli/cli/output" "github.com/arduino/arduino-cli/commands/lib" @@ -48,17 +48,17 @@ func runUninstallCommand(cmd *cobra.Command, args []string) { logrus.Info("Executing `arduino lib uninstall`") instance := instance.CreateInstaceIgnorePlatformIndexErrors() - libRefs, err := librariesindex.ParseArgs(args) + refs, err := globals.ParseReferenceArgs(args, false) if err != nil { - formatter.PrintError(err, "Arguments error") + formatter.PrintError(err, "Invalid argument passed") os.Exit(errorcodes.ErrBadArgument) } - for _, library := range libRefs { + for _, library := range refs { err := lib.LibraryUninstall(context.Background(), &rpc.LibraryUninstallReq{ Instance: instance, - Name: library.Name, - Version: library.Version.String(), + Name: library.PackageName, + Version: library.Version, }, output.TaskProgress()) if err != nil { formatter.PrintError(err, "Error uninstalling "+library.String()) From 7aecdbae635446591f192702e099914047be82cf Mon Sep 17 00:00:00 2001 From: Massimiliano Pippi Date: Mon, 22 Jul 2019 16:23:08 +0200 Subject: [PATCH 2/2] report and catch a specific error when already installed --- arduino/libraries/librariesmanager/install.go | 15 ++++++++++++--- commands/lib/install.go | 9 ++++++++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/arduino/libraries/librariesmanager/install.go b/arduino/libraries/librariesmanager/install.go index cfcdc3f3cc4..34516624557 100644 --- a/arduino/libraries/librariesmanager/install.go +++ b/arduino/libraries/librariesmanager/install.go @@ -18,6 +18,7 @@ package librariesmanager import ( + "errors" "fmt" "github.com/arduino/arduino-cli/arduino/libraries" @@ -26,18 +27,26 @@ import ( paths "github.com/arduino/go-paths-helper" ) +var ( + // ErrAlreadyInstalled is returned when a library is already installed and task + // cannot proceed. + ErrAlreadyInstalled = errors.New("library already installed") +) + // InstallPrerequisiteCheck performs prequisite checks to install a library. It returns the // install path, where the library should be installed and the possible library that is already // installed on the same folder and it's going to be replaced by the new one. func (lm *LibrariesManager) InstallPrerequisiteCheck(indexLibrary *librariesindex.Release) (*paths.Path, *libraries.Library, error) { + saneName := utils.SanitizeName(indexLibrary.Library.Name) + var replaced *libraries.Library - if installedLibs, have := lm.Libraries[indexLibrary.Library.Name]; have { + if installedLibs, have := lm.Libraries[saneName]; have { for _, installedLib := range installedLibs.Alternatives { if installedLib.Location != libraries.Sketchbook { continue } if installedLib.Version.Equal(indexLibrary.Version) { - return installedLib.InstallDir, nil, fmt.Errorf("%s is already installed", indexLibrary.String()) + return installedLib.InstallDir, nil, ErrAlreadyInstalled } replaced = installedLib } @@ -48,7 +57,7 @@ func (lm *LibrariesManager) InstallPrerequisiteCheck(indexLibrary *librariesinde return nil, nil, fmt.Errorf("sketchbook directory not set") } - libPath := libsDir.Join(utils.SanitizeName(indexLibrary.Library.Name)) + libPath := libsDir.Join(saneName) if replaced != nil && replaced.InstallDir.EquivalentTo(libPath) { } else if libPath.IsDir() { diff --git a/commands/lib/install.go b/commands/lib/install.go index 0c9a56e645e..2bcb11f8601 100644 --- a/commands/lib/install.go +++ b/commands/lib/install.go @@ -58,16 +58,23 @@ func installLibrary(lm *librariesmanager.LibrariesManager, libRelease *libraries taskCB(&rpc.TaskProgress{Name: "Installing " + libRelease.String()}) logrus.WithField("library", libRelease).Info("Installing library") libPath, libReplaced, err := lm.InstallPrerequisiteCheck(libRelease) + if err == librariesmanager.ErrAlreadyInstalled { + taskCB(&rpc.TaskProgress{Message: "Alredy installed " + libRelease.String(), Completed: true}) + return nil + } + if err != nil { return fmt.Errorf("checking lib install prerequisites: %s", err) } + if libReplaced != nil { taskCB(&rpc.TaskProgress{Message: fmt.Sprintf("Replacing %s with %s", libReplaced, libRelease)}) } + if err := lm.Install(libRelease, libPath); err != nil { return err } - taskCB(&rpc.TaskProgress{Message: "Installed " + libRelease.String(), Completed: true}) + taskCB(&rpc.TaskProgress{Message: "Installed " + libRelease.String(), Completed: true}) return nil }