33
33
// corresponding symbols.
34
34
// Bundle also must write a package declaration in the output and must
35
35
// choose a name to use in that declaration.
36
+ // If the -pkg option is given, bundle uses that name.
37
+ // Otherwise, the name of the destination package is used.
36
38
// Build constraints for the generated file can be specified using the -tags option.
37
- // If the -package option is given, bundle uses that name.
38
- // Otherwise, if the -dst option is given, bundle uses the last
39
- // element of the destination import path.
40
- // Otherwise, by default bundle uses the package name found in the
41
- // package sources in the current directory.
42
39
//
43
40
// To avoid collisions, bundle inserts a prefix at the beginning of
44
41
// every package-level const, func, type, and var identifier in src's code,
58
55
// bundle -o zip.go archive/zip
59
56
//
60
57
// Bundle golang.org/x/net/http2 for inclusion in net/http,
61
- // prefixing all identifiers by "http2" instead of "http2_",
62
- // and rewriting the import "golang.org/x/net/http2/hpack"
63
- // to "internal/golang.org/x/net/http2/hpack", and also include
64
- // a "!nethttpomithttp2" build constraint:
58
+ // prefixing all identifiers by "http2" instead of "http2_", and
59
+ // including a "!nethttpomithttp2" build constraint:
65
60
//
66
61
// cd $GOROOT/src/net/http
67
- // bundle -o h2_bundle.go \
68
- // -prefix http2 \
69
- // -import golang.org/x/net/http2/hpack=internal/golang.org/x/net/http2/hpack \
70
- // -tags '!nethttpomithttp2' \
71
- // golang.org/x/net/http2
62
+ // bundle -o h2_bundle.go -prefix http2 -tags '!nethttpomithttp2' golang.org/x/net/http2
72
63
//
73
- // Two ways to update the http2 bundle:
64
+ // Update the http2 bundle in net/http :
74
65
//
75
66
// go generate net/http
76
67
//
77
- // cd $GOROOT/src/net/http
78
- // go generate
79
- //
80
- // Update both bundles, restricting ``go generate'' to running bundle commands:
68
+ // Update all bundles in the standard library:
81
69
//
82
- // go generate -run bundle cmd/dist net/http
70
+ // go generate -run bundle std
83
71
//
84
72
package main
85
73
@@ -88,28 +76,24 @@ import (
88
76
"flag"
89
77
"fmt"
90
78
"go/ast"
91
- "go/build"
92
79
"go/format"
93
- "go/parser"
94
80
"go/printer"
95
81
"go/token"
96
82
"go/types"
97
83
"io/ioutil"
98
84
"log"
99
85
"os"
100
- "path"
101
86
"strconv"
102
87
"strings"
103
88
104
- "golang.org/x/tools/go/loader "
89
+ "golang.org/x/tools/go/packages "
105
90
)
106
91
107
92
var (
108
93
outputFile = flag .String ("o" , "" , "write output to `file` (default standard output)" )
109
- dstPath = flag .String ("dst" , "" , "set destination import `path` (default taken from current directory) " )
110
- pkgName = flag .String ("pkg" , "" , "set destination package `name` (default taken from current directory) " )
94
+ dstPath = flag .String ("dst" , ". " , "set destination import `path`" )
95
+ pkgName = flag .String ("pkg" , "" , "set destination package `name`" )
111
96
prefix = flag .String ("prefix" , "&_" , "set bundled identifier prefix to `p` (default is \" &_\" , where & stands for the original name)" )
112
- underscore = flag .Bool ("underscore" , false , "rewrite golang.org/x/* to internal/x/* imports; temporary workaround for golang.org/issue/16333" )
113
97
buildTags = flag .String ("tags" , "" , "the build constraints to be inserted into the generated file" )
114
98
115
99
importMap = map [string ]string {}
@@ -148,23 +132,19 @@ func main() {
148
132
os .Exit (2 )
149
133
}
150
134
151
- if * dstPath != "" {
152
- if * pkgName == "" {
153
- * pkgName = path .Base (* dstPath )
154
- }
155
- } else {
156
- wd , _ := os .Getwd ()
157
- pkg , err := build .ImportDir (wd , 0 )
158
- if err != nil {
159
- log .Fatalf ("cannot find package in current directory: %v" , err )
160
- }
161
- * dstPath = pkg .ImportPath
162
- if * pkgName == "" {
163
- * pkgName = pkg .Name
164
- }
135
+ cfg := & packages.Config {Mode : packages .NeedName }
136
+ pkgs , err := packages .Load (cfg , * dstPath )
137
+ if err != nil {
138
+ log .Fatalf ("cannot load destination package: %v" , err )
139
+ }
140
+ if packages .PrintErrors (pkgs ) > 0 || len (pkgs ) != 1 {
141
+ log .Fatalf ("failed to load destination package" )
142
+ }
143
+ if * pkgName == "" {
144
+ * pkgName = pkgs [0 ].Name
165
145
}
166
146
167
- code , err := bundle (args [0 ], * dstPath , * pkgName , * prefix , * buildTags )
147
+ code , err := bundle (args [0 ], pkgs [ 0 ]. PkgPath , * pkgName , * prefix , * buildTags )
168
148
if err != nil {
169
149
log .Fatal (err )
170
150
}
@@ -191,24 +171,30 @@ func isStandardImportPath(path string) bool {
191
171
return ! strings .Contains (elem , "." )
192
172
}
193
173
194
- var ctxt = & build . Default
174
+ var testingOnlyPackagesConfig * packages. Config
195
175
196
176
func bundle (src , dst , dstpkg , prefix , buildTags string ) ([]byte , error ) {
197
177
// Load the initial package.
198
- conf := loader.Config {ParserMode : parser .ParseComments , Build : ctxt }
199
- conf .TypeCheckFuncBodies = func (p string ) bool { return p == src }
200
- conf .Import (src )
201
-
202
- lprog , err := conf .Load ()
178
+ cfg := & packages.Config {}
179
+ if testingOnlyPackagesConfig != nil {
180
+ * cfg = * testingOnlyPackagesConfig
181
+ } else {
182
+ // Bypass default vendor mode, as we need a package not available in the
183
+ // std module vendor folder.
184
+ cfg .Env = append (os .Environ (), "GOFLAGS=-mod=mod" )
185
+ }
186
+ cfg .Mode = packages .NeedTypes | packages .NeedSyntax | packages .NeedTypesInfo
187
+ pkgs , err := packages .Load (cfg , src )
203
188
if err != nil {
204
189
return nil , err
205
190
}
191
+ if packages .PrintErrors (pkgs ) > 0 || len (pkgs ) != 1 {
192
+ return nil , fmt .Errorf ("failed to load source package" )
193
+ }
194
+ pkg := pkgs [0 ]
206
195
207
- // Because there was a single Import call and Load succeeded,
208
- // InitialPackages is guaranteed to hold the sole requested package.
209
- info := lprog .InitialPackages ()[0 ]
210
196
if strings .Contains (prefix , "&" ) {
211
- prefix = strings .Replace (prefix , "&" , info . Files [0 ].Name .Name , - 1 )
197
+ prefix = strings .Replace (prefix , "&" , pkg . Syntax [0 ].Name .Name , - 1 )
212
198
}
213
199
214
200
objsToUpdate := make (map [types.Object ]bool )
@@ -223,9 +209,9 @@ func bundle(src, dst, dstpkg, prefix, buildTags string) ([]byte, error) {
223
209
// var s struct {T}
224
210
// print(s.T) // ...this must change too
225
211
if _ , ok := from .(* types.TypeName ); ok {
226
- for id , obj := range info .Uses {
212
+ for id , obj := range pkg . TypesInfo .Uses {
227
213
if obj == from {
228
- if field := info .Defs [id ]; field != nil {
214
+ if field := pkg . TypesInfo .Defs [id ]; field != nil {
229
215
rename (field )
230
216
}
231
217
}
@@ -235,7 +221,7 @@ func bundle(src, dst, dstpkg, prefix, buildTags string) ([]byte, error) {
235
221
}
236
222
237
223
// Rename each package-level object.
238
- scope := info . Pkg .Scope ()
224
+ scope := pkg . Types .Scope ()
239
225
for _ , name := range scope .Names () {
240
226
rename (scope .Lookup (name ))
241
227
}
@@ -254,7 +240,7 @@ func bundle(src, dst, dstpkg, prefix, buildTags string) ([]byte, error) {
254
240
fmt .Fprintf (& out , "\n " )
255
241
256
242
// Concatenate package comments from all files...
257
- for _ , f := range info . Files {
243
+ for _ , f := range pkg . Syntax {
258
244
if doc := f .Doc .Text (); strings .TrimSpace (doc ) != "" {
259
245
for _ , line := range strings .Split (doc , "\n " ) {
260
246
fmt .Fprintf (& out , "// %s\n " , line )
@@ -283,11 +269,11 @@ func bundle(src, dst, dstpkg, prefix, buildTags string) ([]byte, error) {
283
269
// to deduplicate instances of the same import name and path.
284
270
var pkgStd = make (map [string ]bool )
285
271
var pkgExt = make (map [string ]bool )
286
- for _ , f := range info . Files {
272
+ for _ , f := range pkg . Syntax {
287
273
for _ , imp := range f .Imports {
288
274
path , err := strconv .Unquote (imp .Path .Value )
289
275
if err != nil {
290
- log .Fatalf ("invalid import path string: %v" , err ) // Shouldn't happen here since conf .Load succeeded.
276
+ log .Fatalf ("invalid import path string: %v" , err ) // Shouldn't happen here since packages .Load succeeded.
291
277
}
292
278
if path == dst {
293
279
continue
@@ -304,9 +290,6 @@ func bundle(src, dst, dstpkg, prefix, buildTags string) ([]byte, error) {
304
290
if isStandardImportPath (path ) {
305
291
pkgStd [spec ] = true
306
292
} else {
307
- if * underscore {
308
- spec = strings .Replace (spec , "golang.org/x/" , "internal/x/" , 1 )
309
- }
310
293
pkgExt [spec ] = true
311
294
}
312
295
}
@@ -326,14 +309,14 @@ func bundle(src, dst, dstpkg, prefix, buildTags string) ([]byte, error) {
326
309
fmt .Fprint (& out , ")\n \n " )
327
310
328
311
// Modify and print each file.
329
- for _ , f := range info . Files {
312
+ for _ , f := range pkg . Syntax {
330
313
// Update renamed identifiers.
331
- for id , obj := range info .Defs {
314
+ for id , obj := range pkg . TypesInfo .Defs {
332
315
if objsToUpdate [obj ] {
333
316
id .Name = prefix + obj .Name ()
334
317
}
335
318
}
336
- for id , obj := range info .Uses {
319
+ for id , obj := range pkg . TypesInfo .Uses {
337
320
if objsToUpdate [obj ] {
338
321
id .Name = prefix + obj .Name ()
339
322
}
@@ -345,7 +328,7 @@ func bundle(src, dst, dstpkg, prefix, buildTags string) ([]byte, error) {
345
328
ast .Inspect (f , func (n ast.Node ) bool {
346
329
if sel , ok := n .(* ast.SelectorExpr ); ok {
347
330
if id , ok := sel .X .(* ast.Ident ); ok {
348
- if obj , ok := info .Uses [id ].(* types.PkgName ); ok {
331
+ if obj , ok := pkg . TypesInfo .Uses [id ].(* types.PkgName ); ok {
349
332
if obj .Imported ().Path () == dst {
350
333
id .Name = "@@@"
351
334
}
@@ -379,12 +362,12 @@ func bundle(src, dst, dstpkg, prefix, buildTags string) ([]byte, error) {
379
362
printComments (& out , f .Comments , last , beg )
380
363
381
364
buf .Reset ()
382
- format .Node (& buf , lprog .Fset , & printer.CommentedNode {Node : decl , Comments : f .Comments })
365
+ format .Node (& buf , pkg .Fset , & printer.CommentedNode {Node : decl , Comments : f .Comments })
383
366
// Remove each "@@@." in the output.
384
367
// TODO(adonovan): not hygienic.
385
368
out .Write (bytes .Replace (buf .Bytes (), []byte ("@@@." ), nil , - 1 ))
386
369
387
- last = printSameLineComment (& out , f .Comments , lprog .Fset , end )
370
+ last = printSameLineComment (& out , f .Comments , pkg .Fset , end )
388
371
389
372
out .WriteString ("\n \n " )
390
373
}
0 commit comments