/usr/share/gocode/src/github.com/constabulary/gb/executor.go is in golang-github-constabulary-gb-dev 0.4.4-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | package gb
import (
"sync"
"github.com/pkg/errors"
)
// Execute executes a tree of *Actions sequentually in depth first order.
func Execute(a *Action) error {
seen := make(map[*Action]error)
return execute(seen, a)
}
func execute(seen map[*Action]error, a *Action) error {
// step 0, have we been here before
if err, ok := seen[a]; ok {
return err
}
// step 1, build all dependencies
for _, d := range a.Deps {
if err := execute(seen, d); err != nil {
return err
}
}
// step 2, now execute ourselves
err := a.Run()
seen[a] = err
return err
}
// ExecuteConcurrent executes all actions in a tree concurrently.
// Each Action will wait until its dependant actions are complete.
func ExecuteConcurrent(a *Action, n int, interrupt <-chan struct{}) error {
var mu sync.Mutex // protects seen
seen := make(map[*Action]chan error)
get := func(result chan error) error {
err := <-result
result <- err
return err
}
permits := make(chan bool, n)
for i := 0; i < cap(permits); i++ {
permits <- true
}
// wg tracks all the outstanding actions
var wg sync.WaitGroup
var execute func(map[*Action]chan error, *Action) chan error
execute = func(seen map[*Action]chan error, a *Action) chan error {
// step 0, have we seen this action before ?
mu.Lock()
if result, ok := seen[a]; ok {
// yes! return the result channel so others can wait
// on our action
mu.Unlock()
return result
}
// step 1, we're the first to run this action
result := make(chan error, 1)
seen[a] = result
mu.Unlock()
// queue all dependant actions.
var results []chan error
for _, dep := range a.Deps {
results = append(results, execute(seen, dep))
}
wg.Add(1)
go func() {
defer wg.Done()
// wait for dependant actions
for _, r := range results {
if err := get(r); err != nil {
result <- err
return
}
}
// wait for a permit and execute our action
select {
case <-permits:
result <- a.Run()
permits <- true
case <-interrupt:
result <- errors.New("interrupted")
return
}
}()
return result
}
err := get(execute(seen, a))
wg.Wait()
return err
}
|