...

Source file src/pkg/cmd/go/internal/tool/tool.go

     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		"cmd/go/internal/base"
    16		"cmd/go/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	}
   134	

View as plain text