Files
commandkit/outcome.go

121 lines
4.2 KiB
Go

package commandkit
import (
"io"
"strings"
)
// Severity classifies a neutral diagnostic.
type Severity string
const (
// SeverityWarning indicates information that does not fail the operation.
SeverityWarning Severity = "warning"
// SeverityError indicates a diagnostic associated with an error.
SeverityError Severity = "error"
)
// OutcomeKind classifies the result of a command invocation.
type OutcomeKind string
const (
// OutcomeSuccess indicates that the operation completed successfully.
OutcomeSuccess OutcomeKind = "success"
// OutcomeUsage indicates invalid command syntax or declared input.
OutcomeUsage OutcomeKind = "usage"
// OutcomeOperational indicates an operational failure.
OutcomeOperational OutcomeKind = "operational"
// OutcomeDomain indicates a result classified by application domain logic.
OutcomeDomain OutcomeKind = "domain"
)
// DeliveryState describes whether CommandKit completed diagnostic delivery.
type DeliveryState string
const (
// DeliveryNone indicates that no diagnostic delivery was attempted.
DeliveryNone DeliveryState = "none"
// DeliveryComplete indicates that diagnostic delivery completed.
DeliveryComplete DeliveryState = "complete"
// DeliveryIncomplete indicates that diagnostic delivery did not complete.
DeliveryIncomplete DeliveryState = "incomplete"
)
// Diagnostic is a deferred message written to an invocation's error stream.
//
// Write is called by CommandKit's diagnostic delivery path. It should return
// any error encountered while writing. A nil Write function has no output.
type Diagnostic struct {
// Severity classifies the diagnostic without depending on a provider library.
Severity Severity
// Write writes the diagnostic to the supplied writer.
Write func(io.Writer) error
}
// Acquired pairs a provider value with diagnostics emitted during acquisition.
type Acquired[T any] struct {
Value T
Diagnostics []Diagnostic
}
// Outcome is the classified result of an operation.
//
// Cause records the operation error. DeliveryError records an error encountered
// while presenting diagnostics or reports; it is kept separate from Cause so
// both failures remain inspectable. Outcome does not implement error.
// Invocation coordination treats a zero Outcome as success with status 0.
type Outcome struct {
// Kind classifies the result.
Kind OutcomeKind
// Status is the suggested process status for this result.
Status int
// Domain names the application-defined classification when Kind is
// OutcomeDomain.
Domain string
// Cause is the error returned by the operation.
Cause error
// DeliveryError is an error encountered while writing a report or
// diagnostics.
DeliveryError error
// DiagnosticDelivery records whether diagnostic writing completed. Its zero
// value is treated as DeliveryNone by invocation coordination.
DiagnosticDelivery DeliveryState
// ReportIncomplete is true when a failed write left a report incomplete.
ReportIncomplete bool
// Diagnostics are delivered in slice order by invocation coordination.
Diagnostics []Diagnostic
}
// Success returns a successful outcome with status 0.
func Success() Outcome {
return Outcome{Kind: OutcomeSuccess, Status: 0, DiagnosticDelivery: DeliveryNone}
}
// Usage returns a usage outcome with status 2 and the supplied cause.
func Usage(cause error) Outcome {
return Outcome{Kind: OutcomeUsage, Status: 2, Cause: cause, DiagnosticDelivery: DeliveryNone}
}
// Failure returns an operational outcome with status 1 and the supplied cause.
func Failure(cause error) Outcome {
return Outcome{Kind: OutcomeOperational, Status: 1, Cause: cause, DiagnosticDelivery: DeliveryNone}
}
// Domain returns an application-domain outcome preserving the supplied name,
// status, and cause.
func Domain(name string, status int, cause error) Outcome {
return Outcome{Kind: OutcomeDomain, Status: status, Domain: name, Cause: cause, DiagnosticDelivery: DeliveryNone}
}
// MessageDiagnostic returns a diagnostic that writes message followed by a
// newline. The writer's error is returned to the caller.
func MessageDiagnostic(severity Severity, message string) Diagnostic {
return Diagnostic{
Severity: severity,
Write: func(w io.Writer) error {
_, err := io.WriteString(w, strings.TrimSuffix(message, "\n")+"\n")
return err
},
}
}