Add ConfigKit comparison acquisition
This commit is contained in:
@@ -11,7 +11,7 @@ import (
|
||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
||||
)
|
||||
|
||||
// FromConfigKit adapts a typed ConfigKit loader to all four native
|
||||
// FromConfigKit adapts a typed ConfigKit loader to all five native
|
||||
// configuration operations. The loader receives the operation's explicit
|
||||
// Selection, initialized input, and shared invocation state, and runs only when
|
||||
// an installed operation selects this scope. Construction and help do not call
|
||||
@@ -24,7 +24,7 @@ func FromConfigKit[I, S, T any](
|
||||
scope := Scope[I, S]{
|
||||
Name: name,
|
||||
Summary: summary,
|
||||
Operations: []Operation{Validate, Show, Sources, Explain},
|
||||
Operations: []Operation{Validate, Show, Sources, Explain, Diff},
|
||||
}
|
||||
if load == nil {
|
||||
return WithScopeError(scope, fmt.Errorf("ConfigKit scope %q loader must not be nil", name))
|
||||
@@ -49,10 +49,71 @@ func FromConfigKit[I, S, T any](
|
||||
Diagnostics: configKitDiagnostics(name, sources, result.Diagnostics()),
|
||||
}, nil
|
||||
}
|
||||
scope.Compare = func(ctx context.Context, request ComparisonRequest[I], state S) (commandkit.Acquired[[]configkit.Difference], error) {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return commandkit.Acquired[[]configkit.Difference]{}, fmt.Errorf("ConfigKit scope %q comparison before left load: %w", name, err)
|
||||
}
|
||||
|
||||
left, leftDiagnostics, err := loadComparisonSide(ctx, name, "left", load, request.Left, state)
|
||||
diagnostics := append([]commandkit.Diagnostic(nil), leftDiagnostics...)
|
||||
if err != nil {
|
||||
return commandkit.Acquired[[]configkit.Difference]{Diagnostics: diagnostics}, err
|
||||
}
|
||||
|
||||
if err := ctx.Err(); err != nil {
|
||||
return commandkit.Acquired[[]configkit.Difference]{Diagnostics: diagnostics}, fmt.Errorf("ConfigKit scope %q comparison after left load: %w", name, err)
|
||||
}
|
||||
|
||||
right, rightDiagnostics, err := loadComparisonSide(ctx, name, "right", load, request.Right, state)
|
||||
diagnostics = append(diagnostics, rightDiagnostics...)
|
||||
if err != nil {
|
||||
return commandkit.Acquired[[]configkit.Difference]{Diagnostics: diagnostics}, err
|
||||
}
|
||||
|
||||
if err := ctx.Err(); err != nil {
|
||||
return commandkit.Acquired[[]configkit.Difference]{Diagnostics: diagnostics}, fmt.Errorf("ConfigKit scope %q comparison before native diff: %w", name, err)
|
||||
}
|
||||
|
||||
differences, err := configkit.Diff(left, right)
|
||||
if err != nil {
|
||||
return commandkit.Acquired[[]configkit.Difference]{Diagnostics: diagnostics}, fmt.Errorf("ConfigKit scope %q native diff: %w", name, err)
|
||||
}
|
||||
return commandkit.Acquired[[]configkit.Difference]{Value: differences, Diagnostics: diagnostics}, nil
|
||||
}
|
||||
return scope
|
||||
}
|
||||
|
||||
func loadComparisonSide[I, S, T any](
|
||||
ctx context.Context,
|
||||
scope, side string,
|
||||
load func(context.Context, Selection, I, S) (*configkit.Result[T], error),
|
||||
request ComparisonSide[I],
|
||||
state S,
|
||||
) (*configkit.Result[T], []commandkit.Diagnostic, error) {
|
||||
result, err := load(ctx, request.Selection, request.Input, state)
|
||||
if err != nil {
|
||||
var loadError *configkit.LoadError
|
||||
var diagnostics []commandkit.Diagnostic
|
||||
if errors.As(err, &loadError) && loadError != nil {
|
||||
diagnostics = configKitComparisonDiagnostics(scope, side, loadError.Sources(), loadError.Diagnostics())
|
||||
}
|
||||
return nil, diagnostics, fmt.Errorf("ConfigKit scope %q %s load: %w", scope, side, err)
|
||||
}
|
||||
if result == nil {
|
||||
return nil, nil, fmt.Errorf("ConfigKit scope %q %s loader returned a nil result", scope, side)
|
||||
}
|
||||
return result, configKitComparisonDiagnostics(scope, side, result.Sources(), result.Diagnostics()), nil
|
||||
}
|
||||
|
||||
func configKitDiagnostics(scope string, sources []configkit.SourceInfo, records []configkit.Diagnostic) []commandkit.Diagnostic {
|
||||
return configKitDiagnosticsWithHeading("Configuration scope "+strconv.Quote(scope)+":\n", sources, records)
|
||||
}
|
||||
|
||||
func configKitComparisonDiagnostics(scope, side string, sources []configkit.SourceInfo, records []configkit.Diagnostic) []commandkit.Diagnostic {
|
||||
return configKitDiagnosticsWithHeading("Configuration scope "+strconv.Quote(scope)+" "+side+":\n", sources, records)
|
||||
}
|
||||
|
||||
func configKitDiagnosticsWithHeading(heading string, sources []configkit.SourceInfo, records []configkit.Diagnostic) []commandkit.Diagnostic {
|
||||
if len(records) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -72,7 +133,7 @@ func configKitDiagnostics(scope string, sources []configkit.SourceInfo, records
|
||||
return []commandkit.Diagnostic{{
|
||||
Severity: severity,
|
||||
Write: func(writer io.Writer) error {
|
||||
if err := writeDiagnosticText(writer, "Configuration scope "+strconv.Quote(scope)+":\n"); err != nil {
|
||||
if err := writeDiagnosticText(writer, heading); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(sources) > 0 {
|
||||
|
||||
Reference in New Issue
Block a user