package commandkit import ( "bytes" "fmt" "strconv" ) func newConfigSourcesCommand[C any](prepared *preparedConfigSuite[C]) (Command, error) { spec := CommandSpec[configInput[C]]{ Name: string(ConfigSources), Summary: "List configuration sources used by a scope.", Flags: configInputFlags(prepared.suite, "text"), CheckInput: func(input configInput[C]) error { _, err := preflightConfig(prepared, input, ConfigSources) return err }, Run: func(invocation Invocation, input configInput[C]) Outcome { return runConfigSources(invocation, prepared, input) }, } return NewCommand(spec) } type sourceReport struct { Scope string `yaml:"scope"` Sources []sourceDTO `yaml:"sources"` } type sourceDTO struct { ID string `yaml:"id"` Label string `yaml:"label"` Path string `yaml:"path"` Layer string `yaml:"layer"` Kind string `yaml:"kind"` UnderlayIndex int `yaml:"underlay_index"` ImportedFrom *locationDTO `yaml:"imported_from"` } type locationDTO struct { SourceID string `yaml:"source_id"` Line int `yaml:"line"` Column int `yaml:"column"` } func runConfigSources[C any](invocation Invocation, prepared *preparedConfigSuite[C], input configInput[C]) Outcome { if err := invocation.Context.Err(); err != nil { return Failure(err) } scopeNames, err := selectConfigScopes(prepared, input, ConfigSources) if err != nil { return Failure(err) } contexts := contextsForScopes(prepared, input, scopeNames) name := scopeNames[0] scope, ok := findConfigScope(prepared, name) if !ok || scope.Acquire == nil { return sourceReportFailure(fmt.Errorf("configuration scope %q has no acquisition callback", name), nil, false) } if err := invocation.Context.Err(); err != nil { return sourceReportFailure(err, nil, false) } acquired, acquireErr := scope.Acquire(invocation.Context, ConfigRequest{Operation: ConfigSources, Selection: input.Selection}, contexts[name]) diagnostics := append([]Diagnostic(nil), acquired.Diagnostics...) if acquireErr != nil { return sourceReportFailure(acquireErr, diagnostics, false) } if err := invocation.Context.Err(); err != nil { return sourceReportFailure(err, diagnostics, false) } if acquired.Value.Sources == nil { return sourceReportFailure(fmt.Errorf("configuration scope %q did not provide a source reader", name), diagnostics, false) } sources := acquired.Value.Sources.Sources() document := sourceReport{Scope: name, Sources: make([]sourceDTO, 0, len(sources))} for _, source := range sources { item := sourceDTO{ ID: source.ID, Label: source.Label, Path: source.Path, Layer: string(source.Layer), Kind: string(source.Kind), UnderlayIndex: source.UnderlayIndex, } if source.ImportedFrom != nil { item.ImportedFrom = &locationDTO{SourceID: source.ImportedFrom.SourceID, Line: source.ImportedFrom.Line, Column: source.ImportedFrom.Column} } document.Sources = append(document.Sources, item) } var report bytes.Buffer if input.Format == "yaml" { if err := encodeYAML(&report, document); err != nil { return sourceReportFailure(err, diagnostics, false) } } else { writeSourceReportText(&report, document) } if err := invocation.Context.Err(); err != nil { return sourceReportFailure(err, diagnostics, false) } if err := writeReport(invocation.Streams.Out, report.Bytes()); err != nil { outcome := sourceReportFailure(err, diagnostics, true) outcome.DeliveryError = err return outcome } outcome := Success() outcome.Diagnostics = diagnostics return outcome } 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, " 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) } } } func sourceReportFailure(cause error, diagnostics []Diagnostic, reportStarted bool) Outcome { outcome := Failure(cause) outcome.Diagnostics = diagnostics outcome.ReportIncomplete = reportStarted return outcome }