Compile configuration selector metadata during capture
This commit is contained in:
@@ -23,20 +23,21 @@ type scopeInventory struct {
|
||||
}
|
||||
|
||||
type preparedScope[I, S any] struct {
|
||||
scope Scope[I, S]
|
||||
selectorIndexes []int
|
||||
scope Scope[I, S]
|
||||
bindings []commandkit.Flag[I]
|
||||
}
|
||||
|
||||
type preparedSuite[I, S any] struct {
|
||||
newInput func() I
|
||||
newState func() S
|
||||
checkInput func(string, Selection, I) error
|
||||
scopes []preparedScope[I, S]
|
||||
byName map[string]*preparedScope[I, S]
|
||||
selectors []Selector[I]
|
||||
operations []Operation
|
||||
inventory scopeInventory
|
||||
issues []error
|
||||
newInput func() I
|
||||
newState func() S
|
||||
checkInput func(string, Selection, I) error
|
||||
scopes []*preparedScope[I, S]
|
||||
byName map[string]*preparedScope[I, S]
|
||||
bindingsByOperation map[Operation][]commandkit.Flag[I]
|
||||
scopeChoices string
|
||||
operations []Operation
|
||||
inventory scopeInventory
|
||||
issues []error
|
||||
}
|
||||
|
||||
// Command eagerly captures a configuration suite as a root-only config family.
|
||||
@@ -80,15 +81,16 @@ func AppCommand[T any](load func(context.Context, Selection) (*configkit.Result[
|
||||
|
||||
func captureSuite[I, S any](suite Suite[I, S]) *preparedSuite[I, S] {
|
||||
prepared := &preparedSuite[I, S]{
|
||||
newInput: suite.NewInput,
|
||||
newState: suite.NewState,
|
||||
checkInput: suite.CheckInput,
|
||||
byName: make(map[string]*preparedScope[I, S], len(suite.Scopes)),
|
||||
selectors: make([]Selector[I], len(suite.Selectors)),
|
||||
newInput: suite.NewInput,
|
||||
newState: suite.NewState,
|
||||
checkInput: suite.CheckInput,
|
||||
byName: make(map[string]*preparedScope[I, S], len(suite.Scopes)),
|
||||
bindingsByOperation: make(map[Operation][]commandkit.Flag[I]),
|
||||
}
|
||||
selectors := make([]Selector[I], len(suite.Selectors))
|
||||
for index, selector := range suite.Selectors {
|
||||
selector.Scopes = append([]string(nil), selector.Scopes...)
|
||||
prepared.selectors[index] = selector
|
||||
selectors[index] = selector
|
||||
}
|
||||
|
||||
seenNames := make(map[string]struct{}, len(suite.Scopes))
|
||||
@@ -113,16 +115,19 @@ func captureSuite[I, S any](suite Suite[I, S]) *preparedSuite[I, S] {
|
||||
if len(scope.Operations) > 0 && scope.Acquire == nil {
|
||||
prepared.issues = append(prepared.issues, fmt.Errorf("configuration scope %q declares operations without an acquisition callback", scope.Name))
|
||||
}
|
||||
prepared.scopes = append(prepared.scopes, preparedScope[I, S]{scope: scope})
|
||||
prepared.scopes = append(prepared.scopes, &preparedScope[I, S]{scope: scope})
|
||||
}
|
||||
// Appending above may move the backing array. Rebuild the lookup only after
|
||||
// the ordered scope slice is complete.
|
||||
prepared.byName = make(map[string]*preparedScope[I, S], len(prepared.scopes))
|
||||
for index := range prepared.scopes {
|
||||
prepared.byName[prepared.scopes[index].scope.Name] = &prepared.scopes[index]
|
||||
sort.SliceStable(prepared.scopes, func(i, j int) bool {
|
||||
return scopeOrder(prepared.scopes[i].scope.Name) < scopeOrder(prepared.scopes[j].scope.Name)
|
||||
})
|
||||
names := make([]string, 0, len(prepared.scopes))
|
||||
for _, scope := range prepared.scopes {
|
||||
prepared.byName[scope.scope.Name] = scope
|
||||
names = append(names, scope.scope.Name)
|
||||
}
|
||||
prepared.scopeChoices = joinNames(names)
|
||||
|
||||
for index, selector := range prepared.selectors {
|
||||
for index, selector := range selectors {
|
||||
seen := make(map[string]struct{}, len(selector.Scopes))
|
||||
uniqueScopes := make([]string, 0, len(selector.Scopes))
|
||||
for _, name := range selector.Scopes {
|
||||
@@ -135,17 +140,17 @@ func captureSuite[I, S any](suite Suite[I, S]) *preparedSuite[I, S] {
|
||||
seen[name] = struct{}{}
|
||||
uniqueScopes = append(uniqueScopes, name)
|
||||
}
|
||||
prepared.selectors[index].Scopes = uniqueScopes
|
||||
selectors[index].Scopes = uniqueScopes
|
||||
if len(selector.Scopes) == 0 {
|
||||
for scopeIndex := range prepared.scopes {
|
||||
if len(prepared.scopes[scopeIndex].scope.Operations) > 0 {
|
||||
prepared.scopes[scopeIndex].selectorIndexes = append(prepared.scopes[scopeIndex].selectorIndexes, index)
|
||||
prepared.scopes[scopeIndex].bindings = append(prepared.scopes[scopeIndex].bindings, selector.Binding)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, name := range uniqueScopes {
|
||||
if scope, exists := prepared.byName[name]; exists && len(scope.scope.Operations) > 0 {
|
||||
scope.selectorIndexes = append(scope.selectorIndexes, index)
|
||||
scope.bindings = append(scope.bindings, selector.Binding)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -158,8 +163,16 @@ func captureSuite[I, S any](suite Suite[I, S]) *preparedSuite[I, S] {
|
||||
break
|
||||
}
|
||||
}
|
||||
for _, selector := range selectors {
|
||||
for _, scope := range prepared.scopes {
|
||||
if containsOperation(scope.scope.Operations, operation) && selectorApplies(selector.Scopes, scope.scope.Name) {
|
||||
prepared.bindingsByOperation[operation] = append(prepared.bindingsByOperation[operation], selector.Binding)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, scope := range orderedScopeRecords(prepared.scopes) {
|
||||
for _, scope := range prepared.scopes {
|
||||
prepared.inventory.Scopes = append(prepared.inventory.Scopes, scopeMetadata{
|
||||
Name: scope.scope.Name,
|
||||
Operations: append([]Operation(nil), scope.scope.Operations...),
|
||||
@@ -187,14 +200,6 @@ func normalizeOperations(operations []Operation, issues *[]error, scope string)
|
||||
return ordered
|
||||
}
|
||||
|
||||
func orderedScopeRecords[I, S any](scopes []preparedScope[I, S]) []preparedScope[I, S] {
|
||||
ordered := append([]preparedScope[I, S](nil), scopes...)
|
||||
sort.SliceStable(ordered, func(i, j int) bool {
|
||||
return scopeOrder(ordered[i].scope.Name) < scopeOrder(ordered[j].scope.Name)
|
||||
})
|
||||
return ordered
|
||||
}
|
||||
|
||||
func scopeOrder(name string) string {
|
||||
switch name {
|
||||
case "app":
|
||||
|
||||
Reference in New Issue
Block a user