2026-10-11 01:30:18 +00:00
|
|
|
package ckconfig
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"io"
|
|
|
|
|
|
|
|
|
|
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
|
|
|
|
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Selection carries the configuration and overlay choices supplied for a
|
|
|
|
|
// configuration scope.
|
|
|
|
|
type Selection struct {
|
2026-10-11 02:06:06 +00:00
|
|
|
// Config is the caller-supplied configuration path, if present.
|
|
|
|
|
Config commandkit.Supplied[string]
|
|
|
|
|
// Overlay is the caller-supplied overlay path, if present.
|
2026-10-11 01:30:18 +00:00
|
|
|
Overlay commandkit.Supplied[string]
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-11 22:00:22 +00:00
|
|
|
// Operation identifies a supported standard configuration operation.
|
2026-10-11 01:30:18 +00:00
|
|
|
type Operation string
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
// Validate checks the selected configuration and reports diagnostics.
|
|
|
|
|
Validate Operation = "validate"
|
|
|
|
|
// Show writes the selected configuration's effective form.
|
|
|
|
|
Show Operation = "show"
|
|
|
|
|
// Sources reports the selected configuration's input sources.
|
|
|
|
|
Sources Operation = "sources"
|
|
|
|
|
// Explain reports the history and provenance of a selected path.
|
|
|
|
|
Explain Operation = "explain"
|
2026-10-11 21:36:34 +00:00
|
|
|
// Diff compares two selections of the same configuration scope.
|
|
|
|
|
Diff Operation = "diff"
|
2026-10-11 01:30:18 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Request describes one configuration operation and its selected inputs.
|
|
|
|
|
type Request struct {
|
2026-10-11 02:06:06 +00:00
|
|
|
// Operation identifies the requested inspection operation.
|
2026-10-11 01:30:18 +00:00
|
|
|
Operation Operation
|
2026-10-11 02:06:06 +00:00
|
|
|
// Selection carries the explicit config and overlay inputs.
|
2026-10-11 01:30:18 +00:00
|
|
|
Selection Selection
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-11 21:36:34 +00:00
|
|
|
// ComparisonSide groups one configuration selection with its independently
|
2026-10-11 22:00:22 +00:00
|
|
|
// initialized and checked typed input. The supplied-state fields of Selection
|
|
|
|
|
// are preserved for the scope's loader.
|
2026-10-11 21:36:34 +00:00
|
|
|
type ComparisonSide[I any] struct {
|
|
|
|
|
// Selection carries the explicit config and overlay inputs for this side.
|
|
|
|
|
Selection Selection
|
|
|
|
|
// Input is initialized and checked for this side before comparison.
|
|
|
|
|
Input I
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ComparisonRequest carries the earlier and later selections supplied to a
|
2026-10-11 22:00:22 +00:00
|
|
|
// scope's comparison callback. Each side has a separately prepared input; the
|
|
|
|
|
// callback receives shared invocation state separately.
|
2026-10-11 21:36:34 +00:00
|
|
|
type ComparisonRequest[I any] struct {
|
|
|
|
|
// Left is the earlier configuration selection.
|
|
|
|
|
Left ComparisonSide[I]
|
|
|
|
|
// Right is the later configuration selection.
|
|
|
|
|
Right ComparisonSide[I]
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-11 01:30:18 +00:00
|
|
|
// EffectiveWriter writes a configuration's native effective representation.
|
|
|
|
|
type EffectiveWriter interface {
|
|
|
|
|
WriteEffective(io.Writer) error
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SourceReader reports the native source inventory for a configuration.
|
|
|
|
|
type SourceReader interface {
|
|
|
|
|
Sources() []configkit.SourceInfo
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ExplanationReader reads and writes a configuration's native path explanation.
|
|
|
|
|
type ExplanationReader interface {
|
|
|
|
|
Explain(configkit.Path) (configkit.Explanation, bool)
|
|
|
|
|
WriteExplanation(io.Writer, configkit.Path) error
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// View exposes native configuration facets without reconstructing their
|
|
|
|
|
// reports.
|
|
|
|
|
type View struct {
|
|
|
|
|
Effective EffectiveWriter
|
|
|
|
|
Sources SourceReader
|
|
|
|
|
Explanation ExplanationReader
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-11 21:36:34 +00:00
|
|
|
// Scope declares the operations and providers for one named configuration.
|
|
|
|
|
// Ordinary inspection operations use Acquire; Diff uses Compare and does not
|
|
|
|
|
// require Acquire unless an ordinary operation is also declared. Construction
|
|
|
|
|
// issues are retained privately until family assembly attaches them to its
|
|
|
|
|
// command declaration.
|
2026-10-11 01:30:18 +00:00
|
|
|
type Scope[I, S any] struct {
|
2026-10-11 02:06:06 +00:00
|
|
|
// Name identifies the scope in CLI selection and reports.
|
|
|
|
|
Name string
|
2026-10-11 13:07:00 +00:00
|
|
|
// Summary describes the scope. Scope discovery reports name and operations only.
|
2026-10-11 02:06:06 +00:00
|
|
|
Summary string
|
|
|
|
|
// Operations selects the standard handlers exposed for this scope.
|
2026-10-11 01:30:18 +00:00
|
|
|
Operations []Operation
|
2026-10-11 21:36:34 +00:00
|
|
|
// Acquire loads the selected configuration for one ordinary inspection
|
|
|
|
|
// invocation.
|
2026-10-11 02:06:06 +00:00
|
|
|
Acquire func(context.Context, Request, I, S) (commandkit.Acquired[View], error)
|
2026-10-11 21:36:34 +00:00
|
|
|
// Compare compares two selections for this scope using one shared state.
|
2026-10-11 22:00:22 +00:00
|
|
|
// Its Acquired result carries native difference records and diagnostics;
|
|
|
|
|
// returned errors retain their supported cause identity. It is required when
|
|
|
|
|
// Diff is declared in Operations.
|
2026-10-11 21:36:34 +00:00
|
|
|
Compare func(context.Context, ComparisonRequest[I], S) (commandkit.Acquired[[]configkit.Difference], error)
|
2026-10-11 01:30:18 +00:00
|
|
|
|
|
|
|
|
issues []error
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Selector binds a typed flag to the configuration scopes that use it.
|
|
|
|
|
type Selector[I any] struct {
|
2026-10-11 02:06:06 +00:00
|
|
|
// Binding is the original typed flag handle captured by the suite.
|
2026-10-11 01:30:18 +00:00
|
|
|
Binding commandkit.Flag[I]
|
2026-10-11 02:06:06 +00:00
|
|
|
// Scopes lists the scope names that receive this flag's value.
|
|
|
|
|
Scopes []string
|
2026-10-11 01:30:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Suite declares the typed input, shared state, selectors, and configuration
|
|
|
|
|
// scopes used to assemble configuration commands.
|
2026-10-11 13:07:00 +00:00
|
|
|
//
|
2026-10-11 22:00:22 +00:00
|
|
|
// Input initialization is separate for each selected ordinary scope and each
|
|
|
|
|
// reached comparison side; state is shared by the invocation's acquisitions or
|
|
|
|
|
// comparison callback. Factory results and callback effects remain
|
2026-10-11 13:07:00 +00:00
|
|
|
// caller-owned: Command does not deep-copy arbitrary objects or repair aliases
|
|
|
|
|
// returned by factories. Core-owned repeated flag collections are copied when
|
|
|
|
|
// applied to separate inputs. Factories are not invoked during construction,
|
|
|
|
|
// installation, help, version, or scope discovery, and need not run after failure.
|
2026-10-11 01:30:18 +00:00
|
|
|
type Suite[I, S any] struct {
|
2026-10-11 22:00:22 +00:00
|
|
|
// NewInput is called once for each selected ordinary scope, or once for each
|
|
|
|
|
// reached side of a comparison, after operation preflight and before applying
|
|
|
|
|
// selectors and calling CheckInput.
|
2026-10-11 13:07:00 +00:00
|
|
|
// If nil, input is the zero value of I, including nil for pointer types.
|
2026-10-11 02:06:06 +00:00
|
|
|
NewInput func() I
|
2026-10-11 22:00:22 +00:00
|
|
|
// NewState is called once when provider execution is reached, after all
|
|
|
|
|
// selected inputs pass their checks. The result is shared by selected
|
|
|
|
|
// acquisitions or the comparison callback.
|
2026-10-11 13:07:00 +00:00
|
|
|
// If nil, state is the zero value of S, including nil for pointer types.
|
2026-10-11 02:06:06 +00:00
|
|
|
NewState func() S
|
|
|
|
|
// Selectors declares typed flags and their applicable scopes.
|
|
|
|
|
Selectors []Selector[I]
|
2026-10-11 22:00:22 +00:00
|
|
|
// CheckInput validates one initialized scope input after applicable values
|
|
|
|
|
// are applied. Comparison sides are checked separately with their selection.
|
2026-10-11 01:30:18 +00:00
|
|
|
CheckInput func(scope string, selection Selection, input I) error
|
2026-10-11 02:06:06 +00:00
|
|
|
// Scopes declares the configuration scopes assembled by Command.
|
|
|
|
|
Scopes []Scope[I, S]
|
2026-10-11 01:30:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// WithScopeError returns a copy of scope that retains err as a construction
|
2026-10-11 02:06:06 +00:00
|
|
|
// issue for ckconfig.Command to report during installation. Existing issues
|
|
|
|
|
// remain available to family assembly, and scope is not mutated. A nil error
|
|
|
|
|
// returns scope unchanged.
|
2026-10-11 01:30:18 +00:00
|
|
|
func WithScopeError[I, S any](scope Scope[I, S], err error) Scope[I, S] {
|
|
|
|
|
if err == nil {
|
|
|
|
|
return scope
|
|
|
|
|
}
|
|
|
|
|
issues := make([]error, len(scope.issues), len(scope.issues)+1)
|
|
|
|
|
copy(issues, scope.issues)
|
|
|
|
|
scope.issues = append(issues, err)
|
|
|
|
|
return scope
|
|
|
|
|
}
|