1818package config
1919
2020import (
21+ "errors"
22+ "fmt"
2123 "os"
24+ "strings"
2225
2326 "github.com/arduino/arduino-cli/cli/errorcodes"
2427 "github.com/arduino/arduino-cli/cli/feedback"
25- "github.com/arduino/arduino-cloud-cli/command/config"
28+ "github.com/arduino/arduino-cloud-cli/arduino"
29+ "github.com/arduino/arduino-cloud-cli/internal/config"
30+ "github.com/arduino/go-paths-helper"
31+ "github.com/manifoldco/promptui"
2632 "github.com/sirupsen/logrus"
2733 "github.com/spf13/cobra"
34+ "github.com/spf13/viper"
35+ )
36+
37+ const (
38+ clientIDLen = 32
39+ clientSecretLen = 64
2840)
2941
3042var initFlags struct {
@@ -36,32 +48,105 @@ var initFlags struct {
3648func initInitCommand () * cobra.Command {
3749 initCommand := & cobra.Command {
3850 Use : "init" ,
39- Short : "Initialize a configuration file with default values " ,
40- Long : "Initialize an Arduino IoT Cloud CLI configuration file with default values " ,
51+ Short : "Initialize a configuration file" ,
52+ Long : "Initialize an Arduino IoT Cloud CLI configuration" ,
4153 Run : runInitCommand ,
4254 }
4355
44- initCommand .Flags ().StringVar (& initFlags .destDir , "dest-dir" , ". " , "Sets where to save the configuration file. " )
45- initCommand .Flags ().BoolVar (& initFlags .overwrite , "overwrite" , false , "Overwrite existing config file. " )
56+ initCommand .Flags ().StringVar (& initFlags .destDir , "dest-dir" , "" , "Sets where to save the configuration file" )
57+ initCommand .Flags ().BoolVar (& initFlags .overwrite , "overwrite" , false , "Overwrite existing config file" )
4658 initCommand .Flags ().StringVar (& initFlags .format , "config-format" , "yaml" , "Format of the configuration file, can be {yaml|json}" )
4759
4860 return initCommand
4961}
5062
5163func runInitCommand (cmd * cobra.Command , args []string ) {
52- logrus .Infof ("Initializing a config file in folder: %s" , initFlags .destDir )
64+ logrus .Info ("Initializing config file" )
65+
66+ // Get default destination directory if it's not passed
67+ if initFlags .destDir == "" {
68+ configPath , err := arduino .DataDir ()
69+ if err != nil {
70+ feedback .Errorf ("Error during config init: cannot retrieve arduino default directory: %v" , err )
71+ os .Exit (errorcodes .ErrGeneric )
72+ }
73+ initFlags .destDir = configPath .String ()
74+ }
75+
76+ // Validate format flag
77+ initFlags .format = strings .ToLower (initFlags .format )
78+ if initFlags .format != "json" && initFlags .format != "yaml" {
79+ feedback .Error ("Error during config init: format is not valid, provide 'json' or 'yaml'" )
80+ os .Exit (errorcodes .ErrGeneric )
81+ }
5382
54- params := & config.InitParams {
55- DestDir : initFlags .destDir ,
56- Overwrite : initFlags .overwrite ,
57- Format : initFlags .format ,
83+ // Check that the destination directory is valid and build the configuration file path
84+ configPath , err := paths .New (initFlags .destDir ).Abs ()
85+ if err != nil {
86+ feedback .Errorf ("Error during config init: cannot retrieve absolute path of %s: %v" , initFlags .destDir , err )
87+ os .Exit (errorcodes .ErrGeneric )
88+ }
89+ if ! configPath .IsDir () {
90+ feedback .Errorf ("Error during config init: %s is not a valid directory" , configPath )
91+ os .Exit (errorcodes .ErrGeneric )
92+ }
93+ configFile := configPath .Join (config .Filename + "." + initFlags .format )
94+ if ! initFlags .overwrite && configFile .Exist () {
95+ feedback .Errorf ("Error during config init: %s already exists, use '--overwrite' to overwrite it" ,
96+ configFile )
97+ os .Exit (errorcodes .ErrGeneric )
5898 }
5999
60- err := config .Init (params )
100+ // Take needed configuration parameters starting an interactive mode
101+ feedback .Print ("To obtain your API credentials visit https://create.arduino.cc/iot/integrations" )
102+ id , key , err := paramsPrompt ()
61103 if err != nil {
62- feedback .Errorf ("Error during config init: %v" , err )
104+ feedback .Errorf ("Error during config init: cannot take config params: %v" , err )
63105 os .Exit (errorcodes .ErrGeneric )
64106 }
65107
66- logrus .Info ("Config file successfully initialized" )
108+ // Write the configuration file
109+ newSettings := viper .New ()
110+ newSettings .SetConfigPermissions (os .FileMode (0600 ))
111+ newSettings .Set ("client" , id )
112+ newSettings .Set ("secret" , key )
113+ if err := newSettings .WriteConfigAs (configFile .String ()); err != nil {
114+ feedback .Errorf ("Error during config init: cannot create config file: %v" , err )
115+ os .Exit (errorcodes .ErrGeneric )
116+ }
117+
118+ feedback .Printf ("Config file successfully initialized at: %s" , configFile )
119+ }
120+
121+ func paramsPrompt () (id , key string , err error ) {
122+ prompt := promptui.Prompt {
123+ Label : "Please enter the Client ID" ,
124+ Validate : func (s string ) error {
125+ if len (s ) != clientIDLen {
126+ return errors .New ("client-id not valid" )
127+ }
128+ return nil
129+ },
130+ }
131+ id , err = prompt .Run ()
132+ if err != nil {
133+ return "" , "" , fmt .Errorf ("client prompt fail: %w" , err )
134+ }
135+
136+ prompt = promptui.Prompt {
137+ Mask : '*' ,
138+ Label : "Please enter the Client Secret" ,
139+ Validate : func (s string ) error {
140+ if len (s ) != clientSecretLen {
141+ return errors .New ("client secret not valid" )
142+ }
143+ return nil
144+ },
145+ }
146+ key , err = prompt .Run ()
147+ if err != nil {
148+ return "" , "" , fmt .Errorf ("client secret prompt fail: %w" , err )
149+ }
150+
151+ return id , key , nil
67152}
0 commit comments