@@ -129,7 +129,7 @@ type buildPlan struct {
129
129
// the instance is also included in insts.
130
130
importing bool
131
131
mergeData bool // do not merge individual data files.
132
- orphaned []* build. File
132
+ orphaned []* decoderInfo
133
133
orphanInstance * build.Instance
134
134
// imported files are files that were orphaned in the build instance, but
135
135
// were placed in the instance by using one the --files, --list or --path
@@ -206,7 +206,7 @@ type streamingIterator struct {
206
206
base cue.Value
207
207
b * buildPlan
208
208
cfg * encoding.Config
209
- a []* build. File
209
+ a []* decoderInfo
210
210
dec * encoding.Decoder
211
211
v cue.Value
212
212
f * ast.File
@@ -278,7 +278,7 @@ func (i *streamingIterator) scan() bool {
278
278
return false
279
279
}
280
280
281
- i .dec = encoding . NewDecoder ( i .a [0 ], i . cfg )
281
+ i .dec = i .a [0 ]. dec ( i . b )
282
282
if i .e = i .dec .Err (); i .e != nil {
283
283
return false
284
284
}
@@ -383,6 +383,87 @@ func newBuildPlan(cmd *Command, args []string, cfg *config) (p *buildPlan, err e
383
383
return p , nil
384
384
}
385
385
386
+ type decoderInfo struct {
387
+ file * build.File
388
+ d * encoding.Decoder // may be nil if delayed
389
+ }
390
+
391
+ func (d * decoderInfo ) dec (b * buildPlan ) * encoding.Decoder {
392
+ if d .d == nil {
393
+ d .d = encoding .NewDecoder (d .file , b .encConfig )
394
+ }
395
+ return d .d
396
+ }
397
+
398
+ func (d * decoderInfo ) close () {
399
+ if d .d != nil {
400
+ d .d .Close ()
401
+ }
402
+ }
403
+
404
+ // getDecoders takes the orphaned files of the given instance and splits them in
405
+ // schemas and values, saving the build.File and encoding.Decoder in the
406
+ // returned slices. It is up to the caller to Close any of the decoders that are
407
+ // returned.
408
+ func (p * buildPlan ) getDecoders (b * build.Instance ) (schemas , values []* decoderInfo , err error ) {
409
+ for _ , f := range b .OrphanedFiles {
410
+ switch f .Encoding {
411
+ case build .Protobuf , build .YAML , build .JSON , build .JSONL , build .Text :
412
+ default :
413
+ return schemas , values , errors .Newf (token .NoPos ,
414
+ "unsupported encoding %q" , f .Encoding )
415
+ }
416
+
417
+ // We add the module root to the path if there is a module defined.
418
+ c := * p .encConfig
419
+ if b .Module != "" {
420
+ c .ProtoPath = append (c .ProtoPath , b .Root )
421
+ }
422
+ d := encoding .NewDecoder (f , & c )
423
+
424
+ fi , err := filetypes .FromFile (f , p .cfg .outMode )
425
+ if err != nil {
426
+ return schemas , values , err
427
+ }
428
+ switch {
429
+ // case !fi.Schema: // TODO: value/schema/auto
430
+ // values = append(values, d)
431
+ case fi .Form != build .Schema && fi .Form != build .Final :
432
+ values = append (values , & decoderInfo {f , d })
433
+
434
+ case f .Interpretation != build .Auto :
435
+ schemas = append (schemas , & decoderInfo {f , d })
436
+
437
+ case d .Interpretation () == "" :
438
+ values = append (values , & decoderInfo {f , d })
439
+
440
+ default :
441
+ schemas = append (schemas , & decoderInfo {f , d })
442
+ }
443
+ }
444
+ return schemas , values , nil
445
+ }
446
+
447
+ // importFiles imports orphan files for existing instances. Note that during
448
+ // import, both schemas and non-schemas are placed (TODO: should we allow schema
449
+ // mode here as well? It seems that the existing package should have enough
450
+ // typing to allow for schemas).
451
+ //
452
+ // It is a separate call to allow closing decoders between processing each
453
+ // package.
454
+ func (p * buildPlan ) importFiles (b * build.Instance ) error {
455
+ // TODO: assume textproto is imported at top-level or just ignore them.
456
+
457
+ schemas , values , err := p .getDecoders (b )
458
+ for _ , d := range append (schemas , values ... ) {
459
+ defer d .close ()
460
+ }
461
+ if err != nil {
462
+ return err
463
+ }
464
+ return p .placeOrphans (b , append (schemas , values ... ))
465
+ }
466
+
386
467
func parseArgs (cmd * Command , args []string , cfg * config ) (p * buildPlan , err error ) {
387
468
p , err = newBuildPlan (cmd , args , cfg )
388
469
if err != nil {
@@ -405,7 +486,7 @@ func parseArgs(cmd *Command, args []string, cfg *config) (p *buildPlan, err erro
405
486
switch {
406
487
case ! b .User :
407
488
if p .importing {
408
- if err = p .placeOrphans (b ); err != nil {
489
+ if err : = p .importFiles (b ); err != nil {
409
490
return nil , err
410
491
}
411
492
}
@@ -420,50 +501,27 @@ func parseArgs(cmd *Command, args []string, cfg *config) (p *buildPlan, err erro
420
501
}
421
502
}
422
503
423
- switch b := p .orphanInstance ; {
424
- case b == nil :
425
- case p .usePlacement () || p .importing :
426
- p .insts = append (p .insts , b )
427
- if err = p .placeOrphans (b ); err != nil {
504
+ if b := p .orphanInstance ; b != nil {
505
+ schemas , values , err := p .getDecoders (b )
506
+ for _ , d := range append (schemas , values ... ) {
507
+ defer d .close ()
508
+ }
509
+ if err != nil {
428
510
return nil , err
429
511
}
430
512
431
- default :
432
- for _ , f := range b .OrphanedFiles {
433
- switch f .Encoding {
434
- case build .Protobuf , build .YAML , build .JSON , build .Text :
435
- default :
436
- return nil , errors .Newf (token .NoPos ,
437
- "unsupported encoding %q" , f .Encoding )
438
- }
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
+
517
+ if values == nil {
518
+ values , schemas = schemas , values
439
519
}
440
520
441
- // TODO: this processing could probably be delayed, or at least
442
- // simplified. The main reason to do this here is to allow interpreting
443
- // the --schema/-d flag, while allowing to use this for OpenAPI and
444
- // JSON Schema in auto-detect mode.
445
- buildFiles := []* build.File {}
446
- for _ , f := range b .OrphanedFiles {
447
- d := encoding .NewDecoder (f , p .encConfig )
521
+ for _ , di := range schemas {
522
+ d := di .dec (p )
448
523
for ; ! d .Done (); d .Next () {
449
- file := d .File ()
450
- sub := & build.File {
451
- Filename : d .Filename (),
452
- Encoding : f .Encoding ,
453
- Interpretation : d .Interpretation (),
454
- Form : f .Form ,
455
- Tags : f .Tags ,
456
- Source : file ,
457
- }
458
- if (! p .mergeData || p .schema != nil ) && d .Interpretation () == "" {
459
- switch sub .Encoding {
460
- case build .YAML , build .JSON , build .Text :
461
- p .orphaned = append (p .orphaned , sub )
462
- continue
463
- }
464
- }
465
- buildFiles = append (buildFiles , sub )
466
- if err := b .AddSyntax (file ); err != nil {
524
+ if err := b .AddSyntax (d .File ()); err != nil {
467
525
return nil , err
468
526
}
469
527
}
@@ -472,11 +530,34 @@ func parseArgs(cmd *Command, args []string, cfg *config) (p *buildPlan, err erro
472
530
}
473
531
}
474
532
533
+ // TODO(v0.4.0): if schema is specified and data format is JSON, YAML or
534
+ // Protobuf, reinterpret with schema.
535
+
536
+ switch {
537
+ case p .usePlacement () || p .importing :
538
+ if err = p .placeOrphans (b , values ); err != nil {
539
+ return nil , err
540
+ }
541
+
542
+ case ! p .mergeData || p .schema != nil :
543
+ p .orphaned = values
544
+
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 {
554
+ return nil , err
555
+ }
556
+ }
557
+ }
558
+
475
559
if len (b .Files ) > 0 {
476
560
p .insts = append (p .insts , b )
477
- } else if len (p .orphaned ) == 0 {
478
- // Instance with only a single build: just print the file.
479
- p .orphaned = append (p .orphaned , buildFiles ... )
480
561
}
481
562
}
482
563
0 commit comments