140 lines
5.4 KiB
Go
140 lines
5.4 KiB
Go
package config
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// effectivePipelineProjection is the single safe, schema-specific view used
|
|
// for inspection, comparison, and identity. Runtime metadata and unresolved
|
|
// family declarations have no slot in this type.
|
|
type effectivePipelineProjection struct {
|
|
Workspace WorkspaceConfig `yaml:"workspace" json:"workspace"`
|
|
Campaigns CampaignsConfig `yaml:"campaigns" json:"campaigns"`
|
|
Storage StorageConfig `yaml:"storage" json:"storage"`
|
|
Spool SpoolConfig `yaml:"spool" json:"spool"`
|
|
Cache CacheConfig `yaml:"cache" json:"cache"`
|
|
Publish *PublishConfig `yaml:"publish" json:"publish"`
|
|
WhisperX WhisperXConfig `yaml:"whisperx" json:"whisperx"`
|
|
Seriatim SeriatimConfig `yaml:"seriatim" json:"seriatim"`
|
|
Audita AuditaConfig `yaml:"audita" json:"audita"`
|
|
Normalize *NormalizeConfig `yaml:"normalize" json:"normalize"`
|
|
Trim *TrimConfig `yaml:"trim" json:"trim"`
|
|
Render *RenderConfig `yaml:"render" json:"render"`
|
|
Scriptorium *effectiveScriptoriumConfig `yaml:"scriptorium" json:"scriptorium"`
|
|
Notarius *NotariusConfig `yaml:"notarius" json:"notarius"`
|
|
Notification NotificationConfig `yaml:"notification" json:"notification"`
|
|
}
|
|
|
|
type effectiveScriptoriumConfig struct {
|
|
Credentials []string `yaml:"credentials,omitempty" json:"credentials,omitempty"`
|
|
Binary string `yaml:"binary" json:"binary"`
|
|
ConfigPath string `yaml:"config_path" json:"config_path"`
|
|
Timeout string `yaml:"timeout" json:"timeout"`
|
|
RenderDebug bool `yaml:"render_debug" json:"render_debug"`
|
|
Artifacts map[string]ScriptoriumArtifactConfig `yaml:"artifacts" json:"artifacts"`
|
|
}
|
|
|
|
type projectedPipelineValue struct {
|
|
record EffectivePipelineValueRecord
|
|
segments []string
|
|
}
|
|
|
|
func projectEffectivePipeline(cfg *PipelineConfig, logicalNotarius bool) effectivePipelineProjection {
|
|
projection := effectivePipelineProjection{
|
|
Workspace: cfg.Workspace, Campaigns: cfg.Campaigns, Storage: cfg.Storage,
|
|
Spool: cfg.Spool, Cache: cfg.Cache, Publish: cfg.Publish,
|
|
WhisperX: cfg.WhisperX, Seriatim: cfg.Seriatim, Audita: cfg.Audita,
|
|
Normalize: cfg.Normalize, Trim: cfg.Trim, Render: cfg.Render,
|
|
Notarius: cfg.Notarius, Notification: cfg.Notification,
|
|
}
|
|
if cfg.Scriptorium != nil {
|
|
projection.Scriptorium = &effectiveScriptoriumConfig{
|
|
Credentials: secretReferenceNames(cfg.Scriptorium.Credentials),
|
|
Binary: cfg.Scriptorium.Binary, ConfigPath: cfg.Scriptorium.ConfigPath,
|
|
Timeout: cfg.Scriptorium.Timeout, RenderDebug: cfg.Scriptorium.RenderDebug,
|
|
Artifacts: cfg.Scriptorium.Artifacts,
|
|
}
|
|
}
|
|
if logicalNotarius && cfg.Notarius != nil && cfg.resolution != nil && cfg.resolution.logicalNotariusCaptured {
|
|
notarius := *cfg.Notarius
|
|
notarius.ConfigPath = cfg.resolution.logicalNotariusConfig
|
|
notarius.WorkingDirectory = cfg.resolution.logicalNotariusWorking
|
|
projection.Notarius = ¬arius
|
|
}
|
|
return projection
|
|
}
|
|
|
|
func projectionJSON(projection effectivePipelineProjection) ([]byte, error) {
|
|
data, err := json.Marshal(projection)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("encode effective pipeline projection: %w", err)
|
|
}
|
|
return data, nil
|
|
}
|
|
|
|
func projectionValueTree(value any) (any, error) {
|
|
data, err := json.Marshal(value)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("encode typed pipeline projection: %w", err)
|
|
}
|
|
decoder := json.NewDecoder(bytes.NewReader(data))
|
|
decoder.UseNumber()
|
|
var root any
|
|
if err := decoder.Decode(&root); err != nil {
|
|
return nil, fmt.Errorf("decode effective pipeline projection: %w", err)
|
|
}
|
|
return root, nil
|
|
}
|
|
|
|
func projectionValueRecords(projection effectivePipelineProjection) ([]EffectivePipelineValueRecord, error) {
|
|
detailed, err := projectionDetailedRecords(projection)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
records := make([]EffectivePipelineValueRecord, 0, len(detailed))
|
|
for _, value := range detailed {
|
|
records = append(records, value.record)
|
|
}
|
|
return records, nil
|
|
}
|
|
|
|
func projectionDetailedRecords(value any) ([]projectedPipelineValue, error) {
|
|
decoded, err := projectionValueTree(value)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
root, ok := decoded.(map[string]any)
|
|
if !ok {
|
|
return nil, fmt.Errorf("effective pipeline projection must be a mapping")
|
|
}
|
|
var records []projectedPipelineValue
|
|
appendProjectionRecords(&records, nil, root)
|
|
sort.Slice(records, func(i, j int) bool { return records[i].record.Path < records[j].record.Path })
|
|
return records, nil
|
|
}
|
|
|
|
func appendProjectionRecords(records *[]projectedPipelineValue, segments []string, value any) {
|
|
if mapping, ok := value.(map[string]any); ok && len(mapping) > 0 {
|
|
keys := make([]string, 0, len(mapping))
|
|
for key := range mapping {
|
|
keys = append(keys, key)
|
|
}
|
|
sort.Strings(keys)
|
|
for _, key := range keys {
|
|
child := append(append([]string(nil), segments...), key)
|
|
appendProjectionRecords(records, child, mapping[key])
|
|
}
|
|
return
|
|
}
|
|
encoded, _ := json.Marshal(value)
|
|
path := strings.Join(segments, ".")
|
|
*records = append(*records, projectedPipelineValue{
|
|
record: EffectivePipelineValueRecord{Path: path, Value: string(encoded)},
|
|
segments: append([]string(nil), segments...),
|
|
})
|
|
}
|