-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
fix(config): support dynamic map keys with dots #8096
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 1 commit
05232af
0a2336e
732adeb
660cc66
6d295eb
e1cbee7
36b62c1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,26 +2,50 @@ package common | |
|
|
||
| import ( | ||
| "fmt" | ||
| "regexp" | ||
| "strings" | ||
| ) | ||
|
|
||
| // Find dynamic map key names passed as Parent["foo"] notation | ||
| var bracketsRe = regexp.MustCompile(`\[([^\[\]]*)\]`) | ||
|
|
||
| // Normalization for supporting arbitrary dynamic keys with dots: | ||
| // Gateway.PublicGateways["gw.example.com"].UseSubdomains | ||
| // Pinning.RemoteServices["pins.example.org"].Policies.MFS.Enable | ||
| func keyToLookupData(key string) (normalizedKey string, dynamicKeys map[string]string) { | ||
|
||
| bracketedKeys := bracketsRe.FindAllString(key, -1) | ||
| dynamicKeys = make(map[string]string, len(bracketedKeys)) | ||
| normalizedKey = key | ||
| for i, mapKeySegment := range bracketedKeys { | ||
| mapKey := strings.TrimLeft(mapKeySegment, "[\"") | ||
| mapKey = strings.TrimRight(mapKey, "\"]") | ||
lidel marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| placeholder := fmt.Sprintf("mapKey%d", i) | ||
lidel marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| dynamicKeys[placeholder] = mapKey | ||
| normalizedKey = strings.Replace(normalizedKey, mapKeySegment, fmt.Sprintf(".%s", placeholder), 1) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will convert a glob string like: ["abc"]["def"] into .UUID1.UUID2 |
||
| } | ||
| return normalizedKey, dynamicKeys | ||
| } | ||
|
|
||
| func MapGetKV(v map[string]interface{}, key string) (interface{}, error) { | ||
| var ok bool | ||
| var mcursor map[string]interface{} | ||
| var cursor interface{} = v | ||
|
|
||
| parts := strings.Split(key, ".") | ||
| normalizedKey, dynamicKeys := keyToLookupData(key) | ||
| parts := strings.Split(normalizedKey, ".") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fails of normalizedKey starts with a ".", which technically it can. |
||
| for i, part := range parts { | ||
| sofar := strings.Join(parts[:i], ".") | ||
|
|
||
| mcursor, ok = cursor.(map[string]interface{}) | ||
| if !ok { | ||
| return nil, fmt.Errorf("%s key is not a map", sofar) | ||
| return nil, fmt.Errorf("%q key is not a map", sofar) | ||
| } | ||
| if dynamicPart, ok := dynamicKeys[part]; ok { | ||
| part = dynamicPart | ||
| } | ||
|
|
||
| cursor, ok = mcursor[part] | ||
| if !ok { | ||
| return nil, fmt.Errorf("%s key has no attributes", sofar) | ||
| return nil, fmt.Errorf("%q key has no attribute %q", sofar, part) | ||
| } | ||
| } | ||
| return cursor, nil | ||
|
|
@@ -32,12 +56,16 @@ func MapSetKV(v map[string]interface{}, key string, value interface{}) error { | |
| var mcursor map[string]interface{} | ||
| var cursor interface{} = v | ||
|
|
||
| parts := strings.Split(key, ".") | ||
| normalizedKey, dynamicKeys := keyToLookupData(key) | ||
| parts := strings.Split(normalizedKey, ".") | ||
| for i, part := range parts { | ||
| mcursor, ok = cursor.(map[string]interface{}) | ||
| if !ok { | ||
| sofar := strings.Join(parts[:i], ".") | ||
| return fmt.Errorf("%s key is not a map", sofar) | ||
| return fmt.Errorf("%q key is not a map", sofar) | ||
| } | ||
| if dynamicPart, ok := dynamicKeys[part]; ok { | ||
| part = dynamicPart | ||
| } | ||
|
|
||
| // last part? set here | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this notation standard/used in other software or are we just making this up this form of escaping? Either way we'd need to document this in the
configcommand.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is how keys in JSON objects are addressed on the web, and since we use JSON for config anyway, means we don't invent anything new, but follow existing JSON convention.:
I've added note about this notation to
ipfs config --helpin 0a2336eThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The return value is not documented accurately on a public method. What about dynamicKeys?