github.com/solo-io/cue@v0.4.7/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 "github.com/solo-io/cue/cue" 24 "github.com/solo-io/cue/cue/errors" 25 "github.com/solo-io/cue/cue/token" 26 "github.com/solo-io/cue/internal/value" 27 ) 28 29 // A Context provides context for running a task. 30 type Context struct { 31 Context context.Context 32 Stdin io.Reader 33 Stdout io.Writer 34 Stderr io.Writer 35 Obj cue.Value 36 Err errors.Error 37 } 38 39 func (c *Context) Lookup(field string) cue.Value { 40 f := c.Obj.Lookup(field) 41 if !f.Exists() { 42 c.addErr(f, nil, "could not find field %q", field) 43 return cue.Value{} 44 } 45 if err := f.Err(); err != nil { 46 c.Err = errors.Append(c.Err, errors.Promote(err, "lookup")) 47 } 48 return f 49 } 50 51 func (c *Context) Int64(field string) int64 { 52 f := c.Obj.Lookup(field) 53 value, err := f.Int64() 54 if err != nil { 55 // TODO: use v for position for now, as f has not yet a 56 // position associated with it. 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.Lookup(field) 65 value, err := f.String() 66 if err != nil { 67 // TODO: use v for position for now, as f has not yet a 68 // position associated with it. 69 c.addErr(f, err, "invalid string argument") 70 return "" 71 } 72 return value 73 } 74 75 func (c *Context) Bytes(field string) []byte { 76 f := c.Obj.Lookup(field) 77 value, err := f.Bytes() 78 if err != nil { 79 c.addErr(f, err, "invalid bytes argument") 80 return nil 81 } 82 return value 83 } 84 85 func (c *Context) addErr(v cue.Value, wrap error, format string, args ...interface{}) { 86 87 err := &taskError{ 88 task: c.Obj, 89 v: v, 90 Message: errors.NewMessage(format, args), 91 } 92 c.Err = errors.Append(c.Err, errors.Wrap(err, wrap)) 93 } 94 95 // taskError wraps some error values to retain position information about the 96 // error. 97 type taskError struct { 98 task cue.Value 99 v cue.Value 100 errors.Message 101 } 102 103 var _ errors.Error = &taskError{} 104 105 func (t *taskError) Path() (a []string) { 106 for _, x := range t.v.Path().Selectors() { 107 a = append(a, x.String()) 108 } 109 return a 110 } 111 112 func (t *taskError) Position() token.Pos { 113 return t.task.Pos() 114 } 115 116 func (t *taskError) InputPositions() (a []token.Pos) { 117 _, nx := value.ToInternal(t.v) 118 119 for _, x := range nx.Conjuncts { 120 if src := x.Source(); src != nil { 121 a = append(a, src.Pos()) 122 } 123 } 124 return a 125 } 126 127 // A RunnerFunc creates a Runner. 128 type RunnerFunc func(v cue.Value) (Runner, error) 129 130 // A Runner defines a command type. 131 type Runner interface { 132 // Init is called with the original configuration before any task is run. 133 // As a result, the configuration may be incomplete, but allows some 134 // validation before tasks are kicked off. 135 // Init(v cue.Value) 136 137 // Runner runs given the current value and returns a new value which is to 138 // be unified with the original result. 139 Run(ctx *Context) (results interface{}, err error) 140 } 141 142 // Register registers a task for cue commands. 143 func Register(key string, f RunnerFunc) { 144 runners.Store(key, f) 145 } 146 147 // Lookup returns the RunnerFunc for a key. 148 func Lookup(key string) RunnerFunc { 149 v, ok := runners.Load(key) 150 if !ok { 151 return nil 152 } 153 return v.(RunnerFunc) 154 } 155 156 var runners sync.Map