104 lines
3.1 KiB
Go
104 lines
3.1 KiB
Go
package app
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
|
|
"gitea.maximumdirect.net/eric/narratio/internal/artifacts"
|
|
"gitea.maximumdirect.net/eric/narratio/internal/config"
|
|
)
|
|
|
|
type artifactSelectionFlag struct {
|
|
values []string
|
|
}
|
|
|
|
func (f *artifactSelectionFlag) String() string {
|
|
return strings.Join(f.values, ",")
|
|
}
|
|
|
|
func (f *artifactSelectionFlag) Set(value string) error {
|
|
f.values = append(f.values, value)
|
|
return nil
|
|
}
|
|
|
|
func (f *artifactSelectionFlag) Normalize() ([]string, error) {
|
|
if len(f.values) == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
seen := map[string]struct{}{}
|
|
out := make([]string, 0, len(f.values))
|
|
for _, raw := range f.values {
|
|
for _, part := range strings.Split(raw, ",") {
|
|
name := strings.TrimSpace(part)
|
|
if name == "" {
|
|
return nil, fmt.Errorf("artifact names must be non-empty")
|
|
}
|
|
if _, ok := seen[name]; ok {
|
|
continue
|
|
}
|
|
seen[name] = struct{}{}
|
|
out = append(out, name)
|
|
}
|
|
}
|
|
|
|
sort.Strings(out)
|
|
return out, nil
|
|
}
|
|
|
|
func validateSelectedArtifacts(cfg *config.Config, selected []string) error {
|
|
_, err := resolveEffectiveArtifacts(cfg, selected)
|
|
return err
|
|
}
|
|
|
|
func resolveEffectiveArtifacts(cfg *config.Config, selected []string) (artifacts.EffectiveArtifactSet, error) {
|
|
if cfg == nil || cfg.Pipeline == nil || cfg.Pipeline.Scriptorium == nil {
|
|
if len(selected) == 0 {
|
|
return artifacts.ResolveEffectiveArtifactSet(nil, nil)
|
|
}
|
|
return artifacts.EffectiveArtifactSet{}, fmt.Errorf("--artifacts requires pipeline.scriptorium.artifacts to be configured")
|
|
}
|
|
configured := artifacts.ConfiguredArtifactDefinitions(cfg.Pipeline.Scriptorium.Artifacts)
|
|
if len(selected) > 0 && len(configured) == 0 {
|
|
return artifacts.EffectiveArtifactSet{}, fmt.Errorf("--artifacts requires at least one configured artifact in pipeline.scriptorium.artifacts")
|
|
}
|
|
effective, err := artifacts.ResolveEffectiveArtifactSet(configured, selected)
|
|
if err != nil {
|
|
if strings.Contains(err.Error(), "is not configured") {
|
|
return artifacts.EffectiveArtifactSet{}, fmt.Errorf("--artifacts includes unknown artifact %q", selectedArtifactName(err))
|
|
}
|
|
return artifacts.EffectiveArtifactSet{}, err
|
|
}
|
|
if err := validateEffectiveArtifactConfiguration(cfg.Pipeline.Scriptorium.Artifacts, effective); err != nil {
|
|
return artifacts.EffectiveArtifactSet{}, err
|
|
}
|
|
return effective, nil
|
|
}
|
|
|
|
func selectedArtifactName(err error) string {
|
|
message := err.Error()
|
|
start := strings.Index(message, "\"")
|
|
if start < 0 {
|
|
return ""
|
|
}
|
|
end := strings.Index(message[start+1:], "\"")
|
|
if end < 0 {
|
|
return ""
|
|
}
|
|
return message[start+1 : start+1+end]
|
|
}
|
|
|
|
func validateEffectiveArtifactConfiguration(configured map[string]config.ScriptoriumArtifactConfig, effective artifacts.EffectiveArtifactSet) error {
|
|
for _, name := range effective.Keys() {
|
|
artifactCfg := configured[name]
|
|
if strings.TrimSpace(artifactCfg.PromptID) == "" {
|
|
return fmt.Errorf("pipeline.scriptorium.artifacts.%s.prompt_id is required when selected", name)
|
|
}
|
|
if strings.TrimSpace(artifactCfg.OutputPath) == "" {
|
|
return fmt.Errorf("pipeline.scriptorium.artifacts.%s.output_path is required when selected", name)
|
|
}
|
|
}
|
|
return nil
|
|
}
|