Prepare configuration scope metadata
This commit is contained in:
109
config.go
109
config.go
@@ -97,6 +97,14 @@ type scopesInventory struct {
|
||||
Scopes []configScopeInfo `yaml:"scopes"`
|
||||
}
|
||||
|
||||
type preparedConfigSuite[C any] struct {
|
||||
suite ConfigSuite[C]
|
||||
ordered []ConfigScope[C]
|
||||
byName map[string]ConfigScope[C]
|
||||
installed []ConfigOperation
|
||||
inventory scopesInventory
|
||||
}
|
||||
|
||||
type configScopesInput struct {
|
||||
Format string
|
||||
}
|
||||
@@ -135,42 +143,27 @@ func RegisterConfig[C any](app *App, suite ConfigSuite[C]) error {
|
||||
if _, exists := app.commands["config"]; exists {
|
||||
return fmt.Errorf("command path %q is already registered", "config")
|
||||
}
|
||||
prepared := prepareConfigSuite(normalized)
|
||||
|
||||
commands := make([]Command, 0, 5)
|
||||
installed := make([]ConfigOperation, 0, 4)
|
||||
if configOperationDeclared(normalized.Scopes, ConfigValidate) {
|
||||
validate, err := newConfigValidateCommand(normalized)
|
||||
for _, operation := range prepared.installed {
|
||||
var command Command
|
||||
switch operation {
|
||||
case ConfigValidate:
|
||||
command, err = newConfigValidateCommand(prepared)
|
||||
case ConfigShow:
|
||||
command, err = newConfigShowCommand(prepared)
|
||||
case ConfigSources:
|
||||
command, err = newConfigSourcesCommand(prepared)
|
||||
case ConfigExplain:
|
||||
command, err = newConfigExplainCommand(prepared)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commands = append(commands, validate)
|
||||
installed = append(installed, ConfigValidate)
|
||||
commands = append(commands, command)
|
||||
}
|
||||
if configOperationDeclared(normalized.Scopes, ConfigShow) {
|
||||
show, err := newConfigShowCommand(normalized)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commands = append(commands, show)
|
||||
installed = append(installed, ConfigShow)
|
||||
}
|
||||
if configOperationDeclared(normalized.Scopes, ConfigSources) {
|
||||
sources, err := newConfigSourcesCommand(normalized)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commands = append(commands, sources)
|
||||
installed = append(installed, ConfigSources)
|
||||
}
|
||||
if configOperationDeclared(normalized.Scopes, ConfigExplain) {
|
||||
explain, err := newConfigExplainCommand(normalized)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commands = append(commands, explain)
|
||||
installed = append(installed, ConfigExplain)
|
||||
}
|
||||
command, err := newConfigScopesCommandWithScopes(normalized.Scopes, installed)
|
||||
command, err := newConfigScopesCommandWithPrepared(prepared)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -290,6 +283,8 @@ func normalizeConfigSuite[C any](suite ConfigSuite[C]) (ConfigSuite[C], error) {
|
||||
scope.Operations = operations
|
||||
normalized.Scopes = append(normalized.Scopes, scope)
|
||||
}
|
||||
seenNames := make(map[string]struct{}, len(normalized.Selectors))
|
||||
seenShorts := make(map[string]struct{}, len(normalized.Selectors))
|
||||
for index := range normalized.Selectors {
|
||||
selector := &normalized.Selectors[index]
|
||||
binding := selector.Binding.binding
|
||||
@@ -321,16 +316,48 @@ func normalizeConfigSuite[C any](suite ConfigSuite[C]) (ConfigSuite[C], error) {
|
||||
unique = append(unique, scopeName)
|
||||
}
|
||||
selector.Scopes = append([]string(nil), unique...)
|
||||
for previous := 0; previous < index; previous++ {
|
||||
other := normalized.Selectors[previous].Binding.binding.meta
|
||||
if other.Name == binding.meta.Name || binding.meta.Short != "" && other.Short == binding.meta.Short {
|
||||
if _, exists := seenNames[binding.meta.Name]; exists {
|
||||
return ConfigSuite[C]{}, fmt.Errorf("duplicate configuration selector flag --%s", binding.meta.Name)
|
||||
}
|
||||
if binding.meta.Short != "" {
|
||||
if _, exists := seenShorts[binding.meta.Short]; exists {
|
||||
return ConfigSuite[C]{}, fmt.Errorf("duplicate configuration selector flag --%s", binding.meta.Name)
|
||||
}
|
||||
seenShorts[binding.meta.Short] = struct{}{}
|
||||
}
|
||||
seenNames[binding.meta.Name] = struct{}{}
|
||||
}
|
||||
return normalized, nil
|
||||
}
|
||||
|
||||
func prepareConfigSuite[C any](suite ConfigSuite[C]) *preparedConfigSuite[C] {
|
||||
prepared := &preparedConfigSuite[C]{
|
||||
suite: suite,
|
||||
ordered: orderedConfigScopes(suite.Scopes),
|
||||
byName: make(map[string]ConfigScope[C], len(suite.Scopes)),
|
||||
installed: make([]ConfigOperation, 0, 4),
|
||||
inventory: scopesInventory{Scopes: make([]configScopeInfo, 0, len(suite.Scopes))},
|
||||
}
|
||||
for _, scope := range suite.Scopes {
|
||||
prepared.byName[scope.Name] = scope
|
||||
}
|
||||
for _, operation := range []ConfigOperation{ConfigValidate, ConfigShow, ConfigSources, ConfigExplain} {
|
||||
if configOperationDeclared(suite.Scopes, operation) {
|
||||
prepared.installed = append(prepared.installed, operation)
|
||||
}
|
||||
}
|
||||
for _, scope := range prepared.ordered {
|
||||
operations := make([]ConfigOperation, 0, len(scope.Operations))
|
||||
for _, operation := range scope.Operations {
|
||||
if containsOperation(prepared.installed, operation) {
|
||||
operations = append(operations, operation)
|
||||
}
|
||||
}
|
||||
prepared.inventory.Scopes = append(prepared.inventory.Scopes, configScopeInfo{Name: scope.Name, Operations: operations})
|
||||
}
|
||||
return prepared
|
||||
}
|
||||
|
||||
func normalizeConfigOperations(operations []ConfigOperation) ([]ConfigOperation, error) {
|
||||
seen := make(map[ConfigOperation]struct{}, len(operations))
|
||||
for _, operation := range operations {
|
||||
@@ -350,7 +377,7 @@ func normalizeConfigOperations(operations []ConfigOperation) ([]ConfigOperation,
|
||||
return ordered, nil
|
||||
}
|
||||
|
||||
func newConfigScopesCommandWithScopes[C any](scopes []ConfigScope[C], installed []ConfigOperation) (Command, error) {
|
||||
func newConfigScopesCommandWithPrepared[C any](prepared *preparedConfigSuite[C]) (Command, error) {
|
||||
formatDefault := "text"
|
||||
spec := CommandSpec[configScopesInput]{
|
||||
Name: "scopes",
|
||||
@@ -362,22 +389,12 @@ func newConfigScopesCommandWithScopes[C any](scopes []ConfigScope[C], installed
|
||||
})},
|
||||
CheckInput: func(input configScopesInput) error { return checkConfigFormat(input.Format) },
|
||||
Run: func(invocation Invocation, input configScopesInput) Outcome {
|
||||
inventory := scopesInventory{Scopes: make([]configScopeInfo, 0, len(scopes))}
|
||||
for _, scope := range orderedConfigScopes(scopes) {
|
||||
operations := make([]ConfigOperation, 0, len(scope.Operations))
|
||||
for _, operation := range scope.Operations {
|
||||
if containsOperation(installed, operation) {
|
||||
operations = append(operations, operation)
|
||||
}
|
||||
}
|
||||
inventory.Scopes = append(inventory.Scopes, configScopeInfo{Name: scope.Name, Operations: operations})
|
||||
}
|
||||
var output []byte
|
||||
var err error
|
||||
if input.Format == "yaml" {
|
||||
output, err = yaml.Marshal(inventory)
|
||||
output, err = yaml.Marshal(prepared.inventory)
|
||||
} else {
|
||||
output = []byte(formatScopeInventory(inventory))
|
||||
output = []byte(formatScopeInventory(prepared.inventory))
|
||||
}
|
||||
if err != nil {
|
||||
return Failure(err)
|
||||
|
||||
Reference in New Issue
Block a user