github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/k8s/json_path.go (about) 1 package k8s 2 3 import ( 4 "fmt" 5 6 "github.com/tilt-dev/tilt/internal/k8s/jsonpath" 7 ) 8 9 // A wrapper around JSONPath with utility functions for 10 // locating particular types we need (like strings). 11 // 12 // Improves the error message to include the problematic path. 13 type JSONPath struct { 14 path string 15 } 16 17 func NewJSONPath(path string) (JSONPath, error) { 18 // Make sure the JSON path parses. 19 jp := jsonpath.New("jp") 20 err := jp.Parse(path) 21 if err != nil { 22 return JSONPath{}, err 23 } 24 25 return JSONPath{ 26 path: path, 27 }, nil 28 } 29 30 // Extract all the strings from the given object. 31 // Returns an error if the object at the specified path isn't a string. 32 func (jp JSONPath) FindStrings(obj interface{}) ([]string, error) { 33 result := []string{} 34 err := jp.VisitStrings(obj, func(match jsonpath.Value, s string) error { 35 result = append(result, s) 36 return nil 37 }) 38 if err != nil { 39 return nil, err 40 } 41 return result, nil 42 } 43 44 // Visit all the strings from the given object. 45 // 46 // Returns an error if the object at the specified path isn't a string. 47 func (jp JSONPath) VisitStrings(obj interface{}, visit func(val jsonpath.Value, str string) error) error { 48 return jp.Visit(obj, func(match jsonpath.Value) error { 49 val := match.Interface() 50 str, ok := val.(string) 51 if !ok { 52 return fmt.Errorf("May only match strings (json_path=%q)\nGot Type: %T\nGot Value: %s", 53 jp.path, val, val) 54 } 55 56 return visit(match, str) 57 }) 58 } 59 60 // Visit all the values from the given object on this path. 61 func (jp JSONPath) Visit(obj interface{}, visit func(val jsonpath.Value) error) error { 62 // JSONPath is stateful and not thread-safe, so we need to parse a new one 63 // each time 64 matcher := jsonpath.New("jp") 65 err := matcher.Parse(jp.path) 66 if err != nil { 67 return fmt.Errorf("Matching (json_path=%q): %v", jp.path, err) 68 } 69 70 matches, err := matcher.FindResults(obj) 71 if err != nil { 72 return fmt.Errorf("Matching (json_path=%q): %v", jp.path, err) 73 } 74 75 for _, matchSet := range matches { 76 for _, match := range matchSet { 77 err := visit(match) 78 if err != nil { 79 return err 80 } 81 } 82 } 83 return nil 84 } 85 86 func (jp JSONPath) String() string { 87 return jp.path 88 }