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