github.com/knieriem/gointernal@v0.2.0-pre2/cmd/go/base/base.go (about)

     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  	"context"
    11  	"flag"
    12  	"fmt"
    13  	"log"
    14  	"os"
    15  	"strings"
    16  	"sync"
    17  )
    18  
    19  // A Command is an implementation of a go command
    20  // like go build or go fix.
    21  type Command struct {
    22  	// Run runs the command.
    23  	// The args are the arguments after the command name.
    24  	Run func(ctx context.Context, cmd *Command, args []string)
    25  
    26  	// UsageLine is the one-line usage message.
    27  	// The words between "go" and the first flag or argument in the line are taken to be the command name.
    28  	UsageLine string
    29  
    30  	// Short is the short description shown in the 'go help' output.
    31  	Short string
    32  
    33  	// Long is the long message shown in the 'go help <this-command>' output.
    34  	Long string
    35  
    36  	// Flag is a set of flags specific to this command.
    37  	Flag flag.FlagSet
    38  
    39  	// CustomFlags indicates that the command will do its own
    40  	// flag parsing.
    41  	CustomFlags bool
    42  
    43  	// Commands lists the available commands and help topics.
    44  	// The order here is the order in which they are printed by 'go help'.
    45  	// Note that subcommands are in general best avoided.
    46  	Commands []*Command
    47  }
    48  
    49  // Prog must be initialized in package main
    50  var Prog *Command
    51  
    52  // hasFlag reports whether a command or any of its subcommands contain the given
    53  // flag.
    54  func hasFlag(c *Command, name string) bool {
    55  	if f := c.Flag.Lookup(name); f != nil {
    56  		return true
    57  	}
    58  	for _, sub := range c.Commands {
    59  		if hasFlag(sub, name) {
    60  			return true
    61  		}
    62  	}
    63  	return false
    64  }
    65  
    66  // LongName returns the command's long name: all the words in the usage line between "go" and a flag or argument,
    67  func (c *Command) LongName() string {
    68  	name := c.UsageLine
    69  	if i := strings.Index(name, " -- "); i >= 0 {
    70  		name = name[:i]
    71  	}
    72  	if i := strings.Index(name, " ["); i >= 0 {
    73  		name = name[:i]
    74  	}
    75  	if name == Prog.UsageLine {
    76  		return ""
    77  	}
    78  	return strings.TrimPrefix(name, Prog.UsageLine+" ")
    79  }
    80  
    81  // Name returns the command's short name: the last word in the usage line before a flag or argument.
    82  func (c *Command) Name() string {
    83  	name := c.LongName()
    84  	if i := strings.LastIndex(name, " "); i >= 0 {
    85  		name = name[i+1:]
    86  	}
    87  	return name
    88  }
    89  
    90  func (c *Command) Usage() {
    91  	fmt.Fprintf(os.Stderr, "usage: %s\n", strings.Replace(c.UsageLine, " -- ", " ", -1))
    92  	fmt.Fprintf(os.Stderr, "Run '%s help %s' for details.\n", Prog.UsageLine, c.LongName())
    93  	SetExitStatus(2)
    94  	Exit()
    95  }
    96  
    97  // Runnable reports whether the command can be run; otherwise
    98  // it is a documentation pseudo-command such as importpath.
    99  func (c *Command) Runnable() bool {
   100  	return c.Run != nil
   101  }
   102  
   103  var atExitFuncs []func()
   104  
   105  func AtExit(f func()) {
   106  	atExitFuncs = append(atExitFuncs, f)
   107  }
   108  
   109  func Exit() {
   110  	for _, f := range atExitFuncs {
   111  		f()
   112  	}
   113  	os.Exit(exitStatus)
   114  }
   115  
   116  func Fatalf(format string, args ...interface{}) {
   117  	Errorf(format, args...)
   118  	Exit()
   119  }
   120  
   121  func Errorf(format string, args ...interface{}) {
   122  	log.Printf(format, args...)
   123  	SetExitStatus(1)
   124  }
   125  
   126  func ExitIfErrors() {
   127  	if exitStatus != 0 {
   128  		Exit()
   129  	}
   130  }
   131  
   132  var exitStatus = 0
   133  var exitMu sync.Mutex
   134  
   135  func SetExitStatus(n int) {
   136  	exitMu.Lock()
   137  	if exitStatus < n {
   138  		exitStatus = n
   139  	}
   140  	exitMu.Unlock()
   141  }
   142  
   143  func GetExitStatus() int {
   144  	return exitStatus
   145  }
   146  
   147  // Usage is the usage-reporting function, filled in by package main
   148  // but here for reference by other packages.
   149  var Usage func()