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  }