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

     1  package config
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/pkg/errors"
     7  	"go.starlark.net/starlark"
     8  
     9  	"github.com/tilt-dev/tilt/internal/sliceutils"
    10  	"github.com/tilt-dev/tilt/internal/tiltfile/starkit"
    11  	"github.com/tilt-dev/tilt/internal/tiltfile/value"
    12  	"github.com/tilt-dev/tilt/pkg/apis/core/v1alpha1"
    13  	"github.com/tilt-dev/tilt/pkg/model"
    14  )
    15  
    16  func setEnabledResources(thread *starlark.Thread, fn *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
    17  	var slResources starlark.Sequence
    18  	err := starkit.UnpackArgs(thread, fn.Name(), args, kwargs,
    19  		"resources",
    20  		&slResources,
    21  	)
    22  	if err != nil {
    23  		return starlark.None, err
    24  	}
    25  
    26  	resources, err := value.SequenceToStringSlice(slResources)
    27  	if err != nil {
    28  		return starlark.None, errors.Wrap(err, "resources must be a list of string")
    29  	}
    30  
    31  	var mns []model.ManifestName
    32  	for _, r := range resources {
    33  		mns = append(mns, model.ManifestName(r))
    34  	}
    35  
    36  	err = starkit.SetState(thread, func(settings Settings) Settings {
    37  		settings.disableAll = false
    38  		settings.enabledResources = mns
    39  		return settings
    40  	})
    41  	if err != nil {
    42  		return starlark.None, err
    43  	}
    44  
    45  	return starlark.None, nil
    46  }
    47  
    48  func clearEnabledResources(thread *starlark.Thread, fn *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
    49  	err := starkit.UnpackArgs(thread, fn.Name(), args, kwargs)
    50  	if err != nil {
    51  		return starlark.None, err
    52  	}
    53  
    54  	err = starkit.SetState(thread, func(settings Settings) Settings {
    55  		settings.disableAll = true
    56  		settings.enabledResources = nil
    57  		return settings
    58  	})
    59  	return starlark.None, err
    60  }
    61  
    62  // for the given args and list of full manifests, figure out which manifests the user actually selected
    63  func (s Settings) EnabledResources(tf *v1alpha1.Tiltfile, manifests []model.Manifest) ([]model.ManifestName, error) {
    64  	if s.disableAll {
    65  		return nil, nil
    66  	}
    67  
    68  	// by default, nil = match all resources
    69  	var requestedManifests []model.ManifestName
    70  
    71  	// if the user called set_enabled_resources, that trumps everything
    72  	if s.enabledResources != nil {
    73  		requestedManifests = s.enabledResources
    74  	} else {
    75  		args := tf.Spec.Args
    76  
    77  		// if the user has not called config.parse and has specified args, use those to select which resources
    78  		if args != nil && !s.configParseCalled {
    79  			for _, arg := range args {
    80  				requestedManifests = append(requestedManifests, model.ManifestName(arg))
    81  			}
    82  		}
    83  	}
    84  
    85  	return match(manifests, requestedManifests)
    86  }
    87  
    88  // add `manifestToAdd` and all of its transitive deps to `result`
    89  func addManifestAndDeps(result map[model.ManifestName]bool, allManifestsByName map[model.ManifestName]model.Manifest, manifestToAdd model.ManifestName) {
    90  	if result[manifestToAdd] {
    91  		return
    92  	}
    93  	result[manifestToAdd] = true
    94  	for _, dep := range allManifestsByName[manifestToAdd].ResourceDependencies {
    95  		addManifestAndDeps(result, allManifestsByName, dep)
    96  	}
    97  }
    98  
    99  // If the user requested only a subset of manifests, get just those manifests
   100  func match(manifests []model.Manifest, requestedManifests []model.ManifestName) ([]model.ManifestName, error) {
   101  	if len(requestedManifests) == 0 {
   102  		var result []model.ManifestName
   103  		for _, m := range manifests {
   104  			result = append(result, m.Name)
   105  		}
   106  		return result, nil
   107  	}
   108  
   109  	manifestsByName := make(map[model.ManifestName]model.Manifest)
   110  	for _, m := range manifests {
   111  		manifestsByName[m.Name] = m
   112  	}
   113  
   114  	manifestsToRun := make(map[model.ManifestName]bool)
   115  	var unknownNames []string
   116  
   117  	for _, m := range requestedManifests {
   118  		if _, ok := manifestsByName[m]; !ok {
   119  			unknownNames = append(unknownNames, string(m))
   120  			continue
   121  		}
   122  
   123  		addManifestAndDeps(manifestsToRun, manifestsByName, m)
   124  	}
   125  
   126  	var result []model.ManifestName
   127  	for _, m := range manifests {
   128  		// Default to including UnresourcedYAML ("Uncategorized") to match historical behavior.
   129  		if manifestsToRun[m.Name] || m.Name == model.UnresourcedYAMLManifestName {
   130  			result = append(result, m.Name)
   131  		}
   132  	}
   133  
   134  	if len(unknownNames) > 0 {
   135  		unmatchedNames := unmatchedManifestNames(manifests, requestedManifests)
   136  
   137  		return nil, fmt.Errorf(`You specified some resources that could not be found: %s
   138  Is this a typo? Existing resources in Tiltfile: %s`,
   139  			sliceutils.QuotedStringList(unknownNames),
   140  			sliceutils.QuotedStringList(unmatchedNames))
   141  	}
   142  
   143  	return result, nil
   144  }
   145  
   146  func unmatchedManifestNames(manifests []model.Manifest, requestedManifests []model.ManifestName) []string {
   147  	requestedManifestsByName := make(map[model.ManifestName]bool)
   148  	for _, m := range requestedManifests {
   149  		requestedManifestsByName[m] = true
   150  	}
   151  
   152  	var ret []string
   153  	for _, m := range manifests {
   154  		if _, ok := requestedManifestsByName[m.Name]; !ok {
   155  			ret = append(ret, string(m.Name))
   156  		}
   157  	}
   158  
   159  	return ret
   160  }