-
Notifications
You must be signed in to change notification settings - Fork 0
/
dependency.go
122 lines (99 loc) · 2.11 KB
/
dependency.go
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package qpm
import (
"context"
"slices"
"sync"
)
// dependencies stratumの依存しているstratumを再帰的に取得する
func dependencies(c Config, a Action, os OS, stratumName string, knownDeps map[string][]string) error {
if _, ok := knownDeps[stratumName]; ok {
return nil
}
var deps []string
if installed, error := IsAlreadyInstalled(stratumName); error != nil {
return error
} else if !installed {
sf, err := readStratumFile(c.AquiferPath, stratumName)
if err != nil {
return err
}
for _, v := range sf[a.String()] {
if slices.Contains(v.OS, os.String()) {
deps = v.Dependency
break
}
}
}
knownDeps[stratumName] = deps
for _, v := range deps {
if err := dependencies(c, a, os, v, knownDeps); err != nil {
return err
}
}
return nil
}
type task struct {
pkg string
deps []string
}
type multiTaskExec struct {
wg *sync.WaitGroup
started bool
tasks []task
packages *sync.Map
}
func (m *multiTaskExec) add(pkg string, deps []string) {
if m.started {
panic("already started")
}
m.wg.Add(1)
m.tasks = append(m.tasks, task{pkg: pkg, deps: deps})
if m.packages == nil {
m.packages = &sync.Map{}
}
if _, ok := m.packages.Load(pkg); !ok {
m.packages.Store(pkg, make(chan struct{}))
}
}
func (*multiTaskExec) waitAllChans(chans []chan struct{}) {
for _, c := range chans {
for {
if _, ok := <-c; !ok {
break
}
}
}
}
func (m *multiTaskExec) execTask(ctx context.Context, t task, f func(string)) {
depChans := make([]chan struct{}, 0)
for _, dep := range t.deps {
c, ok := m.packages.Load(dep)
if ok {
depChans = append(depChans, c.(chan struct{}))
}
}
m.waitAllChans(depChans)
f(t.pkg)
c, ok := m.packages.Load(t.pkg)
if ok {
close(c.(chan struct{}))
m.packages.Delete(t.pkg)
}
}
func (m *multiTaskExec) wait(f func(string)) {
if m.started {
panic("already started")
}
m.started = true
for _, t := range m.tasks {
go func(t task) {
defer m.wg.Done()
m.execTask(context.TODO(), t, f)
}(t)
}
m.wg.Wait()
}
func newMultiTaskExec() *multiTaskExec {
var wg sync.WaitGroup
return &multiTaskExec{wg: &wg}
}