@@ -2,7 +2,9 @@ package kong
2
2
3
3
import (
4
4
"encoding/json"
5
+ "fmt"
5
6
"io"
7
+ "os"
6
8
"strings"
7
9
)
8
10
@@ -66,3 +68,69 @@ func snakeCase(name string) string {
66
68
name = strings .Join (strings .Split (strings .Title (name ), "-" ), "" )
67
69
return strings .ToLower (name [:1 ]) + name [1 :]
68
70
}
71
+
72
+ // EnvResolver provides a resolver for environment variables tags
73
+ func EnvResolver () Resolver {
74
+ // Resolvers are typically only invoked for flags, as shown here:
75
+ // https://github.com/alecthomas/kong/blob/v1.6.0/context.go#L567
76
+ // However, environment variable annotations can also apply to arguments,
77
+ // as demonstrated in this test:
78
+ // https://github.com/alecthomas/kong/blob/v1.6.0/kong_test.go#L1226-L1244
79
+ // To handle this, we ensure that arguments are resolved as well.
80
+ // Since the resolution only needs to happen once, we use this boolean
81
+ // to track whether the resolution process has already been performed.
82
+ argsResolved := false
83
+ return ResolverFunc (func (context * Context , parent * Path , flag * Flag ) (interface {}, error ) {
84
+ if ! argsResolved {
85
+ if err := resolveArgs (context .Path ); err != nil {
86
+ return nil , err
87
+ }
88
+ // once resolved we do not want to run this anymore
89
+ argsResolved = true
90
+ }
91
+ for _ , env := range flag .Tag .Envs {
92
+ envar , ok := os .LookupEnv (env )
93
+ // Parse the first non-empty ENV in the list
94
+ if ok {
95
+ return envar , nil
96
+ }
97
+ }
98
+ return nil , nil
99
+ })
100
+ }
101
+
102
+ func resolveArgs (paths []* Path ) error {
103
+ for _ , path := range paths {
104
+ if path .Command == nil {
105
+ continue
106
+ }
107
+ for _ , positional := range path .Command .Positional {
108
+ if positional .Tag == nil {
109
+ continue
110
+ }
111
+ if err := visitValue (positional ); err != nil {
112
+ return err
113
+ }
114
+ }
115
+ if path .Command .Argument != nil {
116
+ if err := visitValue (path .Command .Argument ); err != nil {
117
+ return err
118
+ }
119
+ }
120
+ }
121
+ return nil
122
+ }
123
+
124
+ func visitValue (value * Value ) error {
125
+ for _ , env := range value .Tag .Envs {
126
+ envar , ok := os .LookupEnv (env )
127
+ if ! ok {
128
+ continue
129
+ }
130
+ token := Token {Type : FlagValueToken , Value : envar }
131
+ if err := value .Parse (ScanFromTokens (token ), value .Target ); err != nil {
132
+ return fmt .Errorf ("%s (from envar %s=%q)" , err , env , envar )
133
+ }
134
+ }
135
+ return nil
136
+ }
0 commit comments