From 3cf635e3c41be385b50778f7818fd50b006f1671 Mon Sep 17 00:00:00 2001 From: Jeff Carr Date: Tue, 21 Oct 2025 06:40:48 -0500 Subject: something to act like bash ENV --- appname.go | 24 ++++++++++++++++ formatENV.go | 51 +++++++++++++++++++++++++++++++++ init.go | 26 +++++++++++++++++ key.proto | 18 +++++++----- load.go | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ panic.go | 23 +++++++++++++++ save.go | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ structs.go | 20 +++++++++++++ verbose.go | 55 ++++++++++++++++++++++++++++++++++++ 9 files changed, 390 insertions(+), 7 deletions(-) create mode 100644 appname.go create mode 100644 formatENV.go create mode 100644 init.go create mode 100644 load.go create mode 100644 panic.go create mode 100644 save.go create mode 100644 structs.go create mode 100644 verbose.go diff --git a/appname.go b/appname.go new file mode 100644 index 0000000..98d8dcc --- /dev/null +++ b/appname.go @@ -0,0 +1,24 @@ +package ENV + +import ( + "errors" + "os/user" +) + +func GetAppname() (string, error) { + if APPNAME != "" { + return APPNAME, nil + } + return "", errors.New("your application must setup config.Init()") +} + +func GetUsername() string { + if Get("username") != "" { + return Get("username") + } + usr, _ := user.Current() + if usr.Username != "" { + return usr.Username + } + return "notsure" // OS Idiocracy +} diff --git a/formatENV.go b/formatENV.go new file mode 100644 index 0000000..0d1efc3 --- /dev/null +++ b/formatENV.go @@ -0,0 +1,51 @@ +package ENV + +import ( + "errors" + "fmt" + "strings" + + "go.wit.com/log" +) + +func formatENV() (string, error) { + if envPB == nil { + return "", errors.New("envPB not initialized") + } + + var out string + uniques := make(map[string]*Key) // check to make sure there are no duplicate entries + + for c := range envPB.IterAll() { + key := strings.ToLower(c.Var) + if len(strings.Fields(key)) != 1 { + log.Info("dropping invalid key = ", c.Var, "value =", c.Value) + continue + } + found := findByLower(key) + if found == nil { + log.Info("findByKey() got nil for key:", key) + } + // todo: warn about duplicates? + uniques[key] = found + } + + for key, c := range uniques { + if c == nil { + log.Info("key has nil c", key) + continue + } + line := fmt.Sprintf("%s=%s", c.Var, c.Value) + out += line + "\n" + } + return out, nil +} + +func findByLower(lookingFor string) *Key { + for c := range envPB.IterAll() { + if strings.ToLower(c.Var) == strings.ToLower(lookingFor) { + return c + } + } + return nil +} diff --git a/init.go b/init.go new file mode 100644 index 0000000..3df1e17 --- /dev/null +++ b/init.go @@ -0,0 +1,26 @@ +package ENV + +// this is an experiment at this point to +// see how this turns out + +func Init(appname, version, buildtime string, fromargv []string) error { + APPNAME = appname + VERSION = version + BUILDTIME = buildtime + argv = fromargv + + err := loadENV() + if err == nil { + envPB.Init = true + } + return err +} + +func InitValid() bool { + if envPB == nil { + // todo: track that the application did not init + envPB = NewKeys() + return false + } + return envPB.Init +} diff --git a/key.proto b/key.proto index 7ee7a1f..ab22c91 100644 --- a/key.proto +++ b/key.proto @@ -4,13 +4,17 @@ syntax = "proto3"; package ENV; -message Key { // - string var = 1; // ENV var name `autogenpb:unique` `autogenpb:sort` - string value = 2; // ENV value name +message Key { // + string var = 1; // ENV var name `autogenpb:unique` `autogenpb:sort` + string value = 2; // ENV value name + bool global = 3; // was defined in application OS settings + string help = 4; // text for explaining the ENV key/value } -message Keys { // `autogenpb:marshal` `autogenpb:nomutex` - string uuid = 1; // `autogenpb:uuid:7a8aaf7f-9851-42f0-89eb-434d2e51f5bb` - string version = 2; // `autogenpb:version:v0.0.1 go.wit.com/lib/ENV` - repeated Key keys = 3; +message Keys { // `autogenpb:marshal` `autogenpb:nomutex` + string uuid = 1; // `autogenpb:uuid:7a8aaf7f-9851-42f0-89eb-434d2e51f5bb` + string version = 2; // `autogenpb:version:v0.0.1 go.wit.com/lib/ENV` + repeated Key keys = 3; + string filename = 4; // can store where the filename is so that saves can be automated + bool init = 5; // can store where the filename is so that saves can be automated } diff --git a/load.go b/load.go new file mode 100644 index 0000000..2986819 --- /dev/null +++ b/load.go @@ -0,0 +1,92 @@ +package ENV + +import ( + "errors" + "os" + "path/filepath" + "strings" + + "go.wit.com/log" +) + +func loadENV() error { + if envPB != nil { + log.Info("envPB already loaded") + return errors.New("envPB already loaded") + } + filename, err := getConfigFilenameENV() + if err != nil { + return err + } + // log.Info("loadENV()", filename) + stuff, err := os.ReadFile(filename) + if err != nil { + return err + } + saveMu.Lock() + defer saveMu.Unlock() + envPB = NewKeys() + for _, line := range strings.Split(string(stuff), "\n") { + line = strings.TrimSpace(line) + if line == "" { + continue + } + parts := strings.Split(line, "=") + if len(parts) != 2 { + // log.Info("INVALID LINE:", i, line) + continue + } + c := new(Key) + c.Var = parts[0] + c.Value = parts[1] + envPB.Append(c) + // log.Printf("ENV LINE: (%v)\n", c) + } + + return err +} + +func getConfigFilenameENV() (string, error) { + appname, err := GetAppname() // already configured by your application + if err != nil { + return "", err + } + + configdir, err := getConfigDir() + if err != nil { + return "", err + } + + filename := filepath.Join(configdir, appname+".ENV") + return filename, nil +} + +func getCacheDir() (string, error) { + if Get("cacheDir") != "" { + return Get("cacheDir"), nil + } + + cacheDir, _ := os.UserCacheDir() + + appname, err := GetAppname() // application should have already configured this + if err != nil { + return cacheDir, err + } + + return filepath.Join(cacheDir, appname), nil +} + +func getConfigDir() (string, error) { + if Get("configDir") != "" { + return Get("configDir"), nil + } + + configDir, _ := os.UserConfigDir() + + appname, err := GetAppname() // application should have already configured this + if err != nil { + return configDir, err + } + + return filepath.Join(configDir, appname), nil +} diff --git a/panic.go b/panic.go new file mode 100644 index 0000000..488cee9 --- /dev/null +++ b/panic.go @@ -0,0 +1,23 @@ +package ENV + +func GetPanic(flag string) string { + saveMu.Lock() + defer saveMu.Unlock() + if envPB == nil { + envPanic(flag) + } + found := envPB.FindByVar(flag) + if found == nil { + envPanic(flag) + } + return found.Value +} + +func envPanic(varname string) { + saveMu.Lock() + defer saveMu.Unlock() + if envPB == nil { + panic("config file is nil") + } + panic("config name '" + varname + "' not found") +} diff --git a/save.go b/save.go new file mode 100644 index 0000000..7083d9d --- /dev/null +++ b/save.go @@ -0,0 +1,88 @@ +package ENV + +import ( + "os" + "strings" + + "go.wit.com/log" +) + +// saves your applications config file +func Save() error { + return saveENV() +} + +func saveENV() error { + filename, err := getConfigFilenameENV() + if err != nil { + return err + } + saveMu.Lock() + defer saveMu.Unlock() + return saveENVnolock(filename) +} + +func saveENVnolock(filename string) error { + outENV, err := formatENV() + if err == nil { + log.Info("SAVEENV IS RUNNING") + log.Info("SAVEENV IS RUNNING") + log.Info("SAVEENV IS RUNNING") + log.Info(outENV) + } + return os.WriteFile(filename, []byte(outENV), 0644) +} + +func Get(flag string) string { + saveMu.Lock() + defer saveMu.Unlock() + if envPB == nil { + return "" + } + c := findByLower(flag) + if c == nil { + return "" + } + + return c.Value +} + +func True(flag string) bool { + saveMu.Lock() + defer saveMu.Unlock() + if envPB == nil { + return false + } + found := envPB.FindByVar(flag) + if found == nil { + return false + } + if strings.ToLower(found.Value) == "true" { + return true + } + return false +} + +func Set(varname string, newValue string) error { + filename, err := getConfigFilenameENV() + if err != nil { + return err + } + saveMu.Lock() + defer saveMu.Unlock() + if envPB == nil { + return NotInitialized + } + found := envPB.FindByVar(varname) + if found != nil { + found.Value = newValue + saveENVnolock(filename) + } + + newvar := new(Key) + newvar.Var = varname + newvar.Value = newValue + envPB.Append(newvar) + saveENVnolock(filename) + return nil +} diff --git a/structs.go b/structs.go new file mode 100644 index 0000000..89c5177 --- /dev/null +++ b/structs.go @@ -0,0 +1,20 @@ +package ENV + +import ( + "errors" + sync "sync" +) + +var envPB *Keys + +// lock access to the PB +var saveMu sync.RWMutex + +// these are normally what are sent from ldflags +var APPNAME string +var BUILDTIME string +var VERSION string + +var argv []string + +var NotInitialized error = errors.New("your application config not initialized") diff --git a/verbose.go b/verbose.go new file mode 100644 index 0000000..31dd0f7 --- /dev/null +++ b/verbose.go @@ -0,0 +1,55 @@ +package ENV + +// this is an experiment at this point to +// see how this turns out + +func Verbose() bool { + // always use the ENV value first + if envPB != nil { + found := envPB.FindByVar("Verbose") + if found == nil { + // Verbose isn't in the ENV. do nothing here + } else { + // return what the ENV has + // fmt.Println("returning from the ENV:" + found.Value) + if found.Value == "true" { + return true + } + return false + } + } + + // nothing in the ENV. check argv + for _, v := range argv { + if v == "--verbose" { + return true + } + } + return false +} + +func If(key string) bool { + // always use the ENV value first + if envPB != nil { + found := envPB.FindByVar(key) + if found == nil { + // Verbose isn't in the ENV. do nothing here + } else { + // return what the ENV has + // fmt.Println("returning from the ENV:" + found.Value) + if found.Value == "true" { + return true + } + return false + } + } + + // nothing in the ENV. check argv + // todo: turn key to lowercase and check here + for _, v := range argv { + if v == "--verbose" { + return true + } + } + return false +} -- cgit v1.2.3