cuelang.org/go@v0.10.1/internal/task/task.go (about) 1 // Copyright 2019 CUE Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package task provides a registry for tasks to be used by commands. 16 package task 17 18 import ( 19 "context" 20 "io" 21 "sync" 22 23 "cuelang.org/go/cue" 24 "cuelang.org/go/cue/errors" 25 "cuelang.org/go/cue/token" 26 "cuelang.org/go/internal/core/adt" 27 "cuelang.org/go/internal/value" 28 ) 29 30 // A Context provides context for running a task. 31 type Context struct { 32 Context context.Context 33 34 Stdin io.Reader 35 Stdout io.Writer 36 Stderr io.Writer 37 Obj cue.Value 38 Err errors.Error 39 } 40 41 func (c *Context) Lookup(field string) cue.Value { 42 f := c.Obj.LookupPath(cue.MakePath(cue.Str(field))) 43 if !f.Exists() { 44 c.addErr(f, nil, "could not find field %q", field) 45 return cue.Value{} 46 } 47 if err := f.Err(); err != nil { 48 c.Err = errors.Append(c.Err, errors.Promote(err, "lookup")) 49 } 50 return f 51 } 52 53 func (c *Context) Int64(field string) int64 { 54 f := c.Obj.LookupPath(cue.MakePath(cue.Str(field))) 55 value, err := f.Int64() 56 if err != nil { 57 c.addErr(f, err, "invalid integer argument") 58 return 0 59 } 60 return value 61 } 62 63 func (c *Context) String(field string) string { 64 f := c.Obj.LookupPath(cue.MakePath(cue.Str(field))) 65 value, err := f.String() 66 if err != nil { 67 c.addErr(f, err, "invalid string argument") 68 return "" 69 } 70 return value 71 } 72 73 func (c *Context) Bytes(field string) []byte { 74 f := c.Obj.LookupPath(cue.MakePath(cue.Str(field))) 75 value, err := f.Bytes() 76 if err != nil { 77 c.addErr(f, err, "invalid bytes argument") 78 return nil 79 } 80 return value 81 } 82 83 func (c *Context) addErr(v cue.Value, wrap error, format string, args ...interface{}) { 84 85 err := &taskError{ 86 task: c.Obj, 87 v: v, 88 Message: errors.NewMessagef(format, args...), 89 } 90 c.Err = errors.Append(c.Err, errors.Wrap(err, wrap)) 91 } 92 93 // taskError wraps some error values to retain position information about the 94 // error. 95 type taskError struct { 96 task cue.Value 97 v cue.Value 98 errors.Message 99 } 100 101 var _ errors.Error = &taskError{} 102 103 func (t *taskError) Path() (a []string) { 104 for _, x := range t.v.Path().Selectors() { 105 a = append(a, x.String()) 106 } 107 return a 108 } 109 110 func (t *taskError) Position() token.Pos { 111 return t.task.Pos() 112 } 113 114 func (t *taskError) InputPositions() (a []token.Pos) { 115 _, nx := value.ToInternal(t.v) 116 117 nx.VisitLeafConjuncts(func(x adt.Conjunct) bool { 118 if src := x.Source(); src != nil { 119 a = append(a, src.Pos()) 120 } 121 return true 122 }) 123 return a 124 } 125 126 // A RunnerFunc creates a Runner. 127 type RunnerFunc func(v cue.Value) (Runner, error) 128 129 // A Runner defines a command type. 130 type Runner interface { 131 // Init is called with the original configuration before any task is run. 132 // As a result, the configuration may be incomplete, but allows some 133 // validation before tasks are kicked off. 134 // Init(v cue.Value) 135 136 // Runner runs given the current value and returns a new value which is to 137 // be unified with the original result. 138 Run(ctx *Context) (results interface{}, err error) 139 } 140 141 // Register registers a task for cue commands. 142 func Register(key string, f RunnerFunc) { 143 runners.Store(key, f) 144 } 145 146 // Lookup returns the RunnerFunc for a key. 147 func Lookup(key string) RunnerFunc { 148 v, ok := runners.Load(key) 149 if !ok { 150 return nil 151 } 152 return v.(RunnerFunc) 153 } 154 155 var runners sync.Map