From 707adf08bfc83cc1697db12811093dbbd5af7a93 Mon Sep 17 00:00:00 2001 From: Donatas Rasiukevicius Date: Sat, 27 Jul 2024 13:41:38 +0200 Subject: [PATCH 1/4] Add option to configure by env --- internal/flag/context.go | 51 ++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/internal/flag/context.go b/internal/flag/context.go index a3fb01beea..dd65f67dcd 100644 --- a/internal/flag/context.go +++ b/internal/flag/context.go @@ -3,6 +3,7 @@ package flag import ( "context" "slices" + "strconv" "strings" "time" @@ -38,12 +39,20 @@ func FirstArg(ctx context.Context) string { return "" } +func FromEnv(name string) string { + var_name := "FLY_" + strings.ToUpper(name) + var_name = strings.ReplaceAll(var_name, "-", "_") + return env.First(var_name) +} + // GetString returns the value of the named string flag ctx carries. func GetString(ctx context.Context, name string) string { - if v, err := FromContext(ctx).GetString(name); err != nil { - return "" - } else { + if v, err := FromContext(ctx).GetString(name); err == nil && v != "" { + return v + } else if v := FromEnv(name); v != "" { return v + } else { + return "" } } @@ -55,20 +64,32 @@ func SetString(ctx context.Context, name, value string) error { // GetInt returns the value of the named int flag ctx carries. It panics // in case ctx carries no flags or in case the named flag isn't an int one. func GetInt(ctx context.Context, name string) int { - if v, err := FromContext(ctx).GetInt(name); err != nil { - panic(err) - } else { + if v, err := FromContext(ctx).GetInt(name); err == nil { return v + } else if v := FromEnv(name); v != "" { + if i, err := strconv.Atoi(v); err == nil { + return i + } else { + panic(err) + } + } else { + panic(err) } } // GetFloat64 returns the value of the named int flag ctx carries. It panics // in case ctx carries no flags or in case the named flag isn't a float64 one. func GetFloat64(ctx context.Context, name string) float64 { - if v, err := FromContext(ctx).GetFloat64(name); err != nil { - panic(err) - } else { + if v, err := FromContext(ctx).GetFloat64(name); err == nil { return v + } else if v := FromEnv(name); v != "" { + if f, err := strconv.ParseFloat(v, 64); err == nil { + return f + } else { + panic(err) + } + } else { + panic(err) } } @@ -119,11 +140,14 @@ func GetDuration(ctx context.Context, name string) time.Duration { // GetBool returns the value of the named boolean flag ctx carries. func GetBool(ctx context.Context, name string) bool { - if v, err := FromContext(ctx).GetBool(name); err != nil { - return false - } else { + if v, err := FromContext(ctx).GetBool(name); err == nil { return v + } else if v := FromEnv(name); v != "" { + if b, err := strconv.ParseBool(v); err == nil { + return b + } } + return false } // IsSpecified returns whether a flag has been specified at all or not. @@ -136,9 +160,6 @@ func IsSpecified(ctx context.Context, name string) bool { // GetOrg is shorthand for GetString(ctx, Org). func GetOrg(ctx context.Context) string { org := GetString(ctx, flagnames.Org) - if org == "" { - org = env.First("FLY_ORG") - } return org } From 9591ece72c5fe4af53608993efe46329c3802f4b Mon Sep 17 00:00:00 2001 From: Donatas Rasiukevicius Date: Mon, 29 Jul 2024 09:40:22 +0200 Subject: [PATCH 2/4] extend functionality to string/duration type vars --- internal/flag/context.go | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/internal/flag/context.go b/internal/flag/context.go index dd65f67dcd..51a367f0e8 100644 --- a/internal/flag/context.go +++ b/internal/flag/context.go @@ -97,20 +97,24 @@ func GetFloat64(ctx context.Context, name string) float64 { // Preserves commas (unlike the following `GetStringSlice`): in `--flag x,y` the value is string[]{`x,y`}. // This is useful to pass key-value pairs like environment variables or build arguments. func GetStringArray(ctx context.Context, name string) []string { - if v, err := FromContext(ctx).GetStringArray(name); err != nil { - return []string{} - } else { + if v, err := FromContext(ctx).GetStringArray(name); err == nil { return v + } else if v := FromEnv(name); v != "" { + return []string{v} + } else { + return []string{} } } // GetStringSlice returns the values of the named string flag ctx carries. // Can be comma separated or passed "by repeated flags": `--flag x,y` is equivalent to `--flag x --flag y`. func GetStringSlice(ctx context.Context, name string) []string { - if v, err := FromContext(ctx).GetStringSlice(name); err != nil { - return []string{} - } else { + if v, err := FromContext(ctx).GetStringSlice(name); err == nil { return v + } else if v := FromEnv(name); v != "" { + return strings.Split(v, ",") + } else { + return []string{} } } @@ -131,10 +135,16 @@ func GetNonEmptyStringSlice(ctx context.Context, name string) []string { // GetDuration returns the value of the named duration flag ctx carries. func GetDuration(ctx context.Context, name string) time.Duration { - if v, err := FromContext(ctx).GetDuration(name); err != nil { - return 0 - } else { + if v, err := FromContext(ctx).GetDuration(name); err == nil { return v + } else if v := FromEnv(name); v != "" { + if d, err := time.ParseDuration(v); err == nil { + return d + } else { + return 0 + } + } else { + return 0 } } From 8c490ea0d1a3f932f53fc6aa8d80dfb8df594841 Mon Sep 17 00:00:00 2001 From: Donatas Rasiukevicius Date: Tue, 30 Jul 2024 10:11:22 +0200 Subject: [PATCH 3/4] add first parent to flag lookup --- internal/flag/context.go | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/internal/flag/context.go b/internal/flag/context.go index 51a367f0e8..db043cc6c1 100644 --- a/internal/flag/context.go +++ b/internal/flag/context.go @@ -2,12 +2,15 @@ package flag import ( "context" + "fmt" "slices" "strconv" "strings" "time" + "github.com/spf13/cobra" "github.com/spf13/pflag" + "github.com/superfly/flyctl/internal/command_context" "github.com/superfly/flyctl/internal/env" "github.com/superfly/flyctl/internal/flag/flagctx" "github.com/superfly/flyctl/internal/flag/flagnames" @@ -39,17 +42,31 @@ func FirstArg(ctx context.Context) string { return "" } -func FromEnv(name string) string { - var_name := "FLY_" + strings.ToUpper(name) +func CmdParentName(cmd *cobra.Command) cobra.Command { + parent := cmd.Parent() + if strings.ToUpper(parent.Name()) == "FLY" { + return *cmd + } else { + return CmdParentName(parent) + } +} + +func FromEnv(ctx context.Context, name string) string { + cmd := command_context.FromContext(ctx) + baseCmd := CmdParentName(cmd) + cmdName := baseCmd.Name() + var_name := "FLY_" + strings.ToUpper(cmdName) + "_" + strings.ToUpper(name) var_name = strings.ReplaceAll(var_name, "-", "_") - return env.First(var_name) + value := env.First(var_name) + fmt.Printf("var_name: %s value: %s\n", var_name, value) + return value } // GetString returns the value of the named string flag ctx carries. func GetString(ctx context.Context, name string) string { if v, err := FromContext(ctx).GetString(name); err == nil && v != "" { return v - } else if v := FromEnv(name); v != "" { + } else if v := FromEnv(ctx, name); v != "" { return v } else { return "" @@ -66,7 +83,7 @@ func SetString(ctx context.Context, name, value string) error { func GetInt(ctx context.Context, name string) int { if v, err := FromContext(ctx).GetInt(name); err == nil { return v - } else if v := FromEnv(name); v != "" { + } else if v := FromEnv(ctx, name); v != "" { if i, err := strconv.Atoi(v); err == nil { return i } else { @@ -82,7 +99,7 @@ func GetInt(ctx context.Context, name string) int { func GetFloat64(ctx context.Context, name string) float64 { if v, err := FromContext(ctx).GetFloat64(name); err == nil { return v - } else if v := FromEnv(name); v != "" { + } else if v := FromEnv(ctx, name); v != "" { if f, err := strconv.ParseFloat(v, 64); err == nil { return f } else { @@ -99,7 +116,7 @@ func GetFloat64(ctx context.Context, name string) float64 { func GetStringArray(ctx context.Context, name string) []string { if v, err := FromContext(ctx).GetStringArray(name); err == nil { return v - } else if v := FromEnv(name); v != "" { + } else if v := FromEnv(ctx, name); v != "" { return []string{v} } else { return []string{} @@ -111,7 +128,7 @@ func GetStringArray(ctx context.Context, name string) []string { func GetStringSlice(ctx context.Context, name string) []string { if v, err := FromContext(ctx).GetStringSlice(name); err == nil { return v - } else if v := FromEnv(name); v != "" { + } else if v := FromEnv(ctx, name); v != "" { return strings.Split(v, ",") } else { return []string{} @@ -137,7 +154,7 @@ func GetNonEmptyStringSlice(ctx context.Context, name string) []string { func GetDuration(ctx context.Context, name string) time.Duration { if v, err := FromContext(ctx).GetDuration(name); err == nil { return v - } else if v := FromEnv(name); v != "" { + } else if v := FromEnv(ctx, name); v != "" { if d, err := time.ParseDuration(v); err == nil { return d } else { @@ -150,9 +167,10 @@ func GetDuration(ctx context.Context, name string) time.Duration { // GetBool returns the value of the named boolean flag ctx carries. func GetBool(ctx context.Context, name string) bool { - if v, err := FromContext(ctx).GetBool(name); err == nil { + isSpecified := IsSpecified(ctx, name) + if v, err := FromContext(ctx).GetBool(name); err == nil && isSpecified { return v - } else if v := FromEnv(name); v != "" { + } else if v := FromEnv(ctx, name); v != "" { if b, err := strconv.ParseBool(v); err == nil { return b } From 70702d99354843a55b6782800b17f5cf24e8f611 Mon Sep 17 00:00:00 2001 From: Donatas Rasiukevicius Date: Tue, 30 Jul 2024 10:46:53 +0200 Subject: [PATCH 4/4] add hierarchical env lookup --- internal/flag/context.go | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/internal/flag/context.go b/internal/flag/context.go index db043cc6c1..48c8738dbf 100644 --- a/internal/flag/context.go +++ b/internal/flag/context.go @@ -2,7 +2,6 @@ package flag import ( "context" - "fmt" "slices" "strconv" "strings" @@ -42,23 +41,29 @@ func FirstArg(ctx context.Context) string { return "" } -func CmdParentName(cmd *cobra.Command) cobra.Command { - parent := cmd.Parent() - if strings.ToUpper(parent.Name()) == "FLY" { - return *cmd +func EnvNameFromCmd(cmd *cobra.Command) string { + if cmd.Parent() != nil { + varname := EnvNameFromCmd(cmd.Parent()) + "_" + cmd.Name() + return strings.ToUpper(varname) } else { - return CmdParentName(parent) + return strings.ToUpper(cmd.Name()) } + } func FromEnv(ctx context.Context, name string) string { cmd := command_context.FromContext(ctx) - baseCmd := CmdParentName(cmd) - cmdName := baseCmd.Name() - var_name := "FLY_" + strings.ToUpper(cmdName) + "_" + strings.ToUpper(name) - var_name = strings.ReplaceAll(var_name, "-", "_") - value := env.First(var_name) - fmt.Printf("var_name: %s value: %s\n", var_name, value) + value := "" + for cmd != nil { + var_name := EnvNameFromCmd(cmd) + "_" + strings.ToUpper(name) + var_name = strings.ReplaceAll(var_name, "-", "_") + value = env.First(var_name) + if value == "" { + cmd = cmd.Parent() + } else { + return value + } + } return value }