forked from hofstadter-io/hof
-
Notifications
You must be signed in to change notification settings - Fork 0
/
runtime.go
205 lines (174 loc) · 4.21 KB
/
runtime.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
package cuetils
import (
"fmt"
"os"
"strings"
"github.com/go-git/go-billy/v5"
"cuelang.org/go/cue"
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/build"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/errors"
"cuelang.org/go/cue/load"
"cuelang.org/go/encoding/json"
"cuelang.org/go/encoding/yaml"
)
type CueSyntaxOptions struct {
Attributes bool
Concrete bool
Definitions bool
Docs bool
Hidden bool
Optional bool
}
func (CSO CueSyntaxOptions) MakeOpts() []cue.Option {
return []cue.Option{
cue.Attributes(CSO.Attributes),
cue.Concrete(CSO.Concrete),
cue.Definitions(CSO.Definitions),
cue.Docs(CSO.Docs),
cue.Hidden(CSO.Hidden),
cue.Optional(CSO.Optional),
}
}
var (
DefaultSyntaxOpts = CueSyntaxOptions{
Attributes: true,
Concrete: false,
Definitions: true,
Docs: true,
Hidden: true,
Optional: true,
}
)
type CueRuntime struct {
Entrypoints []string
Workspace string
FS billy.Filesystem
CueContext *cue.Context
CueConfig *load.Config
BuildInstances []*build.Instance
CueErrors []error
FieldOpts []cue.Option
CueInstance *cue.Instance
CueValue cue.Value
Value interface{}
}
func (CRT *CueRuntime) ConvertToValue(in interface{}) (cue.Value, error) {
O, ook := in.(cue.Value)
if !ook {
switch T := in.(type) {
case string:
i := CRT.CueContext.CompileString(T)
if i.Err() != nil {
return O, i.Err()
}
v := i.Value()
if v.Err() != nil {
return v, v.Err()
}
O = v
default:
return O, fmt.Errorf("unknown type %v in convertToValue(in)", T)
}
}
return O, nil
}
func (CRT *CueRuntime) Load() (err error) {
return CRT.load()
}
func (CRT *CueRuntime) load() (err error) {
// possibly, check for workpath
if CRT.Workspace != "" {
_, err = os.Lstat(CRT.Workspace)
if err != nil {
if _, ok := err.(*os.PathError); !ok && (strings.Contains(err.Error(), "file does not exist") || strings.Contains(err.Error(), "no such file")) {
// error is worse than non-existant
return err
}
// otherwise, does not exist, so we should init?
// XXX want to let applications decide how to handle this
return err
}
}
var errs []error
// XXX TODO XXX
// add the second arg from our runtime when implemented
if CRT.CueContext == nil {
CRT.CueContext = cuecontext.New()
}
CRT.BuildInstances = load.Instances(CRT.Entrypoints, nil)
for _, bi := range CRT.BuildInstances {
// fmt.Printf("%d: start\n", i)
if bi.Err != nil || bi.Incomplete {
es := errors.Errors(bi.Err)
for _, e := range es {
errs = append(errs, e.(error))
}
continue
}
// TODO, compare with len(entrypoints)
// and be more intelligent
// handle data files
for _, f := range bi.OrphanedFiles {
d, err := os.ReadFile(f.Filename)
if err != nil {
fmt.Println("while reading file")
errs = append(errs, err)
continue
}
switch f.Encoding {
case "json":
A, err := json.Extract(f.Filename, d)
if err != nil {
errs = append(errs, err)
continue
}
F := &ast.File{
Filename: f.Filename,
Decls: []ast.Decl{A},
}
bi.AddSyntax(F)
case "yml", "yaml":
F, err := yaml.Extract(f.Filename, d)
if err != nil {
fmt.Println("while yaml extract")
errs = append(errs, err)
continue
}
bi.AddSyntax(F)
// TODO, handle other formats (toml,json)
// which hof already works with
default:
// should only do this if it was also an arg
// otherwise we should ignore other files implicity discovered
// todo, re-enable this with better checks
// err := fmt.Errorf("unknown encoding for", f.Filename, f.Encoding)
// errs = append(errs, err)
continue
}
}
// Build the Instance
V := CRT.CueContext.BuildInstance(bi)
if V.Err() != nil {
es := errors.Errors(V.Err())
for _, e := range es {
errs = append(errs, e.(error))
}
continue
}
CRT.CueValue = V
}
if len(errs) > 0 {
CRT.CueErrors = errs
s := fmt.Sprintf("Errors while loading Cue entrypoints: %s %v\n", CRT.Workspace, CRT.Entrypoints)
for _, E := range errs {
es := errors.Errors(E)
for _, e := range es {
s += CueErrorToString(e)
}
}
return fmt.Errorf(s)
}
return nil
}