diff --git a/internal/cli/config/config.go b/internal/cli/config/config.go index 38666248f91..c59714478d3 100644 --- a/internal/cli/config/config.go +++ b/internal/cli/config/config.go @@ -37,6 +37,7 @@ func NewCommand() *cobra.Command { configCommand.AddCommand(initAddCommand()) configCommand.AddCommand(initDeleteCommand()) configCommand.AddCommand(initDumpCommand()) + configCommand.AddCommand(initGetCommand()) configCommand.AddCommand(initInitCommand()) configCommand.AddCommand(initRemoveCommand()) configCommand.AddCommand(initSetCommand()) diff --git a/internal/cli/config/get.go b/internal/cli/config/get.go new file mode 100644 index 00000000000..cb2a5cb0072 --- /dev/null +++ b/internal/cli/config/get.go @@ -0,0 +1,87 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 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 config + +import ( + "encoding/json" + "fmt" + "os" + + "github.com/arduino/arduino-cli/commands/daemon" + "github.com/arduino/arduino-cli/internal/cli/configuration" + "github.com/arduino/arduino-cli/internal/cli/feedback" + rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "gopkg.in/yaml.v3" +) + +func initGetCommand() *cobra.Command { + getCommand := &cobra.Command{ + Use: "get", + Short: tr("Gets a settings key value."), + Long: tr("Gets a settings key value."), + Example: "" + + " " + os.Args[0] + " config get logging\n" + + " " + os.Args[0] + " config get daemon.port\n" + + " " + os.Args[0] + " config get board_manager.additional_urls", + Args: cobra.MinimumNArgs(1), + Run: runGetCommand, + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return configuration.Settings.AllKeys(), cobra.ShellCompDirectiveDefault + }, + } + return getCommand +} + +func runGetCommand(cmd *cobra.Command, args []string) { + logrus.Info("Executing `arduino-cli config get`") + + svc := daemon.ArduinoCoreServerImpl{} + for _, toGet := range args { + resp, err := svc.SettingsGetValue(cmd.Context(), &rpc.SettingsGetValueRequest{Key: toGet}) + if err != nil { + feedback.Fatal(tr("Cannot get the configuration key %[1]s: %[2]v", toGet, err), feedback.ErrGeneric) + } + var result getResult + err = json.Unmarshal([]byte(resp.GetJsonData()), &result.resp) + if err != nil { + // Should never happen... + panic(fmt.Sprintf("Cannot parse JSON for key %[1]s: %[2]v", toGet, err)) + } + feedback.PrintResult(result) + } +} + +// output from this command may require special formatting. +// create a dedicated feedback.Result implementation to safely handle +// any changes to the configuration.Settings struct. +type getResult struct { + resp interface{} +} + +func (gr getResult) Data() interface{} { + return gr.resp +} + +func (gr getResult) String() string { + gs, err := yaml.Marshal(gr.resp) + if err != nil { + // Should never happen + panic(tr("unable to marshal config to YAML: %v", err)) + } + return string(gs) +} diff --git a/internal/integrationtest/config/config_test.go b/internal/integrationtest/config/config_test.go index 2d830978c98..91bb73af9f6 100644 --- a/internal/integrationtest/config/config_test.go +++ b/internal/integrationtest/config/config_test.go @@ -818,6 +818,35 @@ func TestDelete(t *testing.T) { require.NotContains(t, configLines, "board_manager") } +func TestGet(t *testing.T) { + env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) + defer env.CleanUp() + + // Create a config file + _, _, err := cli.Run("config", "init", "--dest-dir", ".") + require.NoError(t, err) + + // Verifies default state + stdout, _, err := cli.Run("config", "dump", "--format", "json", "--config-file", "arduino-cli.yaml") + require.NoError(t, err) + requirejson.Query(t, stdout, ".config | .daemon | .port", `"50051"`) + + // Get simple key value + stdout, _, err = cli.Run("config", "get", "daemon.port", "--format", "json", "--config-file", "arduino-cli.yaml") + require.NoError(t, err) + requirejson.Contains(t, stdout, `"50051"`) + + // Get structured key value + stdout, _, err = cli.Run("config", "get", "daemon", "--format", "json", "--config-file", "arduino-cli.yaml") + require.NoError(t, err) + requirejson.Contains(t, stdout, `{"port":"50051"}`) + + // Get undefined key + _, stderr, err := cli.Run("config", "get", "foo", "--format", "json", "--config-file", "arduino-cli.yaml") + require.Error(t, err) + requirejson.Contains(t, stderr, `{"error":"Cannot get the configuration key foo: key not found in settings"}`) +} + func TestInitializationOrderOfConfigThroughFlagAndEnv(t *testing.T) { env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) defer env.CleanUp()