1
2
3
4
5
6 package tool
7
8 import (
9 "context"
10 "fmt"
11 exec "internal/execabs"
12 "os"
13 "os/signal"
14 "sort"
15 "strings"
16
17 "cmd/go/internal/base"
18 "cmd/go/internal/cfg"
19 )
20
21 var CmdTool = &base.Command{
22 Run: runTool,
23 UsageLine: "go tool [-n] command [args...]",
24 Short: "run specified go tool",
25 Long: `
26 Tool runs the go tool command identified by the arguments.
27 With no arguments it prints the list of known tools.
28
29 The -n flag causes tool to print the command that would be
30 executed but not execute it.
31
32 For more about each tool command, see 'go doc cmd/<command>'.
33 `,
34 }
35
36 var toolN bool
37
38
39
40
41 func isGccgoTool(tool string) bool {
42 switch tool {
43 case "cgo", "fix", "cover", "godoc", "vet":
44 return true
45 }
46 return false
47 }
48
49 func init() {
50 CmdTool.Flag.BoolVar(&toolN, "n", false, "")
51 }
52
53 func runTool(ctx context.Context, cmd *base.Command, args []string) {
54 if len(args) == 0 {
55 listTools()
56 return
57 }
58 toolName := args[0]
59
60 for _, c := range toolName {
61 switch {
62 case 'a' <= c && c <= 'z', '0' <= c && c <= '9', c == '_':
63 default:
64 fmt.Fprintf(os.Stderr, "go: bad tool name %q\n", toolName)
65 base.SetExitStatus(2)
66 return
67 }
68 }
69 toolPath := base.Tool(toolName)
70 if toolPath == "" {
71 return
72 }
73 if toolN {
74 cmd := toolPath
75 if len(args) > 1 {
76 cmd += " " + strings.Join(args[1:], " ")
77 }
78 fmt.Printf("%s\n", cmd)
79 return
80 }
81 args[0] = toolPath
82 toolCmd := &exec.Cmd{
83 Path: toolPath,
84 Args: args,
85 Stdin: os.Stdin,
86 Stdout: os.Stdout,
87 Stderr: os.Stderr,
88 }
89 err := toolCmd.Start()
90 if err == nil {
91 c := make(chan os.Signal, 100)
92 signal.Notify(c)
93 go func() {
94 for sig := range c {
95 toolCmd.Process.Signal(sig)
96 }
97 }()
98 err = toolCmd.Wait()
99 signal.Stop(c)
100 close(c)
101 }
102 if err != nil {
103
104
105
106
107
108 if e, ok := err.(*exec.ExitError); !ok || !e.Exited() || cfg.BuildX {
109 fmt.Fprintf(os.Stderr, "go tool %s: %s\n", toolName, err)
110 }
111 base.SetExitStatus(1)
112 return
113 }
114 }
115
116
117 func listTools() {
118 f, err := os.Open(base.ToolDir)
119 if err != nil {
120 fmt.Fprintf(os.Stderr, "go: no tool directory: %s\n", err)
121 base.SetExitStatus(2)
122 return
123 }
124 defer f.Close()
125 names, err := f.Readdirnames(-1)
126 if err != nil {
127 fmt.Fprintf(os.Stderr, "go: can't read tool directory: %s\n", err)
128 base.SetExitStatus(2)
129 return
130 }
131
132 sort.Strings(names)
133 for _, name := range names {
134
135 name = strings.ToLower(name)
136
137 if base.ToolIsWindows && strings.HasSuffix(name, base.ToolWindowsExtension) {
138 name = name[:len(name)-len(base.ToolWindowsExtension)]
139 }
140
141
142 if cfg.BuildToolchainName == "gccgo" && !isGccgoTool(name) {
143 continue
144 }
145 fmt.Println(name)
146 }
147 }
148
View as plain text