@@ -2,7 +2,6 @@ package mg
2
2
3
3
import (
4
4
"context"
5
- "fmt"
6
5
"log"
7
6
"os"
8
7
"reflect"
@@ -36,7 +35,6 @@ func (o *onceMap) LoadOrStore(f Fn) *onceFun {
36
35
return existing
37
36
}
38
37
one := & onceFun {
39
- once : & sync.Once {},
40
38
fn : f ,
41
39
displayName : displayName (f .Name ()),
42
40
}
@@ -91,37 +89,44 @@ func CtxDeps(ctx context.Context, fns ...interface{}) {
91
89
92
90
// runDeps assumes you've already called checkFns.
93
91
func runDeps (ctx context.Context , fns []Fn ) {
94
- mu := & sync.Mutex {}
95
- var errs []string
96
- var exit int
97
- wg := & sync.WaitGroup {}
92
+ resultCh := make (chan error , len (fns ))
93
+ var wg sync.WaitGroup
94
+ wg .Add (len (fns ))
98
95
for _ , f := range fns {
99
96
fn := onces .LoadOrStore (f )
100
- wg .Add (1 )
101
97
go func () {
102
98
defer func () {
103
99
if v := recover (); v != nil {
104
- mu .Lock ()
105
- if err , ok := v .(error ); ok {
106
- exit = changeExit (exit , ExitStatus (err ))
107
- } else {
108
- exit = changeExit (exit , 1 )
100
+ var err error
101
+ var ok bool
102
+ if err , ok = v .(error ); ! ok {
103
+ err = Fatal (1 )
104
+ }
105
+ select {
106
+ case <- ctx .Done ():
107
+ case resultCh <- err :
109
108
}
110
- errs = append (errs , fmt .Sprint (v ))
111
- mu .Unlock ()
112
109
}
113
110
wg .Done ()
114
111
}()
115
- if err := fn .run (ctx ); err != nil {
116
- mu .Lock ()
117
- errs = append (errs , fmt .Sprint (err ))
118
- exit = changeExit (exit , ExitStatus (err ))
119
- mu .Unlock ()
112
+ err := fn .run (ctx )
113
+ select {
114
+ case <- ctx .Done ():
115
+ case resultCh <- err :
120
116
}
121
117
}()
122
118
}
123
119
124
120
wg .Wait ()
121
+ close (resultCh )
122
+ var errs []string
123
+ var exit int
124
+ for err := range resultCh {
125
+ if err != nil {
126
+ errs = append (errs , err .Error ())
127
+ exit = changeExit (exit , ExitStatus (err ))
128
+ }
129
+ }
125
130
if len (errs ) > 0 {
126
131
panic (Fatal (exit , strings .Join (errs , "\n " )))
127
132
}
@@ -184,9 +189,12 @@ func displayName(name string) string {
184
189
}
185
190
186
191
type onceFun struct {
187
- once * sync.Once
192
+ once sync.Once
188
193
fn Fn
189
194
err error
195
+ // depPanicked references the panic a dependency had previously
196
+ // failed with if set
197
+ depPanicked interface {}
190
198
191
199
displayName string
192
200
}
@@ -195,10 +203,19 @@ type onceFun struct {
195
203
// the same error output.
196
204
func (o * onceFun ) run (ctx context.Context ) error {
197
205
o .once .Do (func () {
206
+ defer func () {
207
+ if v := recover (); v != nil {
208
+ o .depPanicked = v
209
+ panic (v )
210
+ }
211
+ }()
198
212
if Verbose () {
199
213
logger .Println ("Running dependency:" , displayName (o .fn .Name ()))
200
214
}
201
215
o .err = o .fn .Run (ctx )
202
216
})
217
+ if o .depPanicked != nil {
218
+ panic (o .depPanicked )
219
+ }
203
220
return o .err
204
221
}
0 commit comments