Skip to content

Commit 56697cf

Browse files
committed
cmd/cue: add --outfile flag to get go
This introduces a way to write generated cue schemas to a given file or stdout. It joins all declarations into one giant file and preserves all package comments.
1 parent afdde34 commit 56697cf

File tree

1 file changed

+72
-26
lines changed

1 file changed

+72
-26
lines changed

cmd/cue/cmd/get_go.go

Lines changed: 72 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import (
3737

3838
cueast "cuelang.org/go/cue/ast"
3939
"cuelang.org/go/cue/ast/astutil"
40+
"cuelang.org/go/cue/errors"
4041
"cuelang.org/go/cue/format"
4142
"cuelang.org/go/cue/literal"
4243
"cuelang.org/go/cue/load"
@@ -218,6 +219,8 @@ restrictive enum interpretation of #Switch remains.
218219

219220
cmd.Flags().StringP(string(flagPackage), "p", "", "package name for generated CUE files")
220221

222+
cmd.Flags().String(string(flagOutFile), "", "write generated CUE schema to the given file or stdout (only allows for one package)")
223+
221224
return cmd
222225
}
223226

@@ -247,8 +250,9 @@ func (e *extractor) filter(name string) bool {
247250
type extractor struct {
248251
cmd *Command
249252

250-
allPkgs map[string]*packages.Package
251-
done map[string]bool
253+
allPkgs map[string]*packages.Package
254+
rootPkgs map[string]bool
255+
done map[string]bool
252256

253257
// per package
254258
pkg *packages.Package
@@ -357,6 +361,10 @@ var toString = []*types.Interface{
357361
// - consider not including types with any dropped fields.
358362

359363
func extract(cmd *Command, args []string) error {
364+
if flagLocal.IsSet(cmd) && flagOutFile.IsSet(cmd) {
365+
return errors.New("--local and --outfile are mutually exclusive")
366+
}
367+
360368
// TODO the CUE load using "." (below) assumes that a CUE module and a Go
361369
// module will exist within the same directory (more precisely a Go module
362370
// could be nested within a CUE module), such that the module path in any
@@ -387,9 +395,10 @@ func extract(cmd *Command, args []string) error {
387395
}
388396

389397
e := extractor{
390-
cmd: cmd,
391-
allPkgs: map[string]*packages.Package{},
392-
orig: map[types.Type]*ast.StructType{},
398+
cmd: cmd,
399+
allPkgs: map[string]*packages.Package{},
400+
rootPkgs: map[string]bool{},
401+
orig: map[types.Type]*ast.StructType{},
393402
}
394403

395404
e.initExclusions(flagExclude.String(cmd))
@@ -398,9 +407,14 @@ func extract(cmd *Command, args []string) error {
398407

399408
for _, p := range pkgs {
400409
e.done[p.PkgPath] = true
410+
e.rootPkgs[p.PkgPath] = true
401411
e.addPackage(p)
402412
}
403413

414+
if flagOutFile.IsSet(cmd) && len(e.rootPkgs) > 1 {
415+
return errors.New("--outfile only allows for one package to be specified")
416+
}
417+
404418
for _, p := range pkgs {
405419
if err := e.extractPkg(root, p); err != nil {
406420
return err
@@ -439,6 +453,10 @@ func (e *extractor) extractPkg(root string, p *packages.Package) error {
439453

440454
e.recordTypeInfo(p)
441455

456+
if !e.rootPkgs[p.PkgPath] && flagOutFile.IsSet(e.cmd) {
457+
return nil
458+
}
459+
442460
e.consts = map[string][]string{}
443461

444462
for _, f := range p.Syntax {
@@ -462,8 +480,10 @@ func (e *extractor) extractPkg(root string, p *packages.Package) error {
462480
}
463481
}
464482

465-
if err := os.MkdirAll(dir, 0777); err != nil {
466-
return err
483+
if !flagOutFile.IsSet(e.cmd) {
484+
if err := os.MkdirAll(dir, 0777); err != nil {
485+
return err
486+
}
467487
}
468488

469489
e.usedPkgs = map[string]bool{}
@@ -473,7 +493,21 @@ func (e *extractor) extractPkg(root string, p *packages.Package) error {
473493
args += " --exclude=" + e.exclude
474494
}
475495

496+
pName := flagPackage.String(e.cmd)
497+
if pName == "" {
498+
pName = p.Name
499+
}
500+
501+
var (
502+
decls []cueast.Decl
503+
cuePkg *cueast.Package
504+
)
476505
for i, f := range p.Syntax {
506+
if cuePkg == nil || !flagOutFile.IsSet(e.cmd) {
507+
cuePkg = &cueast.Package{Name: e.ident(pName, false)}
508+
decls = nil
509+
}
510+
477511
e.cmap = ast.NewCommentMap(p.Fset, f, f.Comments)
478512

479513
e.pkgNames = map[string]pkgInfo{}
@@ -494,25 +528,24 @@ func (e *extractor) extractPkg(root string, p *packages.Package) error {
494528
e.pkgNames[pkgPath] = info
495529
}
496530

497-
decls := []cueast.Decl{}
531+
var fileDecls []cueast.Decl
498532
for _, d := range f.Decls {
499533
switch d := d.(type) {
500534
case *ast.GenDecl:
501-
decls = append(decls, e.reportDecl(d)...)
535+
fileDecls = append(fileDecls, e.reportDecl(d)...)
502536
}
503537
}
504538

505-
if len(decls) == 0 && f.Doc == nil {
539+
if len(fileDecls) == 0 && f.Doc == nil && !flagOutFile.IsSet(e.cmd) {
506540
continue
507541
}
542+
decls = append(decls, fileDecls...)
508543

509-
pName := flagPackage.String(e.cmd)
510-
if pName == "" {
511-
pName = p.Name
512-
}
544+
addDoc(f.Doc, cuePkg)
513545

514-
pkg := &cueast.Package{Name: e.ident(pName, false)}
515-
addDoc(f.Doc, pkg)
546+
if flagOutFile.IsSet(e.cmd) && i != len(p.Syntax)-1 {
547+
continue
548+
}
516549

517550
f := &cueast.File{Decls: []cueast.Decl{
518551
&cueast.CommentGroup{List: []*cueast.Comment{
@@ -521,7 +554,7 @@ func (e *extractor) extractPkg(root string, p *packages.Package) error {
521554
&cueast.CommentGroup{List: []*cueast.Comment{
522555
{Text: "//cue:generate cue get go " + args},
523556
}},
524-
pkg,
557+
cuePkg,
525558
}}
526559
f.Decls = append(f.Decls, decls...)
527560

@@ -530,16 +563,29 @@ func (e *extractor) extractPkg(root string, p *packages.Package) error {
530563
}
531564

532565
file := filepath.Base(p.CompiledGoFiles[i])
533-
534566
file = strings.Replace(file, ".go", "_go", 1)
535567
file += "_gen.cue"
568+
filePath := filepath.Join(dir, file)
569+
536570
b, err := format.Node(f, format.Simplify())
537571
if err != nil {
538572
return err
539573
}
540-
err = os.WriteFile(filepath.Join(dir, file), b, 0666)
541-
if err != nil {
542-
return err
574+
575+
if flagOutFile.IsSet(e.cmd) {
576+
filePath = flagOutFile.String(e.cmd)
577+
}
578+
579+
if filePath == "-" {
580+
_, err = os.Stdout.Write(b)
581+
if err != nil {
582+
return err
583+
}
584+
} else {
585+
err = os.WriteFile(filePath, b, 0666)
586+
if err != nil {
587+
return err
588+
}
543589
}
544590
}
545591

@@ -549,10 +595,10 @@ func (e *extractor) extractPkg(root string, p *packages.Package) error {
549595
}
550596
}
551597

552-
for path := range e.usedPkgs {
553-
if !e.done[path] {
554-
e.done[path] = true
555-
if err := e.extractPkg(root, e.allPkgs[path]); err != nil {
598+
for pkgPath := range e.usedPkgs {
599+
if !e.done[pkgPath] {
600+
e.done[pkgPath] = true
601+
if err := e.extractPkg(root, e.allPkgs[pkgPath]); err != nil {
556602
return err
557603
}
558604
}
@@ -883,7 +929,7 @@ func makeDoc(g *ast.CommentGroup, isDoc bool) *cueast.CommentGroup {
883929
// The parser has given us exactly the comment text.
884930
switch c[1] {
885931
case '/':
886-
//-style comment (no newline at the end)
932+
// -style comment (no newline at the end)
887933
a = append(a, &cueast.Comment{Text: c})
888934

889935
case '*':

0 commit comments

Comments
 (0)