Skip to content

Commit

Permalink
Merge pull request #258 from hhromic/implement-204
Browse files Browse the repository at this point in the history
Add support for setting a global env var prefix
  • Loading branch information
alexflint authored Nov 4, 2024
2 parents efb1be7 + cb7e5c1 commit 438bbff
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 37 deletions.
50 changes: 39 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ fmt.Println("Input:", args.Input)
fmt.Println("Output:", args.Output)
```

```
```shell
$ ./example src.txt x.out y.out z.out
Input: src.txt
Output: [x.out y.out z.out]
Expand All @@ -80,12 +80,12 @@ arg.MustParse(&args)
fmt.Println("Workers:", args.Workers)
```

```
```shell
$ WORKERS=4 ./example
Workers: 4
```

```
```shell
$ WORKERS=4 ./example --workers=6
Workers: 6
```
Expand All @@ -100,7 +100,7 @@ arg.MustParse(&args)
fmt.Println("Workers:", args.Workers)
```

```
```shell
$ NUM_WORKERS=4 ./example
Workers: 4
```
Expand All @@ -115,7 +115,7 @@ arg.MustParse(&args)
fmt.Println("Workers:", args.Workers)
```

```
```shell
$ WORKERS='1,99' ./example
Workers: [1 99]
```
Expand All @@ -130,14 +130,35 @@ arg.MustParse(&args)
fmt.Println("Workers:", args.Workers)
```

```
```shell
$ NUM_WORKERS=6 ./example
Workers: 6
$ NUM_WORKERS=6 ./example --count 4
Workers: 4
```

Configuring a global environment variable name prefix is also possible:

```go
var args struct {
Workers int `arg:"--count,env:NUM_WORKERS"`
}

p, err := arg.NewParser(arg.Config{
EnvPrefix: "MYAPP_",
}, &args)

p.MustParse(os.Args[1:])
fmt.Println("Workers:", args.Workers)
```

```shell
$ MYAPP_NUM_WORKERS=6 ./example
Workers: 6
```

### Usage strings

```go
var args struct {
Input string `arg:"positional"`
Expand Down Expand Up @@ -185,6 +206,7 @@ arg.MustParse(&args)
```
#### Ignoring environment variables and/or default values
```go
var args struct {
Test string `arg:"-t,env:TEST" default:"something"`
Expand All @@ -195,10 +217,11 @@ p, err := arg.NewParser(arg.Config{
IgnoreDefault: true,
}, &args)
err = p.Parse(os.Args)
err = p.Parse(os.Args[1:])
```
### Arguments with multiple values
```go
var args struct {
Database string
Expand All @@ -214,6 +237,7 @@ Fetching the following IDs from foo: [1 2 3]
```
### Arguments that can be specified multiple times, mixed with positionals
```go
var args struct {
Commands []string `arg:"-c,separate"`
Expand All @@ -231,6 +255,7 @@ Databases [db1 db2 db3]
```
### Arguments with keys and values
```go
var args struct {
UserIDs map[string]int
Expand All @@ -245,6 +270,7 @@ map[john:123 mary:456]
```
### Version strings
```go
type args struct {
...
Expand All @@ -269,6 +295,7 @@ someprogram 4.3.0
> If a `--version` flag is defined in `args` or any subcommand, it overrides the built-in versioning.
### Custom validation
```go
var args struct {
Foo string
Expand Down Expand Up @@ -310,13 +337,11 @@ Options:
--help, -h display this help and exit
```
### Embedded structs
The fields of embedded structs are treated just like regular fields:
```go
type DatabaseOptions struct {
Host string
Username string
Expand Down Expand Up @@ -384,6 +409,7 @@ func main() {
fmt.Printf("%#v\n", args.Name)
}
```
```shell
$ ./example --name=foo.bar
main.NameDotName{Head:"foo", Tail:"bar"}
Expand Down Expand Up @@ -420,6 +446,7 @@ func main() {
fmt.Printf("%#v\n", args.Name)
}
```
```shell
$ ./example --help
Usage: test [--name NAME]
Expand All @@ -445,6 +472,7 @@ var args struct {
}
arg.MustParse(&args)
```
```shell
$ ./example -h
Usage: example [--optimize LEVEL] [--maxjobs N] SRC [DST [DST ...]]
Expand Down Expand Up @@ -581,7 +609,6 @@ if p.Subcommand() == nil {
}
```
### Custom handling of --help and --version
The following reproduces the internal logic of `MustParse` for the simple case where
Expand Down Expand Up @@ -722,7 +749,8 @@ func main() {
p.WriteUsageForSubcommand(os.Stdout, p.SubcommandNames()...)
os.Exit(1)
}
}```
}
```
```shell
$ ./example --version
Expand Down
13 changes: 8 additions & 5 deletions parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ type Config struct {
// subcommand
StrictSubcommands bool

// EnvPrefix instructs the library to use a name prefix when reading environment variables.
EnvPrefix string

// Exit is called to terminate the process with an error code (defaults to os.Exit)
Exit func(int)

Expand Down Expand Up @@ -235,7 +238,7 @@ func NewParser(config Config, dests ...interface{}) (*Parser, error) {
panic(fmt.Sprintf("%s is not a pointer (did you forget an ampersand?)", t))
}

cmd, err := cmdFromStruct(name, path{root: i}, t)
cmd, err := cmdFromStruct(name, path{root: i}, t, config.EnvPrefix)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -285,7 +288,7 @@ func NewParser(config Config, dests ...interface{}) (*Parser, error) {
return &p, nil
}

func cmdFromStruct(name string, dest path, t reflect.Type) (*command, error) {
func cmdFromStruct(name string, dest path, t reflect.Type, envPrefix string) (*command, error) {
// commands can only be created from pointers to structs
if t.Kind() != reflect.Ptr {
return nil, fmt.Errorf("subcommands must be pointers to structs but %s is a %s",
Expand Down Expand Up @@ -372,9 +375,9 @@ func cmdFromStruct(name string, dest path, t reflect.Type) (*command, error) {
case key == "env":
// Use override name if provided
if value != "" {
spec.env = value
spec.env = envPrefix + value
} else {
spec.env = strings.ToUpper(field.Name)
spec.env = envPrefix + strings.ToUpper(field.Name)
}
case key == "subcommand":
// decide on a name for the subcommand
Expand All @@ -389,7 +392,7 @@ func cmdFromStruct(name string, dest path, t reflect.Type) (*command, error) {
}

// parse the subcommand recursively
subcmd, err := cmdFromStruct(cmdnames[0], subdest, field.Type)
subcmd, err := cmdFromStruct(cmdnames[0], subdest, field.Type, envPrefix)
if err != nil {
errs = append(errs, err.Error())
return false
Expand Down
Loading

0 comments on commit 438bbff

Please sign in to comment.