Skip to content

Commit c77fb7d

Browse files
committed
x/vgo: add deplist command to get build information about (test) deps
This CL is a work in progress for golang/go#24661. Following the pattern laid down by the vet command, we want to pass the build details of the transitive (test) deps of a list of packages onto vetters/linters etc that need to load imports of said packages for go/types (and similar) analysis. Fixes golang/go#24661 Change-Id: If1496dd6a3ed501ad6f124226a05f5d57284c57d
1 parent b39cea3 commit c77fb7d

File tree

5 files changed

+229
-0
lines changed

5 files changed

+229
-0
lines changed
+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// Copyright 2011 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Package deplist implements the ``go deplist'' command.
6+
package deplist
7+
8+
import (
9+
"cmd/go/internal/base"
10+
"cmd/go/internal/load"
11+
"cmd/go/internal/work"
12+
)
13+
14+
var CmdDeplist = &base.Command{
15+
Run: runDeplist,
16+
CustomFlags: true,
17+
UsageLine: "deplist [-n] [-x] [build flags] [deplist flags] [packages]",
18+
Short: "provide JSON package build information for dependencies of packages",
19+
Long: `
20+
Deplist provide JSON package build information for dependencies of packages
21+
`,
22+
}
23+
24+
func runDeplist(cmd *base.Command, args []string) {
25+
deplistFlags, pkgArgs := deplistFlags(args)
26+
27+
work.BuildInit()
28+
29+
test := false
30+
build := false
31+
32+
for _, v := range deplistFlags {
33+
switch v {
34+
case "-test":
35+
test = true
36+
case "-build":
37+
build = true
38+
}
39+
}
40+
41+
if !build {
42+
base.Fatalf("don't yet know what to do without -build flag")
43+
}
44+
45+
deps := make(map[string]bool)
46+
var testDeps []string
47+
48+
pkgs := load.PackagesAndErrors(pkgArgs)
49+
if len(pkgs) == 0 {
50+
base.Fatalf("no packages to deplist")
51+
}
52+
53+
for _, p := range pkgs {
54+
for _, d := range p.Deps {
55+
deps[d] = true
56+
}
57+
58+
if test {
59+
for _, d := range p.TestImports {
60+
testDeps = append(testDeps, d)
61+
}
62+
for _, d := range p.XTestImports {
63+
testDeps = append(testDeps, d)
64+
}
65+
}
66+
}
67+
68+
var testPkgArgs []string
69+
70+
for _, d := range testDeps {
71+
if !deps[d] {
72+
testPkgArgs = append(testPkgArgs, d)
73+
}
74+
}
75+
76+
if len(testPkgArgs) > 0 {
77+
for _, p := range load.PackagesAndErrors(testPkgArgs) {
78+
deps[p.ImportPath] = true
79+
for _, d := range p.Deps {
80+
deps[d] = true
81+
}
82+
}
83+
}
84+
85+
var uniqDeps []string
86+
for p := range deps {
87+
uniqDeps = append(uniqDeps, p)
88+
}
89+
90+
depPkgs := load.PackagesForBuild(uniqDeps)
91+
92+
var b work.Builder
93+
b.Init()
94+
95+
root := &work.Action{Mode: "go deplist"}
96+
for _, p := range depPkgs {
97+
root.Deps = append(root.Deps, b.DeplistAction(work.ModeBuild, work.ModeBuild, p))
98+
}
99+
b.Do(root)
100+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright 2017 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package deplist
6+
7+
import (
8+
"flag"
9+
"fmt"
10+
"os"
11+
"strings"
12+
13+
"cmd/go/internal/base"
14+
"cmd/go/internal/cmdflag"
15+
"cmd/go/internal/work"
16+
)
17+
18+
const cmd = "deplist"
19+
20+
// deplistFlagDefn is the set of flags we process.
21+
var deplistFlagDefn = []*cmdflag.Defn{
22+
{Name: "test", BoolVar: new(bool)},
23+
{Name: "build", BoolVar: new(bool)},
24+
}
25+
26+
var deplistTool string
27+
28+
// add build flags to deplistFlagDefn.
29+
func init() {
30+
var cmd base.Command
31+
work.AddBuildFlags(&cmd)
32+
cmd.Flag.VisitAll(func(f *flag.Flag) {
33+
deplistFlagDefn = append(deplistFlagDefn, &cmdflag.Defn{
34+
Name: f.Name,
35+
Value: f.Value,
36+
})
37+
})
38+
}
39+
40+
// deplistFlags processes the command line, splitting it at the first non-flag
41+
// into the list of flags and list of packages.
42+
func deplistFlags(args []string) (passToDeplist, packageNames []string) {
43+
for i := 0; i < len(args); i++ {
44+
if !strings.HasPrefix(args[i], "-") {
45+
return args[:i], args[i:]
46+
}
47+
48+
f, value, extraWord := cmdflag.Parse(cmd, deplistFlagDefn, args, i)
49+
if f == nil {
50+
fmt.Fprintf(os.Stderr, "deplist: flag %q not defined\n", args[i])
51+
fmt.Fprintf(os.Stderr, "Run \"go help deplist\" for more information\n")
52+
os.Exit(2)
53+
}
54+
if f.Value != nil {
55+
if err := f.Value.Set(value); err != nil {
56+
base.Fatalf("invalid flag argument for -%s: %v", f.Name, err)
57+
}
58+
}
59+
if extraWord {
60+
i++
61+
}
62+
}
63+
return args, nil
64+
}

vendor/cmd/go/internal/work/action.go

+26
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,32 @@ func (b *Builder) VetAction(mode, depMode BuildMode, p *load.Package) *Action {
403403
return a
404404
}
405405

406+
// DeplistAction returns the action for running go deplist on package p.
407+
// It depends on the action for compiling p.
408+
// If the caller may be causing p to be installed, it is up to the caller
409+
// to make sure that the install depends on (runs after) deplist.
410+
func (b *Builder) DeplistAction(mode, depMode BuildMode, p *load.Package) *Action {
411+
// Construct deplist action.
412+
a := b.cacheAction("deplist", p, func() *Action {
413+
a1 := b.CompileAction(mode, depMode, p)
414+
415+
a := &Action{
416+
Mode: "deplist",
417+
Package: p,
418+
Deps: []*Action{a1},
419+
Objdir: a1.Objdir,
420+
}
421+
if a1.Func == nil {
422+
// Built-in packages like unsafe.
423+
return a
424+
}
425+
a.Func = (*Builder).deplist
426+
427+
return a
428+
})
429+
return a
430+
}
431+
406432
// LinkAction returns the action for linking p into an executable
407433
// and possibly installing the result (according to mode).
408434
// depMode is the action (build or install) to use when compiling dependencies.

vendor/cmd/go/internal/work/exec.go

+37
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,43 @@ func (b *Builder) vet(a *Action) error {
761761
return b.run(a, p.Dir, p.ImportPath, env, cfg.BuildToolexec, tool, VetFlags, a.Objdir+"vet.cfg")
762762
}
763763

764+
func (b *Builder) deplist(a *Action) error {
765+
// a.Deps[0] is the build of the package being deplistted.
766+
767+
p := a.Deps[0].Package
768+
769+
enc := json.NewEncoder(os.Stdout)
770+
enc.SetIndent("", "\t")
771+
772+
failed := false
773+
774+
c := cache.Default()
775+
ca, err := c.Get(a.Deps[0].actionID)
776+
if err != nil {
777+
failed = true
778+
}
779+
780+
details := struct {
781+
ImportPath string
782+
PackageFile string
783+
Incomplete bool
784+
}{
785+
ImportPath: p.ImportPath,
786+
}
787+
788+
if !failed {
789+
details.PackageFile = c.OutputFile(ca.OutputID)
790+
} else {
791+
details.Incomplete = true
792+
}
793+
794+
if err := enc.Encode(details); err != nil {
795+
return fmt.Errorf("failed to JSON encode package: %v", err)
796+
}
797+
798+
return nil
799+
}
800+
764801
// linkActionID computes the action ID for a link action.
765802
func (b *Builder) linkActionID(a *Action) cache.ActionID {
766803
p := a.Package

vendor/cmd/go/main.go

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"cmd/go/internal/bug"
2020
"cmd/go/internal/cfg"
2121
"cmd/go/internal/clean"
22+
"cmd/go/internal/deplist"
2223
"cmd/go/internal/doc"
2324
"cmd/go/internal/envcmd"
2425
"cmd/go/internal/fix"
@@ -56,6 +57,7 @@ func init() {
5657
vgo.CmdVerify,
5758
version.CmdVersion,
5859
vet.CmdVet,
60+
deplist.CmdDeplist,
5961

6062
help.HelpBuildmode,
6163
help.HelpC,

0 commit comments

Comments
 (0)