Skip to content

Commit 245d113

Browse files
committed
Refactor config commands (#33)
config command is changed into config init. Secrets cannot be passed anymore as input parameters. Instead, this new command create a skeleton to be manually filled: $ iot-cloud-cli config init --overwrite --dest-dir <destinationFolder> --config-format <json|yaml> It allows to specify a directory in which the configuration file will be initialized. Also, the optional overwrite flag indicates that if a config file already exists in that folder, it will be overwritten. Moreover, the configuration file can be written in both json and yaml format. * Refactor config command * Support multiple config formats * Rename config format flag * Update readme * Update readme
1 parent 9a1cf13 commit 245d113

File tree

7 files changed

+150
-87
lines changed

7 files changed

+150
-87
lines changed

Diff for: README.md

+18-9
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,29 @@ This is all you need to use iot-cloud-cli for device **provisioning**:
1010

1111
## Set a configuration
1212

13-
iot-cloud-cli needs to be configured before being used. In particular a client ID and the corresponding secret ID should be set.
13+
iot-cloud-cli needs a configuration file to be used. At the moment, the configuration file should be contained in the same directory where the cli commands are executed.
14+
The configuration file contains the Arduino IoT Cloud client ID and its corresponding secret.
1415
You can retrieve them from the [cloud](https://create.arduino.cc/iot/integrations) by creating a new API key.
1516

16-
Once you have the IDs, call this command with your parameters:
17+
Once you have the IDs, call this command to init a new configuration file:
1718

18-
`$ iot-cloud-cli config -c <clientID> -s <secretID>`
19+
`$ iot-cloud-cli config init`
1920

20-
A file named `config.yaml` will be created in the Current Working Directory containing the login credentials.
21-
Example
21+
A file named `arduino-cloud.yaml` will be created in the current working directory.
22+
Then you should open such file and replace the client and secret placeholders with the value you previously retrieved.
2223

23-
```yaml
24-
client: 00112233445566778899aabbccddeeff
25-
secret: 00112233445566778899aabbccddeeffffeeddccbbaa99887766554433221100
26-
```
24+
25+
To create a configuration file in a different folder, use this command:
26+
27+
`$ iot-cloud-cli config init --dest-dir <destinationFolder>`
28+
29+
To reset an old configuration file, just overwrite it using this command:
30+
31+
`$ iot-cloud-cli config init --overwrite`
32+
33+
Configuration file is supported in two different format: json and yaml. Use the `--config-format` to choose it. Default is yaml.
34+
35+
`$ iot-cloud-cli config init --config-format json`
2736

2837
## Device provisioning
2938

Diff for: cli/config/config.go

+4-54
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,17 @@
11
package config
22

33
import (
4-
"os"
5-
"strings"
6-
7-
"github.com/arduino/arduino-cli/cli/errorcodes"
8-
"github.com/arduino/arduino-cli/cli/feedback"
9-
paths "github.com/arduino/go-paths-helper"
10-
"github.com/arduino/iot-cloud-cli/command/config"
11-
"github.com/sirupsen/logrus"
124
"github.com/spf13/cobra"
13-
"github.com/spf13/viper"
145
)
156

16-
var configFlags struct {
17-
file string
18-
client string
19-
secret string
20-
}
21-
227
func NewCommand() *cobra.Command {
238
configCommand := &cobra.Command{
249
Use: "config",
25-
Short: "Set the configuration file",
26-
Long: "Set the configuration file to access Arduino IoT Cloud",
27-
Run: runConfigCommand,
28-
}
29-
configCommand.Flags().StringVarP(&configFlags.file, "file", "f", "", "Existing configuration yaml file")
30-
configCommand.Flags().StringVarP(&configFlags.client, "client", "c", "", "Client ID")
31-
configCommand.Flags().StringVarP(&configFlags.secret, "secret", "s", "", "Secret ID")
32-
return configCommand
33-
}
34-
35-
func runConfigCommand(cmd *cobra.Command, args []string) {
36-
if configFlags.file == "" && (configFlags.client == "" || configFlags.secret == "") {
37-
feedback.Error("Error during config: provide either a yaml file or credentials")
38-
os.Exit(errorcodes.ErrGeneric)
10+
Short: "Configuration commands.",
11+
Long: "Configuration commands.",
3912
}
4013

41-
conf := viper.New()
14+
configCommand.AddCommand(initInitCommand())
4215

43-
if configFlags.file != "" {
44-
file := paths.New(configFlags.file)
45-
filename := strings.TrimSuffix(file.String(), file.Ext())
46-
conf.SetConfigName(filename)
47-
conf.SetConfigType(strings.Trim(file.Ext(), "."))
48-
conf.AddConfigPath(".")
49-
err := conf.ReadInConfig()
50-
if err != nil {
51-
feedback.Errorf("Error during config: fatal error config file: %v", err)
52-
os.Exit(errorcodes.ErrGeneric)
53-
}
54-
55-
} else {
56-
conf.BindPFlag("client", cmd.Flag("client"))
57-
conf.BindPFlag("secret", cmd.Flag("secret"))
58-
}
59-
60-
err := config.Config(conf)
61-
if err != nil {
62-
feedback.Errorf("Error during config: storing config file: %v", err)
63-
os.Exit(errorcodes.ErrGeneric)
64-
}
65-
66-
logrus.Info("Configuration file updated")
16+
return configCommand
6717
}

Diff for: cli/config/init.go

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package config
2+
3+
import (
4+
"os"
5+
6+
"github.com/arduino/arduino-cli/cli/errorcodes"
7+
"github.com/arduino/arduino-cli/cli/feedback"
8+
"github.com/arduino/iot-cloud-cli/command/config"
9+
"github.com/sirupsen/logrus"
10+
"github.com/spf13/cobra"
11+
)
12+
13+
var initFlags struct {
14+
destDir string
15+
overwrite bool
16+
format string
17+
}
18+
19+
func initInitCommand() *cobra.Command {
20+
initCommand := &cobra.Command{
21+
Use: "init",
22+
Short: "Initialize a configuration file with default values",
23+
Long: "Initialize an Arduino IoT Cloud CLI configuration file with default values",
24+
Run: runInitCommand,
25+
}
26+
27+
initCommand.Flags().StringVar(&initFlags.destDir, "dest-dir", ".", "Sets where to save the configuration file.")
28+
initCommand.Flags().BoolVar(&initFlags.overwrite, "overwrite", false, "Overwrite existing config file.")
29+
initCommand.Flags().StringVar(&initFlags.format, "config-format", "yaml", "Format of the configuration file, can be {yaml|json}")
30+
31+
return initCommand
32+
}
33+
34+
func runInitCommand(cmd *cobra.Command, args []string) {
35+
logrus.Infof("Initializing a config file in folder: %s", initFlags.destDir)
36+
37+
params := &config.InitParams{
38+
DestDir: initFlags.destDir,
39+
Overwrite: initFlags.overwrite,
40+
Format: initFlags.format,
41+
}
42+
43+
err := config.Init(params)
44+
if err != nil {
45+
feedback.Errorf("Error during config init: %v", err)
46+
os.Exit(errorcodes.ErrGeneric)
47+
}
48+
49+
logrus.Info("Config file successfully initialized")
50+
}

Diff for: command/config/config.go

-20
This file was deleted.

Diff for: command/config/init.go

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package config
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"strings"
7+
8+
"github.com/arduino/go-paths-helper"
9+
"github.com/arduino/iot-cloud-cli/internal/config"
10+
"github.com/spf13/viper"
11+
)
12+
13+
// InitParams contains the parameters needed to initialize a configuration file.
14+
// DestDir - destination directory in which the configuration file will be saved.
15+
// Overwrite - specify if existing config file should be overwritten.
16+
// Format - the config file format, can be 'json' or 'yaml'.
17+
type InitParams struct {
18+
DestDir string
19+
Overwrite bool
20+
Format string
21+
}
22+
23+
func validateFormatString(arg string) error {
24+
if arg != "json" && arg != "yaml" {
25+
return errors.New("passed format is not valid, select between 'json' and 'yaml'")
26+
}
27+
return nil
28+
}
29+
30+
// Init initializes a configuration file with default values.
31+
// If the file doesn't exist, it is created.
32+
// If it exists, it is written to only if overwrite param is true.
33+
func Init(params *InitParams) error {
34+
configPath, err := paths.New(params.DestDir).Abs()
35+
if err != nil {
36+
return fmt.Errorf("%s: %w", "cannot retrieve absolute path of passed dest-dir", err)
37+
}
38+
if !configPath.IsDir() {
39+
return fmt.Errorf("%s: %w", "passed dest-dir is not a valid directory", err)
40+
}
41+
42+
params.Format = strings.ToLower(params.Format)
43+
if err := validateFormatString(params.Format); err != nil {
44+
return err
45+
}
46+
47+
configFile := configPath.Join(config.Filename + "." + params.Format)
48+
49+
if !params.Overwrite && configFile.Exist() {
50+
return errors.New("config file already exists, use --overwrite to discard the existing one")
51+
}
52+
53+
newSettings := viper.New()
54+
config.SetDefaults(newSettings)
55+
if err := newSettings.WriteConfigAs(configFile.String()); err != nil {
56+
return fmt.Errorf("cannot create config file: %v", err)
57+
}
58+
59+
return nil
60+
}

Diff for: internal/config/config.go

+3-4
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,17 @@ import (
1010
// known by iot-cloud-cli
1111
type Config struct {
1212
// Client ID of the user
13-
Client string `yaml:"client"`
13+
Client string `map-structure:"client"`
1414
// Secret ID of the user, unique for each Client ID
15-
Secret string `yaml:"secret"`
15+
Secret string `map-structure:"secret"`
1616
}
1717

1818
// Retrieve returns the actual parameters contained in the
1919
// configuration file, if any. Returns error if no config file is found.
2020
func Retrieve() (*Config, error) {
2121
conf := &Config{}
2222
v := viper.New()
23-
v.SetConfigName("config")
24-
v.SetConfigType("yaml")
23+
v.SetConfigName(Filename)
2524
v.AddConfigPath(".")
2625
err := v.ReadInConfig()
2726
if err != nil {

Diff for: internal/config/default.go

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package config
2+
3+
import "github.com/spf13/viper"
4+
5+
var (
6+
Filename = "arduino-cloud"
7+
)
8+
9+
// SetDefaults sets the default values for configuration keys
10+
func SetDefaults(settings *viper.Viper) {
11+
// Client ID
12+
settings.SetDefault("client", "xxxxxxxxxxxxxx")
13+
// Secret
14+
settings.SetDefault("secret", "xxxxxxxxxxxxxx")
15+
}

0 commit comments

Comments
 (0)