github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/tiltfile/value/label.go (about) 1 package value 2 3 import ( 4 "fmt" 5 "strings" 6 7 "go.starlark.net/starlark" 8 validation "k8s.io/apimachinery/pkg/util/validation" 9 ) 10 11 type LabelValue string 12 13 func (lv *LabelValue) Unpack(v starlark.Value) error { 14 str, ok := AsString(v) 15 if !ok { 16 return fmt.Errorf("Value should be convertible to string, but is type %s", v.Type()) 17 } 18 19 validationErrors := validation.IsQualifiedName(str) 20 if len(validationErrors) != 0 { 21 return fmt.Errorf("Invalid label %q: %s", str, strings.Join(validationErrors, ", ")) 22 } 23 24 validLabelValueErrors := validation.IsValidLabelValue(str) 25 if len(validLabelValueErrors) != 0 { 26 return fmt.Errorf("Invalid label %q: %s", str, strings.Join(validLabelValueErrors, ", ")) 27 } 28 29 // Tilt assumes prefixed labels are not added by the user and thus doesn't use them 30 // for resource grouping. For now, disallow users from adding prefixes so that they're 31 // not confused when they don't show up in resource groups. 32 if strings.Contains(str, "/") { 33 return fmt.Errorf("Invalid label %q: cannot contain /", str) 34 } 35 36 *lv = LabelValue(str) 37 38 return nil 39 } 40 41 func (lv *LabelValue) String() string { 42 return string(*lv) 43 } 44 45 type LabelSet struct { 46 Values map[string]string 47 } 48 49 var _ starlark.Unpacker = &LabelSet{} 50 51 // Unpack an argument that can either be expressed as 52 // a string or as a list of strings. 53 func (ls *LabelSet) Unpack(v starlark.Value) error { 54 ls.Values = nil 55 if v == nil { 56 return nil 57 } 58 59 _, ok := v.(starlark.String) 60 if ok { 61 var l LabelValue 62 err := l.Unpack(v) 63 if err != nil { 64 return err 65 } 66 ls.Values = map[string]string{l.String(): l.String()} 67 return nil 68 } 69 70 var iter starlark.Iterator 71 switch x := v.(type) { 72 case *starlark.List: 73 iter = x.Iterate() 74 case starlark.Tuple: 75 iter = x.Iterate() 76 case starlark.NoneType: 77 return nil 78 default: 79 return fmt.Errorf("value should be a label or List or Tuple of labels, but is of type %s", v.Type()) 80 } 81 82 defer iter.Done() 83 var item starlark.Value 84 ls.Values = make(map[string]string) 85 for iter.Next(&item) { 86 var l LabelValue 87 err := l.Unpack(item) 88 if err != nil { 89 return err 90 } 91 ls.Values[l.String()] = l.String() 92 } 93 94 return nil 95 }