package config import ( "fmt" "sort" "strings" "gitea.maximumdirect.net/eric/narratio/internal/artifactpolicy" ) type artifactDependencyOrigin struct { explicitIndex int inputName string family string } func finalizeArtifactDependencies(cfg *PipelineConfig) { if cfg == nil || cfg.Scriptorium == nil { return } for artifactName, artifact := range cfg.Scriptorium.Artifacts { priorOrigins := artifact.dependencyOrigins origins := make(map[string][]artifactDependencyOrigin) dependencies := make(map[string]struct{}) family := "" if member, ok := cfg.familyCatalog.Members[artifactName]; ok { family = member.Family } for index, dependency := range artifact.DependsOn { dependency = strings.TrimSpace(dependency) if prior, finalized := priorOrigins[dependency]; finalized { explicit := explicitOrigins(prior) if len(explicit) > 0 { dependencies[dependency] = struct{}{} origins[dependency] = append(origins[dependency], explicit...) } continue } dependencies[dependency] = struct{}{} origins[dependency] = append(origins[dependency], artifactDependencyOrigin{ explicitIndex: index, family: family, }) } inputNames := make([]string, 0, len(artifact.Inputs)) for inputName := range artifact.Inputs { inputNames = append(inputNames, inputName) } sort.Strings(inputNames) for _, inputName := range inputNames { descriptor, err := artifactpolicy.DescribeScriptoriumInputSource(artifact.Inputs[inputName].Source) if err != nil || descriptor.Source.Kind != artifactpolicy.SourceKindConfiguredArtifact { continue } dependency := descriptor.Source.ConfiguredKey dependencies[dependency] = struct{}{} origins[dependency] = append(origins[dependency], artifactDependencyOrigin{ explicitIndex: -1, inputName: inputName, family: family, }) } artifact.DependsOn = sortedDependencyKeys(dependencies) artifact.dependencyOrigins = origins cfg.Scriptorium.Artifacts[artifactName] = artifact } } func explicitOrigins(origins []artifactDependencyOrigin) []artifactDependencyOrigin { result := make([]artifactDependencyOrigin, 0, len(origins)) for _, origin := range origins { if origin.explicitIndex >= 0 { result = append(result, origin) } } return result } func sortedDependencyKeys(dependencies map[string]struct{}) []string { result := make([]string, 0, len(dependencies)) for dependency := range dependencies { result = append(result, dependency) } sort.Strings(result) return result } func dependencyOriginField(artifactName, dependency string, artifact ScriptoriumArtifactConfig) string { origins := artifact.dependencyOrigins[dependency] for _, origin := range origins { if origin.explicitIndex < 0 { continue } if origin.family != "" { return fmt.Sprintf("pipeline.scriptorium.artifact_families.%s.member_dependencies[%d]", origin.family, origin.explicitIndex) } return fmt.Sprintf("pipeline.scriptorium.artifacts.%s.depends_on[%d]", artifactName, origin.explicitIndex) } for _, origin := range origins { if origin.inputName == "" { continue } if origin.family != "" { return fmt.Sprintf("pipeline.scriptorium.artifact_families.%s.inputs.%s.source", origin.family, origin.inputName) } return fmt.Sprintf("pipeline.scriptorium.artifacts.%s.inputs.%s.source", artifactName, origin.inputName) } return fmt.Sprintf("pipeline.scriptorium.artifacts.%s.depends_on", artifactName) } func cloneDependencyOrigins(in map[string][]artifactDependencyOrigin) map[string][]artifactDependencyOrigin { if in == nil { return nil } out := make(map[string][]artifactDependencyOrigin, len(in)) for dependency, origins := range in { out[dependency] = append([]artifactDependencyOrigin(nil), origins...) } return out }