package artifacts import ( "fmt" "sort" "strings" "gitea.maximumdirect.net/eric/narratio/internal/artifactpolicy" "gitea.maximumdirect.net/eric/narratio/internal/config" ) // EffectiveArtifactSet is the resolved set of configured artifacts that an // analyze invocation will execute. type EffectiveArtifactSet struct { keys []string resolved bool } // ResolveEffectiveArtifactSet applies an explicit artifact selection when one // is supplied; otherwise it selects the configured enabled artifacts. func ResolveEffectiveArtifactSet( configured map[string]ConfiguredArtifactDefinition, selected []string, ) (EffectiveArtifactSet, error) { configuredKeys := make(map[string]ConfiguredArtifactDefinition, len(configured)) for key, definition := range configured { trimmed := strings.TrimSpace(key) if !artifactpolicy.IsConfiguredKey(trimmed) { return EffectiveArtifactSet{}, fmt.Errorf("configured artifact key %q must match ^[a-z][a-z0-9_]*$", key) } configuredKeys[trimmed] = definition } if len(selected) > 0 { set := make(map[string]struct{}, len(selected)) for _, key := range selected { trimmed := strings.TrimSpace(key) if !artifactpolicy.IsConfiguredKey(trimmed) { return EffectiveArtifactSet{}, fmt.Errorf("selected artifact key %q must match ^[a-z][a-z0-9_]*$", key) } if _, ok := configuredKeys[trimmed]; !ok { return EffectiveArtifactSet{}, fmt.Errorf("selected artifact %q is not configured", trimmed) } set[trimmed] = struct{}{} } return newEffectiveArtifactSet(set), nil } set := make(map[string]struct{}, len(configuredKeys)) for key, definition := range configuredKeys { if definition.Enabled { set[key] = struct{}{} } } return newEffectiveArtifactSet(set), nil } // ConfiguredArtifactDefinitions converts Scriptorium configuration into the // definition form used by the runtime catalog. func ConfiguredArtifactDefinitions(items map[string]config.ScriptoriumArtifactConfig) map[string]ConfiguredArtifactDefinition { if len(items) == 0 { return nil } definitions := make(map[string]ConfiguredArtifactDefinition, len(items)) for key, item := range items { definitions[key] = ConfiguredArtifactDefinition{ Enabled: item.Enabled, OutputPath: item.OutputPath, } } return definitions } // Keys returns the selected configured artifact keys in deterministic order. func (s EffectiveArtifactSet) Keys() []string { return append([]string(nil), s.keys...) } // Includes reports whether a configured artifact belongs to the effective set. func (s EffectiveArtifactSet) Includes(key string) bool { trimmed := strings.TrimSpace(key) index := sort.SearchStrings(s.keys, trimmed) return index < len(s.keys) && s.keys[index] == trimmed } // Resolved reports whether the set was created by ResolveEffectiveArtifactSet. func (s EffectiveArtifactSet) Resolved() bool { return s.resolved } func newEffectiveArtifactSet(set map[string]struct{}) EffectiveArtifactSet { keys := make([]string, 0, len(set)) for key := range set { keys = append(keys, key) } sort.Strings(keys) return EffectiveArtifactSet{keys: keys, resolved: true} }