@@ -13,7 +13,9 @@ import (
13
13
"fmt"
14
14
"io"
15
15
"os"
16
+ "reflect"
16
17
"sort"
18
+ "strconv"
17
19
"strings"
18
20
"text/template"
19
21
@@ -157,7 +159,10 @@ For more information about the meaning of these fields see the documentation
157
159
for the go/build package's Context type.
158
160
159
161
The -json flag causes the package data to be printed in JSON format
160
- instead of using the template format.
162
+ instead of using the template format. The JSON flag can optionally be
163
+ provided with a set of comma-separated required field names to be output.
164
+ If so, those required fields will always appear in JSON output, but
165
+ others may be omitted to save work in computing the JSON struct.
161
166
162
167
The -compiled flag causes list to set CompiledGoFiles to the Go source
163
168
files presented to the compiler. Typically this means that it repeats
@@ -316,29 +321,79 @@ For more about modules, see https://golang.org/ref/mod.
316
321
func init () {
317
322
CmdList .Run = runList // break init cycle
318
323
work .AddBuildFlags (CmdList , work .DefaultBuildFlags )
324
+ CmdList .Flag .Var (& listJsonFields , "json" , "" )
319
325
}
320
326
321
327
var (
322
- listCompiled = CmdList .Flag .Bool ("compiled" , false , "" )
323
- listDeps = CmdList .Flag .Bool ("deps" , false , "" )
324
- listE = CmdList .Flag .Bool ("e" , false , "" )
325
- listExport = CmdList .Flag .Bool ("export" , false , "" )
326
- listFmt = CmdList .Flag .String ("f" , "" , "" )
327
- listFind = CmdList .Flag .Bool ("find" , false , "" )
328
- listJson = CmdList .Flag .Bool ("json" , false , "" )
329
- listM = CmdList .Flag .Bool ("m" , false , "" )
330
- listRetracted = CmdList .Flag .Bool ("retracted" , false , "" )
331
- listTest = CmdList .Flag .Bool ("test" , false , "" )
332
- listU = CmdList .Flag .Bool ("u" , false , "" )
333
- listVersions = CmdList .Flag .Bool ("versions" , false , "" )
328
+ listCompiled = CmdList .Flag .Bool ("compiled" , false , "" )
329
+ listDeps = CmdList .Flag .Bool ("deps" , false , "" )
330
+ listE = CmdList .Flag .Bool ("e" , false , "" )
331
+ listExport = CmdList .Flag .Bool ("export" , false , "" )
332
+ listFmt = CmdList .Flag .String ("f" , "" , "" )
333
+ listFind = CmdList .Flag .Bool ("find" , false , "" )
334
+ listJson bool
335
+ listJsonFields jsonFlag // If not empty, only output these fields.
336
+ listM = CmdList .Flag .Bool ("m" , false , "" )
337
+ listRetracted = CmdList .Flag .Bool ("retracted" , false , "" )
338
+ listTest = CmdList .Flag .Bool ("test" , false , "" )
339
+ listU = CmdList .Flag .Bool ("u" , false , "" )
340
+ listVersions = CmdList .Flag .Bool ("versions" , false , "" )
334
341
)
335
342
343
+ // A StringsFlag is a command-line flag that interprets its argument
344
+ // as a space-separated list of possibly-quoted strings.
345
+ type jsonFlag map [string ]bool
346
+
347
+ func (v * jsonFlag ) Set (s string ) error {
348
+ if v , err := strconv .ParseBool (s ); err == nil {
349
+ listJson = v
350
+ return nil
351
+ }
352
+ listJson = true
353
+ if * v == nil {
354
+ * v = make (map [string ]bool )
355
+ }
356
+ for _ , f := range strings .Split (s , "," ) {
357
+ (* v )[f ] = true
358
+ }
359
+ return nil
360
+ }
361
+
362
+ func (v * jsonFlag ) String () string {
363
+ var fields []string
364
+ for f := range * v {
365
+ fields = append (fields , f )
366
+ }
367
+ sort .Strings (fields )
368
+ return strings .Join (fields , "," )
369
+ }
370
+
371
+ func (v * jsonFlag ) IsBoolFlag () bool {
372
+ return true
373
+ }
374
+
375
+ func (v * jsonFlag ) needAll () bool {
376
+ return len (* v ) == 0
377
+ }
378
+
379
+ func (v * jsonFlag ) needAny (fields ... string ) bool {
380
+ if v .needAll () {
381
+ return true
382
+ }
383
+ for _ , f := range fields {
384
+ if (* v )[f ] {
385
+ return true
386
+ }
387
+ }
388
+ return false
389
+ }
390
+
336
391
var nl = []byte {'\n' }
337
392
338
393
func runList (ctx context.Context , cmd * base.Command , args []string ) {
339
394
modload .InitWorkfile ()
340
395
341
- if * listFmt != "" && * listJson == true {
396
+ if * listFmt != "" && listJson == true {
342
397
base .Fatalf ("go list -f cannot be used with -json" )
343
398
}
344
399
@@ -357,9 +412,18 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
357
412
}
358
413
}
359
414
360
- var do func (any )
361
- if * listJson {
415
+ var do func (x any )
416
+ if listJson {
362
417
do = func (x any ) {
418
+ if ! listJsonFields .needAll () {
419
+ v := reflect .ValueOf (x ).Elem () // do is always called with a non-nil pointer.
420
+ // Clear all non-requested fields.
421
+ for i := 0 ; i < v .NumField (); i ++ {
422
+ if ! listJsonFields .needAny (v .Type ().Field (i ).Name ) {
423
+ v .Field (i ).Set (reflect .Zero (v .Type ().Field (i ).Type ))
424
+ }
425
+ }
426
+ }
363
427
b , err := json .MarshalIndent (x , "" , "\t " )
364
428
if err != nil {
365
429
out .Flush ()
@@ -589,7 +653,7 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
589
653
}
590
654
591
655
// Do we need to run a build to gather information?
592
- needStale := * listJson || strings .Contains (* listFmt , ".Stale" )
656
+ needStale := ( listJson && listJsonFields . needAny ( "Stale" , "StaleReason" )) || strings .Contains (* listFmt , ".Stale" )
593
657
if needStale || * listExport || * listCompiled {
594
658
var b work.Builder
595
659
b .Init ()
0 commit comments