1
2
3
4
5 package script
6
7 import (
8 "cmd/go/internal/imports"
9 "fmt"
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 := imports.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 := imports.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{eval: eval, usage: CondUsage{Summary: summary}}
127 }
128
129 type onceCond struct {
130 once sync.Once
131 v bool
132 err error
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 l.once.Do(func() { l.v, l.err = l.eval() })
144 return l.v, l.err
145 }
146
147
148
149
150
151
152
153 func CachedCondition(summary string, eval func(string) (bool, error)) Cond {
154 return &cachedCond{eval: eval, usage: CondUsage{Summary: summary, Prefix: true}}
155 }
156
157 type cachedCond struct {
158 m sync.Map
159 eval func(string) (bool, error)
160 usage CondUsage
161 }
162
163 func (c *cachedCond) Usage() *CondUsage { return &c.usage }
164
165 func (c *cachedCond) Eval(_ *State, suffix string) (bool, error) {
166 for {
167 var ready chan struct{}
168
169 v, loaded := c.m.Load(suffix)
170 if !loaded {
171 ready = make(chan struct{})
172 v, loaded = c.m.LoadOrStore(suffix, (<-chan struct{})(ready))
173
174 if !loaded {
175 inPanic := true
176 defer func() {
177 if inPanic {
178 c.m.Delete(suffix)
179 }
180 close(ready)
181 }()
182
183 b, err := c.eval(suffix)
184 inPanic = false
185
186 if err == nil {
187 c.m.Store(suffix, b)
188 return b, nil
189 } else {
190 c.m.Store(suffix, err)
191 return false, err
192 }
193 }
194 }
195
196 switch v := v.(type) {
197 case bool:
198 return v, nil
199 case error:
200 return false, v
201 case <-chan struct{}:
202 <-v
203 }
204 }
205 }
206
View as plain text