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

     1  package feature
     2  
     3  import (
     4  	"fmt"
     5  )
     6  
     7  // The status of a feature flag
     8  // It starts as Active (we're using this flag to evaluate the feature)
     9  // Then when we no longer need it, we make it a noop. Leave it for an upgrade cycle.
    10  // Then move it to Obsolete, which will cause a warning. Leave it for an upgrade cycle.
    11  // Then remove the flag altogether.
    12  type Status int
    13  
    14  const (
    15  	Active Status = iota
    16  	Noop
    17  	Obsolete
    18  	// After Obsolete is Error, but it's not a value we can set
    19  )
    20  
    21  const MultipleContainersPerPod = "multiple_containers_per_pod"
    22  const Events = "events"
    23  const Snapshots = "snapshots"
    24  const UpdateHistory = "update_history"
    25  const Facets = "facets"
    26  const Labels = "labels"
    27  const LiveUpdateV2 = "live_update_v2"
    28  const DisableResources = "disable_resources"
    29  const BulkDisableResources = "bulk_disable_resources"
    30  const ClusterRefresh = "cluster_refresh"
    31  const OfflineSnapshotCreation = "offline_snapshot_creation"
    32  
    33  // The Value a flag can have. Status should never be changed.
    34  type Value struct {
    35  	Enabled bool
    36  	Status  Status
    37  }
    38  
    39  // Defaults is the initial values for a FeatureSet.
    40  // Don't modify after initializing.
    41  type Defaults map[string]Value
    42  
    43  // MainDefaults is the defaults we use in Main
    44  var MainDefaults = Defaults{
    45  	MultipleContainersPerPod: Value{
    46  		Enabled: true,
    47  		Status:  Obsolete,
    48  	},
    49  	Events: Value{
    50  		Enabled: true,
    51  		Status:  Obsolete,
    52  	},
    53  	Snapshots: Value{
    54  		Enabled: true,
    55  		// Snapshots FF is used by disable_snapshots() which hides the button
    56  		// in the web UI
    57  		Status: Active,
    58  	},
    59  	UpdateHistory: Value{
    60  		Enabled: false,
    61  		Status:  Obsolete,
    62  	},
    63  	Facets: Value{
    64  		Enabled: true,
    65  		Status:  Obsolete,
    66  	},
    67  	Labels: Value{
    68  		Enabled: true,
    69  		Status:  Obsolete,
    70  	},
    71  	LiveUpdateV2: Value{
    72  		Enabled: true,
    73  		Status:  Obsolete,
    74  	},
    75  	DisableResources: Value{
    76  		Enabled: true,
    77  		Status:  Obsolete,
    78  	},
    79  	BulkDisableResources: Value{
    80  		Enabled: false,
    81  		Status:  Obsolete,
    82  	},
    83  	ClusterRefresh: Value{
    84  		Enabled: false,
    85  		Status:  Active,
    86  	},
    87  	OfflineSnapshotCreation: Value{
    88  		Enabled: true,
    89  		Status:  Obsolete,
    90  	},
    91  }
    92  
    93  // FeatureSet is a mutable set of Features.
    94  type FeatureSet map[string]Value
    95  
    96  // Create a FeatureSet from defaults.
    97  func FromDefaults(d Defaults) FeatureSet {
    98  	r := make(FeatureSet)
    99  	for k, v := range d {
   100  		r[k] = v
   101  	}
   102  	return r
   103  }
   104  
   105  // ObsoleteError is an error that a feature flag is obsolete
   106  type ObsoleteError string
   107  
   108  func (s ObsoleteError) Error() string {
   109  	return string(s)
   110  }
   111  
   112  // Set sets enabled for a feature if it's active. Returns an error if flag is unknown or obsolete.
   113  func (s FeatureSet) Set(name string, enabled bool) error {
   114  	v, ok := s[name]
   115  	if !ok {
   116  		return fmt.Errorf("Unknown feature flag: %s", name)
   117  	}
   118  
   119  	switch v.Status {
   120  	case Obsolete:
   121  		return ObsoleteError(fmt.Sprintf("Obsolete feature flag: %s", name))
   122  	case Noop:
   123  		return nil
   124  	}
   125  
   126  	v.Enabled = enabled
   127  	s[name] = v
   128  	return nil
   129  }
   130  
   131  // Get gets whether a feature is enabled.
   132  func (s FeatureSet) Get(name string) bool {
   133  	v, ok := s[name]
   134  	if !ok {
   135  		panic("get of unknown feature flag (code should use feature.Foo instead of \"foo\" to get a flag)")
   136  	}
   137  	return v.Enabled
   138  }
   139  
   140  // ToEnabled returns a copy of the enabled values of the FeatureSet
   141  func (s FeatureSet) ToEnabled() map[string]bool {
   142  	r := make(map[string]bool)
   143  	for k, v := range s {
   144  		r[k] = v.Enabled
   145  	}
   146  	return r
   147  }