Move configuration reports to shared rendering

This commit is contained in:
2026-11-07 03:57:10 +00:00
parent 7159f52f4d
commit 6c35da3ab6
23 changed files with 461 additions and 821 deletions

View File

@@ -1,59 +1,56 @@
package ckconfig
import (
"bytes"
"fmt"
"io"
"strconv"
"text/template"
commandkit "go.maximumdirect.net/commandkit"
configkit "go.maximumdirect.net/configkit"
"go.yaml.in/yaml/v4"
)
type sourceReport struct {
Scope string `yaml:"scope"`
Sources []sourceDTO `yaml:"sources"`
Scope string `json:"scope" yaml:"scope"`
Sources []sourceDTO `json:"sources" yaml:"sources"`
}
type sourceDTO struct {
ID string `yaml:"id"`
Label string `yaml:"label"`
Path string `yaml:"path"`
Destination string `yaml:"destination"`
Placement string `yaml:"placement"`
DestinationIsFallback bool `yaml:"destination_is_fallback"`
Layer string `yaml:"layer"`
Kind string `yaml:"kind"`
UnderlayIndex int `yaml:"underlay_index"`
ImportedFrom *locationDTO `yaml:"imported_from"`
VersionEvidence *sourceVersionEvidenceDTO `yaml:"version_evidence"`
EmptyImportSelections []emptyImportSelectionDTO `yaml:"empty_import_selections"`
ID string `json:"id" yaml:"id"`
Label string `json:"label" yaml:"label"`
Path string `json:"path" yaml:"path"`
Destination string `json:"destination" yaml:"destination"`
Placement string `json:"placement" yaml:"placement"`
DestinationIsFallback bool `json:"destination_is_fallback" yaml:"destination_is_fallback"`
Layer string `json:"layer" yaml:"layer"`
Kind string `json:"kind" yaml:"kind"`
UnderlayIndex int `json:"underlay_index" yaml:"underlay_index"`
ImportedFrom *locationDTO `json:"imported_from" yaml:"imported_from"`
VersionEvidence *sourceVersionEvidenceDTO `json:"version_evidence" yaml:"version_evidence"`
EmptyImportSelections []emptyImportSelectionDTO `json:"empty_import_selections" yaml:"empty_import_selections"`
}
type emptyImportSelectionDTO struct {
Path string `yaml:"path"`
Location locationDTO `yaml:"location"`
Selector string `yaml:"selector"`
Path string `json:"path" yaml:"path"`
Location locationDTO `json:"location" yaml:"location"`
Selector string `json:"selector" yaml:"selector"`
}
type locationDTO struct {
SourceID string `yaml:"source_id"`
Line int `yaml:"line"`
Column int `yaml:"column"`
SourceID string `json:"source_id" yaml:"source_id"`
Line int `json:"line" yaml:"line"`
Column int `json:"column" yaml:"column"`
}
type sourceVersionEvidenceDTO struct {
Path string `yaml:"path"`
Version versionDTO `yaml:"version"`
Location *locationDTO `yaml:"location"`
Redacted bool `yaml:"redacted"`
Path string `json:"path" yaml:"path"`
Version versionDTO `json:"version" yaml:"version"`
Location *locationDTO `json:"location" yaml:"location"`
Redacted bool `json:"redacted" yaml:"redacted"`
}
type versionDTO struct {
Present bool `yaml:"present"`
Null bool `yaml:"null"`
Text string `yaml:"text"`
Present bool `json:"present" yaml:"present"`
Null bool `json:"null" yaml:"null"`
Text string `json:"text" yaml:"text"`
}
func runConfigSources[I, S any](invocation commandkit.Invocation, plan *configOperationPlan[I, S], state S) commandkit.Outcome {
@@ -128,73 +125,40 @@ func runConfigSources[I, S any](invocation commandkit.Invocation, plan *configOp
if err := invocation.Context.Err(); err != nil {
return configFailure("Configuration source listing was canceled.", acquired.Explanation, err)
}
return renderPreparedConfigReport(invocation, acquired.Explanation, func() ([]byte, error) {
var report bytes.Buffer
if plan.format == "yaml" {
if err := encodeYAML(&report, document); err != nil {
return nil, err
}
} else {
writeSourceReportText(&report, document)
}
return report.Bytes(), nil
})
_ = reporter.Report(commandkit.Report{Value: document, TextTemplate: sourceTextTemplate})
return commandkit.Success()
}
func writeSourceReportText(writer *bytes.Buffer, document sourceReport) {
_, _ = fmt.Fprintf(writer, "Scope: %s\n", strconv.Quote(document.Scope))
if len(document.Sources) == 0 {
_, _ = writer.WriteString("Sources: []\n")
return
}
_, _ = writer.WriteString("Sources:\n")
for _, source := range document.Sources {
_, _ = fmt.Fprintf(writer, " - id: %s\n", strconv.Quote(source.ID))
_, _ = fmt.Fprintf(writer, " label: %s\n", strconv.Quote(source.Label))
_, _ = fmt.Fprintf(writer, " path: %s\n", strconv.Quote(source.Path))
_, _ = fmt.Fprintf(writer, " destination: %s\n", strconv.Quote(source.Destination))
_, _ = fmt.Fprintf(writer, " placement: %s\n", strconv.Quote(source.Placement))
_, _ = fmt.Fprintf(writer, " destination_is_fallback: %t\n", source.DestinationIsFallback)
_, _ = fmt.Fprintf(writer, " layer: %s\n", strconv.Quote(source.Layer))
_, _ = fmt.Fprintf(writer, " kind: %s\n", strconv.Quote(source.Kind))
_, _ = fmt.Fprintf(writer, " underlay_index: %d\n", source.UnderlayIndex)
if source.ImportedFrom == nil {
_, _ = writer.WriteString(" imported_from: null\n")
} else {
_, _ = fmt.Fprintf(writer, " imported_from: {source_id: %s, line: %d, column: %d}\n",
strconv.Quote(source.ImportedFrom.SourceID), source.ImportedFrom.Line, source.ImportedFrom.Column)
}
if source.VersionEvidence == nil {
_, _ = writer.WriteString(" version_evidence: null\n")
} else {
check := source.VersionEvidence
_, _ = fmt.Fprintf(writer, " version_evidence:\n path: %s\n", strconv.Quote(check.Path))
_, _ = fmt.Fprintf(writer, " version:\n present: %t\n null: %t\n text: %s\n",
check.Version.Present, check.Version.Null, strconv.Quote(check.Version.Text))
if check.Location == nil {
_, _ = writer.WriteString(" location: null\n")
} else {
_, _ = fmt.Fprintf(writer, " location: {source_id: %s, line: %d, column: %d}\n",
strconv.Quote(check.Location.SourceID), check.Location.Line, check.Location.Column)
}
_, _ = fmt.Fprintf(writer, " redacted: %t\n", check.Redacted)
}
if len(source.EmptyImportSelections) == 0 {
_, _ = writer.WriteString(" empty_import_selections: []\n")
} else {
_, _ = writer.WriteString(" empty_import_selections:\n")
for _, selection := range source.EmptyImportSelections {
_, _ = fmt.Fprintf(writer, " - path: %s\n location: {source_id: %s, line: %d, column: %d}\n selector: %s\n", strconv.Quote(selection.Path), strconv.Quote(selection.Location.SourceID), selection.Location.Line, selection.Location.Column, strconv.Quote(selection.Selector))
}
}
}
}
func encodeYAML(writer io.Writer, document any) error {
encoder := yaml.NewEncoder(writer)
encoder.SetIndent(2)
return encoder.Encode(document)
}
var sourceTextTemplate = template.Must(commandkit.ParseTextTemplate("sources", `Scope: {{printf "%q" .Scope}}
{{if .Sources}}Sources:
{{range .Sources}} - id: {{printf "%q" .ID}}
label: {{printf "%q" .Label}}
path: {{printf "%q" .Path}}
destination: {{printf "%q" .Destination}}
placement: {{printf "%q" .Placement}}
destination_is_fallback: {{.DestinationIsFallback}}
layer: {{printf "%q" .Layer}}
kind: {{printf "%q" .Kind}}
underlay_index: {{.UnderlayIndex}}
{{if .ImportedFrom}} imported_from: {source_id: {{printf "%q" .ImportedFrom.SourceID}}, line: {{.ImportedFrom.Line}}, column: {{.ImportedFrom.Column}}}
{{else}} imported_from: null
{{end}}{{if .VersionEvidence}} version_evidence:
path: {{printf "%q" .VersionEvidence.Path}}
version:
present: {{.VersionEvidence.Version.Present}}
null: {{.VersionEvidence.Version.Null}}
text: {{printf "%q" .VersionEvidence.Version.Text}}
{{if .VersionEvidence.Location}} location: {source_id: {{printf "%q" .VersionEvidence.Location.SourceID}}, line: {{.VersionEvidence.Location.Line}}, column: {{.VersionEvidence.Location.Column}}}
{{else}} location: null
{{end}} redacted: {{.VersionEvidence.Redacted}}
{{else}} version_evidence: null
{{end}}{{if .EmptyImportSelections}} empty_import_selections:
{{range .EmptyImportSelections}} - path: {{printf "%q" .Path}}
location: {source_id: {{printf "%q" .Location.SourceID}}, line: {{.Location.Line}}, column: {{.Location.Column}}}
selector: {{printf "%q" .Selector}}
{{end}}{{else}} empty_import_selections: []
{{end}}{{end}}{{else}}Sources: []
{{end}}`, nil))
func locationReports(locations []configkit.Location) []locationDTO {
report := make([]locationDTO, 0, len(locations))