Add effective artifact catalog command
This commit is contained in:
132
internal/config/artifact_catalog.go
Normal file
132
internal/config/artifact_catalog.go
Normal file
@@ -0,0 +1,132 @@
|
||||
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 = nonEmptySortedStrings([]string{member.Source})
|
||||
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 {
|
||||
if 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{}{}
|
||||
declaration := configkit.Keys("scriptorium", "artifacts", key)
|
||||
for _, change := range cfg.resolution.configkitMetadata.History(declaration) {
|
||||
if change.Origin.Layer != configkit.LayerBase && change.Origin.Layer != configkit.LayerProfile {
|
||||
continue
|
||||
}
|
||||
for _, location := range change.Origin.Locations {
|
||||
source := pathsByID[location.SourceID]
|
||||
if source == "" {
|
||||
source = location.SourceID
|
||||
}
|
||||
seen[source] = struct{}{}
|
||||
}
|
||||
}
|
||||
if len(seen) == 0 {
|
||||
prefix := "scriptorium.artifacts." + key
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user