package artifacts import ( "fmt" "sort" "strings" "gitea.maximumdirect.net/eric/narratio/internal/config" ) // PreviousArtifactRequirement describes one previous-session artifact dependency. type PreviousArtifactRequirement struct { Name string Required bool Sources []string } // CollectPreviousArtifactRequirements scans enabled Scriptorium artifacts and returns // deduplicated previous-session artifact requirements in deterministic order. func CollectPreviousArtifactRequirements( artifactsCfg map[string]config.ScriptoriumArtifactConfig, ) []PreviousArtifactRequirement { if len(artifactsCfg) == 0 { return nil } artifactNames := sortedScriptoriumArtifactNames(artifactsCfg) byName := map[string]PreviousArtifactRequirement{} for _, artifactName := range artifactNames { artifactCfg := artifactsCfg[artifactName] if !artifactCfg.Enabled { continue } inputNames := sortedScriptoriumInputKeys(artifactCfg.Inputs) for _, inputName := range inputNames { inputCfg := artifactCfg.Inputs[inputName] previousName, ok := PreviousSessionArtifactName(inputCfg.Source) if !ok { continue } location := fmt.Sprintf( "pipeline.scriptorium.artifacts.%s.inputs.%s.source", artifactName, inputName, ) requirement := byName[previousName] requirement.Name = previousName requirement.Required = requirement.Required || inputCfg.Required requirement.Sources = append(requirement.Sources, location) byName[previousName] = requirement } } if len(byName) == 0 { return nil } requirements := make([]PreviousArtifactRequirement, 0, len(byName)) for _, requirement := range byName { requirement.Sources = dedupeAndSortStrings(requirement.Sources) requirements = append(requirements, requirement) } sort.Slice(requirements, func(i, j int) bool { return requirements[i].Name < requirements[j].Name }) return requirements } func sortedScriptoriumArtifactNames(artifactsCfg map[string]config.ScriptoriumArtifactConfig) []string { names := make([]string, 0, len(artifactsCfg)) for name := range artifactsCfg { names = append(names, name) } sort.Strings(names) return names } func sortedScriptoriumInputKeys(inputs map[string]config.ScriptoriumInputConfig) []string { if len(inputs) == 0 { return nil } names := make([]string, 0, len(inputs)) for name := range inputs { names = append(names, name) } sort.Strings(names) return names } func dedupeAndSortStrings(values []string) []string { if len(values) == 0 { return nil } seen := map[string]struct{}{} out := make([]string, 0, len(values)) for _, value := range values { trimmed := strings.TrimSpace(value) if trimmed == "" { continue } if _, ok := seen[trimmed]; ok { continue } seen[trimmed] = struct{}{} out = append(out, trimmed) } sort.Strings(out) return out }