Resolve "Deprecate Providers package in favor of Worker"

This commit is contained in:
2025-10-09 15:53:02 +00:00
parent a1993c6c36
commit c512f51a57
26 changed files with 1695 additions and 2239 deletions

View File

@@ -1,45 +1,114 @@
package domain
import (
"errors"
"sort"
"strings"
)
type Pattern struct {
Namespace string
Labels map[string]map[string]string
Exact bool
var ErrBadPattern = errors.New("pattern: invalid format")
// ParamMatchKind selects how a tag's params must match.
type ParamMatchKind uint8
const (
MatchAny ParamMatchKind = iota // "tag" or "tag[*]"
MatchNone // "tag[]"
MatchExact // "tag[k=v;...]"
)
// TagSpec is the per-tag constraint.
type TagSpec struct {
Kind ParamMatchKind
Params map[string]string // only for MatchExact; keys sorted on emit
}
// Canonical returns a canonical string representation of the Pattern struct
// TODO: Ensure labels and namespaces are set to lowercase
func (p *Pattern) Canonical() string {
var b strings.Builder
b.Grow(len(p.Namespace) + 10*len(p.Labels) + 20) // preallocate a rough size estimate
// Pattern is an immutable canonical key.
// Canonical form (tags unordered in input, sorted on emit):
//
// namespace::tag1[]:tag2[*]:tag3[k=v;foo=bar].* // superset
// namespace::tag1[]:tag2[*]:tag3[k=v;foo=bar] // exact set
type Pattern struct{ key string }
b.WriteString(p.Namespace)
// NewPattern builds the canonical key from structured input with strict validation.
// If a tag name equals "*" it sets superset and omits it from canonical tags.
func NewPattern(namespace string, tags map[string]TagSpec, superset bool) (Pattern, error) {
ns := strings.TrimSpace(namespace)
if !validNamespace(ns) {
return Pattern{}, ErrBadPattern
}
// Validate tags and normalize.
clean := make(map[string]TagSpec, len(tags))
for name, spec := range tags {
n := strings.TrimSpace(name)
if n == "*" {
superset = true
continue
}
if !validPatternTagName(n) {
return Pattern{}, ErrBadPattern
}
switch spec.Kind {
case MatchAny:
clean[n] = TagSpec{Kind: MatchAny}
case MatchNone:
clean[n] = TagSpec{Kind: MatchNone}
case MatchExact:
if len(spec.Params) == 0 {
// Treat empty exact as none.
clean[n] = TagSpec{Kind: MatchNone}
continue
}
dst := make(map[string]string, len(spec.Params))
for k, v := range spec.Params {
kk := strings.TrimSpace(k)
vv := strings.TrimSpace(v)
if !validParamKey(kk) || !validPatternParamValue(vv) {
return Pattern{}, ErrBadPattern
}
if _, dup := dst[kk]; dup {
return Pattern{}, ErrBadPattern
}
dst[kk] = vv
}
clean[n] = TagSpec{Kind: MatchExact, Params: dst}
default:
// Reject unknown kinds rather than silently defaulting.
return Pattern{}, ErrBadPattern
}
}
var b strings.Builder
b.Grow(len(ns) + 2 + 16*len(clean) + 32 + 2)
b.WriteString(ns)
b.WriteString("::")
labelNames := make([]string, 0, len(p.Labels))
for name := range p.Labels {
labelNames = append(labelNames, name)
names := make([]string, 0, len(clean))
for n := range clean {
names = append(names, n)
}
sort.Strings(labelNames) // sort the labels for determinism
sort.Strings(names)
for i, name := range labelNames {
for i, name := range names {
if i > 0 {
b.WriteByte('|')
b.WriteByte(':')
}
b.WriteString(name)
params := p.Labels[name]
if len(params) > 0 {
keys := make([]string, 0, len(params))
for k := range params {
spec := clean[name]
switch spec.Kind {
case MatchAny:
b.WriteString("[*]")
case MatchNone:
b.WriteString("[]")
case MatchExact:
keys := make([]string, 0, len(spec.Params))
for k := range spec.Params {
keys = append(keys, k)
}
sort.Strings(keys) // sort params for determinism
sort.Strings(keys)
b.WriteByte('[')
for j, k := range keys {
if j > 0 {
@@ -47,48 +116,232 @@ func (p *Pattern) Canonical() string {
}
b.WriteString(k)
b.WriteByte('=')
b.WriteString(params[k])
b.WriteString(spec.Params[k])
}
b.WriteByte(']')
}
}
b.WriteString("::")
if p.Exact {
b.WriteString("t")
} else {
b.WriteString("f")
if superset {
if len(names) > 0 {
b.WriteByte('.')
}
b.WriteByte('*')
}
return b.String()
return Pattern{key: b.String()}, nil
}
// Satisfies checks if a domain.Identifier satisfies the pattern.
func (p *Pattern) Satisfies(id Identifier) bool {
ns, idLabels, err := id.Parse()
if err != nil || ns != p.Namespace {
// NewPatternFromRaw wraps a raw key without validation.
func NewPatternFromRaw(raw string) Pattern { return Pattern{key: raw} }
// Key returns the canonical key string.
func (p Pattern) Key() string { return p.key }
// Parse returns namespace, tag specs, and superset flag.
// Accepts tokens: "tag", "tag[*]", "tag[]", "tag[k=v;...]". Also accepts ".*" suffix or a ":*" token anywhere.
// First token wins on duplicate tag names; first key wins on duplicate params.
func (p Pattern) Parse() (string, map[string]TagSpec, bool, error) {
k := p.key
// namespace
i := strings.Index(k, "::")
if i <= 0 {
return "", nil, false, ErrBadPattern
}
ns := strings.TrimSpace(k[:i])
if !validNamespace(ns) {
return "", nil, false, ErrBadPattern
}
raw := k[i+2:]
// suffix superset ".*"
superset := false
if strings.HasSuffix(raw, ".*") {
superset = true
raw = raw[:len(raw)-2]
}
specs := make(map[string]TagSpec, 8)
if raw == "" {
return ns, specs, superset, nil
}
for tok := range strings.SplitSeq(raw, ":") {
tok = strings.TrimSpace(tok)
if tok == "" {
continue
}
if tok == "*" {
superset = true
continue
}
lb := strings.IndexByte(tok, '[')
if lb == -1 {
name := tok
if !validPatternTagName(name) {
return "", nil, false, ErrBadPattern
}
if _, exists := specs[name]; !exists {
specs[name] = TagSpec{Kind: MatchAny}
}
continue
}
rb := strings.LastIndexByte(tok, ']')
if rb == -1 || rb < lb || rb != len(tok)-1 {
return "", nil, false, ErrBadPattern
}
name := strings.TrimSpace(tok[:lb])
if !validPatternTagName(name) {
return "", nil, false, ErrBadPattern
}
// first tag wins
if _, exists := specs[name]; exists {
continue
}
rawBody := tok[lb+1 : rb]
// forbid outer whitespace like "[ x=1 ]"
if rawBody != strings.TrimSpace(rawBody) {
return "", nil, false, ErrBadPattern
}
body := strings.TrimSpace(rawBody)
switch body {
case "":
specs[name] = TagSpec{Kind: MatchNone}
case "*":
specs[name] = TagSpec{Kind: MatchAny}
default:
params := make(map[string]string, 4)
for pair := range strings.SplitSeq(body, ";") {
pair = strings.TrimSpace(pair)
if pair == "" {
continue
}
kv := strings.SplitN(pair, "=", 2)
if len(kv) != 2 {
return "", nil, false, ErrBadPattern
}
key := strings.TrimSpace(kv[0])
val := strings.TrimSpace(kv[1])
if !validParamKey(key) || !validPatternParamValue(val) || val == "" {
return "", nil, false, ErrBadPattern
}
// first key wins
if _, dup := params[key]; !dup {
params[key] = val
}
}
specs[name] = TagSpec{Kind: MatchExact, Params: params}
}
}
return ns, specs, superset, nil
}
// Equal compares canonical keys.
func (p Pattern) Equal(q Pattern) bool { return p.key == q.key }
// CompiledPattern is a parsed pattern optimized for matching.
type CompiledPattern struct {
ns string
superset bool
specs map[string]TagSpec
}
// Compile parses and returns a compiled form.
func (p Pattern) Compile() (CompiledPattern, error) {
ns, specs, sup, err := p.Parse()
if err != nil {
return CompiledPattern{}, err
}
return CompiledPattern{ns: ns, specs: specs, superset: sup}, nil
}
// Parse on CompiledPattern returns the structured contents without error.
func (cp CompiledPattern) Parse() (namespace string, tags map[string]TagSpec, superset bool) {
return cp.ns, cp.specs, cp.superset
}
// Match parses id and tests it against the pattern.
// Returns false on parse error.
func (p Pattern) Match(id Identifier) bool {
cp, err := p.Compile()
if err != nil {
return false
}
return cp.Match(id)
}
// Match tests id against the compiled pattern.
func (cp CompiledPattern) Match(id Identifier) bool {
ns, tags, err := id.Parse()
if err != nil || ns != cp.ns {
return false
}
// Every pattern label must be present in the identifier.
for lname, wantParams := range p.Labels {
haveParams, ok := idLabels[lname]
// All pattern tags must be satisfied.
for name, spec := range cp.specs {
params, ok := tags[name]
if !ok {
return false
}
// If pattern specifies params, they must be a subset of identifier's params.
for k, v := range wantParams {
hv, ok := haveParams[k]
if !ok || hv != v {
switch spec.Kind {
case MatchAny:
// any or none is fine
case MatchNone:
if len(params) != 0 {
return false
}
case MatchExact:
if len(params) != len(spec.Params) {
return false
}
for k, v := range spec.Params {
if params[k] != v {
return false
}
}
default:
return false
}
// If pattern has no params for this label, it matches any/none params in the identifier.
}
// Exact applies to label names only: no extras allowed.
if p.Exact && len(idLabels) != len(p.Labels) {
// If exact-set match, forbid extra tags.
if !cp.superset && len(tags) != len(cp.specs) {
return false
}
return true
}
// --- validation helpers ---
func validPatternTagName(s string) bool {
if s == "" || s == "*" {
return false
}
for _, r := range s {
switch r {
case '[', ']', ':':
return false
}
if isSpace(r) {
return false
}
}
return true
}
func validPatternParamValue(s string) bool {
// allow spaces; forbid only bracket, pair, and kv delimiters
for _, r := range s {
switch r {
case '[', ']', ';', '=':
return false
}
}
return true
}