github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/tiltfile/links/links.go (about)

     1  package links
     2  
     3  import (
     4  	"fmt"
     5  	"net/url"
     6  
     7  	"github.com/pkg/errors"
     8  	"go.starlark.net/starlark"
     9  	"go.starlark.net/starlarkstruct"
    10  
    11  	"github.com/tilt-dev/tilt/pkg/model"
    12  
    13  	"github.com/tilt-dev/tilt/internal/tiltfile/starkit"
    14  	"github.com/tilt-dev/tilt/internal/tiltfile/value"
    15  )
    16  
    17  type Link struct {
    18  	*starlarkstruct.Struct
    19  	model.Link
    20  }
    21  
    22  var _ starlark.Value = Link{}
    23  
    24  // Parse resource links (string or `link`) into model.Link
    25  // Not to be confused with a LinkED List :P
    26  type LinkList struct {
    27  	Links []model.Link
    28  }
    29  
    30  func (ll *LinkList) Unpack(v starlark.Value) error {
    31  	seq := value.ValueOrSequenceToSlice(v)
    32  	for _, val := range seq {
    33  		switch val := val.(type) {
    34  		case starlark.String:
    35  			li, err := strToLink(val)
    36  			if err != nil {
    37  				return err
    38  			}
    39  			ll.Links = append(ll.Links, li)
    40  		case Link:
    41  			ll.Links = append(ll.Links, val.Link)
    42  		default:
    43  			return fmt.Errorf("`Want a string, a link, or a sequence of these; found %v (type: %T)", val, val)
    44  		}
    45  	}
    46  	return nil
    47  }
    48  
    49  func strToLink(s starlark.String) (model.Link, error) {
    50  	withScheme, err := parseAndMaybeAddScheme(string(s))
    51  	if err != nil {
    52  		return model.Link{}, errors.Wrapf(err, "validating URL %q", string(s))
    53  	}
    54  	return model.Link{URL: withScheme}, nil
    55  }
    56  
    57  func parseAndMaybeAddScheme(uStr string) (*url.URL, error) {
    58  	if uStr == "" {
    59  		return nil, fmt.Errorf("url empty")
    60  	}
    61  	u, err := url.Parse(uStr)
    62  	if err != nil {
    63  		// NOTE(maia): this unfortunately isn't a very robust check, `url.Parse`
    64  		// returns an error in very few cases, but it's better than nothing.
    65  		return nil, err
    66  	}
    67  
    68  	if u.Scheme == "" {
    69  		// If the given URL string doesn't have a scheme, assume it's http
    70  		u.Scheme = "http"
    71  	}
    72  
    73  	return u, nil
    74  }
    75  
    76  // Implements functions for dealing with k8s secret settings.
    77  type Plugin struct{}
    78  
    79  var _ starkit.Plugin = Plugin{}
    80  
    81  func NewPlugin() Plugin {
    82  	return Plugin{}
    83  }
    84  
    85  func (e Plugin) OnStart(env *starkit.Environment) error {
    86  	return env.AddBuiltin("link", e.link)
    87  }
    88  
    89  func (e Plugin) link(thread *starlark.Thread, fn *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
    90  	var url, name string
    91  
    92  	if err := starkit.UnpackArgs(thread, fn.Name(), args, kwargs,
    93  		"url", &url,
    94  		"name?", &name); err != nil {
    95  		return nil, err
    96  	}
    97  
    98  	withScheme, err := parseAndMaybeAddScheme(url)
    99  	if err != nil {
   100  		return nil, errors.Wrapf(err, "validating URL %q", url)
   101  	}
   102  
   103  	return Link{
   104  		Struct: starlarkstruct.FromStringDict(starlark.String("link"), starlark.StringDict{
   105  			"url":  starlark.String(withScheme.String()),
   106  			"name": starlark.String(name),
   107  		}),
   108  		Link: model.Link{
   109  			URL:  withScheme,
   110  			Name: name,
   111  		},
   112  	}, nil
   113  }