Add new Client API

Signed-off-by: Helder Correia <174525+helderco@users.noreply.github.com>
This commit is contained in:
Helder Correia
2022-03-07 12:12:39 -01:00
parent a5a0207dde
commit da90baa087
30 changed files with 1566 additions and 9 deletions

View File

@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"strings"
"sync"
"cuelang.org/go/cue"
@@ -20,6 +21,10 @@ var (
cue.Str("$dagger"),
cue.Str("task"),
cue.Hid("_name", pkg.DaggerPackage))
lookups = []LookupFunc{
defaultLookup,
pathLookup,
}
)
// State is the state of the task.
@@ -33,6 +38,7 @@ const (
)
type NewFunc func() Task
type LookupFunc func(*compiler.Value) (Task, error)
type Task interface {
Run(ctx context.Context, pctx *plancontext.Context, s solver.Solver, v *compiler.Value) (*compiler.Value, error)
@@ -60,13 +66,26 @@ func New(typ string) Task {
}
func Lookup(v *compiler.Value) (Task, error) {
for _, lookup := range lookups {
t, err := lookup(v)
if err != nil {
return nil, err
}
if t != nil {
return t, nil
}
}
return nil, ErrNotTask
}
func defaultLookup(v *compiler.Value) (Task, error) {
if v.Kind() != cue.StructKind {
return nil, ErrNotTask
return nil, nil
}
typ := v.LookupPath(typePath)
if !typ.Exists() {
return nil, ErrNotTask
return nil, nil
}
typeString, err := typ.String()
@@ -78,5 +97,49 @@ func Lookup(v *compiler.Value) (Task, error) {
if t == nil {
return nil, fmt.Errorf("unknown type %q", typeString)
}
return t, nil
}
func pathLookup(v *compiler.Value) (Task, error) {
selectors := v.Path().Selectors()
// The `actions` field won't have any path based tasks since it's in user land
if len(selectors) == 0 || selectors[0].String() == "actions" {
return nil, nil
}
// Try an exact match first
if t := New(v.Path().String()); t != nil {
return t, nil
}
// FIXME: is there a way to avoid having to loop here?
var t Task
tasks.Range(func(key, value interface{}) bool {
if matchPathMask(selectors, key.(string)) {
fn := value.(NewFunc)
t = fn()
return false
}
return true
})
return t, nil
}
func matchPathMask(sels []cue.Selector, mask string) bool {
parts := strings.Split(mask, ".")
if len(sels) != len(parts) {
return false
}
for i, sel := range sels {
// use a '*' in a path mask part to match any selector
if parts[i] == "*" {
continue
}
if sel.String() != parts[i] {
return false
}
}
return true
}