...

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

     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 base defines shared basic pieces of the go command,
     6	// in particular logging and the Command structure.
     7	package base
     8	
     9	import (
    10		"bytes"
    11		"errors"
    12		"flag"
    13		"fmt"
    14		"go/scanner"
    15		"log"
    16		"os"
    17		"os/exec"
    18		"strings"
    19		"sync"
    20	
    21		"cmd/go/internal/cfg"
    22		"cmd/go/internal/str"
    23	)
    24	
    25	// A Command is an implementation of a go command
    26	// like go build or go fix.
    27	type Command struct {
    28		// Run runs the command.
    29		// The args are the arguments after the command name.
    30		Run func(cmd *Command, args []string)
    31	
    32		// UsageLine is the one-line usage message.
    33		// The words between "go" and the first flag or argument in the line are taken to be the command name.
    34		UsageLine string
    35	
    36		// Short is the short description shown in the 'go help' output.
    37		Short string
    38	
    39		// Long is the long message shown in the 'go help <this-command>' output.
    40		Long string
    41	
    42		// Flag is a set of flags specific to this command.
    43		Flag flag.FlagSet
    44	
    45		// CustomFlags indicates that the command will do its own
    46		// flag parsing.
    47		CustomFlags bool
    48	
    49		// Commands lists the available commands and help topics.
    50		// The order here is the order in which they are printed by 'go help'.
    51		// Note that subcommands are in general best avoided.
    52		Commands []*Command
    53	}
    54	
    55	var Go = &Command{
    56		UsageLine: "go",
    57		Long:      `Go is a tool for managing Go source code.`,
    58		// Commands initialized in package main
    59	}
    60	
    61	// LongName returns the command's long name: all the words in the usage line between "go" and a flag or argument,
    62	func (c *Command) LongName() string {
    63		name := c.UsageLine
    64		if i := strings.Index(name, " ["); i >= 0 {
    65			name = name[:i]
    66		}
    67		if name == "go" {
    68			return ""
    69		}
    70		return strings.TrimPrefix(name, "go ")
    71	}
    72	
    73	// Name returns the command's short name: the last word in the usage line before a flag or argument.
    74	func (c *Command) Name() string {
    75		name := c.LongName()
    76		if i := strings.LastIndex(name, " "); i >= 0 {
    77			name = name[i+1:]
    78		}
    79		return name
    80	}
    81	
    82	func (c *Command) Usage() {
    83		fmt.Fprintf(os.Stderr, "usage: %s\n", c.UsageLine)
    84		fmt.Fprintf(os.Stderr, "Run 'go help %s' for details.\n", c.LongName())
    85		SetExitStatus(2)
    86		Exit()
    87	}
    88	
    89	// Runnable reports whether the command can be run; otherwise
    90	// it is a documentation pseudo-command such as importpath.
    91	func (c *Command) Runnable() bool {
    92		return c.Run != nil
    93	}
    94	
    95	var atExitFuncs []func()
    96	
    97	func AtExit(f func()) {
    98		atExitFuncs = append(atExitFuncs, f)
    99	}
   100	
   101	func Exit() {
   102		for _, f := range atExitFuncs {
   103			f()
   104		}
   105		os.Exit(exitStatus)
   106	}
   107	
   108	func Fatalf(format string, args ...interface{}) {
   109		Errorf(format, args...)
   110		Exit()
   111	}
   112	
   113	func Errorf(format string, args ...interface{}) {
   114		log.Printf(format, args...)
   115		SetExitStatus(1)
   116	}
   117	
   118	func ExitIfErrors() {
   119		if exitStatus != 0 {
   120			Exit()
   121		}
   122	}
   123	
   124	var exitStatus = 0
   125	var exitMu sync.Mutex
   126	
   127	func SetExitStatus(n int) {
   128		exitMu.Lock()
   129		if exitStatus < n {
   130			exitStatus = n
   131		}
   132		exitMu.Unlock()
   133	}
   134	
   135	func GetExitStatus() int {
   136		return exitStatus
   137	}
   138	
   139	// Run runs the command, with stdout and stderr
   140	// connected to the go command's own stdout and stderr.
   141	// If the command fails, Run reports the error using Errorf.
   142	func Run(cmdargs ...interface{}) {
   143		cmdline := str.StringList(cmdargs...)
   144		if cfg.BuildN || cfg.BuildX {
   145			fmt.Printf("%s\n", strings.Join(cmdline, " "))
   146			if cfg.BuildN {
   147				return
   148			}
   149		}
   150	
   151		cmd := exec.Command(cmdline[0], cmdline[1:]...)
   152		cmd.Stdout = os.Stdout
   153		cmd.Stderr = os.Stderr
   154		if err := cmd.Run(); err != nil {
   155			Errorf("%v", err)
   156		}
   157	}
   158	
   159	// RunStdin is like run but connects Stdin.
   160	func RunStdin(cmdline []string) {
   161		cmd := exec.Command(cmdline[0], cmdline[1:]...)
   162		cmd.Stdin = os.Stdin
   163		cmd.Stdout = os.Stdout
   164		cmd.Stderr = os.Stderr
   165		cmd.Env = cfg.OrigEnv
   166		StartSigHandlers()
   167		if err := cmd.Run(); err != nil {
   168			Errorf("%v", err)
   169		}
   170	}
   171	
   172	// Usage is the usage-reporting function, filled in by package main
   173	// but here for reference by other packages.
   174	var Usage func()
   175	
   176	// ExpandScanner expands a scanner.List error into all the errors in the list.
   177	// The default Error method only shows the first error
   178	// and does not shorten paths.
   179	func ExpandScanner(err error) error {
   180		// Look for parser errors.
   181		if err, ok := err.(scanner.ErrorList); ok {
   182			// Prepare error with \n before each message.
   183			// When printed in something like context: %v
   184			// this will put the leading file positions each on
   185			// its own line. It will also show all the errors
   186			// instead of just the first, as err.Error does.
   187			var buf bytes.Buffer
   188			for _, e := range err {
   189				e.Pos.Filename = ShortPath(e.Pos.Filename)
   190				buf.WriteString("\n")
   191				buf.WriteString(e.Error())
   192			}
   193			return errors.New(buf.String())
   194		}
   195		return err
   196	}
   197	

View as plain text