Skip to content

Commit

Permalink
pkg: drop cue/build and pkg/internal from gen.go
Browse files Browse the repository at this point in the history
The code just needs to parse CUE files to extract the declarations.
There is no need to build instances and values to extract the syntax;
we can parse the syntax directly.

This gives us better results in any case,
as the resulting syntax directly follows the source.
For example, the original source uses octal integer literals
and uses some inline structs for readability, and we keep those now.

As a bonus, as we no longer use the CUE evaluator, `go generate`
drops from ~0.35s to ~0.25s on my laptop.

Signed-off-by: Daniel Martí <[email protected]>
Change-Id: Id6c03c49421c4b2ead467b523bcd4f25b41c002b
Dispatch-Trailer: {"type":"trybot","CL":1201388,"patchset":1,"ref":"refs/changes/88/1201388/1","targetBranch":"master"}
  • Loading branch information
mvdan authored and cueckoo committed Sep 17, 2024
1 parent 2fceb5c commit 299e22e
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 88 deletions.
74 changes: 32 additions & 42 deletions pkg/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,10 @@ import (

"golang.org/x/tools/go/packages"

"cuelang.org/go/cue"
"cuelang.org/go/cue/build"
"cuelang.org/go/cue/errors"
"cuelang.org/go/cue/ast"
cueformat "cuelang.org/go/cue/format"
"cuelang.org/go/cue/parser"
"cuelang.org/go/internal"
pkginternal "cuelang.org/go/pkg/internal"
)

const genFile = "pkg.go"
Expand Down Expand Up @@ -217,25 +215,28 @@ func (g *generator) processCUE() error {
// Note: we avoid using the cue/load and the cuecontext packages
// because they depend on the standard library which is what this
// command is generating - cyclic dependencies are undesirable in general.
ctx := pkginternal.NewContext()
val, err := loadCUEPackage(ctx, g.dir, g.cuePkgPath)
// We only need to load the declarations from one CUE file if it exists.
expr, err := loadCUEDecls(g.dir)
if err != nil {
if errors.Is(err, errNoCUEFiles) {
return nil
}
errors.Print(os.Stderr, err, nil)
return fmt.Errorf("error processing %s: %v", g.cuePkgPath, err)
}

v := val.Syntax(cue.Raw())
// fmt.Printf("%T\n", v)
// fmt.Println(astinternal.DebugStr(v))
n := internal.ToExpr(v)
b, err := cueformat.Node(n)
if expr == nil { // No syntax to add.
return nil
}
b, err := cueformat.Node(expr)
if err != nil {
return err
}

// Compact the CUE by removing empty lines. This requires re-formatting to align fields.
// TODO(mvdan): provide a "compact" option in cue/format for this purpose?
b = bytes.ReplaceAll(b, []byte("\n\n"), []byte("\n"))
b, err = cueformat.Source(b)
if err != nil {
return err
}
b = bytes.TrimSpace(b) // no trailing newline

// Try to use a Go string with backquotes, for readability.
// If not possible due to cueSrc itself having backquotes,
// use a single-line double-quoted string, removing tabs for brevity.
Expand Down Expand Up @@ -460,38 +461,27 @@ func (g *generator) adtKind(typ types.Type) string {
return ""
}

var errNoCUEFiles = errors.New("no CUE files in directory")

// loadCUEPackage loads a CUE package as a value. We avoid using cue/load because
// that depends on the standard library and as this generator is generating the standard
// library, we don't want that cyclic dependency.
// It only has to deal with the fairly limited subset of CUE packages that are
// present inside pkg/....
func loadCUEPackage(ctx *cue.Context, dir string, pkgPath string) (cue.Value, error) {
inst := &build.Instance{
PkgName: path.Base(pkgPath),
Dir: dir,
DisplayPath: pkgPath,
ImportPath: pkgPath,
}
// loadCUEDecls parses a single CUE file from a directory and returns its contents
// as an expression, typically a struct holding all of a file's declarations.
func loadCUEDecls(dir string) (ast.Expr, error) {
cuefiles, err := filepath.Glob(filepath.Join(dir, "*.cue"))
if err != nil {
return cue.Value{}, err
if err != nil || len(cuefiles) == 0 {
return nil, err
}
if len(cuefiles) == 0 {
return cue.Value{}, errNoCUEFiles
return nil, nil
}
for _, file := range cuefiles {
if err := inst.AddFile(file, nil); err != nil {
return cue.Value{}, err
}
if len(cuefiles) > 1 {
// Supporting multiple CUE files would require merging declarations.
return nil, fmt.Errorf("multiple CUE files not supported in this generator")
}
if err := inst.Complete(); err != nil {
return cue.Value{}, err
src, err := os.ReadFile(cuefiles[0])
if err != nil {
return nil, err
}
vals, err := ctx.BuildInstances([]*build.Instance{inst})
file, err := parser.ParseFile(cuefiles[0], src)
if err != nil {
return cue.Value{}, err
return nil, err
}
return vals[0], nil
return internal.ToExpr(file), nil
}
4 changes: 1 addition & 3 deletions pkg/tool/exec/pkg.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions pkg/tool/file/pkg.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 8 additions & 24 deletions pkg/tool/http/pkg.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 3 additions & 9 deletions pkg/tool/os/pkg.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 5 additions & 7 deletions pkg/uuid/pkg.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 299e22e

Please sign in to comment.