1
2
3
4
5 package script
6
7 import (
8 "fmt"
9 "internal/syslist"
10 "os"
11 "runtime"
12 "sync"
13 )
14
15
16
17
18
19 func DefaultConds() map[string]Cond {
20 conds := make(map[string]Cond)
21
22 conds["GOOS"] = PrefixCondition(
23 "runtime.GOOS == <suffix>",
24 func(_ *State, suffix string) (bool, error) {
25 if suffix == runtime.GOOS {
26 return true, nil
27 }
28 if _, ok := syslist.KnownOS[suffix]; !ok {
29 return false, fmt.Errorf("unrecognized GOOS %q", suffix)
30 }
31 return false, nil
32 })
33
34 conds["GOARCH"] = PrefixCondition(
35 "runtime.GOARCH == <suffix>",
36 func(_ *State, suffix string) (bool, error) {
37 if suffix == runtime.GOARCH {
38 return true, nil
39 }
40 if _, ok := syslist.KnownArch[suffix]; !ok {
41 return false, fmt.Errorf("unrecognized GOOS %q", suffix)
42 }
43 return false, nil
44 })
45
46 conds["compiler"] = PrefixCondition(
47 "runtime.Compiler == <suffix>",
48 func(_ *State, suffix string) (bool, error) {
49 if suffix == runtime.Compiler {
50 return true, nil
51 }
52 switch suffix {
53 case "gc", "gccgo":
54 return false, nil
55 default:
56 return false, fmt.Errorf("unrecognized compiler %q", suffix)
57 }
58 })
59
60 conds["root"] = BoolCondition("os.Geteuid() == 0", os.Geteuid() == 0)
61
62 return conds
63 }
64
65
66 func Condition(summary string, eval func(*State) (bool, error)) Cond {
67 return &funcCond{eval: eval, usage: CondUsage{Summary: summary}}
68 }
69
70 type funcCond struct {
71 eval func(*State) (bool, error)
72 usage CondUsage
73 }
74
75 func (c *funcCond) Usage() *CondUsage { return &c.usage }
76
77 func (c *funcCond) Eval(s *State, suffix string) (bool, error) {
78 if suffix != "" {
79 return false, ErrUsage
80 }
81 return c.eval(s)
82 }
83
84
85 func PrefixCondition(summary string, eval func(*State, string) (bool, error)) Cond {
86 return &prefixCond{eval: eval, usage: CondUsage{Summary: summary, Prefix: true}}
87 }
88
89 type prefixCond struct {
90 eval func(*State, string) (bool, error)
91 usage CondUsage
92 }
93
94 func (c *prefixCond) Usage() *CondUsage { return &c.usage }
95
96 func (c *prefixCond) Eval(s *State, suffix string) (bool, error) {
97 return c.eval(s, suffix)
98 }
99
100
101
102 func BoolCondition(summary string, v bool) Cond {
103 return &boolCond{v: v, usage: CondUsage{Summary: summary}}
104 }
105
106 type boolCond struct {
107 v bool
108 usage CondUsage
109 }
110
111 func (b *boolCond) Usage() *CondUsage { return &b.usage }
112
113 func (b *boolCond) Eval(s *State, suffix string) (bool, error) {
114 if suffix != "" {
115 return false, ErrUsage
116 }
117 return b.v, nil
118 }
119
120
121
122
123
124
125 func OnceCondition(summary string, eval func() (bool, error)) Cond {
126 return &onceCond{
127 eval: sync.OnceValues(eval),
128 usage: CondUsage{Summary: summary},
129 }
130 }
131
132 type onceCond struct {
133 eval func() (bool, error)
134 usage CondUsage
135 }
136
137 func (l *onceCond) Usage() *CondUsage { return &l.usage }
138
139 func (l *onceCond) Eval(s *State, suffix string) (bool, error) {
140 if suffix != "" {
141 return false, ErrUsage
142 }
143 return l.eval()
144 }
145
146
147
148
149
150
151
152 func CachedCondition(summary string, eval func(string) (bool, error)) Cond {
153 return &cachedCond{eval: eval, usage: CondUsage{Summary: summary, Prefix: true}}
154 }
155
156 type cachedCond struct {
157 m sync.Map
158 eval func(string) (bool, error)
159 usage CondUsage
160 }
161
162 func (c *cachedCond) Usage() *CondUsage { return &c.usage }
163
164 func (c *cachedCond) Eval(_ *State, suffix string) (bool, error) {
165 for {
166 var ready chan struct{}
167
168 v, loaded := c.m.Load(suffix)
169 if !loaded {
170 ready = make(chan struct{})
171 v, loaded = c.m.LoadOrStore(suffix, (<-chan struct{})(ready))
172
173 if !loaded {
174 inPanic := true
175 defer func() {
176 if inPanic {
177 c.m.Delete(suffix)
178 }
179 close(ready)
180 }()
181
182 b, err := c.eval(suffix)
183 inPanic = false
184
185 if err == nil {
186 c.m.Store(suffix, b)
187 return b, nil
188 } else {
189 c.m.Store(suffix, err)
190 return false, err
191 }
192 }
193 }
194
195 switch v := v.(type) {
196 case bool:
197 return v, nil
198 case error:
199 return false, v
200 case <-chan struct{}:
201 <-v
202 }
203 }
204 }
205
View as plain text