Skip to content

Conversation

@yolken-segment
Copy link
Contributor

Description

This change adds a new kubeapply template function, lookup, that can be used to look up a dot-delimited path in a map or struct. If the path exists, it returns the value, otherwise it returns nil. Adding this because the sprig get function doesn't support looking more than one level down.

Copy link

@achille-roussel achille-roussel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding this!


// lookup does a dot-separated path lookup on the input struct or map. If the input or any of
// its children on the targeted path are not a map or struct, it returns nil.
func lookup(path string, input interface{}) interface{} {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The get function of Sprig receives the input as first argument I believe, which reads with the more naturally as get <object> <field>.

There are pros and cons to either ways, taking the input as last argument helps in the pipeline form where the output of the previous command is passed as last argument. I'm a bit concerned that we may trick everyone into getting it wrong if get and lookup have swapped signatures tho.

How about offering both maybe?

func lookup(input interface{}, path string) interface{} {
  ...
}
// naming is hard
func select(path string, input interface{}) interface{} {
  return lookup(input, path)
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, interesting, for some reason I thought I was following the get convention. Will fix it up.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. For the alternative, named it pathLookup since select is a golang keyword.

for i := 0; i < len(components); {
component := components[i]

switch obj.Kind() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like Sprig made the opinionated choice to use map[string]interface{} only https://github.com/Masterminds/sprig/blob/39e4d5d0e0d566a256746e59749821155f209d11/dict.go#L8

Do you know if we may ever run into cases where a struct is passed to this function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Map only is fine. I was trying to be super-flexible but probably unnecessary :-).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

"urlEncode": url.QueryEscape,
}

zeroValue = reflect.Value{}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using reflect.Value.IsValid is usually the preferred way to check I believe.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, nice. Fixed.

obj = obj.MapIndex(reflect.ValueOf(component))
i++
case reflect.Ptr, reflect.Interface:
// Get the thing being pointed to or interfaced, don't advance index

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm under the impression that we may have to check reflect.Value.IsNil before we dereference the pointer, otherwise the code could panic.

Copy link
Contributor Author

@yolken-segment yolken-segment Feb 23, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a check here.

obj = obj.Elem()
default:
// Got an unexpected type
return nil

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would a panic be more appropriate here? It seems like we'd be using the function really wrong if we run into this case.

Alternatively, we could return the value itself.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, so there are two cases here- one that's an error and one that isn't. Separated them and updated the function to return an error if the user tries to traverse a non-map type.

@achille-roussel
Copy link

Thanks for adding this!

@yolken-segment yolken-segment merged commit b828d00 into master Feb 23, 2021
@yolken-segment yolken-segment deleted the yolken-add-better-default-funcs branch February 23, 2021 20:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants