Add configuration path discovery
This commit is contained in:
@@ -13,6 +13,10 @@ type configCommandInput[I, S any] struct {
|
||||
against Selection
|
||||
scope commandkit.Supplied[string]
|
||||
path commandkit.Supplied[string]
|
||||
list commandkit.Supplied[bool]
|
||||
historical commandkit.Supplied[bool]
|
||||
under commandkit.Supplied[string]
|
||||
explicit commandkit.Supplied[bool]
|
||||
values commandkit.FlagValues[I]
|
||||
againstValues commandkit.FlagValues[I]
|
||||
plan *configOperationPlan[I, S]
|
||||
@@ -34,6 +38,11 @@ type configOperationPlan[I, S any] struct {
|
||||
operation Operation
|
||||
scopeName string
|
||||
path configkit.Path
|
||||
list bool
|
||||
help bool
|
||||
historical bool
|
||||
under *configkit.Path
|
||||
explicit commandkit.Supplied[bool]
|
||||
scopes []selectedScopeInput[I, S]
|
||||
comparison *preparedComparison[I, S]
|
||||
}
|
||||
@@ -89,8 +98,13 @@ func newConfigOperationCommand[I, S any](prepared *preparedSuite[I, S], operatio
|
||||
}
|
||||
}
|
||||
if operation == Explain {
|
||||
flags = append(flags, commandkit.ValueFlag(commandkit.FlagMeta{Name: "path", Usage: "JSON Pointer path to explain.", Required: true}, (*string)(nil), parseConfigString,
|
||||
func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).path = value }))
|
||||
flags = append(flags,
|
||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "path", Usage: "JSON Pointer path to explain."}, (*string)(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).path = value }),
|
||||
commandkit.BoolFlag(commandkit.FlagMeta{Name: "list", Usage: "List configuration paths."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).list = value }),
|
||||
commandkit.BoolFlag(commandkit.FlagMeta{Name: "historical", Usage: "Include historical-only paths when listing."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).historical = value }),
|
||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "under", Usage: "List paths under a JSON Pointer."}, (*string)(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).under = value }),
|
||||
commandkit.BoolFlag(commandkit.FlagMeta{Name: "explicit", Usage: "Filter listed current paths by explicitness."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).explicit = value }),
|
||||
)
|
||||
}
|
||||
flags = append(flags, commandkit.CaptureFlags(prepared.bindingsByOperation[operation], func(input **configCommandInput[I, S]) *commandkit.FlagValues[I] {
|
||||
if input == nil || *input == nil {
|
||||
@@ -110,8 +124,9 @@ func newConfigOperationCommand[I, S any](prepared *preparedSuite[I, S], operatio
|
||||
name, summary := operationDeclaration(operation)
|
||||
return commandkit.NewCommand(commandkit.CommandSpec[*configCommandInput[I, S]]{
|
||||
Name: name, Summary: summary,
|
||||
NewInput: func() *configCommandInput[I, S] { return &configCommandInput[I, S]{} },
|
||||
Flags: flags,
|
||||
Description: operationDescription(operation),
|
||||
NewInput: func() *configCommandInput[I, S] { return &configCommandInput[I, S]{} },
|
||||
Flags: flags,
|
||||
CheckInput: func(input *configCommandInput[I, S]) error {
|
||||
if input == nil {
|
||||
return fmt.Errorf("configuration input must not be nil")
|
||||
@@ -124,6 +139,13 @@ func newConfigOperationCommand[I, S any](prepared *preparedSuite[I, S], operatio
|
||||
})
|
||||
}
|
||||
|
||||
func operationDescription(operation Operation) string {
|
||||
if operation == Explain {
|
||||
return "Use --list to discover paths or --path POINTER to explain one path."
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func operationDeclaration(operation Operation) (string, string) {
|
||||
switch operation {
|
||||
case Validate:
|
||||
@@ -142,6 +164,18 @@ func operationDeclaration(operation Operation) (string, string) {
|
||||
}
|
||||
|
||||
func prepareConfigOperation[I, S any](prepared *preparedSuite[I, S], operation Operation, input *configCommandInput[I, S]) error {
|
||||
if operation == Explain {
|
||||
if input.list.Value && input.path.Set {
|
||||
return fmt.Errorf("--list and --path cannot be combined")
|
||||
}
|
||||
if !input.list.Value && (input.historical.Set || input.under.Set || input.explicit.Set) {
|
||||
return fmt.Errorf("--historical, --under, and --explicit require --list")
|
||||
}
|
||||
if !input.list.Value && !input.path.Set {
|
||||
input.plan = &configOperationPlan[I, S]{prepared: prepared, operation: operation, help: true}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
scopeName := "app"
|
||||
if input.scope.Set {
|
||||
@@ -170,26 +204,38 @@ func prepareConfigOperation[I, S any](prepared *preparedSuite[I, S], operation O
|
||||
if (len(input.selection.Overrides) > 0 || len(input.against.Overrides) > 0) && !scope.scope.Features.Overrides {
|
||||
return fmt.Errorf("configuration scope %q does not support overrides", scope.scope.Name)
|
||||
}
|
||||
if operation == Explain && input.list.Value && !scope.scope.Features.PathDiscovery {
|
||||
return fmt.Errorf("configuration scope %q does not support path discovery", scope.scope.Name)
|
||||
}
|
||||
}
|
||||
|
||||
var path configkit.Path
|
||||
if operation == Explain {
|
||||
if !input.path.Set {
|
||||
return fmt.Errorf("configuration explanation requires --path")
|
||||
}
|
||||
if operation == Explain && input.path.Set {
|
||||
parsed, err := configkit.ParsePath(input.path.Value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid configuration path: %w", err)
|
||||
}
|
||||
path = parsed
|
||||
}
|
||||
var under *configkit.Path
|
||||
if input.under.Set {
|
||||
parsed, err := configkit.ParsePath(input.under.Value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid subtree path: %w", err)
|
||||
}
|
||||
under = &parsed
|
||||
}
|
||||
|
||||
plan := &configOperationPlan[I, S]{
|
||||
prepared: prepared,
|
||||
operation: operation,
|
||||
scopeName: scopeName,
|
||||
path: path,
|
||||
scopes: make([]selectedScopeInput[I, S], 0, len(selected)),
|
||||
prepared: prepared,
|
||||
operation: operation,
|
||||
scopeName: scopeName,
|
||||
path: path,
|
||||
list: input.list.Value,
|
||||
historical: input.historical.Value,
|
||||
under: under,
|
||||
explicit: input.explicit,
|
||||
scopes: make([]selectedScopeInput[I, S], 0, len(selected)),
|
||||
}
|
||||
if operation == Diff {
|
||||
scope := selected[0]
|
||||
|
||||
Reference in New Issue
Block a user