Skip to content
This repository was archived by the owner on Nov 18, 2021. It is now read-only.

Commit aaf6e84

Browse files
committed
cmd/cue/cmd: compute schema before values
This allows the schema with which data files will be merged before they are parsed. This is necessary to support protobuf parsing, including Protobuf / JSON mappings. The usage of this property will be done in a followup CL. Issue #5 Change-Id: I54b8826070217bd3d4e61d7d6f5b692f33553b12 Reviewed-on: https://cue-review.googlesource.com/c/cue/+/9322 Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
1 parent 8ba98ee commit aaf6e84

2 files changed

Lines changed: 91 additions & 74 deletions

File tree

cmd/cue/cmd/common.go

Lines changed: 90 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,10 @@ type buildPlan struct {
123123
cmd *Command
124124
insts []*build.Instance
125125

126+
// instance is a pre-compiled instance, which exists if value files are
127+
// being processed, which may require a schema to decode.
128+
instance *cue.Instance
129+
126130
cfg *config
127131

128132
// If orphanFiles are mixed with CUE files and/or if placement flags are used,
@@ -149,18 +153,25 @@ type buildPlan struct {
149153
outFile *build.File
150154

151155
encConfig *encoding.Config
152-
merge []*build.Instance
153156
}
154157

155158
// instances iterates either over a list of instances, or a list of
156159
// data files. In the latter case, there must be either 0 or 1 other
157160
// instance, with which the data instance may be merged.
158161
func (b *buildPlan) instances() iterator {
159162
var i iterator
160-
if len(b.orphaned) == 0 {
161-
i = &instanceIterator{a: buildInstances(b.cmd, b.insts), i: -1}
162-
} else {
163+
switch {
164+
case len(b.orphaned) > 0:
163165
i = newStreamingIterator(b)
166+
case len(b.insts) > 0:
167+
i = &instanceIterator{
168+
inst: b.instance,
169+
a: buildInstances(b.cmd, b.insts),
170+
i: -1,
171+
}
172+
default:
173+
i = &instanceIterator{a: []*cue.Instance{b.instance}, i: -1}
174+
b.instance = nil
164175
}
165176
if len(b.expressions) > 0 {
166177
return &expressionIter{
@@ -183,33 +194,44 @@ type iterator interface {
183194
}
184195

185196
type instanceIterator struct {
186-
a []*cue.Instance
187-
i int
188-
e error
197+
inst *cue.Instance
198+
a []*cue.Instance
199+
i int
200+
e error
189201
}
190202

191203
func (i *instanceIterator) scan() bool {
192204
i.i++
193205
return i.i < len(i.a) && i.e == nil
194206
}
195207

196-
func (i *instanceIterator) close() {}
197-
func (i *instanceIterator) err() error { return i.e }
198-
func (i *instanceIterator) value() cue.Value { return i.a[i.i].Value() }
199-
func (i *instanceIterator) instance() *cue.Instance { return i.a[i.i] }
200-
func (i *instanceIterator) file() *ast.File { return nil }
201-
func (i *instanceIterator) id() string { return i.a[i.i].Dir }
208+
func (i *instanceIterator) close() {}
209+
func (i *instanceIterator) err() error { return i.e }
210+
func (i *instanceIterator) value() cue.Value {
211+
v := i.a[i.i].Value()
212+
if i.inst != nil {
213+
v = v.Unify(i.inst.Value())
214+
}
215+
return v
216+
}
217+
func (i *instanceIterator) instance() *cue.Instance {
218+
if i.inst != nil {
219+
return nil
220+
}
221+
return i.a[i.i]
222+
}
223+
func (i *instanceIterator) file() *ast.File { return nil }
224+
func (i *instanceIterator) id() string { return i.a[i.i].Dir }
202225

203226
type streamingIterator struct {
204-
r *cue.Runtime
205-
inst *cue.Instance
206-
b *buildPlan
207-
cfg *encoding.Config
208-
a []*decoderInfo
209-
dec *encoding.Decoder
210-
v cue.Value
211-
f *ast.File
212-
e error
227+
r *cue.Runtime
228+
b *buildPlan
229+
cfg *encoding.Config
230+
a []*decoderInfo
231+
dec *encoding.Decoder
232+
v cue.Value
233+
f *ast.File
234+
e error
213235
}
214236

215237
func newStreamingIterator(b *buildPlan) *streamingIterator {
@@ -220,28 +242,9 @@ func newStreamingIterator(b *buildPlan) *streamingIterator {
220242
}
221243

222244
// TODO: use orphanedSchema
223-
switch len(b.insts) {
224-
case 0:
225-
i.r = &cue.Runtime{}
226-
case 1:
227-
p := b.insts[0]
228-
inst := buildInstances(b.cmd, []*build.Instance{p})[0]
229-
if inst.Err != nil {
230-
return &streamingIterator{e: inst.Err}
231-
}
232-
i.r = internal.GetRuntime(inst).(*cue.Runtime)
233-
if b.schema == nil {
234-
b.encConfig.Schema = inst.Value()
235-
} else {
236-
schema := inst.Eval(b.schema)
237-
if err := schema.Err(); err != nil {
238-
return &streamingIterator{e: err}
239-
}
240-
b.encConfig.Schema = schema
241-
}
242-
default:
243-
return &streamingIterator{e: errors.Newf(token.NoPos,
244-
"cannot combine data streaming with multiple instances")}
245+
i.r = &cue.Runtime{}
246+
if v := b.encConfig.Schema; v.Exists() {
247+
i.r = internal.GetRuntime(v).(*cue.Runtime)
245248
}
246249

247250
return i
@@ -252,9 +255,6 @@ func (i *streamingIterator) value() cue.Value { return i.v }
252255
func (i *streamingIterator) instance() *cue.Instance { return nil }
253256

254257
func (i *streamingIterator) id() string {
255-
if i.inst != nil {
256-
return i.inst.Dir
257-
}
258258
return ""
259259
}
260260

@@ -510,10 +510,6 @@ func parseArgs(cmd *Command, args []string, cfg *config) (p *buildPlan, err erro
510510
return nil, err
511511
}
512512

513-
// TODO(v0.4.0): what to do:
514-
// - when there is already a single instance
515-
// - when we are importing and there are schemas and values.
516-
517513
if values == nil {
518514
values, schemas = schemas, values
519515
}
@@ -530,42 +526,63 @@ func parseArgs(cmd *Command, args []string, cfg *config) (p *buildPlan, err erro
530526
}
531527
}
532528

533-
// TODO(v0.4.0): if schema is specified and data format is JSON, YAML or
534-
// Protobuf, reinterpret with schema.
529+
if len(p.insts) > 1 && p.schema != nil {
530+
return nil, errors.Newf(token.NoPos,
531+
"cannot use --schema/-d with flag more than one schema")
532+
}
535533

536-
switch {
537-
case p.usePlacement() || p.importing:
538-
if err = p.placeOrphans(b, values); err != nil {
539-
return nil, err
534+
var schema *build.Instance
535+
switch n := len(p.insts); n {
536+
default:
537+
return nil, errors.Newf(token.NoPos,
538+
"too many packages defined (%d) in combination with files", n)
539+
case 1:
540+
if len(schemas) > 0 {
541+
return nil, errors.Newf(token.NoPos,
542+
"cannot combine packages with individual schema files")
540543
}
544+
schema = p.insts[0]
545+
p.insts = nil
546+
547+
case 0:
548+
bb := *b
549+
schema = &bb
550+
b.BuildFiles = nil
551+
b.Files = nil
552+
}
541553

542-
case !p.mergeData || p.schema != nil:
543-
p.orphaned = values
554+
if schema != nil && len(schema.Files) > 0 {
555+
inst := buildInstances(p.cmd, []*build.Instance{schema})[0]
544556

545-
default:
546-
for _, di := range values {
547-
d := di.dec(p)
548-
for ; !d.Done(); d.Next() {
549-
if err := b.AddSyntax(d.File()); err != nil {
550-
return nil, err
551-
}
552-
}
553-
if err := d.Err(); err != nil {
557+
if inst.Err != nil {
558+
return nil, err
559+
}
560+
p.instance = inst
561+
p.encConfig.Schema = inst.Value()
562+
if p.schema != nil {
563+
v := inst.Eval(p.schema)
564+
if err := v.Err(); err != nil {
554565
return nil, err
555566
}
567+
p.encConfig.Schema = v
556568
}
557569
}
558570

571+
switch {
572+
case p.mergeData, p.usePlacement(), p.importing:
573+
if err = p.placeOrphans(b, values); err != nil {
574+
return nil, err
575+
}
576+
577+
default:
578+
p.orphaned = values
579+
}
580+
559581
if len(b.Files) > 0 {
560582
p.insts = append(p.insts, b)
561583
}
562584
}
563585

564-
if len(p.insts) > 1 && p.schema != nil {
565-
return nil, errors.Newf(token.NoPos,
566-
"cannot use --schema/-d flag more than one schema")
567-
}
568-
569586
if len(p.expressions) > 1 {
570587
p.encConfig.Stream = true
571588
}

cmd/cue/cmd/vet.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ func doVet(cmd *Command, args []string) error {
143143
func vetFiles(cmd *Command, b *buildPlan) {
144144
// Use -r type root, instead of -e
145145

146-
if len(b.insts) == 0 {
146+
if !b.encConfig.Schema.Exists() {
147147
exitOnErr(cmd, errors.New("data files specified without a schema"), true)
148148
}
149149

0 commit comments

Comments
 (0)