3
3
package config
4
4
5
5
import (
6
- "errors"
7
6
"fmt"
8
7
"reflect"
8
+ "regexp"
9
+ "strconv"
10
+ "strings"
9
11
"sync"
10
12
11
13
"github.com/git-lfs/git-lfs/tools"
@@ -120,32 +122,27 @@ func (c *Configuration) Unmarshal(v interface{}) error {
120
122
field := into .Field (i )
121
123
sfield := into .Type ().Field (i )
122
124
123
- key , env , err := c .parseTag (sfield .Tag )
124
- if err != nil {
125
- return err
126
- }
127
-
128
- if env == nil {
129
- continue
130
- }
131
-
132
125
var val interface {}
133
- switch sfield .Type .Kind () {
134
- case reflect .String :
135
- var ok bool
126
+ for _ , lookup := range c .parseTag (sfield .Tag ) {
127
+ if _ , ok := lookup .Get (); ! ok {
128
+ continue
129
+ }
136
130
137
- val , ok = env .Get (key )
138
- if ! ok {
139
- val = field .String ()
131
+ switch sfield .Type .Kind () {
132
+ case reflect .String :
133
+ val , _ = lookup .Get ()
134
+ case reflect .Int :
135
+ val = lookup .Int (int (field .Int ()))
136
+ case reflect .Bool :
137
+ val = lookup .Bool (field .Bool ())
138
+ default :
139
+ return fmt .Errorf ("lfs/config: unsupported target type for field %q: %v" ,
140
+ sfield .Name , sfield .Type .String ())
141
+ }
142
+
143
+ if val != nil {
144
+ break
140
145
}
141
- case reflect .Int :
142
- val = env .Int (key , int (field .Int ()))
143
- case reflect .Bool :
144
- val = env .Bool (key , field .Bool ())
145
- default :
146
- return fmt .Errorf (
147
- "lfs/config: unsupported target type for field %q: %v" ,
148
- sfield .Name , sfield .Type .String ())
149
146
}
150
147
151
148
if val != nil {
@@ -156,27 +153,59 @@ func (c *Configuration) Unmarshal(v interface{}) error {
156
153
return nil
157
154
}
158
155
156
+ var (
157
+ tagRe = regexp .MustCompile ("((\\ w+:\" [^\" ]*\" )\\ b?)+" )
158
+ emptyEnv = EnvironmentOf (MapFetcher (nil ))
159
+ )
160
+
161
+ type lookup struct {
162
+ key string
163
+ env Environment
164
+ }
165
+
166
+ func (l * lookup ) Get () (interface {}, bool ) { return l .env .Get (l .key ) }
167
+ func (l * lookup ) Int (or int ) int { return l .env .Int (l .key , or ) }
168
+ func (l * lookup ) Bool (or bool ) bool { return l .env .Bool (l .key , or ) }
169
+
159
170
// parseTag returns the key, environment, and optional error assosciated with a
160
171
// given tag. It will return the XOR of either the `git` or `os` tag. That is to
161
172
// say, a field tagged with EITHER `git` OR `os` is valid, but pone tagged with
162
173
// both is not.
163
174
//
164
175
// If neither field was found, then a nil environment will be returned.
165
- func (c * Configuration ) parseTag (tag reflect.StructTag ) (key string , env Environment , err error ) {
166
- git , os := tag .Get ("git" ), tag .Get ("os" )
176
+ func (c * Configuration ) parseTag (tag reflect.StructTag ) []* lookup {
177
+ var lookups []* lookup
178
+
179
+ parts := tagRe .FindAllString (string (tag ), - 1 )
180
+ for _ , part := range parts {
181
+ sep := strings .SplitN (part , ":" , 2 )
182
+ if len (sep ) != 2 {
183
+ panic (fmt .Sprintf ("config: invalid struct tag %q" , tag ))
184
+ }
167
185
168
- if len (git ) != 0 && len (os ) != 0 {
169
- return "" , nil , errors .New ("lfs/config: ambiguous tags" )
170
- }
186
+ var env Environment
187
+ switch strings .ToLower (sep [0 ]) {
188
+ case "git" :
189
+ env = c .Git
190
+ case "os" :
191
+ env = c .Os
192
+ default :
193
+ // ignore other struct tags, like `json:""`, etc.
194
+ env = emptyEnv
195
+ }
171
196
172
- if len (git ) != 0 {
173
- return git , c .Git , nil
174
- }
175
- if len (os ) != 0 {
176
- return os , c .Os , nil
197
+ uq , err := strconv .Unquote (sep [1 ])
198
+ if err != nil {
199
+ panic (err .Error ())
200
+ }
201
+
202
+ lookups = append (lookups , & lookup {
203
+ key : uq ,
204
+ env : env ,
205
+ })
177
206
}
178
207
179
- return
208
+ return lookups
180
209
}
181
210
182
211
// BasicTransfersOnly returns whether to only allow "basic" HTTP transfers.
0 commit comments