package ckconfig import ( "fmt" "io" commandkit "gitea.maximumdirect.net/eric/CommandKit" ) func runConfigOperation[I, S any](invocation commandkit.Invocation, operation Operation, input *configCommandInput[I, S]) commandkit.Outcome { if input == nil || input.plan == nil { return commandkit.Failure("Configuration operation was not prepared.") } if err := invocation.Context.Err(); err != nil { return configFailure("Configuration operation was canceled.", commandkit.Explanation{}, err) } plan := input.plan var state S if plan.prepared.newState != nil { state = plan.prepared.newState() } switch operation { case Validate: return runConfigValidation(invocation, plan, state) case Show: return runConfigShow(invocation, plan, state) case Sources: return runConfigSources(invocation, plan, state) case Explain: return runConfigExplanation(invocation, plan, state) case Diff: return runConfigDiff(invocation, plan, state) default: return commandkit.Failure(fmt.Sprintf("Unsupported configuration operation %q.", operation)) } } func queueConfigDiagnostics(reporter *commandkit.Reporter, diagnostics []commandkit.Diagnostic) { deferred := reporter.AtEnd() for _, diagnostic := range diagnostics { if diagnostic.Write == nil { continue } switch diagnostic.Severity { case commandkit.SeverityInfo: _ = deferred.Info("", diagnostic.Write) case commandkit.SeverityDebug: _ = deferred.Debug("", diagnostic.Write) case commandkit.SeverityProgress: _ = reporter.Progress("", diagnostic.Write) default: _ = deferred.Warn("", diagnostic.Write) } } } func configFailure(message string, explanation commandkit.Explanation, cause error) commandkit.Outcome { if explanation.Message != "" || len(explanation.Details) > 0 { message = explanation.Message } outcome := commandkit.Failure(message, explanation.Details...) if cause != nil { outcome = outcome.WithCause(cause) } return outcome } func configAcquisitionFailure( reporter *commandkit.Reporter, operation, scope string, acquired commandkit.Acquired[View], cause error, ) commandkit.Outcome { queueConfigDiagnostics(reporter, acquired.Diagnostics) message := fmt.Sprintf("Unable to %s configuration scope %q.", operation, scope) return configFailure(message, acquired.Explanation, cause) } // Preserve the preparation/delivery cancellation checkpoint for buffered reports. func renderPreparedConfigReport(invocation commandkit.Invocation, explanation commandkit.Explanation, prepare func() ([]byte, error)) commandkit.Outcome { var canceled error renderErr := invocation.Reporter().RenderOutput(func(writer io.Writer) error { report, err := prepare() if err != nil { return err } if canceled = invocation.Context.Err(); canceled != nil { return nil } _, err = writer.Write(report) return err }) if canceled == nil && renderErr != nil { canceled = invocation.Context.Err() } if canceled != nil { return configFailure("Configuration report preparation was canceled.", explanation, canceled) } return commandkit.Success() }