Skip to content

Commit 01f62ae

Browse files
committed
Fix circular dependency detection
Ensure circular dependencies are detected a panic with the plugin URI that first experienced the circular dependency. Signed-off-by: Derek McGowan <derek@mcg.dev>
1 parent 8599102 commit 01f62ae

1 file changed

Lines changed: 20 additions & 10 deletions

File tree

plugin.go

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -112,34 +112,44 @@ type Registry []*Registration
112112
// Graph computes the ordered list of registrations based on their dependencies,
113113
// filtering out any plugins which match the provided filter.
114114
func (registry Registry) Graph(filter DisableFilter) []Registration {
115-
handled := make(map[*Registration]bool, len(registry))
115+
handled := make(map[*Registration]struct{}, len(registry))
116116
if filter != nil {
117117
for _, r := range registry {
118118
if filter(r) {
119-
handled[r] = true
119+
handled[r] = struct{}{}
120120
}
121121
}
122122
}
123123

124124
ordered := make([]Registration, 0, len(registry)-len(handled))
125+
stack := make([]*Registration, 0, cap(ordered))
125126
for _, r := range registry {
126-
if handled[r] {
127+
if _, ok := handled[r]; ok {
127128
continue
128129
}
129-
handled[r] = true
130-
children(r, registry, handled, &ordered)
130+
children(append(stack, r), registry, handled, &ordered)
131+
handled[r] = struct{}{}
131132
ordered = append(ordered, *r)
132133
}
133134
return ordered
134135
}
135136

136-
func children(reg *Registration, registry []*Registration, handled map[*Registration]bool, ordered *[]Registration) {
137+
func children(stack []*Registration, registry []*Registration, handled map[*Registration]struct{}, ordered *[]Registration) {
138+
reg := stack[len(stack)-1]
137139
for _, t := range reg.Requires {
138140
for _, r := range registry {
139-
if (t == "*" || r.Type == t) && r != reg && !handled[r] {
140-
handled[r] = true
141-
children(r, registry, handled, ordered)
142-
*ordered = append(*ordered, *r)
141+
if (t == "*" || r.Type == t) && r != reg {
142+
if _, ok := handled[r]; !ok {
143+
// Ensure not in current stack
144+
for _, p := range stack[:len(stack)-1] {
145+
if p == r {
146+
panic(fmt.Errorf("circular plugin dependency at %s: %w", r.URI(), ErrPluginCircularDependency))
147+
}
148+
}
149+
children(append(stack, r), registry, handled, ordered)
150+
handled[r] = struct{}{}
151+
*ordered = append(*ordered, *r)
152+
}
143153
}
144154
}
145155
}

0 commit comments

Comments
 (0)