Skip to content

Commit

Permalink
configs: Removed Config struct and using globals to store configuration
Browse files Browse the repository at this point in the history
There is no real need to keep different "Configs", the various
Serialize/Unserialize from different sources (env vars, preferences.txt,
config.yaml etc) now acts directly on the global configuration.
  • Loading branch information
cmaglie committed Feb 21, 2018
1 parent 2b1779e commit 6102660
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 123 deletions.
6 changes: 2 additions & 4 deletions commands/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
package commands

import (
"github.com/bcmi-labs/arduino-cli/configs"
"github.com/sirupsen/logrus"
)

Expand All @@ -51,7 +50,6 @@ var ErrLogrus = logrus.New()

// GlobalFlags represents flags available in all the program.
var GlobalFlags struct {
Debug bool // If true, dump debug output to stderr.
Format string // The Output format (e.g. text, json).
configs.Configs // The Configurations for the CLI.
Debug bool // If true, dump debug output to stderr.
Format string // The Output format (e.g. text, json).
}
25 changes: 11 additions & 14 deletions commands/config/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import (
func init() {
command.AddCommand(initCommand)
initCommand.Flags().BoolVar(&initFlags._default, "default", false, "If omitted, ask questions to the user about setting configuration properties, otherwise use default configuration.")
initCommand.Flags().StringVar(&initFlags.location, "save-as", configs.ConfigFilePath, "Sets where to save the configuration file [default is ./.cli-config.yml].")
initCommand.Flags().StringVar(&initFlags.location, "save-as", "", "Sets where to save the configuration file [default is ./.cli-config.yml].")
}

var initFlags struct {
Expand All @@ -64,33 +64,30 @@ var initCommand = &cobra.Command{
func runInitCommand(cmd *cobra.Command, args []string) {
logrus.Info("Executing `arduino config init`")

var conf configs.Configs

if !initFlags._default {
if !formatter.IsCurrentFormat("text") {
formatter.PrintErrorMessage("The interactive mode is supported only in text mode.")
os.Exit(commands.ErrBadCall)
}
logrus.Info("Asking questions to the user to populate configuration")
conf = configsFromQuestions()
} else {
logrus.Info("Setting default configuration")
conf = configs.Default()
configsFromQuestions()
}

filepath := initFlags.location
if filepath == "" {
filepath = configs.ConfigFilePath
}
err := conf.Serialize(initFlags.location)
err := configs.Serialize(filepath)
if err != nil {
formatter.PrintError(err, "Cannot create config file.")
os.Exit(commands.ErrGeneric)
} else {
formatter.PrintResult("Config file PATH: " + initFlags.location)
}
formatter.PrintResult("Config file PATH: " + filepath)
logrus.Info("Done")
}

// ConfigsFromQuestions asks some questions to the user to properly initialize configs.
// It does not have much sense to use it in JSON formatting, though.
func configsFromQuestions() configs.Configs {
ret := configs.Default()
func configsFromQuestions() {
//logrus.Info("Asking questions to the user to populate configuration")
// Set of questions here.
return ret
}
13 changes: 3 additions & 10 deletions commands/root/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ import (
"os"
"strings"

"github.com/bcmi-labs/arduino-cli/pathutils"

"github.com/bcmi-labs/arduino-cli/commands"
"github.com/bcmi-labs/arduino-cli/commands/board"
"github.com/bcmi-labs/arduino-cli/commands/compile"
Expand Down Expand Up @@ -154,25 +152,21 @@ func preRun(cmd *cobra.Command, args []string) {
// initConfigs initializes the configuration from the specified file.
func initConfigs() {
logrus.Info("Initiating configuration")
c, err := configs.Unserialize(configs.ConfigFilePath)
err := configs.Unserialize(configs.ConfigFilePath)
if err != nil {
logrus.WithError(err).Warn("Did not manage to get config file, using default configuration")
commands.GlobalFlags.Configs = configs.Default()
}
if configs.Bundled() {
logrus.Info("CLI is bundled into the IDE")
err := configs.UnserializeFromIDEPreferences(&c)
err := configs.UnserializeFromIDEPreferences()
if err != nil {
logrus.WithError(err).Warn("Did not manage to get config file of IDE, using default configuration")
commands.GlobalFlags.Configs = configs.Default()
}
} else {
logrus.Info("CLI is not bundled into the IDE")
}
configs.LoadFromEnv()
logrus.Info("Configuration set")
commands.GlobalFlags.Configs = c
configs.ArduinoDataFolder = pathutils.NewConstPath(commands.GlobalFlags.Configs.ArduinoDataFolder)
configs.SketchbookFolder = pathutils.NewConstPath(commands.GlobalFlags.Configs.SketchbookPath)
}

func initViper() {
Expand Down Expand Up @@ -246,5 +240,4 @@ func TestInit() {
// IgnoreConfigs is used in tests to ignore the config file.
func IgnoreConfigs() {
logrus.Info("Ignoring configurations and using always default ones")
commands.GlobalFlags.Configs = configs.Default()
}
32 changes: 18 additions & 14 deletions configs/arduino_ide.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,33 +33,40 @@ import (
"errors"
"path/filepath"

"github.com/bcmi-labs/arduino-cli/pathutils"

"github.com/arduino/go-properties-map"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
)

// UnserializeFromIDEPreferences loads the config from an IDE
// preferences.txt file, by Updating the specified otherConfigs
func UnserializeFromIDEPreferences(otherConfigs *Configs) error {
func UnserializeFromIDEPreferences() error {
logrus.Info("Unserializing from IDE preferences")
props, err := properties.Load(filepath.Join(otherConfigs.ArduinoDataFolder, "preferences.txt"))
dataDir, err := ArduinoDataFolder.Get()
if err != nil {
logrus.WithError(err).Warn("Error looking for IDE preferences")
return err
}
props, err := properties.Load(filepath.Join(dataDir, "preferences.txt"))
if err != nil {
logrus.WithError(err).Warn("Error during unserialize from IDE preferences")
return err
}
err = proxyConfigsFromIDEPrefs(otherConfigs, props)
err = proxyConfigsFromIDEPrefs(props)
if err != nil {
logrus.WithError(err).Warn("Error during unserialize from IDE preferences")
return err
}
sketchbookPath, exists := props.SubTree("sketchbook")["path"]
if exists {
otherConfigs.SketchbookPath = sketchbookPath
if dir, has := props["sketchbook.path"]; has {
SketchbookFolder = pathutils.NewConstPath(dir)
ArduinoHomeFolder = SketchbookFolder
}
return nil
}

func proxyConfigsFromIDEPrefs(otherConfigs *Configs, props properties.Map) error {
func proxyConfigsFromIDEPrefs(props properties.Map) error {
proxy := props.SubTree("proxy")
switch proxy["type"] {
case "auto":
Expand All @@ -76,13 +83,10 @@ func proxyConfigsFromIDEPrefs(otherConfigs *Configs, props properties.Map) error
username := manualConfig["username"]
password := manualConfig["password"]

otherConfigs.ProxyType = "manual"
otherConfigs.ProxyManualConfig = &ProxyConfigs{
Hostname: hostname,
Username: username,
Password: password,
}
viper.Set("proxy", otherConfigs.ProxyManualConfig)
ProxyType = "manual"
ProxyHostname = hostname
ProxyUsername = username
ProxyPassword = password
break
case "none":
// No proxy
Expand Down
153 changes: 72 additions & 81 deletions configs/configs.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,19 @@ import (
"os"
"path/filepath"

"github.com/sirupsen/logrus"
"github.com/bcmi-labs/arduino-cli/pathutils"

"github.com/spf13/viper"
"github.com/sirupsen/logrus"

"gopkg.in/yaml.v2"
)

// ConfigFilePath represents the default location of the config file (same directory as executable).
var ConfigFilePath = detectConfigFilePath()
var ConfigFilePath = getDefaultConfigFilePath()

func detectConfigFilePath() string {
// getDefaultConfigFilePath returns the default path for .cli-config.yml,
// this is the directory where the arduino-cli executable resides.
func getDefaultConfigFilePath() string {
fileLocation, err := os.Executable()
if err != nil {
fileLocation = "."
Expand All @@ -58,120 +60,109 @@ func detectConfigFilePath() string {
return fileLocation
}

// Configs represents the possible configurations for the CLI.
type Configs struct {
ProxyType string `yaml:"proxy_type"`
ProxyManualConfig *ProxyConfigs `yaml:"manual_configs,omitempty"`
SketchbookPath string `yaml:"sketchbook_path,omitempty"`
ArduinoDataFolder string `yaml:"arduino_data,omitempty"`
type yamlConfig struct {
ProxyType string `yaml:"proxy_type"`
ProxyManualConfig *yamlProxyConfig `yaml:"manual_configs,omitempty"`
SketchbookPath string `yaml:"sketchbook_path,omitempty"`
ArduinoDataFolder string `yaml:"arduino_data,omitempty"`
}

// ProxyConfigs represents a possible manual proxy configuration.
type ProxyConfigs struct {
type yamlProxyConfig struct {
Hostname string `yaml:"hostname"`
Username string `yaml:"username,omitempty"`
Password string `yaml:"password,omitempty"` // can be encrypted, see issue #71
}

// defaultConfig represents the default configuration.
var defaultConfig Configs
// ProxyType is the type of proxy configured
var ProxyType = "auto"

var envConfig = Configs{
ProxyType: os.Getenv("PROXY_TYPE"),
SketchbookPath: os.Getenv("SKETCHBOOK_FOLDER"),
ArduinoDataFolder: os.Getenv("ARDUINO_DATA"),
}
// ProxyHostname is the proxy hostname
var ProxyHostname string

func init() {
defArduinoData, _ := ArduinoDataFolder.Get()
defSketchbook, _ := ArduinoHomeFolder.Get()
// ProxyUsername is the proxy user
var ProxyUsername string

defaultConfig = Configs{
ProxyType: "auto",
SketchbookPath: defSketchbook,
ArduinoDataFolder: defArduinoData,
}
}
// ProxyPassword is the proxy password
var ProxyPassword string

// Default returns a copy of the default configuration.
func Default() Configs {
logrus.Info("Returning default configuration")
return defaultConfig
// LoadFromEnv read configurations from the environment variables
func LoadFromEnv() {
if p, has := os.LookupEnv("PROXY_TYPE"); has {
ProxyType = p
}
if dir, has := os.LookupEnv("SKETCHBOOK_DIR"); has {
SketchbookFolder = pathutils.NewConstPath(dir)
ArduinoHomeFolder = SketchbookFolder
}
if dir, has := os.LookupEnv("ARDUINO_DATA_DIR"); has {
ArduinoDataFolder = pathutils.NewConstPath(dir)
}
}

// Unserialize loads the configs from a yaml file.
// Returns the default configuration if there is an
// error.
func Unserialize(path string) (Configs, error) {
func Unserialize(path string) error {
logrus.Info("Unserializing configurations from ", path)
content, err := ioutil.ReadFile(path)
if err != nil {
logrus.WithError(err).Warn("Error during unserialize, using default configuration")
return Default(), err
logrus.WithError(err).Warn("Error reading config, using default configuration")
return err
}
var ret Configs
var ret yamlConfig
err = yaml.Unmarshal(content, &ret)
if err != nil {
logrus.WithError(err).Warn("Error during unserialize, using default configuration")
return Default(), err
logrus.WithError(err).Warn("Error parsing config, using default configuration")
return err
}

if ret.ArduinoDataFolder != "" {
ArduinoDataFolder = pathutils.NewConstPath(ret.ArduinoDataFolder)
}
fixMissingFields(&ret)
return ret, nil
if ret.SketchbookPath != "" {
SketchbookFolder = pathutils.NewConstPath(ret.SketchbookPath)
}
if ret.ProxyType != "" {
ProxyType = ret.ProxyType
if ret.ProxyManualConfig != nil {
ProxyHostname = ret.ProxyManualConfig.Hostname
ProxyUsername = ret.ProxyManualConfig.Username
ProxyPassword = ret.ProxyManualConfig.Password
}
}
return nil
}

// Serialize creates a file in the specified path with
// corresponds to a config file reflecting the configs.
func (c Configs) Serialize(path string) error {
func Serialize(path string) error {
logrus.Info("Serializing configurations to ", path)
c := &yamlConfig{}
if dir, err := SketchbookFolder.Get(); err == nil {
c.SketchbookPath = dir
}
if dir, err := ArduinoDataFolder.Get(); err == nil {
c.ArduinoDataFolder = dir
}
c.ProxyType = ProxyType
if ProxyType == "manual" {
c.ProxyManualConfig = &yamlProxyConfig{
Hostname: ProxyHostname,
Username: ProxyUsername,
Password: ProxyPassword,
}
}
content, err := yaml.Marshal(c)
if err != nil {
logrus.WithError(err).Warn("Error during serialize")
logrus.WithError(err).Warn("Error encoding config")
return err
}
err = ioutil.WriteFile(path, content, 0666)
if err != nil {
logrus.WithError(err).Warn("Error during serialize")
logrus.WithError(err).Warn("Error writing config")
return err
}
return nil
}

func fixMissingFields(c *Configs) {
def := defaultConfig
env := envConfig

compareAndReplace := func(envVal string, configVal *string, defVal string) {
if envVal != "" {
*configVal = envVal
} else if *configVal == "" {
*configVal = defVal
}
}

compareAndReplace(env.ProxyType, &c.ProxyType, def.ProxyType)
compareAndReplace(env.SketchbookPath, &c.SketchbookPath, def.SketchbookPath)
compareAndReplace(env.ArduinoDataFolder, &c.ArduinoDataFolder, def.ArduinoDataFolder)

if env.ProxyManualConfig != nil {
c.ProxyManualConfig = &ProxyConfigs{
Hostname: env.ProxyManualConfig.Hostname,
Username: env.ProxyManualConfig.Username,
Password: env.ProxyManualConfig.Password,
}
} else if c.ProxyManualConfig == nil {
if def.ProxyManualConfig != nil {
//fmt.Println(def.ProxyManualConfig)
c.ProxyManualConfig = &ProxyConfigs{
Hostname: def.ProxyManualConfig.Hostname,
Username: def.ProxyManualConfig.Username,
Password: def.ProxyManualConfig.Password,
}
}

viper.AutomaticEnv()
}
}

var arduinoIDEDirectory *string

// Bundled returns if the CLI is bundled with the Arduino IDE.
Expand Down

0 comments on commit 6102660

Please sign in to comment.