]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/helper/experiment/experiment.go
Initial transfer of provider code
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / helper / experiment / experiment.go
1 // experiment package contains helper functions for tracking experimental
2 // features throughout Terraform.
3 //
4 // This package should be used for creating, enabling, querying, and deleting
5 // experimental features. By unifying all of that onto a single interface,
6 // we can have the Go compiler help us by enforcing every place we touch
7 // an experimental feature.
8 //
9 // To create a new experiment:
10 //
11 // 1. Add the experiment to the global vars list below, prefixed with X_
12 //
13 // 2. Add the experiment variable to the All listin the init() function
14 //
15 // 3. Use it!
16 //
17 // To remove an experiment:
18 //
19 // 1. Delete the experiment global var.
20 //
21 // 2. Try to compile and fix all the places where the var was referenced.
22 //
23 // To use an experiment:
24 //
25 // 1. Use Flag() if you want the experiment to be available from the CLI.
26 //
27 // 2. Use Enabled() to check whether it is enabled.
28 //
29 // As a general user:
30 //
31 // 1. The `-Xexperiment-name` flag
32 // 2. The `TF_X_<experiment-name>` env var.
33 // 3. The `TF_X_FORCE` env var can be set to force an experimental feature
34 // without human verifications.
35 //
36 package experiment
37
38 import (
39 "flag"
40 "fmt"
41 "os"
42 "strconv"
43 "strings"
44 "sync"
45 )
46
47 // The experiments that are available are listed below. Any package in
48 // Terraform defining an experiment should define the experiments below.
49 // By keeping them all within the experiment package we force a single point
50 // of definition and use. This allows the compiler to enforce references
51 // so it becomes easy to remove the features.
52 var (
53 // Shadow graph. This is already on by default. Disabling it will be
54 // allowed for awhile in order for it to not block operations.
55 X_shadow = newBasicID("shadow", "SHADOW", false)
56 )
57
58 // Global variables this package uses because we are a package
59 // with global state.
60 var (
61 // all is the list of all experiements. Do not modify this.
62 All []ID
63
64 // enabled keeps track of what flags have been enabled
65 enabled map[string]bool
66 enabledLock sync.Mutex
67
68 // Hidden "experiment" that forces all others to be on without verification
69 x_force = newBasicID("force", "FORCE", false)
70 )
71
72 func init() {
73 // The list of all experiments, update this when an experiment is added.
74 All = []ID{
75 X_shadow,
76 x_force,
77 }
78
79 // Load
80 reload()
81 }
82
83 // reload is used by tests to reload the global state. This is called by
84 // init publicly.
85 func reload() {
86 // Initialize
87 enabledLock.Lock()
88 enabled = make(map[string]bool)
89 enabledLock.Unlock()
90
91 // Set defaults and check env vars
92 for _, id := range All {
93 // Get the default value
94 def := id.Default()
95
96 // If we set it in the env var, default it to true
97 key := fmt.Sprintf("TF_X_%s", strings.ToUpper(id.Env()))
98 if v := os.Getenv(key); v != "" {
99 def = v != "0"
100 }
101
102 // Set the default
103 SetEnabled(id, def)
104 }
105 }
106
107 // Enabled returns whether an experiment has been enabled or not.
108 func Enabled(id ID) bool {
109 enabledLock.Lock()
110 defer enabledLock.Unlock()
111 return enabled[id.Flag()]
112 }
113
114 // SetEnabled sets an experiment to enabled/disabled. Please check with
115 // the experiment docs for when calling this actually affects the experiment.
116 func SetEnabled(id ID, v bool) {
117 enabledLock.Lock()
118 defer enabledLock.Unlock()
119 enabled[id.Flag()] = v
120 }
121
122 // Force returns true if the -Xforce of TF_X_FORCE flag is present, which
123 // advises users of this package to not verify with the user that they want
124 // experimental behavior and to just continue with it.
125 func Force() bool {
126 return Enabled(x_force)
127 }
128
129 // Flag configures the given FlagSet with the flags to configure
130 // all active experiments.
131 func Flag(fs *flag.FlagSet) {
132 for _, id := range All {
133 desc := id.Flag()
134 key := fmt.Sprintf("X%s", id.Flag())
135 fs.Var(&idValue{X: id}, key, desc)
136 }
137 }
138
139 // idValue implements flag.Value for setting the enabled/disabled state
140 // of an experiment from the CLI.
141 type idValue struct {
142 X ID
143 }
144
145 func (v *idValue) IsBoolFlag() bool { return true }
146 func (v *idValue) String() string { return strconv.FormatBool(Enabled(v.X)) }
147 func (v *idValue) Set(raw string) error {
148 b, err := strconv.ParseBool(raw)
149 if err == nil {
150 SetEnabled(v.X, b)
151 }
152
153 return err
154 }