Skip to content

Commit

Permalink
feat(flag)!: Adding shorthand support
Browse files Browse the repository at this point in the history
Signed-off-by: Vincent Boutour <[email protected]>
  • Loading branch information
ViBiOh committed Apr 16, 2023
1 parent e902a3d commit acdde9d
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 19 deletions.
4 changes: 2 additions & 2 deletions cmd/advanced/advanced.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ type databaseConfig struct {

func databaseFlags(fs *flag.FlagSet, prefix string, overrides ...flags.Override) databaseConfig {
return databaseConfig{
url: flags.String(fs, prefix, "db", "Url", "Database url", "", overrides),
url: flags.String(fs, prefix, "db", "Url", "", "Database url", "", overrides),
port: flags.Uint(fs, prefix, "db", "Port", "Database port", 5432, overrides),
name: flags.String(fs, prefix, "db", "Name", "Database name", "user", overrides),
name: flags.String(fs, prefix, "db", "Name", "", "Database name", "user", overrides),
timeout: flags.Duration(fs, prefix, "db", "Timeout", "Request timeout", time.Second, overrides),
}
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/simple/simple.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
func main() {
fs := flag.NewFlagSet("my-cli", flag.ExitOnError)

address := flags.String(fs, "exemple", "server", "Address", "Listen address", "", nil)
address := flags.String(fs, "exemple", "server", "Address", "a", "Listen address", "", nil)
port := flags.Uint(fs, "exemple", "server", "Port", "Listen port (0 to disable)", 1080, nil)
headers := flags.StringSlice(fs, "exemple", "server", "Header", "Header to add", []string{"x-user", "x-auth"}, nil)

Expand Down
62 changes: 51 additions & 11 deletions flag.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,89 +10,129 @@ import (
)

// String creates a string flag
func String(fs *flag.FlagSet, prefix, docPrefix, name, label string, value string, overrides []Override) *string {
func String(fs *flag.FlagSet, prefix, docPrefix, name, shorthand, label string, value string, overrides []Override) *string {
flagName, envName := getNameAndEnv(fs, FirstUpperCase(prefix), name)

output := new(string)

initialValue := defaultValue(defaultStaticValue(name, value, overrides), envName, func(input string) (string, error) {
return input, nil
})

if len(shorthand) > 0 {
fs.StringVar(output, FirstLowerCase(prefix+FirstUpperCase(shorthand)), initialValue, fmt.Sprintf("Shorthand for -%s", FirstLowerCase(flagName)))
}

fs.StringVar(output, FirstLowerCase(flagName), initialValue, formatLabel(prefix, docPrefix, label, envName))

return output
}

// Int creates an int flag
func Int(fs *flag.FlagSet, prefix, docPrefix, name, label string, value int, overrides []Override) *int {
func Int(fs *flag.FlagSet, prefix, docPrefix, name, shorthand, label string, value int, overrides []Override) *int {
flagName, envName := getNameAndEnv(fs, FirstUpperCase(prefix), name)

output := new(int)

initialValue := defaultValue(defaultStaticValue(name, value, overrides), envName, func(input string) (int, error) {
intVal, err := strconv.ParseInt(input, 10, 32)
return int(intVal), err
})

return fs.Int(FirstLowerCase(flagName), initialValue, formatLabel(prefix, docPrefix, label, envName))
if len(shorthand) > 0 {
fs.IntVar(output, FirstLowerCase(prefix+FirstUpperCase(shorthand)), initialValue, fmt.Sprintf("Shorthand for -%s", FirstLowerCase(flagName)))
}

fs.IntVar(output, FirstLowerCase(flagName), initialValue, formatLabel(prefix, docPrefix, label, envName))

return output
}

// Int64 creates an int64 flag
func Int64(fs *flag.FlagSet, prefix, docPrefix, name, label string, value int64, overrides []Override) *int64 {
flagName, envName := getNameAndEnv(fs, FirstUpperCase(prefix), name)

output := new(int64)

initialValue := defaultValue(defaultStaticValue(name, value, overrides), envName, func(input string) (int64, error) {
return strconv.ParseInt(input, 10, 64)
})

return fs.Int64(FirstLowerCase(flagName), initialValue, formatLabel(prefix, docPrefix, label, envName))
fs.Int64Var(output, FirstLowerCase(flagName), initialValue, formatLabel(prefix, docPrefix, label, envName))

return output
}

// Uint creates an uint flag
func Uint(fs *flag.FlagSet, prefix, docPrefix, name, label string, value uint, overrides []Override) *uint {
flagName, envName := getNameAndEnv(fs, FirstUpperCase(prefix), name)

output := new(uint)

initialValue := defaultValue(defaultStaticValue(name, value, overrides), envName, func(input string) (uint, error) {
intVal, err := strconv.ParseUint(input, 10, 32)
return uint(intVal), err
})

return fs.Uint(FirstLowerCase(flagName), initialValue, formatLabel(prefix, docPrefix, label, envName))
fs.UintVar(output, FirstLowerCase(flagName), initialValue, formatLabel(prefix, docPrefix, label, envName))

return output
}

// Uint64 creates an uint64 flag
func Uint64(fs *flag.FlagSet, prefix, docPrefix, name, label string, value uint64, overrides []Override) *uint64 {
flagName, envName := getNameAndEnv(fs, FirstUpperCase(prefix), name)
return fs.Uint64(FirstLowerCase(flagName), defaultValue(defaultStaticValue(name, value, overrides), envName, func(input string) (uint64, error) {

output := new(uint64)

initialValue := defaultValue(defaultStaticValue(name, value, overrides), envName, func(input string) (uint64, error) {
return strconv.ParseUint(input, 10, 64)
}), formatLabel(prefix, docPrefix, label, envName))
})

fs.Uint64Var(output, FirstLowerCase(flagName), initialValue, formatLabel(prefix, docPrefix, label, envName))

return output
}

// Float64 creates a float64 flag
func Float64(fs *flag.FlagSet, prefix, docPrefix, name, label string, value float64, overrides []Override) *float64 {
flagName, envName := getNameAndEnv(fs, FirstUpperCase(prefix), name)

output := new(float64)

initialValue := defaultValue(defaultStaticValue(name, value, overrides), envName, func(input string) (float64, error) {
return strconv.ParseFloat(input, 64)
})

return fs.Float64(FirstLowerCase(flagName), initialValue, formatLabel(prefix, docPrefix, label, envName))
fs.Float64Var(output, FirstLowerCase(flagName), initialValue, formatLabel(prefix, docPrefix, label, envName))

return output
}

// Bool creates a bool flag
func Bool(fs *flag.FlagSet, prefix, docPrefix, name, label string, value bool, overrides []Override) *bool {
flagName, envName := getNameAndEnv(fs, FirstUpperCase(prefix), name)

output := new(bool)

initialValue := defaultValue(defaultStaticValue(name, value, overrides), envName, strconv.ParseBool)

return fs.Bool(FirstLowerCase(flagName), initialValue, formatLabel(prefix, docPrefix, label, envName))
fs.BoolVar(output, FirstLowerCase(flagName), initialValue, formatLabel(prefix, docPrefix, label, envName))

return output
}

// Duration creates a duration flag
func Duration(fs *flag.FlagSet, prefix, docPrefix, name, label string, value time.Duration, overrides []Override) *time.Duration {
flagName, envName := getNameAndEnv(fs, FirstUpperCase(prefix), name)

output := new(time.Duration)

initialValue := defaultValue(defaultStaticValue(name, value, overrides), envName, time.ParseDuration)

return fs.Duration(FirstLowerCase(flagName), initialValue, formatLabel(prefix, docPrefix, label, envName))
fs.DurationVar(output, FirstLowerCase(flagName), initialValue, formatLabel(prefix, docPrefix, label, envName))

return output
}

type stringSlice struct {
Expand Down Expand Up @@ -144,7 +184,7 @@ func StringSlice(fs *flag.FlagSet, prefix, docPrefix, name, label string, value

p := new([]string)

fs.Var(newStringSlice(initialValue, p), FirstLowerCase(flagName), formatLabel(prefix, docPrefix, label, envName))
fs.Var(newStringSlice(initialValue, p), FirstLowerCase(flagName), formatLabel(prefix, docPrefix, label, envName)+"\n\t `string slice`, environment value should be comma separated")

return p
}
Expand Down
10 changes: 5 additions & 5 deletions flag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func TestString(t *testing.T) {
for intention, tc := range cases {
t.Run(intention, func(t *testing.T) {
fs := flag.NewFlagSet("String", flag.ContinueOnError)
String(fs, tc.prefix, tc.docPrefix, tc.name, tc.label, tc.defaultValue, tc.overrides)
String(fs, tc.prefix, tc.docPrefix, tc.name, "", tc.label, tc.defaultValue, tc.overrides)

var writer strings.Builder
fs.SetOutput(&writer)
Expand Down Expand Up @@ -125,7 +125,7 @@ func TestInt(t *testing.T) {
for intention, tc := range cases {
t.Run(intention, func(t *testing.T) {
fs := flag.NewFlagSet("Int", flag.ContinueOnError)
Int(fs, tc.prefix, tc.docPrefix, tc.name, tc.label, tc.defaultValue, nil)
Int(fs, tc.prefix, tc.docPrefix, tc.name, "", tc.label, tc.defaultValue, nil)

var writer strings.Builder
fs.SetOutput(&writer)
Expand Down Expand Up @@ -541,23 +541,23 @@ func TestStringSlice(t *testing.T) {
"test",
nil,
"Test flag",
"Usage of Values:\n -test value\n \t[cli] Test flag {VALUES_TEST}\n",
"Usage of Values:\n -test string slice\n \t[cli] Test flag {VALUES_TEST}\n \t\t string slice, environment value should be comma separated\n",
},
"with prefix": {
"context",
"cli",
"test",
[]string{"value"},
"Test flag",
"Usage of Values:\n -contextTest value\n \t[context] Test flag {VALUES_CONTEXT_TEST} (default [value])\n",
"Usage of Values:\n -contextTest string slice\n \t[context] Test flag {VALUES_CONTEXT_TEST}\n \t\t string slice, environment value should be comma separated (default [value])\n",
},
"env": {
"",
"cli",
"value",
[]string{"value"},
"Test flag",
"Usage of Values:\n -value value\n \t[cli] Test flag {VALUES_VALUE} (default [overriden])\n",
"Usage of Values:\n -value string slice\n \t[cli] Test flag {VALUES_VALUE}\n \t\t string slice, environment value should be comma separated (default [overriden])\n",
},
}

Expand Down

0 comments on commit acdde9d

Please sign in to comment.