2021-02-17 03:31:03 +01:00
|
|
|
package compiler
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"cuelang.org/go/cue"
|
2021-05-01 03:05:37 +02:00
|
|
|
"cuelang.org/go/cue/cuecontext"
|
2021-02-17 03:31:03 +01:00
|
|
|
cueerrors "cuelang.org/go/cue/errors"
|
2021-03-18 23:03:45 +01:00
|
|
|
cuejson "cuelang.org/go/encoding/json"
|
|
|
|
cueyaml "cuelang.org/go/encoding/yaml"
|
2021-02-17 03:31:03 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
// DefaultCompiler is the default Compiler and is used by Compile
|
2021-05-01 03:05:37 +02:00
|
|
|
DefaultCompiler = New()
|
2021-02-17 03:31:03 +01:00
|
|
|
)
|
|
|
|
|
2021-05-01 03:05:37 +02:00
|
|
|
func Compile(name string, src string) (*Value, error) {
|
2021-02-17 03:31:03 +01:00
|
|
|
return DefaultCompiler.Compile(name, src)
|
|
|
|
}
|
|
|
|
|
2021-04-08 03:41:44 +02:00
|
|
|
func NewValue() *Value {
|
|
|
|
return DefaultCompiler.NewValue()
|
2021-02-17 03:31:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME can be refactored away now?
|
2021-05-01 03:05:37 +02:00
|
|
|
func Wrap(v cue.Value) *Value {
|
|
|
|
return DefaultCompiler.Wrap(v)
|
2021-02-17 03:31:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func Err(err error) error {
|
|
|
|
return DefaultCompiler.Err(err)
|
|
|
|
}
|
|
|
|
|
2021-03-18 23:03:45 +01:00
|
|
|
func DecodeJSON(path string, data []byte) (*Value, error) {
|
|
|
|
return DefaultCompiler.DecodeJSON(path, data)
|
|
|
|
}
|
|
|
|
|
|
|
|
func DecodeYAML(path string, data []byte) (*Value, error) {
|
|
|
|
return DefaultCompiler.DecodeYAML(path, data)
|
|
|
|
}
|
|
|
|
|
2021-02-17 03:31:03 +01:00
|
|
|
// Polyfill for a cue runtime
|
|
|
|
// (we call it compiler to avoid confusion with dagger runtime)
|
|
|
|
// Use this instead of cue.Runtime
|
|
|
|
type Compiler struct {
|
|
|
|
l sync.RWMutex
|
2021-05-01 03:05:37 +02:00
|
|
|
*cue.Context
|
|
|
|
}
|
|
|
|
|
|
|
|
func New() *Compiler {
|
|
|
|
return &Compiler{
|
|
|
|
Context: cuecontext.New(),
|
|
|
|
}
|
2021-02-17 03:31:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Compiler) lock() {
|
|
|
|
c.l.Lock()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Compiler) unlock() {
|
|
|
|
c.l.Unlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Compiler) rlock() {
|
|
|
|
c.l.RLock()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Compiler) runlock() {
|
|
|
|
c.l.RUnlock()
|
|
|
|
}
|
|
|
|
|
2021-04-08 03:41:44 +02:00
|
|
|
// Compile an empty value
|
|
|
|
func (c *Compiler) NewValue() *Value {
|
2021-04-09 01:30:55 +02:00
|
|
|
empty, err := c.Compile("", "_")
|
2021-02-19 23:04:40 +01:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
return empty
|
2021-02-17 03:31:03 +01:00
|
|
|
}
|
|
|
|
|
2021-05-01 03:05:37 +02:00
|
|
|
func (c *Compiler) Compile(name string, src string) (*Value, error) {
|
2021-02-17 03:31:03 +01:00
|
|
|
c.lock()
|
|
|
|
defer c.unlock()
|
|
|
|
|
2021-05-01 03:05:37 +02:00
|
|
|
v := c.Context.CompileString(src, cue.Filename(name))
|
|
|
|
if v.Err() != nil {
|
2021-02-17 03:31:03 +01:00
|
|
|
// FIXME: cleaner way to unwrap cue error details?
|
2021-05-01 03:05:37 +02:00
|
|
|
return nil, Err(v.Err())
|
2021-04-09 01:30:55 +02:00
|
|
|
}
|
2021-05-01 03:05:37 +02:00
|
|
|
return c.Wrap(v), nil
|
2021-04-09 01:30:55 +02:00
|
|
|
}
|
|
|
|
|
2021-03-18 23:03:45 +01:00
|
|
|
func (c *Compiler) DecodeJSON(path string, data []byte) (*Value, error) {
|
2021-05-01 03:05:37 +02:00
|
|
|
expr, err := cuejson.Extract(path, data)
|
2021-03-18 23:03:45 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, Err(err)
|
|
|
|
}
|
2021-05-01 03:05:37 +02:00
|
|
|
v := c.Context.BuildExpr(expr, cue.Filename(path))
|
|
|
|
if err := v.Err(); err != nil {
|
|
|
|
return nil, Err(err)
|
|
|
|
}
|
|
|
|
return c.Wrap(v), nil
|
2021-03-18 23:03:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Compiler) DecodeYAML(path string, data []byte) (*Value, error) {
|
2021-05-01 03:05:37 +02:00
|
|
|
f, err := cueyaml.Extract(path, data)
|
2021-03-18 23:03:45 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, Err(err)
|
|
|
|
}
|
2021-05-01 03:05:37 +02:00
|
|
|
v := c.Context.BuildFile(f, cue.Filename(path))
|
|
|
|
if err := v.Err(); err != nil {
|
|
|
|
return nil, Err(err)
|
|
|
|
}
|
|
|
|
return c.Wrap(v), nil
|
2021-03-18 23:03:45 +01:00
|
|
|
}
|
|
|
|
|
2021-05-01 03:05:37 +02:00
|
|
|
func (c *Compiler) Wrap(v cue.Value) *Value {
|
|
|
|
return &Value{
|
|
|
|
val: v,
|
|
|
|
cc: c,
|
|
|
|
}
|
2021-02-17 03:31:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Compiler) Err(err error) error {
|
|
|
|
if err == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return errors.New(cueerrors.Details(err, &cueerrors.Config{}))
|
|
|
|
}
|