blob: a6a54d2e9a52a8e92cd1523c665b5dd2c6b3c73a [file] [log] [blame]
Marcel van Lohuizen10fd4962019-04-26 12:14:49 +02001// 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.
16package task
17
18import (
19 "context"
20 "io"
21 "sync"
22
23 "cuelang.org/go/cue"
Marcel van Lohuizena7b4ca82019-12-24 11:31:28 +010024 "cuelang.org/go/cue/errors"
Marcel van Lohuizen10fd4962019-04-26 12:14:49 +020025)
26
27// A Context provides context for running a task.
28type Context struct {
29 Context context.Context
Marcel van Lohuizena3a4b712020-01-12 15:57:56 +010030 Stdin io.Reader
Marcel van Lohuizen10fd4962019-04-26 12:14:49 +020031 Stdout io.Writer
32 Stderr io.Writer
Marcel van Lohuizena7b4ca82019-12-24 11:31:28 +010033 Obj cue.Value
34 Err errors.Error
35}
36
37func (c *Context) Lookup(field string) cue.Value {
38 f := c.Obj.Lookup(field)
39 if !f.Exists() {
40 c.Err = errors.Append(c.Err, errors.Newf(c.Obj.Pos(),
41 "could not find field %q", field))
42 return cue.Value{}
43 }
44 if err := f.Err(); err != nil {
45 c.Err = errors.Append(c.Err, errors.Promote(err, "lookup"))
46 }
47 return f
48}
49
50func (c *Context) Int64(field string) int64 {
51 f := c.Obj.Lookup(field)
52 value, err := f.Int64()
53 if err != nil {
54 // TODO: use v for position for now, as f has not yet a
55 // position associated with it.
56 c.Err = errors.Append(c.Err, errors.Wrapf(err, c.Obj.Pos(),
57 "invalid integer argument for field %q", field))
58 return 0
59 }
60 return value
61}
62
63func (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.Err = errors.Append(c.Err, errors.Wrapf(err, c.Obj.Pos(),
70 "invalid string argument for field %q", field))
71 c.Err = errors.Promote(err, "ddd")
72 return ""
73 }
74 return value
75}
76
77func (c *Context) Bytes(field string) []byte {
78 f := c.Obj.Lookup(field)
79 value, err := f.Bytes()
80 if err != nil {
81 // TODO: use v for position for now, as f has not yet a
82 // position associated with it.
83 c.Err = errors.Append(c.Err, errors.Wrapf(err, c.Obj.Pos(),
84 "invalid bytes argument for field %q", field))
85 return nil
86 }
87 return value
Marcel van Lohuizen10fd4962019-04-26 12:14:49 +020088}
89
90// A RunnerFunc creates a Runner.
91type RunnerFunc func(v cue.Value) (Runner, error)
92
93// A Runner defines a command type.
94type Runner interface {
95 // Init is called with the original configuration before any task is run.
96 // As a result, the configuration may be incomplete, but allows some
97 // validation before tasks are kicked off.
98 // Init(v cue.Value)
99
100 // Runner runs given the current value and returns a new value which is to
101 // be unified with the original result.
Marcel van Lohuizena7b4ca82019-12-24 11:31:28 +0100102 Run(ctx *Context) (results interface{}, err error)
Marcel van Lohuizen10fd4962019-04-26 12:14:49 +0200103}
104
105// Register registers a task for cue commands.
106func Register(key string, f RunnerFunc) {
107 runners.Store(key, f)
108}
109
110// Lookup returns the RunnerFunc for a key.
111func Lookup(key string) RunnerFunc {
112 v, ok := runners.Load(key)
113 if !ok {
114 return nil
115 }
116 return v.(RunnerFunc)
117}
118
119var runners sync.Map