github.com/bir3/gocompiler@v0.3.205/src/cmd/gocmd/internal/tool/tool.go (about) 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 tool implements the “go tool” command. 6 package tool 7 8 import ( 9 "context" 10 "fmt" 11 "github.com/bir3/gocompiler/src/go/build" 12 "os" 13 "os/exec" 14 "os/signal" 15 "sort" 16 "strings" 17 18 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/base" 19 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/cfg" 20 ) 21 22 var CmdTool = &base.Command{ 23 Run: runTool, 24 UsageLine: "go tool [-n] command [args...]", 25 Short: "run specified go tool", 26 Long: ` 27 Tool runs the go tool command identified by the arguments. 28 With no arguments it prints the list of known tools. 29 30 The -n flag causes tool to print the command that would be 31 executed but not execute it. 32 33 For more about each tool command, see 'go doc cmd/<command>'. 34 `, 35 } 36 37 var toolN bool 38 39 // Return whether tool can be expected in the gccgo tool directory. 40 // Other binaries could be in the same directory so don't 41 // show those with the 'go tool' command. 42 func isGccgoTool(tool string) bool { 43 switch tool { 44 case "cgo", "fix", "cover", "godoc", "vet": 45 return true 46 } 47 return false 48 } 49 50 func init() { 51 base.AddChdirFlag(&CmdTool.Flag) 52 CmdTool.Flag.BoolVar(&toolN, "n", false, "") 53 } 54 55 func runTool(ctx context.Context, cmd *base.Command, args []string) { 56 if len(args) == 0 { 57 listTools() 58 return 59 } 60 toolName := args[0] 61 // The tool name must be lower-case letters, numbers or underscores. 62 for _, c := range toolName { 63 switch { 64 case 'a' <= c && c <= 'z', '0' <= c && c <= '9', c == '_': 65 default: 66 fmt.Fprintf(os.Stderr, "go: bad tool name %q\n", toolName) 67 base.SetExitStatus(2) 68 return 69 } 70 } 71 toolPath := base.Tool(toolName) 72 if toolPath == "" { 73 return 74 } 75 if toolN { 76 cmd := toolPath 77 if len(args) > 1 { 78 cmd += " " + strings.Join(args[1:], " ") 79 } 80 fmt.Printf("%s\n", cmd) 81 return 82 } 83 args[0] = toolPath // in case the tool wants to re-exec itself, e.g. cmd/dist 84 toolCmd := &exec.Cmd{ 85 Path: toolPath, 86 Args: args, 87 Stdin: os.Stdin, 88 Stdout: os.Stdout, 89 Stderr: os.Stderr, 90 } 91 err := toolCmd.Start() 92 if err == nil { 93 c := make(chan os.Signal, 100) 94 signal.Notify(c) 95 go func() { 96 for sig := range c { 97 toolCmd.Process.Signal(sig) 98 } 99 }() 100 err = toolCmd.Wait() 101 signal.Stop(c) 102 close(c) 103 } 104 if err != nil { 105 // Only print about the exit status if the command 106 // didn't even run (not an ExitError) or it didn't exit cleanly 107 // or we're printing command lines too (-x mode). 108 // Assume if command exited cleanly (even with non-zero status) 109 // it printed any messages it wanted to print. 110 if e, ok := err.(*exec.ExitError); !ok || !e.Exited() || cfg.BuildX { 111 fmt.Fprintf(os.Stderr, "go tool %s: %s\n", toolName, err) 112 } 113 base.SetExitStatus(1) 114 return 115 } 116 } 117 118 // listTools prints a list of the available tools in the tools directory. 119 func listTools() { 120 f, err := os.Open(build.ToolDir) 121 if err != nil { 122 fmt.Fprintf(os.Stderr, "go: no tool directory: %s\n", err) 123 base.SetExitStatus(2) 124 return 125 } 126 defer f.Close() 127 names, err := f.Readdirnames(-1) 128 if err != nil { 129 fmt.Fprintf(os.Stderr, "go: can't read tool directory: %s\n", err) 130 base.SetExitStatus(2) 131 return 132 } 133 134 sort.Strings(names) 135 for _, name := range names { 136 // Unify presentation by going to lower case. 137 // If it's windows, don't show the .exe suffix. 138 name = strings.TrimSuffix(strings.ToLower(name), cfg.ToolExeSuffix()) 139 140 // The tool directory used by gccgo will have other binaries 141 // in addition to go tools. Only display go tools here. 142 if cfg.BuildToolchainName == "gccgo" && !isGccgoTool(name) { 143 continue 144 } 145 fmt.Println(name) 146 } 147 }