github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/tiltfile/k8s/locators.go (about) 1 package k8s 2 3 import ( 4 "fmt" 5 6 "go.starlark.net/starlark" 7 8 "github.com/pkg/errors" 9 10 "github.com/tilt-dev/tilt/internal/k8s" 11 "github.com/tilt-dev/tilt/internal/tiltfile/value" 12 ) 13 14 // Deserializing locators from starlark values. 15 type JSONPathImageLocatorListSpec struct { 16 Specs []JSONPathImageLocatorSpec 17 } 18 19 func (s JSONPathImageLocatorListSpec) IsEmpty() bool { 20 return len(s.Specs) == 0 21 } 22 23 func (s *JSONPathImageLocatorListSpec) Unpack(v starlark.Value) error { 24 list := value.ValueOrSequenceToSlice(v) 25 for _, item := range list { 26 spec := JSONPathImageLocatorSpec{} 27 err := spec.Unpack(item) 28 if err != nil { 29 return err 30 } 31 s.Specs = append(s.Specs, spec) 32 } 33 return nil 34 } 35 36 func (s JSONPathImageLocatorListSpec) ToImageLocators(selector k8s.ObjectSelector) ([]k8s.ImageLocator, error) { 37 result := []k8s.ImageLocator{} 38 for _, spec := range s.Specs { 39 locator, err := spec.ToImageLocator(selector) 40 if err != nil { 41 return nil, err 42 } 43 result = append(result, locator) 44 } 45 return result, nil 46 } 47 48 type JSONPathImageLocatorSpec struct { 49 jsonPath string 50 } 51 52 func (s *JSONPathImageLocatorSpec) Unpack(v starlark.Value) error { 53 var ok bool 54 s.jsonPath, ok = starlark.AsString(v) 55 if !ok { 56 return fmt.Errorf("Expected string, got: %s", v) 57 } 58 return nil 59 } 60 61 func (s JSONPathImageLocatorSpec) ToImageLocator(selector k8s.ObjectSelector) (k8s.ImageLocator, error) { 62 return k8s.NewJSONPathImageLocator(selector, s.jsonPath) 63 } 64 65 type JSONPathImageObjectLocatorSpec struct { 66 jsonPath string 67 repoField string 68 tagField string 69 } 70 71 func (s JSONPathImageObjectLocatorSpec) IsEmpty() bool { 72 return s == JSONPathImageObjectLocatorSpec{} 73 } 74 75 func (s *JSONPathImageObjectLocatorSpec) Unpack(v starlark.Value) error { 76 d, ok := v.(*starlark.Dict) 77 if !ok { 78 return fmt.Errorf("Expected dict of the form {'json_path': str, 'repo_field': str, 'tag_field': str}. Actual: %s", v) 79 } 80 81 values, err := validateStringDict(d, []string{"json_path", "repo_field", "tag_field"}) 82 if err != nil { 83 return errors.Wrap(err, "Expected dict of the form {'json_path': str, 'repo_field': str, 'tag_field': str}") 84 } 85 86 s.jsonPath, s.repoField, s.tagField = values[0], values[1], values[2] 87 return nil 88 } 89 90 func (s JSONPathImageObjectLocatorSpec) ToImageLocator(selector k8s.ObjectSelector) (k8s.ImageLocator, error) { 91 return k8s.NewJSONPathImageObjectLocator(selector, s.jsonPath, s.repoField, s.tagField) 92 } 93 94 func validateStringDict(d *starlark.Dict, expectedFields []string) ([]string, error) { 95 indices := map[string]int{} 96 result := make([]string, len(expectedFields)) 97 for i, f := range expectedFields { 98 indices[f] = i 99 } 100 101 for _, item := range d.Items() { 102 key, val := item[0], item[1] 103 keyString, ok := starlark.AsString(key) 104 if !ok { 105 return nil, fmt.Errorf("Unexpected key: %s", key) 106 } 107 108 index, ok := indices[keyString] 109 if !ok { 110 return nil, fmt.Errorf("Unexpected key: %s", key) 111 } 112 113 valString, ok := starlark.AsString(val) 114 if !ok { 115 return nil, fmt.Errorf("Expected string at key %q. Got: %s", key, val.Type()) 116 } 117 118 result[index] = valString 119 } 120 121 if len(d.Items()) != len(expectedFields) { 122 return nil, fmt.Errorf("Missing keys. Actual keys: %s", d.Keys()) 123 } 124 return result, nil 125 }