package ckconfig import ( "bytes" "fmt" "io" "strconv" "unicode" commandkit "gitea.maximumdirect.net/eric/CommandKit" ) type effectiveDocument struct { name string view View } func runConfigShow[I, S any](invocation commandkit.Invocation, plan *configOperationPlan[I, S], state S) commandkit.Outcome { documents := make([]effectiveDocument, 0, len(plan.scopes)) reporter := invocation.Reporter() for _, selected := range plan.scopes { if err := invocation.Context.Err(); err != nil { return configFailure("Configuration show was canceled.", commandkit.Explanation{}, err) } if selected.scope.scope.Acquire == nil { message := fmt.Sprintf("Configuration scope %q has no acquisition callback.", selected.scope.scope.Name) return commandkit.Failure(message) } acquired, acquireErr := selected.scope.scope.Acquire(invocation.Context, Request{ Operation: Show, Selection: plan.selection, }, selected.input, state) if acquireErr != nil { return configAcquisitionFailure(reporter, "show", selected.scope.scope.Name, acquired, acquireErr) } queueConfigDiagnostics(reporter, acquired.Diagnostics) if err := invocation.Context.Err(); err != nil { return configFailure("Configuration show was canceled.", acquired.Explanation, err) } if acquired.Value.Effective == nil { message := fmt.Sprintf("Configuration scope %q did not provide an effective configuration writer.", selected.scope.scope.Name) return commandkit.Failure(message) } documents = append(documents, effectiveDocument{name: selected.scope.scope.Name, view: acquired.Value}) } if err := invocation.Context.Err(); err != nil { return configFailure("Configuration show was canceled.", commandkit.Explanation{}, err) } if len(documents) == 1 && plan.scopeName != "all" { err := reporter.RenderOutput(func(writer io.Writer) error { return documents[0].view.Effective.WriteEffective(writer) }) if err != nil && invocation.Context.Err() != nil { return configFailure("Configuration show was canceled.", commandkit.Explanation{}, invocation.Context.Err()) } return commandkit.Success() } err := reporter.RenderOutput(func(writer io.Writer) error { for index, document := range documents { if err := invocation.Context.Err(); err != nil { return err } var native bytes.Buffer if err := document.view.Effective.WriteEffective(&native); err != nil { return err } if err := invocation.Context.Err(); err != nil { return err } framed, hasDirective := frameEffectiveYAML(document.name, native.Bytes()) if index > 0 && hasDirective { if _, err := io.WriteString(writer, "...\n"); err != nil { return err } } if index < len(documents)-1 && len(framed) > 0 && framed[len(framed)-1] != '\n' { framed = append(framed, '\n') } if _, err := writer.Write(framed); err != nil { return err } } return nil }) if err != nil && invocation.Context.Err() != nil { return configFailure("Configuration show was canceled.", commandkit.Explanation{}, invocation.Context.Err()) } return commandkit.Success() } type yamlPreamble struct { markerStart int markerEnd int markerFound bool inlineMarker bool preambleEnd int hasDirective bool } func analyzeYAMLPreamble(native []byte) yamlPreamble { var analysis yamlPreamble for start := 0; start < len(native); { end := len(native) if newline := bytes.IndexByte(native[start:], '\n'); newline >= 0 { end = start + newline + 1 } lineEnd := end if lineEnd > start && native[lineEnd-1] == '\n' { lineEnd-- } trimmed := bytes.TrimSpace(native[start:lineEnd]) if isYAMLDocumentStart(trimmed) { content := bytes.TrimSpace(trimmed[3:]) analysis.markerStart = start analysis.markerEnd = end analysis.markerFound = true analysis.inlineMarker = len(content) > 0 && content[0] != '#' return analysis } if bytes.HasPrefix(trimmed, []byte("%YAML ")) || bytes.HasPrefix(trimmed, []byte("%TAG ")) { analysis.hasDirective = true } if len(trimmed) == 0 || trimmed[0] == '#' || bytes.HasPrefix(trimmed, []byte("%YAML ")) || bytes.HasPrefix(trimmed, []byte("%TAG ")) { analysis.preambleEnd = end } else { return analysis } start = end } return analysis } func frameEffectiveYAML(scope string, native []byte) ([]byte, bool) { analysis := analyzeYAMLPreamble(native) label := scope for _, character := range scope { if unicode.IsControl(character) { label = strconv.Quote(scope) break } } comment := []byte("# scope: " + label + "\n") if analysis.markerFound { out := make([]byte, 0, len(native)+len(comment)) if analysis.inlineMarker { out = append(out, native[:analysis.markerStart]...) out = append(out, comment...) out = append(out, native[analysis.markerStart:]...) return out, analysis.hasDirective } out = append(out, native[:analysis.markerEnd]...) if analysis.markerEnd > analysis.markerStart && native[analysis.markerEnd-1] != '\n' { out = append(out, '\n') } out = append(out, comment...) out = append(out, native[analysis.markerEnd:]...) return out, analysis.hasDirective } result := make([]byte, 0, len(native)+len(comment)+5) if analysis.hasDirective { result = append(result, native[:analysis.preambleEnd]...) } result = append(result, []byte("---\n")...) result = append(result, comment...) if analysis.hasDirective { result = append(result, native[analysis.preambleEnd:]...) } else { result = append(result, native...) } return result, analysis.hasDirective } func isYAMLDocumentStart(line []byte) bool { return bytes.HasPrefix(line, []byte("---")) && (len(line) == 3 || line[3] == ' ' || line[3] == '\t') }