From bd8adb23c8a62134a4dc6f21b2ecf6f50faaa3b4 Mon Sep 17 00:00:00 2001 From: yalefresne Date: Wed, 26 Mar 2025 14:02:17 +0100 Subject: [PATCH] Feat: handle environment config --- commands/config.go | 78 ++++++++++++++++++++++++++++++++++++++++++++++ commands/root.go | 53 ++++++++++++++++++++++++++++--- config/env.go | 52 +++++++++++++++++++++++++++++++ 3 files changed, 178 insertions(+), 5 deletions(-) create mode 100644 commands/config.go create mode 100644 config/env.go diff --git a/commands/config.go b/commands/config.go new file mode 100644 index 0000000..2c8855e --- /dev/null +++ b/commands/config.go @@ -0,0 +1,78 @@ +package cmd + +import ( + "errors" + "fmt" + "os" + "os/exec" + + "github.com/MyLittleParis/dvopsctl/config" + "github.com/MyLittleParis/dvopsctl/utils" +) + +var envFilePath = config.GetEnvFilePath() + +func AddEnvVar(variable, value string) (int, error) { + value = utils.CleanString(value) + variable = config.SanitizeName(variable) + + if oldValue, found := os.LookupEnv(config.EnvPrefix + variable); found { + fmt.Printf("%s already exist, value: %s\n", variable, oldValue) + + if utils.AskForConfirmation("Do you want to update value ?", os.Stdin, os.Stdout) { + _, err := UpdateEnvVar(value, variable) + + if err != nil { + return -1, err + } + + return 0, errors.New("Variable updated") + } else { + return 0, errors.New("Variable already set") + } + } + + newLine := fmt.Sprintf("%s=%s", variable, value) + envFile, err := os.OpenFile(envFilePath, os.O_APPEND|os.O_WRONLY, 0644) + + if err != nil { + fmt.Println(err) + } + + defer envFile.Close() + + if _, err = envFile.Write([]byte("\n"+newLine)); err != nil { + fmt.Println(err) + } + + return 0, nil +} + + +func ListEnvVars() (int, error) { + + config.ListEnvVars() + + return -1, errors.New(noEnv) +} + +func SetEnvVars() (int, error) { + + config.SetEnvVars() + + return -1, errors.New(noEnv) +} + +func UpdateEnvVar(variable, value string) (int, error) { + value = utils.CleanString(value) + variable = config.SanitizeName(variable) + + pattern := fmt.Sprintf("s/%s=.*/%s=%s/g", variable, variable, value) + + sed := exec.Command("sed", "-i", "-e", pattern, envFilePath) + if err := sed.Start(); err != nil { + return -1, err + } + + return 0, nil +} diff --git a/commands/root.go b/commands/root.go index 3f5e51d..7f2ac2d 100644 --- a/commands/root.go +++ b/commands/root.go @@ -15,8 +15,28 @@ func Run(args []string) (int, error) { var rootError error var errCode int + SetEnvVars() + + configCmd := flag.NewFlagSet("config", flag.ExitOnError) + // subcommands + configGet := configCmd.Bool("get", false, "Get dvopsctl environment variables") + configSet := configCmd.Bool("set", false, "Set dvopsctl config from environment variable on .env file") + configAdd := configCmd.Bool("add", false, "Add dvopsctl config, add environment variable on .env file") + configUpdate := configCmd.Bool("update", false, "Update dvopsctl config, update environment variable on .env file") + // args + configName := configCmd.String("n", "", "Environment variable's name on .env file") + configValue := configCmd.String("v", "", "Environment variable's value on .env file") + + configCmd.Usage = func() { + fmt.Println("config [options]") + configCmd.PrintDefaults() + fmt.Println("") + } + serverCmd := flag.NewFlagSet("server", flag.ExitOnError) + // subcommands serverOpen := serverCmd.Bool("open", false, "Open local SERVER_NAME if found in .env file") + serverCmd.Usage = func() { fmt.Println("server [options]") serverCmd.PrintDefaults() @@ -25,7 +45,8 @@ func Run(args []string) (int, error) { // Commands list to use it in usage function commands := []*flag.FlagSet{ - serverCmd, + configCmd, + serverCmd, } var usage func() @@ -44,15 +65,37 @@ func Run(args []string) (int, error) { } switch args[1] { + case "config": + configCmd.Parse(args[2:]) + if *configGet { + ListEnvVars() + } + if *configSet { + SetEnvVars() + } + if *configAdd { + if *configName != "" && *configValue != "" { + AddEnvVar(*configName, *configValue) + } else { + fmt.Println("config -add command needs -n NAME and -v VALUE of your environment variable.") + } + } + if *configUpdate { + if *configName != "" && *configValue != "" { + AddEnvVar(*configName, *configValue) + } else { + fmt.Println("config -add command needs -n NAME and -v VALUE of your environment variable.") + } + } case "server": serverCmd.Parse(args[2:]) if *serverOpen { errCode, rootError = ServerOpen() } - default: - fmt.Println("Unknown command: " + args[1]) - usage() - return -1, errors.New(unknownCmd) + default: + fmt.Println("Unknown command: " + args[1]) + usage() + return -1, errors.New(unknownCmd) } return errCode, rootError diff --git a/config/env.go b/config/env.go new file mode 100644 index 0000000..75a220a --- /dev/null +++ b/config/env.go @@ -0,0 +1,52 @@ +package config + +import ( + "bufio" + "fmt" + "os" + "strings" + + "github.com/MyLittleParis/dvopsctl/utils" +) + +const EnvFile = ".env" +const EnvPrefix = "DVOPS_" + +func GetEnvFilePath() string { + return utils.GetModuleRoot() + EnvFile +} + +func SanitizeName(name string) string { + name = strings.ReplaceAll(name, " ", "_") + name = strings.ToUpper(name) + + return name +} + +func setEnvVar(variable, value string) { + value = utils.CleanString(value) + + os.Setenv(EnvPrefix + variable, value) +} + +func SetEnvVars() { + rootPath := utils.GetModuleRoot() + if content, err := os.Open(rootPath + EnvFile); err == nil { + scanner := bufio.NewScanner(content) + for scanner.Scan() { + if variable, value, found := strings.Cut(scanner.Text(), "="); found { + setEnvVar(variable, value) + } + } + } +} + +func ListEnvVars() { + fmt.Println("List environment variables") + for _, env := range os.Environ() { + variable, value, _ := strings.Cut(env, "=") + if strings.Contains(variable, EnvPrefix) { + fmt.Println(variable, value) + } + } +}