@@ -29,7 +29,6 @@ import (
29
29
"flag"
30
30
"fmt"
31
31
"go/ast"
32
- gobuild "go/build"
33
32
"go/constant"
34
33
"go/format"
35
34
"go/parser"
@@ -43,6 +42,8 @@ import (
43
42
"strings"
44
43
"text/template"
45
44
45
+ "golang.org/x/tools/go/packages"
46
+
46
47
"cuelang.org/go/cue"
47
48
"cuelang.org/go/cue/build"
48
49
"cuelang.org/go/cue/errors"
@@ -56,8 +57,6 @@ const genFile = "pkg.go"
56
57
//go:embed packages.txt
57
58
var packagesStr string
58
59
59
- var packages = strings .Fields (packagesStr )
60
-
61
60
type headerParams struct {
62
61
GoPkg string
63
62
CUEPkg string
@@ -89,19 +88,35 @@ var _ = adt.TopKind // in case the adt package isn't used
89
88
{{end}}
90
89
` ))
91
90
91
+ const pkgParent = "cuelang.org/go/pkg"
92
+
92
93
func main () {
93
94
flag .Parse ()
94
95
log .SetFlags (log .Lshortfile )
95
96
log .SetOutput (os .Stdout )
96
97
97
- for _ , pkg := range packages {
98
+ var packagesList []string
99
+ for _ , pkg := range strings .Fields (packagesStr ) {
98
100
if pkg == "path" {
99
101
// TODO remove this special case. Currently the path
100
102
// pkg.go file cannot be generated automatically but that
101
103
// will be possible when we can attach arbitrary signatures
102
104
// to builtin functions.
103
105
continue
104
106
}
107
+ packagesList = append (packagesList , path .Join (pkgParent , pkg ))
108
+ }
109
+
110
+ cfg := & packages.Config {Mode : packages .NeedName | packages .NeedFiles }
111
+ pkgs , err := packages .Load (cfg , packagesList ... )
112
+ if err != nil {
113
+ fmt .Fprintf (os .Stderr , "load: %v\n " , err )
114
+ os .Exit (1 )
115
+ }
116
+ if packages .PrintErrors (pkgs ) > 0 {
117
+ os .Exit (1 )
118
+ }
119
+ for _ , pkg := range pkgs {
105
120
if err := generate (pkg ); err != nil {
106
121
log .Fatalf ("%s: %v" , pkg , err )
107
122
}
@@ -116,32 +131,32 @@ type generator struct {
116
131
first bool
117
132
}
118
133
119
- func generate (cuePkgPath string ) error {
120
- goPkgPath := path . Join ( "cuelang.org/ go/pkg" , cuePkgPath )
121
- pkg , err := gobuild . Import ( goPkgPath , "" , 0 )
122
- if err != nil {
123
- return err
124
- }
125
-
134
+ func generate (pkg * packages. Package ) error {
135
+ // go/packages supports multiple build systems, including some which don't keep
136
+ // a Go package entirely within a single directory.
137
+ // However, we know for certain that CUE uses modules, so it is the case here.
138
+ // We can figure out the directory from the first Go file.
139
+ pkgDir := filepath . Dir ( pkg . GoFiles [ 0 ])
140
+ cuePkg := strings . TrimPrefix ( pkg . PkgPath , pkgParent + "/" )
126
141
g := generator {
127
- dir : pkg . Dir ,
128
- cuePkgPath : cuePkgPath ,
142
+ dir : pkgDir ,
143
+ cuePkgPath : cuePkg ,
129
144
w : & bytes.Buffer {},
130
145
fset : token .NewFileSet (),
131
146
}
132
147
133
148
params := headerParams {
134
149
GoPkg : pkg .Name ,
135
- CUEPkg : cuePkgPath ,
150
+ CUEPkg : cuePkg ,
136
151
}
137
152
// As a special case, the "tool" package cannot be imported from CUE.
138
153
skipRegister := params .CUEPkg == "tool"
139
154
if skipRegister {
140
155
params .CUEPkg = ""
141
156
}
142
157
143
- if doc , err := os .ReadFile (filepath .Join (pkg . Dir , "doc.txt" )); err == nil {
144
- defs , err := os .ReadFile (filepath .Join (pkg . Dir , pkg .Name + ".cue" ))
158
+ if doc , err := os .ReadFile (filepath .Join (pkgDir , "doc.txt" )); err == nil {
159
+ defs , err := os .ReadFile (filepath .Join (pkgDir , pkg .Name + ".cue" ))
145
160
if err != nil {
146
161
return err
147
162
}
@@ -164,7 +179,9 @@ func generate(cuePkgPath string) error {
164
179
if filename == genFile {
165
180
continue
166
181
}
167
- g .processGo (filepath .Join (pkg .Dir , filename ))
182
+ if err := g .processGo (filename ); err != nil {
183
+ return err
184
+ }
168
185
}
169
186
fmt .Fprintf (g .w , "},\n " )
170
187
if err := g .processCUE (); err != nil {
@@ -178,7 +195,7 @@ func generate(cuePkgPath string) error {
178
195
b = g .w .Bytes () // write the unformatted source
179
196
}
180
197
181
- filename := filepath .Join (pkg . Dir , genFile )
198
+ filename := filepath .Join (pkgDir , genFile )
182
199
183
200
if err := os .WriteFile (filename , b , 0666 ); err != nil {
184
201
return err
0 commit comments