145 lines
4.1 KiB
Go
145 lines
4.1 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
|
|
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
"gitea.maximumdirect.net/eric/narratio/internal/artifactpolicy"
|
|
)
|
|
|
|
// EffectiveArtifactRecord describes one concrete artifact after configuration
|
|
// resolution and family expansion.
|
|
type EffectiveArtifactRecord struct {
|
|
Key string
|
|
SourceID string
|
|
DefinitionSources []string
|
|
Enabled bool
|
|
OutputPath string
|
|
Dependencies []string
|
|
FamilyKey string
|
|
CharacterID string
|
|
FamilySource string
|
|
PartySource string
|
|
}
|
|
|
|
// EffectiveArtifactCatalog returns the deterministic concrete artifact catalog
|
|
// consumed by runtime planning.
|
|
func EffectiveArtifactCatalog(cfg *PipelineConfig, party ResolvedParty) ([]EffectiveArtifactRecord, error) {
|
|
if cfg == nil {
|
|
return nil, fmt.Errorf("pipeline config is required")
|
|
}
|
|
if cfg.Scriptorium == nil || len(cfg.Scriptorium.Artifacts) == 0 {
|
|
return []EffectiveArtifactRecord{}, nil
|
|
}
|
|
|
|
keys := make([]string, 0, len(cfg.Scriptorium.Artifacts))
|
|
for key := range cfg.Scriptorium.Artifacts {
|
|
keys = append(keys, key)
|
|
}
|
|
sort.Strings(keys)
|
|
records := make([]EffectiveArtifactRecord, 0, len(keys))
|
|
for _, key := range keys {
|
|
artifact := cfg.Scriptorium.Artifacts[key]
|
|
record := EffectiveArtifactRecord{
|
|
Key: key,
|
|
SourceID: artifactpolicy.ConfiguredSourceID(key),
|
|
Enabled: artifact.Enabled,
|
|
OutputPath: artifact.OutputPath,
|
|
Dependencies: append([]string(nil), artifact.DependsOn...),
|
|
}
|
|
if member, ok := cfg.familyCatalog.Members[key]; ok {
|
|
record.DefinitionSources = artifactFamilyDefinitionSources(cfg, member.Family)
|
|
record.FamilyKey = member.Family
|
|
record.CharacterID = member.CharacterID
|
|
record.FamilySource = member.Source
|
|
record.PartySource = party.Source.Path
|
|
} else {
|
|
record.DefinitionSources = artifactDefinitionSources(cfg, key)
|
|
}
|
|
record.Dependencies = nonEmptySortedStrings(record.Dependencies)
|
|
records = append(records, record)
|
|
}
|
|
return records, nil
|
|
}
|
|
|
|
func artifactDefinitionSources(cfg *PipelineConfig, key string) []string {
|
|
return declarationDefinitionSources(cfg,
|
|
configkit.Keys("scriptorium", "artifacts", key),
|
|
"scriptorium.artifacts."+key,
|
|
)
|
|
}
|
|
|
|
func artifactFamilyDefinitionSources(cfg *PipelineConfig, key string) []string {
|
|
return declarationDefinitionSources(cfg,
|
|
configkit.Keys("scriptorium", "artifact_families", key),
|
|
"scriptorium.artifact_families."+key,
|
|
)
|
|
}
|
|
|
|
func declarationDefinitionSources(cfg *PipelineConfig, declaration configkit.Path, prefix string) []string {
|
|
if cfg == nil || cfg.resolution == nil {
|
|
return nil
|
|
}
|
|
pathsByID := make(map[string]string, len(cfg.resolution.configkitSources))
|
|
for _, source := range cfg.resolution.configkitSources {
|
|
path := source.Path
|
|
if path == "" {
|
|
path = source.Label
|
|
}
|
|
pathsByID[source.ID] = path
|
|
}
|
|
|
|
seen := map[string]struct{}{}
|
|
for _, change := range cfg.resolution.configkitMetadata.History(declaration) {
|
|
if change.Origin.Layer != configkit.LayerBase && change.Origin.Layer != configkit.LayerOverlay {
|
|
continue
|
|
}
|
|
for _, location := range change.Origin.Locations {
|
|
source := pathsByID[location.SourceID]
|
|
if source == "" {
|
|
source = location.SourceID
|
|
}
|
|
seen[source] = struct{}{}
|
|
}
|
|
}
|
|
if len(seen) == 0 {
|
|
for _, ownership := range cfg.resolution.ownership {
|
|
if ownership.path != prefix && !strings.HasPrefix(ownership.path, prefix+".") {
|
|
continue
|
|
}
|
|
for _, source := range ownership.sources {
|
|
if source != pipelineDefaultOwnershipSource && source != "resolution" {
|
|
seen[source] = struct{}{}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if len(seen) == 0 && cfg.resolution.rootPath != "" {
|
|
seen[cfg.resolution.rootPath] = struct{}{}
|
|
}
|
|
result := make([]string, 0, len(seen))
|
|
for source := range seen {
|
|
result = append(result, source)
|
|
}
|
|
sort.Strings(result)
|
|
return result
|
|
}
|
|
|
|
func nonEmptySortedStrings(values []string) []string {
|
|
seen := map[string]struct{}{}
|
|
for _, value := range values {
|
|
value = strings.TrimSpace(value)
|
|
if value != "" {
|
|
seen[value] = struct{}{}
|
|
}
|
|
}
|
|
result := make([]string, 0, len(seen))
|
|
for value := range seen {
|
|
result = append(result, value)
|
|
}
|
|
sort.Strings(result)
|
|
return result
|
|
}
|